Kleines "Labyrinth-Spiel", freu mich über jede Kritik!



  • ..... schrieb:

    Hey,

    ich finde dein Spiel sehr gelungen. Insbesondere, da es nur eine Konsole benötigt. Sehr schön 👎

    Man kann übrigens das Spielfeld verlassen. Wenn das Spiel beginnt, dann kann man einfach "verschwinden".

    Damit es immer einen Weg nach draußen gibt, das ist eigentlich nicht so schwierig. Nehmen wir an, du hast ein Labyrinth, dass 5x5 groß ist:

    _ _ _ _ _
    _ _ _ _ _
    _ _ _ _ _
    _ _ _ _ _
    _ _ _ _ _

    Nun suchst du zufällig eine Stelle am Rand aus:

    _ _ _ _ _
    _ _ _ _ _
    _ _ _ _ E
    _ _ _ _ _
    _ _ _ _ _

    Von dieser Stelle bildest du nun zufällig einen Weg (zufällig eine Aktion auswählen: hoch, runter, links, rechts) und das solange bis du wieder an irgendeinem Rand bist:

    _ _ _ _ _
    _ _ _ _ _
    * * _ * E
    _ * * * _
    _ _ _ _ _

    Diese Koordinaten speicherst du in ein Array, anschließend generierst du zufällig weitere Blöcke. Dabei überprüfst du, ob diese Stelle schon für den Weg belegt ist. Wenn das so ist, dann setzt du dort keinen Block.

    So hast du immer einen Weg, und evtl. sogar mehrere. Aber immer mindestens einen.

    Für system("cls") gibt es keine portable Lösung. Da stößt du so langsam an die Grenze einer Konsolenanwendung.

    Tschuldigung. Falscher Daumen. Es war natürlich der gemeint: 👍 👍 👍 👍 👍 👍 👍 👍 👍



  • Herzlichen Dank, das freut mich sehr, dass es dir gefällt! 🙂

    Danke für den Hinweis mit dem Lösungsweg, werde ich gleich mit einbauen 😉 und verschwinden darf natürlich auch keiner 🙄 🙄



  • ..... schrieb:

    Tschuldigung. Falscher Daumen. Es war natürlich der gemeint: 👍 👍 👍 👍 👍 👍 👍 👍 👍

    musst du deshalb das forum zumüllen und den ganzen ramsch nochmal wiederholen? 🙄



  • du könntest anstatt

    system("cls")
    

    Ev auch mit ANSI escape codes wieder an den anfang der Ausgabe springen und neu ausgeben...
    Hab es jedoch noch nie gebraucht^^



  • So, ich habe das ganze jetzt nochmal ein bisschen überarbeitet, es ist jetzt nicht mehr möglich aus dem Bild zu "verschwinden", auch gibt es jetzt immer min. einen Lösungsweg. Die Spielfeldgroesse ist ein wenig flexibler geworden. Da ich an vielen Stellen einiges geändert habe, poste ich lieber nochmal den ganzen Code, anstatt nur die Änderungen. Ich hoffe ihr seht mir das etwas längere Listing nach 🙄 Schonmal vielen Dank an alle die sich das ganze trotzdem anschauen 🙂 🙂 Wie gesagt, ich freue mich über jeden Hinweis, sei es eine Möglichkeit etwas besser zu schreiben, ein Fehler oder eine andere Kleinigkeit.

    Viele Grüße

    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <time.h>
    #include <limits.h>
    
    #define MAX_X 25
    #define MAX_Y 50
    
    typedef struct figure fig;
    
    struct figure
    {
        int x_coord;
        int y_coord;
    };
    
    int spielfeld(char **feld,int x,int y, fig *spieler_pos,int *schritte);
    void input(fig *spieler_pos,char **feld);
    void eingabe_universal(char wahl,void *adresse,char typ);
    
    /*******************************************************************/
    /*******************************************************************/
    /*******************************************************************/
    
    int main()
    {
        puts("*****************************************************************");
        puts("**           Kleines Labyrinth Version 1.1                     **");
        puts("*****************************************************************");
        puts("**          Steuerung:  A W S D - Steuerung                    **");
        puts("**          Jeden Schritt mit ENTER bestaetigen                **");
        puts("*****************************************************************\n");
    
        fig spieler_pos;
    
        int i=0,j=0,temp=0,temp_x=0,temp_y=0,schritte=0;
        char **feld;
        int groesse_x=0,groesse_y=0;
    
        srand(time(NULL));
    
        /* Angeben der Spielfeldgroesse */
    
        printf("Maximale Spielfeldgroesse: %i x %i",MAX_X,MAX_Y);
        printf("\nSpielfeldgroesse x: ");
    
        eingabe_universal('i',&groesse_x,'x');
    
        if(groesse_x <= 0)
        {
            printf("\neingegen: groesse_x: %i",groesse_x);
            printf("\nZahl muss groesser 0 sein!");
            return 0;
        }
    
        printf("\nSpielfeldgroesse y: ");
    
        eingabe_universal('i',&groesse_y,'y');
    
        if(groesse_y <= 0)
        {
            printf("\neingegen: groesse_y: %i",groesse_y);
            printf("\nZahl muss groesser 0 sein!");
            return 0;
        }
    
        /* reservieren des Speichers fürs Spielfeld */
    
        if( (feld = malloc(sizeof(char *) * groesse_x)) == NULL)
        free(feld);
    
        for(i=0; i<groesse_x;i++)
        {
            feld[i] = malloc(groesse_y * sizeof(char));
            if(feld[i] == NULL)
            {
                free(feld[i]);
                printf("\nERROR\n");
                break;
            }
        }
    
        /* Spielfeldrand erstellen */
    
        //linker Rand
        for(i=0;i<groesse_x;i++)
        {
            feld[i][0] = '*';
        }
        //oberer Rand
        for(j=0;j<groesse_y;j++)
        {
            feld[0][j] = '*';
        }
        //rechter Rand
        for(i=0;i<groesse_x;i++)
        {
            feld[i][groesse_y-1] = '*';
        }
        //unterer Rand
        for(j=0;j<groesse_y;j++)
        {
            feld[groesse_x-1][j] = '*';
        }
    
        /******************************************************/
        /*Sicherstellen, dass min. 1 Lösungsweg vorhanden ist!*/
        /******************************************************/
    
        /*temp_x und temp_y sind die Koordinaten UNTER dem Ziel*/
        temp_x = 1;
        temp_y = groesse_y-2;
    
        /*suchen eines Weges VOM Ziel ZUM Start*/
        do
        {
        /*Am rechten Rand, nur nach unten oder links*/
        if(temp_y == (groesse_y-2))
        {
            if( (temp=rand()) < RAND_MAX/2)
            {
                if(temp_y > 1)
                {temp_y--;}
            }
            else
            {
             if(temp_x < (groesse_x-2))
             {temp_x++;}
            }
        }
        /*jetzt links oben oder unten*/
        else
        {
            if( (temp=rand()) < (RAND_MAX/3) )
            {
                if( temp_y > 1) //prüfen ob man an den Feldrand kommen würde
                {temp_y--;}
                else
                {temp_x++;}
            }
            else if( (temp=rand()) < (RAND_MAX/2) )
            {
                if(temp_x < (groesse_x-2)) //prüfen ob man an den Feldrand kommen würde
                {temp_x++;}
                else
                {temp_y--;}
            }
            else
            {
                if( temp_x > 2) //prüfen ob man an den Feldrand kommen würde
                {temp_x--;}
                else
                {
                if(temp_x < (groesse_x-2)) //prüfen ob man an den Feldrand kommen würde
                {temp_x++;}
                }
            }
        }
        feld[temp_x][temp_y] = ' ';
        }
        while((temp_x != (groesse_x-2) ) || (temp_y !=1));
    
        /* zufälliges initialisieren des inneren Spielfelds mit
           einem * oder einem Leerzeichen. * zu 1/3, leerzeichen ca 2/3 */
    
        for(i=1;i<=groesse_x-2;i++)
        {
            for(j=1;j<=groesse_y-2;j++)
            {
            if( (temp = rand()) < (RAND_MAX/3))
            {
                feld[i][j] = ' ';
            }
            else
            {
                if( (feld[i][j] != ' ') )
                {
                    feld[i][j] = '*';
                }
            }
            }
        }
    
        //Ziel setzen und Feld davor freimachen
    
        feld[0][groesse_y-2] = 'Z';
        feld[1][groesse_y-2] = ' ';
    
        //StartPosition setzen
        spieler_pos.y_coord = 0;
        spieler_pos.x_coord = groesse_x -2;
        feld[spieler_pos.x_coord][spieler_pos.y_coord] = 'X';
        feld[spieler_pos.x_coord][spieler_pos.y_coord+1] = ' '; //Zur Sicherheit, dass man raus kann
        //
        for(i=0;i<groesse_x;i++)
        {
            printf("\n");
            for(j=0;j<groesse_y;j++)
            {
                printf("%c",feld[i][j]);
            }
        }
    
        //Schleife ist solange wahr, bis der Spieler beim Ziel angekommen ist
        while(spielfeld(feld,groesse_x,groesse_y,&spieler_pos,&schritte));
    
        printf("\n\ngewonnen!!!\n\n");
    
       return 0;
    }
    
    /*******************************************************************/
    /*******************************************************************/
    /*******************************************************************/
    
    /*Diese Funktion liest char oder int ein, und prüft auf die Richtigkeit der Eingabe*/
    
    void eingabe_universal(char wahl,void *adresse,char typ)
    {
        int i=0;
    
        /*einlesen und pruefen ob Zahl eingetippt wurde*/
    
        if(wahl == 'i')
        {
        char temp[4];
        fgets(temp,sizeof(temp),stdin);
    
        for(i=0;i<4;i++)
        {
            if( (temp[i] < 48 || temp[i] > 57) && !(temp[i] == '\0' || temp[i] == '\n'))
            {
                printf("\nError, falsche Eingabe, bitte eine Zahl eingeben!");
                return;
            }
        }
        if( typ == 'x')
        {
            if((i = atoi(temp)) > MAX_X)
            {
            printf("\nERROR, Zahl größer %i",MAX_X);
            return;
            }
        }
        else if( typ == 'y')
        {
        if((i = atoi(temp)) > MAX_Y)
            {
            printf("\nERROR, Zahl größer %i",MAX_Y);
            return;
            }
        }
        *(int *) adresse = i;
        }
    
        /* Falls Buchstaben eingelesen und geprueft werden: */
    
        else if(wahl == 'c')
        {
            char temp[3];
            fgets(temp,sizeof(temp),stdin);
    
            for(i=0;i<3;i++)
            {
            if( !(temp[i] == 'a' || temp[i] == 'w' || temp[i] == 's' || temp[i] == 'd' || temp[i] == '\n' || temp[i] == '\0') )
            {
                printf("\nError, falsche Eingabe!");
            }
            else *(char *)adresse = temp[0];
            }
    
        return;
        }
    }
    
    /*******************************************************************/
    /*******************************************************************/
    /*******************************************************************/
    
    int spielfeld(char **feld,int x,int y, fig *spieler_pos,int *schritte)
    {
        int i=0,j=0;
    
        //Eingeben der Laufrichtung und überprüfen ob dort eine Wand ist oder nicht
        input(spieler_pos,feld);
    
        //Neues setzen der Spielerposition
        feld[spieler_pos->x_coord][spieler_pos->y_coord] = 'X';
    
        //Clearen der Console, gibts hierfür eine portable Lösung?!
        system("cls");
    
        //Generieren des Neuen Spielfelds
        for(i=0;i<x;i++)
        {
            for(j=0;j<y;j++)
            {
                printf("%c",feld[i][j]);
            }
            printf("\n");
        }
    
        *schritte += 1; //Zählen der Schritte die man bis zum Ziel gebraucht hat
    
        if(feld[0][y-2] == 'X')
        {
            printf("\nAnzahl benoetigter Schritte: %i",*schritte);
            return 0;
        }
        else return 1;
    }
    
    /*******************************************************************/
    /*******************************************************************/
    /*******************************************************************/
    
    void input(fig *spieler_pos,char **feld)
    {
        /*Der Spieler bewegt sich mit der bekannten A-W-S-D Steuerung
          muss aber nach jeder Eingabe mit ENTER bestätigen*/
    
        char weg;
        printf("\n:");
        eingabe_universal('c',&weg,'z'); // 'z' muss aufgrund der Funktionsdefiniton angegeben werden,
                                         //  ist hier aber ohne jeglichen Effekt!
    
        //Prüfen in welche Richtung gegangen werden soll
    
        if(weg == 'a')
        {
            if(feld[spieler_pos->x_coord][spieler_pos->y_coord-1] != '*' && spieler_pos->y_coord >0)
            {
            feld[spieler_pos->x_coord][spieler_pos->y_coord] = ' ';
            spieler_pos->y_coord -= 1;
            }
            else printf("\n geht nicht!\n");
    
        }
        else if(weg == 'd')
        {
            if(feld[spieler_pos->x_coord][spieler_pos->y_coord+1] != '*')
            {
            feld[spieler_pos->x_coord][spieler_pos->y_coord] = ' ';
            spieler_pos->y_coord += 1;
            }
            else printf("\n geht nicht!\n");
    
        }
        else if(weg == 'w')
        {
            if(feld[spieler_pos->x_coord-1][spieler_pos->y_coord] != '*')
            {
            feld[spieler_pos->x_coord][spieler_pos->y_coord] = ' ';
            spieler_pos->x_coord -= 1;
            }
            else printf("\n geht nicht!\n");
    
        }
        else if(weg == 's')
        {
            if(feld[spieler_pos->x_coord+1][spieler_pos->y_coord] != '*')
            {
            feld[spieler_pos->x_coord][spieler_pos->y_coord] = ' ';
            spieler_pos->x_coord += 1;
            }
            else printf("\n geht nicht!\n");
        }
    
        return;
    }
    


  • Sehr nettes Spiel.
    Wenn man etwas falsches eingegeben hat, sollte die Meldung aber besser nach dem Spielfeld angezeigt werden, da sonst die obere Labyrinthreihe "weggeschoben" wird.

    Eine portabler***e*** Möglichkeit zum Bildschirmlöschen gibt's schon und zwar:

    #ifdef __WIN32__
    system("cls");
    #else
    system("clear");
    #endif
    

    Sollte man am besten in eine eigene Funktion auslagern.



  • Ihr immer mit Eurem scheiß system("cls") . Für Windows gibt es da entsprechende WinAPI-Funktionen:

    const HANDLE OutputHandle = GetStdHandle(STD_OUTPUT_HANDLE);
    
    void gotoxy(short x, short y)
    {
        const COORD position = { x, y };
    
        SetConsoleCursorPosition(OutputHandle, position);
    }
    
    void clrscr()
    {
        gotoxy(0, 0);
    
        const CONSOLE_SCREEN_BUFFER_INFO info = GetScreenBufferInfo();
        const COORD position = { info.dwCursorPosition.X, info.dwCursorPosition.Y };
        const DWORD lenght = info.dwSize.X * info.dwSize.Y;
        DWORD number;
    
        FillConsoleOutputAttribute(OutputHandle, info.wAttributes, length, position, &number);
        FillConsoleOutputCharacter(OutputHandle, TEXT(' '), length, position, &number);
    }
    

    Und bei Linux schreibt man schlicht und ergreifend

    cout << "\033[2J";
    

    Und nicht system("clear") . 😡

    Ansonsten:
    Die Fehlermeldung, wenn man eine falsche Eingabe getätigt hat, erscheint immer nur ganz kurz und danach wird sofort der Bildschirm gelöscht.
    Außerdem könntest Du vielleicht getch() für die Eingabe nehmen. Obwohl das nicht mehr plattformunabhängig ist, aber Du könntest ja auch hier ein #ifdef benutzen, so daß Windows-Benutzer mit getch() spielen können, während Linux-Benutzer weiterhin mit Eingabe + Enter spielen.
    Und ich weiß nicht, ob es nötig ist, immer wieder den gesamten Bildschirm zu löschen und neuzuzeichnen. Geh doch einfach an die Position der Spielfigur, übermale sie mit einem Leerzeichen und zeichne sie dann an der neuen Position. Das gotoxy hab ich ja oben schon hingeschrieben. Für Linux geht es so:

    cout << "\033[" << y + 1 << ";" << x + 1 << "m";
    

    (Bitte beachten: Mit den Windows-Funktionen ist die Position oben links (0,0), während sie bei der Linuxfunktion (1,1) ist. Deshalb das x + 1 und das y + 1, damit Du mit denselben Positionsangaben beide Varianten benutzen kannst.)



  • NES-Spieler schrieb:

    Ihr immer mit Eurem scheiß system("cls") .

    💡 daran ist nix scheiße und für so ein spiel durchaus angemesen 💡



  • Wow, was für eine geniale Begründung! Ja, damit hast Du mich jetzt echt überzeugt. 🙄



  • deine einsicht freut mich, so brauche ich wenigstens keine überflüssigen erklärungen für so etwas offensichtliches abzugeben.
    🙂



  • Vielleicht solltest Du es doch erklären, damit ich auch ganz sicher gehen kann, daß ich es wirklich verstanden habe: Warum ist es nicht scheiße, den Befehl, der eigentlich dazu gedacht ist, explizit externe Programme bzw. Kommandozeilenbefehle aufzurufen, zweckzuentfremden, um ein Verhalten zu simulieren, das eigentlich zum eigenen Programm gehört und gar nichts mit dem bewußten Aufrufen externer Kommandos zu tun hat?



  • NES-Spieler schrieb:

    Warum ist es nicht scheiße, den Befehl, der eigentlich dazu gedacht ist, explizit externe Programme bzw. Kommandozeilenbefehle aufzurufen, zweckzuentfremden, um ein Verhalten zu simulieren, das eigentlich zum eigenen Programm gehört und gar nichts mit dem bewußten Aufrufen externer Kommandos zu tun hat?

    Also geht es dir nur ums Prinzip? Oder gibt es auch ein echtes Problem?

    Wobei, es bringt einem Anfänger sicher gewaltig viel mehr, wenn er statt system("cls") 20 Zeilen WinAPI-Code aus einem Internetforum kopiert, ohne eine einzige davon zu verstehen. 🙄



  • Stimmt. Soll er sich lieber schlechten Stil angewöhnen und lernen, daß es besser ist, mal schnell irgendwas hinzuhacken, statt zu gucken, ob es irgendwo Funktionen gibt, die genau dafür gedacht sind. Wieso sollte man sich auch mit WinAPI-Funktionen auseinandersetzen, wenn man einfach system("cls") schreiben kann? Ist zwar ein Systemaufruf, der normalerweise nur dazu gedacht ist, externe Anwendungen zu starten, aber er erfüllt doch seinen Zweck, nicht wahr? Und wenn man die Konsole offen lassen will, bis der Benutzer Enter bzw. eine Taste drückt, nimmt man system("pause") statt cin.get() bzw. fgets oder was es da in C auch immer gibt, stimmt's? Immerhin muß man sich bei solchen Funktionen um das mögliche Leeren des Puffers kümmern, falls da noch irgendeine Eingabe drin hängt, und das würde den Anfänger ja vollkommen überfordern. Und wenn er das Labyrinth in blau mit weißem Hintergrund darstellen will, dann empfehlen wir ihm system("color f9") statt ihn darauf hinzuweisen, daß es auch dafür richtige Funktionen gibt. Immerhin ist er ja ein Anfänger, also sollte man ihm keinen Code zeigen, durch den er sich erstmal durchfuchsen müßte, um ihn zu verstehen. Könnte ja sein, daß er dadurch noch was lernt oder vielleicht sogar angeregt wird, selbst in die Richtung nachzforschen, falls ihm in den Sinn kommt, daß er die clrscr -Funktion so umschreiben will, daß man angeben kann, von wo bis wo der Bildschirm gelöscht werden soll. Viel besser sind da billige Hacks, die allgemeine Shellbefehle einfach im lokalen Programm aufrufen. Wieso benutzen wir eigentlich noch cout und printf ? Nehmen wir doch gleich system("echo ...") . Und wenn wir mal rausfinden wollen, was es so für Ordner und Dateien im aktuellen Pfad gibt, dann machen wir system("dir /b > Dateien.txt") , lesen dann die Datei aus und löschen sie dann wieder mit system("del Dateien.txt") .



  • NES-Spieler schrieb:

    Wieso sollte man sich auch mit WinAPI-Funktionen auseinandersetzen, wenn man einfach system("cls") schreiben kann?

    Genau das frage ich mich auch.

    statt ihn darauf hinzuweisen, daß es auch dafür richtige Funktionen gibt.

    Es gibt aber keine "richtigen" Funktionen dafür. Nicht, wenn man plattformunabhängiges C programmiert. Man muss Win-API benutzen, und überaus schöner Code ist das auch nicht.

    Leider sagst du nach wie vor nicht, was wirklich das Problem ist. "Hack", "schnelle Shellbefehle", "schlechter Stil"... Werd lieber mal konkret. Einen Anfänger kümmern deine momentanen Argumente nämlich kein bisschen, solange er mit einer Zeile dasselbe erreicht wie du mit 20.

    Wieso benutzen wir eigentlich noch cout und printf ?

    Schlechter Vergleich. Die beiden sind einfach zu benutzen, portabel und erfordern kein wochenlanges Einstudieren in ein Framework.



  • Systemanalytiker schrieb:

    Nicht, wenn man plattformunabhängiges C programmiert.

    system("cls"); ist auch nicht gerade plattformunabhängig. funktioniert lediglich für ein paar plattformen mehr als nur eine.

    letztlich läuft die ganze diskussion doch nur darauf hinaus, dass beide seiten recht haben. ja, das ist nicht sonderlich doller stil (erst recht, wenn man das als allgemeingültigen prototyp für situationen ansieht, in denen man anders nicht spontan weiter weiß), aber nein, das ist noch lange kein grund, als anfänger darauf unbedingt zu verzichten.

    ru,
    cirion



  • Und wenn ihr schon mal dabei seid... Warum nicht gleich SDL verwenden?



  • Systemanalytiker schrieb:

    Leider sagst du nach wie vor nicht, was wirklich das Problem ist. "Hack", "schnelle Shellbefehle", "schlechter Stil"... Werd lieber mal konkret. Einen Anfänger kümmern deine momentanen Argumente nämlich kein bisschen, solange er mit einer Zeile dasselbe erreicht wie du mit 20.

    Bitteschön: www.c-plusplus.net/forum/viewtopic-var-t-is-39453.html. Sogar ein FAQ-Eintrag, was zumindest zeigt, daß ich mit meiner Abneigung nicht allein dastehe.

    dasdasa schrieb:

    Und wenn ihr schon mal dabei seid... Warum nicht gleich SDL verwenden?

    Weil die Frage nach SDL nicht nur eine codetechnische ist, sondern eine, die auch das Aussehen des Programms komplett ändern würde.

    cirion schrieb:

    aber nein, das ist noch lange kein grund, als anfänger darauf unbedingt zu verzichten.

    Außer natürlich, wenn man die richtige Variante bereits fertig vorgelegt bekommen hat. Und da ich mir vorstellen kann, daß als nächstes die Frage kommt, wie man das Spiel auch farbig gestaltet, wäre in dem Fall die WinAPI sowieso unausweichlich, denn dann hat's sich mit den Systembefehlen geschissen, wenn man nicht nur eine Farbe für alles haben will.



  • NES-Spieler schrieb:

    Bitteschön: www.c-plusplus.net/forum/viewtopic-var-t-is-39453.html. Sogar ein FAQ-Eintrag, was zumindest zeigt, daß ich mit meiner Abneigung nicht allein dastehe.

    Keines der Argumente greift hier.
    Plattformabhängigkeit? Recht egal, die angestrebte Alternative wäre WinAPI, wenn ich mich recht erinnere.
    Geschwindigkeit? Für eine Wartefunktion.
    Hänger bei Fehlern? Naja, da schreibt man pause halt mal richtig.
    Sicherheit? Soll ich meinen Rechner knacken?



  • Es ist einfach Zweckentfremdung. system ist dazu da, explizit externe Programme zu starten. Das Löschen eines Bildschirms ist aber nichts, was rein logisch dem Aufruf eines externen Programms gleichkommen sollte, sondern das ist nur eine Funktionalität des eigenen Programms. Ja, ja, rein praktisch mag es jetzt vielleicht noch egal sein, aber ich sage: "Wehret den Anfängen!" Heute nimmt man system("cls") als Notlösung, morgen hält man es nicht für nötig, einen oft vorkommenen Wert als Konstante zu deklarieren, "da er sich ja sowieso nicht ändert" und man die Zahl auch direkt hinschreiben kann. Und übermorgen? Da friemelt man sich ein so beschissenes Konstrukt zusammen, das eine tickende Zeitbombe ist, weil man nie gelernt hat, was sauberes Programmieren bedeutet.



  • Rufst Du ping mit system auf oder machste rawsockets per hand? Und touch? Und ftp?


Anmelden zum Antworten