Contents
2. The main loop
|
How to program a text adventure in C
by Ruud Helderman
<r.helderman@hccnet.nl>
Licensed under
MIT License
2. The main loop
Let’s bring some basic interaction into our program!
The basic principle of a text adventure is simple:
- The player enters a command.
- The program
parses
and executes the command.
- Repeat steps 1 and 2 until the player decides to quit.
The code sample below consists of three functions,
one for each step:
- Function getInput.
- Function parseAndExecute.
- Function main,
which takes care of calling the other two functions repeatedly.
main.c |
- #include <stdbool.h>
- #include <stdio.h>
- #include "parsexec.h"
- static char input[100] = "look around";
- static bool getInput(void)
- {
- printf("\n--> ");
- return fgets(input, sizeof input, stdin) != NULL;
- }
- int main()
- {
- printf("Welcome to Little Cave Adventure.\n");
- while (parseAndExecute(input) && getInput());
- printf("\nBye!\n");
- return 0;
- }
|
Explanation:
- Line 1:
in case some legacy compiler does not support stdbool.h
(it was introduced with
C99),
please be informed that you can easily do without;
just replace all instances of bool, true and false
with int, 1 and 0, respectively.
- Line 5:
string buffer to collect keyboard input.
It is pre-filled with a command that will be executed at startup:
“look around.”
- Line 9:
the
prompt;
feel free to change it into anything you like,
for example a polite “Please enter command.”
- Line 10:
standard function
fgets
gets input from the keyboard.
If the player presses
end-of-file,
function getInput will return false
and the program will end (see line 16).
- Line 16:
this is the main loop;
it alternately calls getInput and parseAndExecute
until either one of them returns false.
I deliberately swapped the function calls
(calling parseAndExecute before getInput)
because I want to execute a pre-determined command first
(as specified on line 5).
I implemented function parseAndExecute in a separate module,
as it is the function that is subject to change in chapters to come.
parsexec.h |
- extern bool parseAndExecute(char *input);
|
parsexec.c |
- #include <stdbool.h>
- #include <stdio.h>
- #include <string.h>
- bool parseAndExecute(char *input)
- {
- char *verb = strtok(input, " \n");
- char *noun = strtok(NULL, " \n");
- if (verb != NULL)
- {
- if (strcmp(verb, "quit") == 0)
- {
- return false;
- }
- else if (strcmp(verb, "look") == 0)
- {
- printf("It is very dark in here.\n");
- }
- else if (strcmp(verb, "go") == 0)
- {
- printf("It's too dark to go anywhere.\n");
- }
- else
- {
- printf("I don't know how to '%s'.\n", verb);
- }
- }
- return true;
- }
|
Explanation:
- Line 3:
from string.h
we will be using some standard string manipulation functions
(strcmp, strtok).
- Line 8, 9:
standard function strtok is used to build a very basic verb-noun
parser
in just two lines of code.
- Line 9:
your C compiler may give a warning
regarding the unused variable ‘noun’ on this line.
Please ignore this message; the issue will be resolved in the next chapter.
- Line 10:
nothing to do if the player enters nothing (or just spaces).
- Line 12, 16, 20:
using standard function
strcmp
to match keyboard input with known verbs
(quit, look and go).
For now, this is a
case-sensitive match,
so the player should be careful not to hold
shift or press
caps lock.
- Line 14:
returning false will cause the main loop to end
(see main.c line 16).
- Line 26:
a typical
printf-style format string,
with %s as placeholder for the additional parameter verb.
Sample output |
Welcome to Little Cave Adventure.
It is very dark in here.
--> go north
It's too dark to go anywhere.
--> look around
It is very dark in here.
--> eat sandwich
I don't know how to 'eat'.
--> quit
Bye!
|
This program, however small it may be, already responds
to commands like go north, look around and quit;
see the sample output on the right.
But of course, it is not much of a game.
It has no locations, no items; all there is, is darkness.
So in the next chapter, we will begin adding locations.
Quit
Notice our program stops at nothing but a command from the player
(either quit or
end-of-file).
So what about
‘game over’
situations, i.e. death and victory?
Well, those are conditions that might end the game,
but not necessarily end the program.
- Death:
the player gets killed by an
orc;
he falls from a cliff; his spaceship blows up.
A good adventure should encourage the player to try again;
not cast him off upon his first failure.
- Victory:
the player found each and every treasure,
he rescued the princess,
he escaped the maze.
It took the player days, maybe months to reach this ultimate goal.
Imagine his disappointment to get thrown out of the program
right after the obligatory ‘congratulations’ message,
just because there is nothing left to achieve.
Why not give the player the time to move around freely
and cherish his moment of victory?
There is also a practical problem
with terminating the program without the player’s consent: in a
windowing system,
it is not unlikely for a
text-based
program to be running in a terminal window
that immediately closes when the program ends,
even before the player has had a chance to read the final message.
We could delay this effect with “press
any key
to exit” or “wanna quit (y/n)”,
but why bother when there is already a perfectly sane alternative?
Just let the player type in ‘quit’
whenever he is ready to leave the imaginary world behind.
Naturally, all this is just an advice; you can take it or leave it.
That’s the great thing about writing a game in a
general-purpose language:
you can mould it any way you like.
Next chapter: 3. Locations