Previous Top


Here is some sample code I wrote for a very small adventure game type program as part of the How interactive fiction works series of nodes. Have fun. (I tried cutting and pasting from here and verified that this code actually works.)

Try making your own modifications to the game. In increasing order of difficulty, you might try:

  • Adding more objects
  • Adding more rooms
  • Adding more verbs
  • Adding more complex verbs, (or improving the parser in some other way.)

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

#define NDIRS 10
#define NOWHERE -1

struct room_t {         /* one  for each room in the game */ 
        char *short_name;        
        char *description;      
        int tt[NDIRS];  /* n,ne,e,se,s,sw,w,nw,up,down */
};      

struct item_t {         /* one for each object in the game */ 
        char *short_name;
        char *description;
        int location;   /* index into room array */
        int portable;   /* can be carried? */
};

struct player_t {
        int location;   /* where am I?, what room number? */
};

struct verb_t {
        char *word;     /* "go", "take", etc. */ 
        void (*f)(void *game, int *objlist); /* C func to call */ 
};      
        

struct room_t room[] = {        /* here are the rooms... */
        { "player's pocket", 
                "", /* special room for items the player "has" */ 
                { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } 
        },
        { "Room One", 
                "This is Room One.  This is where it all begins.\n"
                "It's decorated entirely by your imagination.\n"
                "There is a dark opening in the stone wall to\n"
                "the East, and a doorway in the southern wall\n" 
                "leads out into the forest.",
                { -1, -1,  2, -1,  3, -1, -1, -1, -1, -1 } 
        },
        { "The Batcave",  /* room 2 */
                "You are in what seems to be The Batcave\n" 
                "Batman and the boy-wonder seem to be absent.\n"
                "Room One lies to the West, and there is a warp\n" 
                "in the space-time continuum to the South.",
                { -1, -1, -1, -1,  4, -1,  1, -1, -1, -1 } 
        },
        { "Forest",  /* room 3 */
                "You are in a dark forest.  A river flows by\n"
                "blocking travel to the Wast and South.  North,\n"
                "there is a doorway set in a stone wall.  To\n"
                "the West lies a warp in the space-time "
                "continuum.\n",
                {  1, -1,  4, -1, -1, -1, -1, -1, -1, -1 }
        },
        { "Space Warp",  /* room 4 */
                "You are in a warp in the space-time continumm.\n"
                "It feels strangely ordinary.  You see a patch of\n"
                "forest to the West, and a cave lies to the North.\n",
                { 2, -1, -1, -1, -1, -1, 3, -1, -1, -1 }
        },
};

struct item_t item[] = {

        /* first "objects" are directions, */
        /* the object numbers (0-9) are indices into the tt[] */
        /* array of the struct room_t */
        {     "north", "",  NOWHERE, 0 },
        { "northeast", "",  NOWHERE, 0 },
        {      "east", "",  NOWHERE, 0 },
        { "southeast", "",  NOWHERE, 0 },
        {     "south", "",  NOWHERE, 0 },
        { "southwest", "",  NOWHERE, 0 },
        {      "west", "",  NOWHERE, 0 },
        { "northwest", "",  NOWHERE, 0 },
        {        "up", "",  NOWHERE, 0 },
        {      "down", "",  NOWHERE, 0 },

        /* real objects */
        { "hammer", "a small rock hammer",  1, 1 },
        { "ring", "a gold ring",  1, 1 },
        { "bell", "a large iron bell",  2, 0 },
        { "sword", "A gleaming sword",  2, 1 },
        { "lantern", "a kerosene lantern",  3, 1 },
#       define GUITAR 15
        { "guitar", "a Gibson Flying V electric guitar",  4, 1 },
#       define SEEKNDESTROY 16
        { "seek-n-destroy", "",  32766, 1 },
};

void gonorth();         /* declaration of verb functions */
void gonortheast();
void goeast();
void gosoutheast();
void gosouth();
void gosouthwest();
void gowest();
void gonorthwest();
void go();
void take();
void doinventory();
void drop();
void look();
void inventory();
void doquit();
void play();

struct verb_t verb[] = {        /* the verbs the game understands */
        { "n", gonorth },
        { "ne", gonortheast },
        { "e", goeast },
        { "se", gosoutheast },
        { "s", gosouth, },
        { "s", gosouth, },
        { "sw", gosouthwest, },
        { "w", gowest, },
        { "nw", gonorthwest, },
        { "go", go, },
        { "take", take, },
        { "drop", drop, },
        { "inventory", doinventory, },
        { "look", look, },
        { "quit", doquit, },
        { "play", play, },
};

struct player_t player = { 1 }; /* starts off in room #1 */

struct game_t {                 /* the state of the game */
        struct player_t *p;     /* a player, */
        struct room_t *r;       /* the rooms */
        int nrooms;
        struct item_t *i;       /* the objects */
        int nitems;
        int done;               /* did they quit? */
};



void inventory(struct game_t *g, int location)
{
        int i, count=0;

        if (location == 0) printf("\nYou are carrying:\n");

        for (i=0;i<g->nitems;i++)
                if (g->i[i].location == location) /* here? */ {
                        printf("  %s\n", g->i[i].description);
                        count++;
                }
        if (count==0)   /* was _nothing_ "here" ? */
                printf("  nothing%s\n",
                        (location == 0) ? "." : " special.");
}

void look(struct game_t *g)
{
        int count=0,i;
        struct room_t *r = &g->r[g->p->location];

        printf("\n%s\n\n%s\n\n", r->short_name, r->description);
        printf("You see:\n");

        inventory(g, g->p->location);

        printf("\nObvious exits:\n  ");
        for (i=0;i<NDIRS;i++)
          if (r->tt[i] != NOWHERE) {
                  count++;
                  printf("%s, ", g->i[i].short_name);
          }
        if (count==0) printf("none");
        printf("\n\n");
}

void go(struct game_t *g, int *dirs)
{
        int new_location, *d;

        for (d = dirs; *d != -1; d++)
        {
                new_location = g->r[g->p->location].tt[*d];

                /* is the requested direction clear? */
                if (new_location == -1)
                        printf("You cannot go in that direction.\n");
                else
                {
                        g->p->location = new_location;
                        look(g);
                }
        }
}

void gonorth(struct game_t *g, int *whatever)
{ int dirs[] = {0,-1}; go(g, dirs); }

void gonortheast(struct game_t *g, int *whatever)
{ int dirs[] = {1,-1}; go(g, dirs); }

void goeast(struct game_t *g, int *whatever)
{ int dirs[] = {2,-1}; go(g, dirs); }

void gosoutheast(struct game_t *g, int *whatever)
{ int dirs[] = {3,-1}; go(g, dirs); }

void gosouth(struct game_t *g, int *whatever)
{ int dirs[] = {4,-1}; go(g, dirs); }

void gosouthwest(struct game_t *g, int *whatever)
{ int dirs[] = {5,-1}; go(g, dirs); }

void gowest(struct game_t *g, int *whatever)
{ int dirs[] = {6,-1}; go(g, dirs); }

void gonorthwest(struct game_t *g, int *whatever)
{ int dirs[] = {7,-1}; go(g, dirs); }

void goup(struct game_t *g, int *whatever)
{ int dirs[] = {8,-1}; go(g, dirs); }

void godown(struct game_t *g, int *whatever)
{ int dirs[] = {9, -1}; go(g, dirs); }


void doinventory(struct game_t *g, int object[])
{ inventory(g, 0); }

void take(struct game_t *g, int object[])
{
        int *i;
        char *objname, location, portable;

        for (i=object; *i >= 0; i++)
        {
                objname = g->i[*i].description;
                location = g->i[*i].location;
                portable = g->i[*i].portable;
                if (location != g->p->location) {
                        printf("%s: that is not here.\n",
                                objname);
                        continue;
                }
                if (!portable) {
                        printf("%s: You cannot carry that.\n",
                                objname);
                        continue;
                }
                g->i[*i].location = 0; /* take it. */
                printf("%s: Taken.\n", objname);
        }
}

void drop(struct game_t *g, int *object)
{
        int *i;
        int location;
        char *objname;

        for (i=object;*i>=0;i++)
        {
                objname = g->i[*i].description;
                location = g->i[*i].location;
                if (location != 0) {
                        printf("%s: You do not have that.\n",
                                objname);
                        continue;
                }
                g->i[*i].location = g->p->location;
                printf("%s: dropped.\n", objname);
        }
}

void doquit(void *g, int *whatever)
{  struct game_t *game = (struct game_t *) g;
   game->done = 1; }

void play(void *g, int *object)
{
        struct game_t *game;
        game = (struct game_t *) g;

        if (game->i[GUITAR].location != 0) {
                printf("You don't have an instrument.\n");
                return;
        }
        if (*object == -1 || *object == GUITAR) {
                printf("Hmmm, not sure what song to play...seek-n-destroy");
                return;
        }
        if (*object == SEEKNDESTROY) {
                printf("Alright!  Hmm, it sounds kinda week without\n"
                        "an amp....and the solo eludes you.\n");
                return;
        }
        else printf("Hmm, I'm not familiar with that one.\n"
                        "How does it go?\n");
}

void get_user_input(char *input)
{
        char *c;

        printf("\n> ");
        /* This is how not to read a string in C */
        scanf("%[^\n]%*c", input);
        for(c=input;*c;c++) *c = tolower(*c);
}

int lookup_object(struct game_t *g, char *name)
{
        int i, rc=-1;

        for (i=0;(i<g->nitems) && (rc < 0); i++)
                if (strcmp(name, g->i[i].short_name) == 0)
                        rc = i;
        return(rc);
}

void do_command(struct game_t *game, char *command)
{
        char *vrbword, *objstr;
        int i, v=-1, found=0, obj=0, o, objectlist[50];

        vrbword = strtok(command, " .,;");

        for (i=0;i<(sizeof(verb)/sizeof(struct verb_t)) && v<0;i++)
                if (strcmp(verb[i].word, vrbword)==0)
                        v=i;
        if (v<0)
        {
                printf("Sorry, I don't know the verb '%s'\n", vrbword);
                return;
        }
        objectlist[0] = -1;
        while ((objstr = strtok(NULL, " ,.")) != NULL)
        {
                o = lookup_object(game, objstr);
                if (o==-1) {
                        printf("I don't know the word '%s'\n",
                                objstr);
                        return;
                }
                objectlist[obj] = o;
                obj++; objectlist[obj] = -1;
        }
        if (verb[v].f != NULL)
                verb[v].f(game, &objectlist[0]);
        else
                printf("'%s' not implemented\n", vrbword);
}

void playit(struct game_t *game)
{
        char input[4096];

        printf("\n\nWelcome to the the demo-drome!\n\n");
        look(game);

        do {    get_user_input(input);
                do_command(game, input);
        } while (!game->done);
}

int main(int argc, char *argv[])
{
        struct game_t game;

        game.p = &player;
        game.r = room;
        game.nrooms = (sizeof(room) / sizeof(struct room_t));
        game.i = item;
        game.nitems = (sizeof(item) / sizeof(struct item_t));
        game.done = 0;
        playit(&game);
}


Previous Top

Log in or register to write something here or to contact authors.