Thread: Help with my text adventure game.

  1. #1
    Registered User
    Join Date
    Sep 2007
    Location
    Canada
    Posts
    6

    Help with my text adventure game.

    I'm a 15-year-old and I'm making a text adventure game for my computer class. I've learned the most basic commands (printf, scanf, loops) and as I go it just gets more and more confusing. My game is pretty much going to be like Zork. I'm programming it in C and I'm using Dev-Cpp.

    Here's what I have so far:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        int x, y, a;
        x=5;
        y=5;
        printf("[%d,%d]You are standing on the north side of a lake. Your pants are floating in the water.\n", x, y);
        scanf("%s %s", &a);
        if (a="get pants");   /* I need to fix this line */
        {
        printf("You put on the wet pants. They feel slimy.\n");
        }
        else 
        {
        printf("Are you sure you want to walk around with no pants on?\n");
        }
        
        sleep (5000);
        
    
    }
    How do I fix this code? Also, I'm sure there are other commands I need to know to make this thing work. When the character goes east I'll add 1 to the x value, -1 for west, etcetera. For items, I'll just have an integer, 1 means you have the item, 0 means you don't. I just need help with the user input for things like "get pants," "use sword," and other things like that.

  2. #2
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    You need to fix the line above the one you marked, too. You need to supply parameters to scanf according to what you say you're reading. You say you're reading two strings. You give it place to store one integer.

    Do you have to do this in C? A text adventure involves lots of string manipulation, and the memory management issues involved don't make it a very easy project in C.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  3. #3
    Registered User
    Join Date
    Sep 2007
    Location
    Canada
    Posts
    6
    Yeah, he said it's got to be in C.

    So how would I fix those lines? Would I have to use a function other than scanf?

  4. #4
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    fgets would be simpler if you just want to read in the whole line. More importantly, you have to make place for a string for the user:
    Code:
    char buffer[BUFFER_SIZE];
    fgets(buffer, BUFFER_SIZE, stdin);
    where BUFFER_SIZE is a constant you define that should be around 200 characters - depends on what kind of commands you expect, though.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  5. #5
    Dr Dipshi++ mike_g's Avatar
    Join Date
    Oct 2006
    Location
    On me hyperplane
    Posts
    1,218
    Once you have set up 'a' as a character array, to check a string for equality use strcmp() which is included in <string.h>
    Also here:
    Code:
    if (a="get pants");   /* I need to fix this line */
    You are killing your if statement by putting the semi colon at the end of the line.
    Do this:
    Code:
    if (strcmp(a, "get pants")==0)
    And your conditional check should work.
    Last edited by mike_g; 09-28-2007 at 06:00 PM.

  6. #6
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    You may want to consider a parser that doesn't try to parse the whole sentence at once. For example, "get" is a verb to pick something up. The "something" is an object, so you want a parser that does something like this:
    Get one word. Check the word against "get", "go", "walk", "run", "fight". If you put the words in a structure, together with the type of word the next word should be (object, direction, enemy, etc), you then have a simple structure that can deal with fairly complex situations, without you actually putting all the different combinations together.

    You can make it more complex too:
    "fight dragon with sword"

    And accept things like
    "get down" [avoiding being seen/hit by enemy], "get up" [after falling over]

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  7. #7
    Registered User
    Join Date
    Sep 2007
    Location
    Canada
    Posts
    6
    For parsing words separately from one another, my teacher told me to use strtok. I'll also need to be able to put all the information about each square on the map, the teacher is saying I should use struct. It's a big computer class and only a couple of us are doing programming, so he's always off helping someone else. I can't find any simple info or examples for those functions...

    Here's what I have now:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        int x, y, z;
        x=5;
        y=5;
        z=0;
        printf("[&#37;d,%d] You are standing on the north side of a lake. Your pants are floating in the water. [Points: %d]\n", x, y, z);
        char buffer[50];
        fgets(buffer, 50, stdin);
        
        if (strcmp(buffer,"get pants\n") == 0)
        {
        z=z+5;                       
        printf("[%d,%d] You put on the wet pants. They feel slimy. [Points: %d]\n", x, y, z);
        }
        else if (strcmp(buffer,"west\n") == 0)
        {
        printf("[%d,%d] Are you sure you want to walk around with no pants on? [Points: %d]\n", x, y, z);     
        }
        else if (strcmp(buffer,"east\n") == 0)
        {
        printf("[%d,%d] Are you sure you want to walk around with no pants on? [Points: %d]\n", x, y, z);     
        }
        else if (strcmp(buffer,"north\n") == 0)
        {
        printf("[%d,%d] Are you sure you want to walk around with no pants on? [Points: %d]\n", x, y, z);     
        }
        else if (strcmp(buffer,"south\n") == 0)
        {
        printf("[%d,%d] Are you sure you want to walk around with no pants on? [Points: %d]\n", x, y, z);     
        }
        else
        {
            printf("That is an unknown command.\n");
        }
        
        fgets(buffer, 50, stdin);
        if (strcmp(buffer,"get pants\n") == 0)
        {
        z=z+5;                       
        printf("[%d,%d] You put on the wet pants. They feel slimy. [Points: %d]\n", x, y, z);
        }
        
        sleep(2000);    
    
    }

  8. #8
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    strtok is certainly a way to split a string into portions, yes. And using a struct is the right way to store the data about different locations in your map.

    You'll want to indent your code properly, so that it's easier to follow what is inside which if-statement, etc.

    And you definitely need to use some sort of loop to do the main program loop - imagine that it may take hundreds of steps to be able to walk through the game.

    And you probably should think about using functions to split the program into parts.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  9. #9
    Registered User
    Join Date
    Sep 2007
    Location
    Canada
    Posts
    6
    See, when my teacher told me to use those commands, he told me to look them up instead of teaching how to use them in my situation. I haven't found anything about how to use them for a text adventure game.

    I've fixed the code now so that it's easier to read. Is there a way to jump back and forth to different areas of the code? For instance in BASIC, you have the goto functon.

    My teacher also said that I should split it up into different programs, have one for all the commands, one for map data, etc., but he never explained how to do so.

    I'm staying after school tomorrow with a couple other people who are doing programming, so he'll probably show me all the commands and stuff then.

  10. #10
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    He probably meant functions, not programs. Unless you've already learned interprocess communication, which I consider extremely unlikely.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  11. #11
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Verb/Noun combos
    As matsp has said splitting the sentences into VERB NOUN combinations turns out to be very effective. You can
    simply ignore participles and other parts of speech that add nothing to the command. The key is to allow the user to type these in but in the code you are looking for something like:

    VERB NOUN [AND] VERB NOUN ....

    So come up with a list of verbs and nouns. You can make the nouns relative to the room you are in or you can make them global to the game. I prefer global since it makes the parser more consistent. The old games that allowed you to use a certain noun in a certain room but nowhere else.....really irritated me.

    Continuous update while waiting for command
    If you are wanting to have other things happen while your parser is 'waiting' you will need to use something other than what you have shown. For that you will need unbuffered input and will want to check for carriage return to accept the command. This type of input works like this:
    • Wait for a keypress
    • Determine if keypress is a letter, number, valid, etc
    • If valid add string representation of keypress into string and update screen accordingly
    • If invalid, ignore keypress
    • If backspace perform backspace function and make string in memory equivalent to its current length-1. This effectively 'chops' off the last letter in the string. This won't work for mid phrase backspaces but you can pretty much ignore those.
    • When RETURN or ENTER is pressed run the final string through the parser functions.
    • Do background processing while waiting for keypresses - this allows the game world to function while the parser is waiting for input


    Basic text game systems
    I do not recommend doing this entirely in C because C++ affords so many opportunities for projects such as this. Doing this in pure C will take a very long time as opposed to C++.

    But if you must do this in C then you need the following functionality:
    • Input and response system
    • Game system
    • Text parser system
    • Map system
    • AI system (for other characters in the game)
    • Combat system
    • Game object system
    • Save/Load system


    Simple response system
    The way Sierra-On-Line did this with their early King's Quest and other text parser games was by ID's. Once in The Dagger of Amon-Ra I came across this error message:

    Cannot find response #xxx for command #xxx.
    This gave me the idea that they were essentially giving each verb and ID# and each noun an ID#. The parser would recognize key verbs and nouns based on a dataset and turn these into ID#s. So a command would look like this:

    TAKE (verb 9) THE (ignored but accepted) DAGGER (noun 52).

    This means that you can now write code to handle the final input command code of 9, 52. So you would write a utility to allow you to input all the verbs and all the nouns. Then you write code to allow you to set variables. You would create a simple tool that allowed them to name a variable and then check it's value prior to responding. Then designing the game data is a fairly simple affair. Most responses will follow this pattern:

    • Command is recognized
    • Variables relative to command are checked
    • Correct response based on current variable state is presented
    • Correct action relative to response is performed


    DO NOT harccode this into your game engine code. Rather code functions that take inputs from various datasets, interpret them in a meaningful fashion and return a result or perform an action. The engine is not the game - it merely runs the game based on supplied data using functions provided by the engine framework. Change the data and you effectively change the game w/o altering the engine code.

    Tools to create the game 'data'
    So to make the job easier you need to write tools before you write the game. A small example:

    Please type response for TAKE DAGGER in Kitchen (room #5). DAGGER is in room #5.
    -> You cautiously pick up the dagger being careful not to hurt yourself.

    So VERBs NOUNs ROOMs and OBJECTs are all based on ID numbers.


    Putting objects in rooms/inventory
    How do you specify which object is in which room? You can either use pointers or you can use IDs.

    Code:
    for (int i=0;i<numObjects;i++)
    {
      if (Objects[i].Room==Player.CurrentRoom)
      {
         printf("You see &#37;s here.",Objects[i].Descrip);
      }
    }
    This is slow but it works. To add items to inventory just set inventory as Room #9999. So if an object's room number is 9999 - you know it's in the player's inventory.

    As you can see this can get quite complex. But that should give you a general idea. Remember think about it this way:
    • Game data - the data that makes the game
    • Game engine - the engine that reads the game data and 'presents' the game to the user.

    The more you separate these two the easier and less confusing your project will be.

    Google for text adventure game engines
    I recommend you google for free text adventure game engines. They are all over the place. Creating a text game without using any code is a good way to understand how those engines work under the hood. Once you get the feel for how they address certain problems you can begin to put these ideas into code in your own project. So in short you need to research and experiment with those engines a bit before you start yours.

    Yes this is a long post and these are complex ideas that take a bit of time to implement. But if you separate game engine code from game data and create some small tools to help put the data on disk in a form the engine can read.....you will have a very powerful system. Not to mention if you pull it off it will surely impress the teacher.
    Hard-coding all responses and data is the naive approach and the wrong one.

    Infocom text parsers
    You could code for years and never match Infocom's text parsers. They were the best parsers in their day and not even the likes of Sierra-On-Line even came close. Several tried to beat Infocom and failed. Their parsers would accept just about anything and give you some crazy response. Fond memories.
    Last edited by VirtualAce; 10-03-2007 at 01:23 PM.

  12. #12
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Bubba,

    That's a great summary.

    Can I just add that a different solution to "Update while waiting for command" would be to use multithreading - yes, this will introduce a whole host of new problems, but correctly used, it can be a very efficient way to dsitribute the work and split the task of "updating" different things in different parts of the game "simultaneously". But it's probably easier to use non-blocking reads.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  13. #13
    Registered User
    Join Date
    Nov 2005
    Posts
    673
    Well, I suppose with a very small amount of effort you could learn to use the SDL multithreading functions. Although you still will have to understand the basics of multithreading, mutexes, conditions, and semaphores, but it is not like it is a extremely complex programming concept.

  14. #14
    Registered User
    Join Date
    Sep 2007
    Location
    Canada
    Posts
    6
    Thanks for the help everyone (especially Bubba). I think I can really get to work now.

  15. #15
    Registered User
    Join Date
    Sep 2007
    Location
    Canada
    Posts
    6
    Okay, now the teacher has switched the project to C++ with only a week and a half left in the course. Here is my code (it compiles and runs with no errors):
    Code:
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    class Item {
          
          
          
    };
    
    class Square {
          
    string description;
    
    
    public: 
       // constructors
       Square(string description) { 
          this->description = description;       
       }
       Square() {
          this->description = "Default";
       }   
       Square(Square &source) {
          this->description = source.description;
       }
    
       // output functions
       void print() {
          cout << description;             
       }
    
    };
    
    
    int main()
    {
      int x;
      int y;
      
      x=0;
      y=0;
               
      Square map[7][7];
       
        
      Square a0("a0\n"); 
      map[0][0] = a0;
      
      Square a1("a1\n");
      map[0][1] = a1;     
      
      ...map code in between here...
    
      Square d1("d1\n");
      map[3][1] = d1;
      
      Square d2("You are in a foggy grassland. There is a waterfall to the east that empties into a lake to your north.\n");
      map[3][2] = d2;
      
      Square d3("You are in a foggy grassland. There is an old shack to the west and rapids to the east.\n");
      map[3][3] = d3;
      
      Square d4("d4\n");
      map[3][4] = d4;
      
     ...more map code...
      
      Square g6("g6\n");
      map[6][6] = g6;
      
      a0.print();
    
    
      string nav;
      
      while (true) {     
      cin >> nav;
    
      if (nav == "east")
      {
         x++;
      }
      else if (nav == "west")
      {
         x--;
      }
      else if (nav == "north")
      {
         y--;
      }
      else if (nav == "south")
      {
         y++;
      }
      else if (nav == "e")
      {
         x++;
      }
      else if (nav == "w")
      {
         x--;
      }
      else if (nav == "s")
      {
         y++;
      }
      else if (nav == "n")
      {
         y--;
      }
      else
      {
      cout << "Command unknown.\n";
      };  
      
        if (x > 6) {
           cout << "You cannot travel any farther east." << endl;
           x = 6;      
        }
        if (y > 6) {
           cout << "You cannot travel any farther south." << endl;
           y = 6;      
        }
        if (x < 0) {
           cout << "You cannot travel any farther west." << endl;
           x = 0;      
        }
        if (y < 0) {
           cout << "You cannot travel any farther north." << endl;
           y = 0;      
        }
        
             cout << "[" << x << "," << y << "]";
        map[x][y].print();
      }
        
        
    
    while(1);
    return(0);
    }
    I'm working on the descriptions for each square on the map. After that I'll need to enter more commands that the player can type (get item, etc.). I'm assuming I'll have to define verbs and nouns and the player will have to type both for the command.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. C Programming 2d Array Question
    By jeev2005 in forum C Programming
    Replies: 3
    Last Post: 04-26-2006, 03:18 PM
  2. A bunch of Linker Errors...
    By Junior89 in forum Windows Programming
    Replies: 4
    Last Post: 01-06-2006, 02:59 PM
  3. Game Independent Anti-cheat Project Needs Programmers
    By GIA Project Lea in forum Projects and Job Recruitment
    Replies: 3
    Last Post: 09-15-2005, 07:41 PM
  4. Saving a text game
    By Unregistered in forum C++ Programming
    Replies: 4
    Last Post: 03-27-2002, 01:33 PM
  5. Text Based Game
    By drdroid in forum C++ Programming
    Replies: 2
    Last Post: 02-18-2002, 06:21 PM