Jump to content
  • Advertisement
Sign in to follow this  
ICanC

Text adventure design in C

This topic is 1328 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

hello,

 

I am learning C and feel comfortable with most basics. I have created a very basic text adventure that worked ok but resulted in disgusting code.

 

Basically the game has a function for each room, with the same basic loop, printing of options, and a switch statement to get input (int input for predefined options in the menu) - and example of which is :

void beach(void)
{
	int here = 1;
	while (here)
	{
		fflush(stdin);
		system("cls");
		printf(TITLE);
		char *lookaround = "You are on a sandy beach, disoriented.";
		char *menu = "1. (Beach) Look Around\n\n2. Go North\n\n3. Go South\n\n4. Go East\n\n5. Go West\n\n6. Inventory\n\n\n> ";
		prints(menu);

		char choice;
		scanf("%c", &choice);
		switch (choice)
		{
			case '1': system("cls"); printf(TITLE); prints(lookaround); wait(); break;
			case '2': system("cls"); mountain(); break;
			case '3': system("cls"); market(); break;
			case '4': system("cls"); chapel(); break;
			case '5': system("cls"); swamp(); break;
			case '6': system("cls"); printf(TITLE); inventory(); break;
		}
	}
}

Basically each room function followed a similar theme, making it rather easy to add special options to certain rooms, but still poor design as to add on basically involved copying and pasting 1 room, then making alterations to the new room function. Before I go any further I am trying to improve my understanding and design, using structures and pointers. But whilst I understand how they work, I find it very difficult to figure out how best to implement it and would be very grateful for advice or links to help. Here is a tiny example of an attempt to better organise the program (though not doing anything of course)

#include <stdio.h>
#include <string.h>

void setupareas(void);

enum dir
{
	north = 1,
	east = 2,
	south = 3,
	west = 4
};

struct area
{
	char thedescription[200];
	char menu[200];
	char commands[3][100];
};

void printer(struct area *);

int main(void)
{
	setupareas();
	return 0;
}

void setupareas(void)
{
	struct area beach;
	strcpy(beach.thedescription, "A lovely beach");
	strcpy(beach.menu, "1. North\n\n2. East\n\n3. South\n\n4. West");
	printer(&beach);
}

void printer(struct area * p)
{
	printf("%s", p->thedescription);
	printf("\n\n");
	printf("%s", p->menu);
}	

But really I have no idea what I am doing. Any advice, examples on a basic text adventure setup for C or links to good sites would be great!

 

Please no C++ examples, recommendations that I should upgrade to C++ and use classes etc. I have my reasons for wanting to understand C and it would be great to get advice from a C expert.

 

Thanks!

Share this post


Link to post
Share on other sites
Advertisement

The trick is to have a single game loop.
Inside you get input in a generic way, process it in a way which depends on the game's state, then output the current status to the screen.
This avoids repeating the loop, input and output code everywhere (possibly obfuscated by being slightly different each time).

.

To add to this - whenever you have to reuse the same code blocks many times, it would save a lot of typing ( and debugging ) if you spun them off into functions.

An example would be your "menu" - you could spin that off into a function that takes a location, and returns a number .

 

On a side note: You can 'cheat' in C by using/abusing structs as classes, but that is beyond the scope of this topic.

Edited by Code Fox

Share this post


Link to post
Share on other sites

wow thanks Lenny, that's awesome. I will study this code and try to build ontop of it.

Share this post


Link to post
Share on other sites

Holy shit.

There's so much wrong in this thread I can hardly believe.

 

Do not hardcode locations/rooms in code.

Do not produce structs by using C code.

 

Lenny, seriously, I sympathize with the structure you proposed, but you should really have spared us from demonstrating the terrible practice of mixing code with assets. Have phun managing the numeric index for 'touch' information.

True solution: data driven architecture. Here's a JSON to populate areas (not the same thing, as I couldn't be bothered in keeping track of the indices), then you only have to parse it and get your structures out.


{
    "locations": {
        "beach" : {
            "desc": "A sandy beach covered in shells.",
            "near": [ [ "north", "forest" ] ]
        },
        "forest" : {
            "desc": "A dark and spooky forest.",
            "near": [ [ "south", "beach" ], [ "east", "hill" ] ],
            "items": [ "temple_key" ]
        },
        "hill" : {
            "desc": "A windswept hilltop covered in tussock.",
            "near": [ [ "west", "forest" ], [ "north", "mountain" ] ],
            "items": [ "tin_can", "rotting_adventurer_corpse" ]
        },
        "mountain" : {
            "desc": "A tall lonely mountain.",
            "near": [ [ "south", "hill" ] ]
        }
    }
}

Bonus: here's how it looks in notepad++ json viewer.

Left as an exercise: HTML5+CSS landscape editor!

Share this post


Link to post
Share on other sites

I'd like to reinforce Krohm's statement: Do not hardcode locations/rooms in code.
I think a practical approach that is worth learning (and i remember it being used in quite a few MUDs) would be linked-lists of structs.

Each room-struct would have a next-pointer to another room.

Store your rooms in text-files, JSON is nice, but just some plaintext might well be enough.

You parse your files and create rooms linking each one to the one before. Last one gets next = NULL, so you know that's where your list ends.

Of course you keep a room* to the first room to access the list. 

In the datafiles you specify the rooms that can be accessed from a room, by some unique identifier, a number preferably.

After parsing rooms you setup each room-struct's pointers to accessible rooms, so you don't have to search the list later on.

When player types a "go north" or similar command, you know what room to use.

All strings unique to a room are in that room's text-data, and have been read to the room's struct by the game, like name, description, looktext and so on, or even items to be picked up in that room.

The player actions/commands you could put in an array of command-structs. Each command-struct would hold a string and a function-pointer to a function to be called when player enters that string. For more learning you create a hash-map of the commands so you can look up functions corresponding to command in style!

You might want to look into source of classic text-games, like Rivers of Mud, or take a look around here.

Edited by ninnghazad

Share this post


Link to post
Share on other sites
Oh well, if its constant data it could be statically initialized to cut down on needless initialization code.
Using a 2D array for the data and looking at adjacent fields might be easier to create and use than structs with a couple of pointers.
For such a beginner project recompiling when changing some data would not be that bad, as it should go pretty fast. Later on he might want to learn loading from a file, but something simple like csv format would be easier to use (telling to use JSON/JavaScript/HTLM/CSS is kind of missing the point when someone is trying to learn C).

Share this post


Link to post
Share on other sites

I suggest you put the areas in a text file and load them into your program as your next step. It is not that hard and you can use a simple format where each line is a single command and a parameter.
 

AREA SandyBeach
LOOK You are on a sandy beach, disoriented.
GONORTH Mountain
GOSOUTH Market
GOEAST Chapel
GOWEST Swamp

AREA Swamp
LOOK The swamp is filled with frogs.
GOEAST SandyBeach

Use fopen() to open the file and fclose() to close it when you are done. In a loop use getline() to read each new line into a temporary buffer. Using strstr() you can compare the temporary buffer with the commands you support and handle each one. If the command is AREA create a new area and all the following commands act on the last created area . You can get the rest of the data after the command by indexing the temporary buffer with the length of the command word.

 

So your main loop will have the index of the current area (if you keep them all in an array). When the player say go east you look up the goeast string in your current area. If it is set to anything search your area array for a area with that name. If found change the current area index.

 

When you have it so you can walk around forward and back between areas i would suggest the next step is to add flags to the room. If you walk into the area with the flag DARK for example you need to have a light in your inventory to even see something. Add a flags string to your area struct and add a new command to set it. Then the code that handle the display of the area text can check for the DARK flag and handle it.

FLAG DARK|COLD|HASCAKE
Edited by DUDVim

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!