CONTENTS
1. Introduction
2. The main loop
3. Locations
4. Objects
5. Inventory
6. Passages
7. Distance
8. North, east, south, west
9. Code generation
10. More attributes
11. Conditions
12. Open and close
13. The parser

How to program a text adventure in C

3. Locations

Traditionally, a text adventure is a virtual world consisting of (many) different locations. Though this is not essential (some adventures take place in a single room!), it is a good way to explain the use of data structures.

We start by defining a struct to represent a location. It contains two simple attributes to start with (more may follow later).

Very basic map

struct location { const char *description; const char *tag; };

Next, we define an array of locations. For now, we keep it really simple: just two locations.

struct location locs[2];

We can use an initializer to immediately fill in all the static data.

struct location locs[2] = { {"an open field", "field"}, {"a little cave", "cave"} };

Using the data from the array is simple. For example, the following line of code will output "You are in an open field."

printf("You are in %s.\n", locs[0].description);

Let's put this into practice. In the code sample from the previous chapter, we alter lines 3, 26, 30 and 43 (slightly highlighted below).

Sample output
Welcome to Little Cave Adventure. You are in an open field. --> go cave OK. You are in a little cave. --> go field OK. You are in an open field. --> go field You are already there. --> look around You are in an open field. --> go kitchen I don't understand where you want to go. --> quit Bye!
main.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #include <stdio.h> #include <string.h> #include "location.h" static char input[100]; static int getInput() { printf("\n--> "); return fgets(input, sizeof(input), stdin) != NULL; } static int parseAndExecute() { char *verb = strtok(input, " \n"); char *noun = strtok(NULL, " \n"); if (verb != NULL) { if (strcmp(verb, "quit") == 0) { return 0; } else if (strcmp(verb, "look") == 0) { executeLook(noun); } else if (strcmp(verb, "go") == 0) { executeGo(noun); } else { printf("I don't know how to '%s'.\n", verb); } } return 1; } int main() { printf("Welcome to Little Cave Adventure.\n"); executeLook("around"); while (getInput() && parseAndExecute()); printf("\nBye!\n"); return 0; }

Explanation:

Next, we add a new module to the project.

location.h
1 2 extern void executeLook(const char *noun); extern void executeGo(const char *noun);
location.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 #include <stdio.h> #include <string.h> struct location { const char *description; const char *tag; } locs[] = { {"an open field", "field"}, {"a little cave", "cave"} }; #define numberOfLocations (sizeof(locs) / sizeof(*locs)) static unsigned locationOfPlayer = 0; void executeLook(const char *noun) { if (noun != NULL && strcmp(noun, "around") == 0) { printf("You are in %s.\n", locs[locationOfPlayer].description); } else { printf("I don't understand what you want to see.\n"); } } void executeGo(const char *noun) { unsigned i; for (i = 0; i < numberOfLocations; i++) { if (noun != NULL && strcmp(noun, locs[i].tag) == 0) { if (i == locationOfPlayer) { printf("You are already there.\n"); } else { printf("OK.\n"); locationOfPlayer = i; executeLook("around"); } return; } } printf("I don't understand where you want to go.\n"); }

Explanation:

Now the commands look around and go <location> have really come to life! Feel free to experiment by adding more locations. Of course, the game is still far from perfect. Right now, there is too much freedom: from every location, the player can reach any other location without restrictions. In chapter 6, we will show how to 'connect' locations. But next up, we will start adding objects to the game.


Next chapter: 4. Objects