/*
** cia.c     Taken from Hugh Lampert's October 1980 CLoad Game,
**           which was written in TRS-80 Level II Basic by:
**               Hugh Lampert
**               110 Linder Pl.
**               Malverne, NY  11565
**
**           Converted to C by Will Menninger, March 2003.
**           Tried to be faithful to the original.  Fixed
**           a couple idiosyncracies and some grammar/spelling.
**           Also added ability to load and save the game.
**
*/

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

typedef struct
    {
    char *description;
    char *shortname;
    int location;
    } OBJECT;

typedef struct
    {
    char *description;
    int adjacent_location[4];  /* 0=N, 1=S, 2=E, 3=W */
    } LOCATION;

#define NOBJECTS 50
#define NOBJ2    46
#define NLOCATIONS 30
typedef struct
    {
    char name[64];
    int elevator_floor;
    int guard_status;
    int have_drugged_coffee;
    int guard_sleep_level;
    int monitors_on;
    int elevator_operational;
    int sculpture_openable;
    int battery_inserted;
    int television_connected;
    int wearing_gloves;
    int painting_found;
    int rope_on_hook;
    int floor_wired;
    int tape_inserted;
    int turn_number;
    int iloc;
    int nobj;
    char combination[6];
    OBJECT object[NOBJECTS+2];
    LOCATION location[NLOCATIONS+2];
    } GAMESTAT;

static char *textbar = ">--------------------------------------------------------------<";

static OBJECT object[NOBJECTS+2]=
{
{"dummy entry","xxx",0},
{"a video cassette recorder","rec",2},
{"a video tape","tap",0},
{"a large battery","bat",0},
{"a blank credit card","car",0},
{"an electronic lock","loc",0},
{"an elaborate paper weight","wei",5},
{"a locked wooden door","doo",4},
{"an open wooden door","doo",0},
{"a solid looking door","doo",10},
{"an open door","doo",0},
{"an alert security guard","gua",10},
{"a sleeping security guard","gua",0},
{"a locked maintenance closet","clo",14},
{"a maintenance closet","clo",0},
{"a plastic bag","bag",13},
{"an old-fashioned key","key",9},
{"a small metal square on the wall","squ",16},
{"a lever on the square","lev",16},
{"an old mahogany desk","des",5},
{"a broom","bro",13},
{"a dustpan","dus",13},
{"a spiral notebook","not",0},
{"a mahogany drawer","dra",0},
{"a glass case on a pedestal","cas",6},
{"a razor blade","bla",27},
{"a very large ruby","rub",0},
{"a sign on the square","sig",16},
{"a quarter","qua",0},
{"a coffee machine","mac",8},
{"a cup of steaming hot coffee","cup",0},
{"a small capsule","cap",0},
{"a large scuplture","scu",3},
{"a tall office building","bui",1},
{"a pair of sliding doors","doo",3},
{"a large button on the wall","but",29},
{"a panel of buttons numbered one thru three","pan",9},
{"a strong nylon rope","rop",17},
{"a large hook with a rope hanging from it","hoo",21},
{"a C.I.A. identification badge","bad",-1},
{"a portable television","tel",7},
{"a bank of monitors","mon",7},
{"a chaos I.D. card","car",30},
{"a bank of monitors","mon",19},
{"a small painting","pai",23},
{"a pair of rubber gloves","glo",13},
{"a box with a button on it","box",24},
{"one","one",9},
{"two","two",9},
{"three","thr",9},
{"slit","sli",10},
{"","",0}
};

static LOCATION location[NLOCATIONS+2] =
{
{"dummy entry",{0,0,0,0}},
{"on a busy street",{0,0,0,0}},
{"in a visitor's room",{0,0,3,0}},
{"in the lobby of the building",{1,0,4,2}},
{"in a dingy ante room",{0,0,0,3}},
{"in the company president's office",{0,0,0,4}},
{"in a small sound-proofed cubicle",{0,12,0,0}},
{"in a security office",{0,0,8,0}},
{"in a small hallway",{0,14,9,7}},
{"in a small room",{3,0,0,0}},
{"in a short corridor",{0,15,0,9}},
{"in a hallway made of metal",{0,0,12,10}},
{"in a small plain room",{6,0,0,11}},
{"in a maintenance closet",{0,0,14,0}},
{"in a cafeteria",{8,0,0,0}},
{"in a side corridor",{10,0,16,0}},
{"in a power generator room",{0,0,0,15}},
{"in a sub-basement below the chute",{0,0,18,0}},
{"in the entrance to the secret complex",{0,20,19,17}},
{"in a secret monitoring room",{0,0,0,18}},
{"on a ledge in front of a metal pit thousands of feet deep",{18,0,0,0}},
{"on the other side of the pit",{0,0,22,0}},
{"in a long corridor",{0,25,23,21}},
{"in a large room",{0,26,0,22}},
{"in a secret laboratory",{0,0,25,0}},
{"in a narrow cross corridor",{22,0,0,24}},
{"in a cross examination room",{23,28,0,0}},
{"in a small bathroom",{0,0,28,0}},
{"in the office of the chief of CHAOS",{26,30,0,27}},
{"in the CHAOS control room",{0,0,30,0}},
{"near the end of the complex",{28,0,0,29}},
{"",{0,0,0,0}}
};

static char *commandlist[] =
{ "go ","get","drop","push","pull","look","insert","open","wear",
  "read","start","break","cut","throw","connect","quit","bon","inventory",
  "" };

static char *mission=
"\nYour mission, %s, is to recover a ruby that is being\n"
"used in top secret government projects as a part in a\n"
"laser projector.\n"
"  You will have a partner who is not too bright and needs\n"
"you to tell him what to do.  Use two word commands like:\n\n"
"           get notebook    go west    look door\n\n"
"Some commands use only one word.  Example:  inventory\n"
"Two special commands:  s <filename>   (save the game)\n"
"                       l <filename>   (load a game)\n"
"  If you want to see changes in your surroundings, type:  look\n"
"The ruby has been captured by a secret spy ring known as\n"
"CHAOS.  We suspect they are under cover somewhere in this\n"
"neighborhood.  Good luck!\n";

static int  gamestat_proc_request(GAMESTAT *gs,char *word1,char *word2,int ur);
static int  gamestat_drop_object(GAMESTAT *gs,char *word2,int iobj);
static int  gamestat_get_object(GAMESTAT *gs,char *word2,int iobj);
static int  gamestat_go_check(GAMESTAT *gs,char *word2);
static int  gamestat_object_is_useable(GAMESTAT *gs,char *word2,int *iobj);
static int  gamestat_push_object(GAMESTAT *gs,char *word2,int iobj);
static int  gamestat_pull_object(GAMESTAT *gs,char *word2,int iobj);
static int  gamestat_look_object(GAMESTAT *gs,char *word2,int iobj);
static int  gamestat_put_object(GAMESTAT *gs,char *word2,int iobj);
static int  gamestat_open_object(GAMESTAT *gs,char *word2,int iobj);
static int  gamestat_wear_object(GAMESTAT *gs,char *word2,int iobj);
static int  gamestat_read_object(GAMESTAT *gs,char *word2,int iobj);
static int  gamestat_start_object(GAMESTAT *gs,char *word2,int iobj);
static int  gamestat_break_object(GAMESTAT *gs,char *word2,int iobj);
static int  gamestat_cut_object(GAMESTAT *gs,char *word2,int iobj);
static int  gamestat_throw_object(GAMESTAT *gs,char *word2,int iobj);
static int  gamestat_connect_object(GAMESTAT *gs,char *word2,int iobj);
static void gamestat_inventory(GAMESTAT *gs);
static void get_second_word(char *dst,char *src);
static int  play_again(void);
static int  gamestat_moverequest(GAMESTAT *gs,char *buf,char *buf2);
static int  parse_user_input(char *buf);
static int  gamestat_evaluate_situation(GAMESTAT *gs);
static void gamestat_describe_location(GAMESTAT *gs,int nodir);
static void gamestat_init(GAMESTAT *gs);
static void time_delay(int seconds);
static int  xstricmp(char *s1,char *s2);
static int  xstrnicmp(char *s1,char *s2,int n);
static void xstrlwr(char *d,char *s,int maxlen);
static void clean_line(char *buf);


int main(void)

    {
    static GAMESTAT _gs;
    GAMESTAT *gs;
    time_t now;
    int i,status,ur,nodir,mro;
    char buf[128],buf2[128];

    time(&now);
    srand(now);
    gs=&_gs;
    gamestat_init(gs);
    printf("\nC.I.A. Adventure\n\n"
           "Originally by Hugh Lampert (for TRS-80), Oct. 1980 C-Load Magazine.\n"
           "    http://www.wurb.com/if/game/497\n"
           "Converted to C by Will Menninger, March, 2003.\n"
           "    http://willus.com/archive\n");
    nodir=0;
    mro=0;
    while (1)
        {
        if (!mro)
            {
            gamestat_describe_location(gs,nodir);
            nodir=0;
            status=gamestat_evaluate_situation(gs);
            if (status==0 || status==-10)
                {
                if (status==-10)
                    {
                    time_delay(1);
                    printf("I'm dead!\nYou didn't win.\n");
                    }
                else
                    printf("You win!\n");
                if (play_again())
                    {
                    gamestat_init(gs);
                    continue;
                    }
                else
                    break;
                }
            if (status==-1)
                continue;
            for (gs->nobj=0,i=1;i<=NOBJ2;i++)
                if (gs->object[i].location==-1)
                    gs->nobj++;
            }
        mro=0;
        ur=gamestat_moverequest(gs,buf,buf2);
        status=gamestat_proc_request(gs,buf,buf2,ur);
        if (status==-1) /* Quit */
            break;
        if (status==-2) /* Look */
            continue;
        if (status==-3)
            {
            nodir=1;
            continue;
            }
        if (status==-4)
            {
            mro=1;
            continue;
            }
        if (status==-10)
            {
            time_delay(1);
            printf("I'm dead!\nYou didn't win.\n");
            if (play_again())
                {
                gamestat_init(gs);
                continue;
                }
            else
                break;
            }
        }
    return(0);
    }


static int gamestat_proc_request(GAMESTAT *gs,char *word1,char *word2,int ur)

    {
    int iobj;
    char buf[16];

    printf("\n");
    if (!xstrnicmp(word1,"qui",3))
        {
        printf("What?  You would leave me here to die alone?\n"
               "Just for that, I'm going to destroy this game.\n\n");
        time_delay(1);
        printf("\n\n"
               "BOOOOOOOOOOOOOM!\n");
        time_delay(1);
        printf("\nPress <ENTER> to exit.\n");
        fgets(buf,10,stdin);
        return(-1);
        }
    if (!xstrnicmp(word1,"bon",3))
        {
        if (gs->iloc==14)
            {
            printf("Whoops!  A trap door opened beneath me and\n"
                   "I find myself falling.\n");
            time_delay(3);
            gs->iloc=17;
            return(-2);
            }
        printf("Nothing happened.\n");
        return(-3);
        }
    if (!xstrnicmp(word1,"inv",3))
        {
        gamestat_inventory(gs);
        return(-3);
        }
    if (!xstrnicmp(word1,"loo",3) && word2[0]=='\0')
        return(-2);
    if (word2[0]=='\0')
        {
        printf("Please use two word commands so I can understand you.\n");
        return(-4);
        }
    if (!xstricmp(word2,"1"))
        strcpy(word2,"one");
    if (!xstricmp(word2,"2"))
        strcpy(word2,"two");
    if (!xstricmp(word2,"3"))
        strcpy(word2,"three");
    for (iobj=1;iobj<NOBJECTS;iobj++)
        if (!xstrnicmp(word2,gs->object[iobj].shortname,3))
            break;
    if (iobj>=NOBJECTS)
        iobj=0;
    if (iobj==0 && xstrnicmp(word2,"nor",3) && xstrnicmp(word2,"sou",3)
                && xstrnicmp(word2,"eas",3) && xstrnicmp(word2,"wes",3))
        {
        printf("I don't know what it is you are talking about.\n");
        return(-4);
        }
    switch (ur)
        {
        case 1:
            return(gamestat_go_check(gs,word2));
        case 2:
            return(gamestat_get_object(gs,word2,iobj));
        case 3:
            return(gamestat_drop_object(gs,word2,iobj));
        case 4:
            return(gamestat_push_object(gs,word2,iobj));
        case 5:
            return(gamestat_pull_object(gs,word2,iobj));
        case 6:
            return(gamestat_look_object(gs,word2,iobj));
        case 7:
            return(gamestat_put_object(gs,word2,iobj));
        case 8:
            return(gamestat_open_object(gs,word2,iobj));
        case 9:
            return(gamestat_wear_object(gs,word2,iobj));
        case 10:
            return(gamestat_read_object(gs,word2,iobj));
        case 11:
            return(gamestat_start_object(gs,word2,iobj));
        case 12:
            return(gamestat_break_object(gs,word2,iobj));
        case 13:
            return(gamestat_cut_object(gs,word2,iobj));
        case 14:
            return(gamestat_throw_object(gs,word2,iobj));
        case 15:
            return(gamestat_connect_object(gs,word2,iobj));
        }                
    return(0);
    }


static int gamestat_drop_object(GAMESTAT *gs,char *word2,int iobj)

    {
    int i;

    for (i=1;i<=NOBJ2;i++)
        if (!xstrnicmp(word2,gs->object[i].shortname,3)
               && gs->object[i].location==-1)
            break;
    if (i>NOBJ2)
        {
        printf("I don't seem to be carrying it.\n");
        return(-3);
        }
    if (i==30)
        {
        printf("I dropped the cup, but it broke into small pieces.\n"
               "The coffee soaked into the ground.\n");
        gs->object[30].location=0;
        gs->have_drugged_coffee=0;
        return(-3);
        }
    if (i==45)
        gs->wearing_gloves=0;
    if (i==31 && gs->object[30].location==-1)
        {
        printf("O.K.  I dropped it.\n"
               "But it fell in the coffee!\n");
        gs->object[31].location=0;
        gs->have_drugged_coffee=1;
        return(-3);
        }
    printf("O.K.  I dropped it.\n");
    gs->object[i].location=gs->iloc;
    return(-3);
    }


static int gamestat_get_object(GAMESTAT *gs,char *word2,int iobj)

    {
    static int getable[23]={2,3,4,6,15,16,20,21,22,23,25,26,27,28,
                            30,31,37,39,40,42,44,45,46};
    int i;

    if (!gamestat_object_is_useable(gs,word2,&iobj))
        return(-3);
    for (i=0;i<23;i++)
        if (iobj==getable[i])
            break;
    if (i>=23)
        {
        printf("I can't carry that!\n");
        return(-3);
        }
    i=getable[i];
    if (gs->object[i].location==-1)
        {
        printf("I already have it.\n");
        return(-3);
        }
    if (gs->nobj >= 5)
        {
        printf("I can't carry anymore.\n");
        return(-3);
        }
    printf("O.K.\n");
    gs->object[i].location=-1;
    if (!xstrnicmp(word2,"pai",3) && !gs->painting_found)
        {
        gs->painting_found=1;
        gs->object[31].location=gs->iloc;
        printf("Something fell from the frame!\n");
        }
    if (!xstrnicmp(word2,"tel",3))
        gs->television_connected=0;
    return(-3);
    }


static int gamestat_go_check(GAMESTAT *gs,char *word2)

    {
    int i;
    static char *nogo="I can't go that way at the moment.\n";

    if (!xstrnicmp(word2,"nor",3) && gs->location[gs->iloc].adjacent_location[0]>0)
        {
        gs->iloc = gs->location[gs->iloc].adjacent_location[0];
        return(-2);
        }
    if (!xstrnicmp(word2,"sou",3) && gs->location[gs->iloc].adjacent_location[1]>0)
        {
        gs->iloc = gs->location[gs->iloc].adjacent_location[1];
        return(-2);
        }
    if (!xstrnicmp(word2,"eas",3) && gs->location[gs->iloc].adjacent_location[2]>0)
        {
        gs->iloc = gs->location[gs->iloc].adjacent_location[2];
        return(-2);
        }
    if (!xstrnicmp(word2,"wes",3) && gs->location[gs->iloc].adjacent_location[3]>0)
        {
        gs->iloc = gs->location[gs->iloc].adjacent_location[3];
        return(-2);
        }
    if (!xstrnicmp(word2,"nor",3) || !xstrnicmp(word2,"sou",3)
         || !xstrnicmp(word2,"eas",3) || !xstrnicmp(word2,"wes",3))
        {
        printf("%s",nogo);
        return(-3);
        }
    if (!gamestat_object_is_useable(gs,word2,&i))
        return(-3);
    if (i==8)
        {
        gs->iloc=5;
        return(-2);
        }
    if (i==37 && gs->iloc==20 && gs->rope_on_hook)
        {
        gs->iloc=21;
        return(-2);
        }
    if (i==10)
        {
        gs->iloc=11;
        return(-2);
        }
    if (i==14)
        {
        gs->iloc=13;
        return(-2);
        }
    if (i==33)
        {
        gs->iloc=3;
        return(-2);
        }
    if (i==34 && gs->elevator_operational)
        {
        gs->iloc=9;
        return(-2);
        }
    printf("%s",nogo);
    return(-3);
    }


static int gamestat_object_is_useable(GAMESTAT *gs,char *word2,int *iobj)

    {
    int i;

    for (i=1;gs->object[i].description[0]!='\0';i++)
        if (!xstrnicmp(word2,gs->object[i].shortname,3) 
           && (gs->object[i].location==gs->iloc || gs->object[i].location==-1))
            break;
    if (gs->object[i].description[0]=='\0')
        {
        printf("I don't see that here.\n");
        return(0);
        }
    (*iobj)=i;
    return(1);
    }


static int gamestat_push_object(GAMESTAT *gs,char *word2,int iobj)

    {
    if (!xstrnicmp(word2,"but",3) && gs->iloc==3 && !gs->elevator_operational)
        {
        gs->elevator_operational=1;
        printf("The doors open with a whoosh!\n");
        return(-3);
        }
    if (gs->object[46].location==-1 && !xstrnicmp(word2,"but",3))
        {
        printf("I push the button on the box and ...\n");
        time_delay(1);
        }
    else
        {
        if (!gamestat_object_is_useable(gs,word2,&iobj))
            return(-3);
        if (iobj==17 && !gs->wearing_gloves)
            {
            printf("There's electricity coarsing through the square!\n"
                   "I'm being electrocuted!\n");
            return(-10);
            }
        if (iobj==35 && gs->monitors_on)
            {
            printf("The button on the wall goes in .....\n"
                   "CLICK!  Something seems different now.\n");
            gs->monitors_on=0;
            return(-3);
            }
        if ((iobj==47 && gs->elevator_floor!=1) 
               || (iobj==48 && gs->elevator_floor!=2)
               || (iobj==49 && gs->elevator_floor!=3))
            {
            static int newroom[3]={3,8,10};
            gs->location[9].adjacent_location[0]=newroom[iobj-47];
            gs->elevator_floor=iobj-46;
            printf("The door close and I feel as if the room is moving.\n");
            time_delay(2);
            printf("Suddenly the doors open again.\n");
            return(-2);
            }
        }
    if (gs->object[46].location==-1 && (gs->iloc==6 || gs->iloc==29))
        {
        printf("There is a blinding flash....\n");
        time_delay(3);
        gs->iloc=1;
        gs->elevator_floor=1;
        gs->location[9].adjacent_location[0]=3;
        return(-2);
        }
    printf("Nothing happens.\n");
    return(-3);
    }


static int gamestat_pull_object(GAMESTAT *gs,char *word2,int iobj)

    {
    if (!gamestat_object_is_useable(gs,word2,&iobj))
        return(-3);
    if (iobj==18 && !gs->wearing_gloves)
        {
        printf("The lever has electricity coarsing through it!\n"
               "I'm being electrocuted!\n");
        return(-10);
        }
    if (iobj==18 && gs->floor_wired)
        {
        printf("The lever goes all the way up and clicks.\n"
               "Something seems different now.\n");
        gs->floor_wired=0;
        return(-3);
        }
    printf("Nothing happens.\n");
    return(-3);
    }


static int gamestat_look_object(GAMESTAT *gs,char *word2,int iobj)

    {
    static char *nothing="I see nothing of interest.\n";

    if (gs->iloc==5 && !xstrnicmp(word2,"drawer",3))
        {
        printf("It looks fragile.\n");
        return(-3);
        }
    if (!gamestat_object_is_useable(gs,word2,&iobj))
        return(-3);
    switch (iobj)
        {
        case 1:
            if (!gs->battery_inserted)
                {
                printf("There's no power for it.\n");
                break;
                }
            if (!gs->television_connected)
                {
                printf("There's no T.V. to watch on.\n");
                break;
                }
            printf("%s",nothing);
            break;
        case 6:
            printf("It looks heavy.\n");
            break;
        case 7:
            printf("It's locked.\n");
            break;
        case 13:
            printf("It's a very strong bag.\n");
            break;
        case 19:
            printf("I can see a locked drawer in it.\n");
            break;
        case 22:
        case 27:
            printf("There's writing on it.\n");
            break;
        case 34:
            if (gs->elevator_operational)
                printf("The doors are open.\n");
            else
                printf("There's a button near the doors.\n");
            break;
        case 24:
            printf("I can see a gleaming stone in it.\n");
            break;
        case 9:
            printf("There is a small slit near the door.\n");
            break;
        case 41:
            if (!gs->monitors_on)
                printf("The screen is dark.\n");
            else
                printf("I see a metal pit thousands of feet deep on one monitor.\n"
                       "On the other side of the pit, I see a large hook.\n");
            break;
        case 43:
            if (!gs->monitors_on)
                printf("The screen is dark.\n");
            else
                printf("I see a room with a case on a pedestal in it.\n");
            break;
        case 44:
            printf("I see a picture of a grinning jackal.\n");
            break;
        default:
            printf("%s",nothing);
            break;
        }
    return(-3);
    }


static int gamestat_put_object(GAMESTAT *gs,char *word2,int iobj)

    {
    static char *nothing="Nothing happened.\n";
    char buf[64];
    int iobj2;

    if (!gamestat_object_is_useable(gs,word2,&iobj))
        return(-3);
    if (iobj!=3 && iobj!=2 && iobj!=4 && iobj!=28)
        {
        printf("I can't insert that!\n");
        return(-3);
        }
    printf("Tell me, in one word, into what?  ");
    fgets(buf,60,stdin);
    clean_line(buf);
    if (!gamestat_object_is_useable(gs,buf,&iobj2))
        return(-3);
    if (iobj==3 && iobj2==1)
        {
        printf("O.K.\n");
        gs->battery_inserted=1;
        gs->object[iobj].location=0;
        return(-3);
        }
    if (iobj==4 && iobj2==50 && gs->guard_sleep_level<=0)
        {
        printf("The guard won't let me!\n");
        return(-3);
        }
    if (iobj==2 && iobj2==1)
        {
        printf("O.K.  The tape is in the recorder.\n");
        gs->object[iobj].location=0;
        gs->tape_inserted=1;
        return(-3);
        }
    if (iobj==4 && iobj2==50)
        {
        printf("Pop!  A section of the wall opens.....\n"
               "revealing something very interesting.\n");
        gs->object[iobj].location=0;
        gs->object[5].location=gs->iloc;
        return(-3);
        }
    if (iobj==28 && iobj2==29)
        {
        printf("Pop!  A cup of coffee comes out of the machine.\n");
        gs->object[iobj].location=0;
        gs->object[30].location=gs->iloc;
        return(-30);
        }
    printf("%s",nothing);
    return(-3);
    }


static int gamestat_open_object(GAMESTAT *gs,char *word2,int iobj)

    {
    char buf[64];

    if (!xstrnicmp(word2,"drawer",3) && gs->iloc==5 
                                    && gs->object[23].location==0)
        {
        printf("It's stuck.\n");
        return(-3);
        }
    if (!gamestat_object_is_useable(gs,word2,&iobj))
        return(-3);
    if (iobj!=7 && iobj!=9 && iobj!=13 && iobj!=15 && iobj!=23
                && iobj!=32 && iobj!=5)
        {
        printf("I can't open that!\n");
        return(-3);
        }
    if (iobj==7 && gs->object[16].location==-1)
        {
        printf("O.K.  I opened the door.\n");
        gs->object[iobj].location=0;
        gs->object[8].location=4;
        return(-3);
        }
    if (iobj==9)
        {
        printf("I can't.  It doesn't work.\n");
        return(-3);
        }
    if (iobj==13 && gs->object[16].location==-1)
        {
        printf("O.K.  The closet is opened.\n");
        gs->object[iobj].location=0;
        gs->object[14].location=14;
        return(-3);
        }
    if (iobj==15)
        {
        printf("I can't.  It's too strong.\n");
        return(-3);
        }
    if (iobj==23)
        {
        printf("It's stuck.\n");
        return(-3);
        }
    if (iobj==32 && gs->object[28].location==0 && gs->object[4].location==0
                 && gs->sculpture_openable)
        {
        printf("I open the sculpture.\n"
               "Something falls out.\n");
        gs->object[28].location=gs->iloc;
        gs->object[4].location=gs->iloc;
        return(-3);
        }
    if (iobj!=5)
        {
        printf("I can't do that......yet!\n");
        return(-3);
        }
    printf("What's the combination?  ");
    fgets(buf,120,stdin);
    clean_line(buf);
    if (!xstricmp(buf,gs->combination))
        {
        printf("The door is slowly opening.\n");
        gs->object[iobj].location=0;
        gs->object[9].location=0;
        gs->object[10].location=10;
        return(-3);
        }
    printf("You must have the wrong combination or you are not\n"
           "saying it right.\n");
    return(-3);
    }


static int gamestat_wear_object(GAMESTAT *gs,char *word2,int iobj)

    {
    if (!gamestat_object_is_useable(gs,word2,&iobj))
        return(-3);
    if (!xstrnicmp(word2,"glove",3) && gs->object[45].location==-1)
        {
        printf("O.K.  I'm now wearing the gloves.\n");
        gs->wearing_gloves=1;
        return(-3);
        }
    printf("I can't wear that!\n");
    return(-3);
    }


static int gamestat_read_object(GAMESTAT *gs,char *word2,int iobj)

    {
    if (!gamestat_object_is_useable(gs,word2,&iobj))
        return(-3);
    if (xstrnicmp(word2,"sign",3) && xstrnicmp(word2,"note",3))
        {
        printf("I can't read that.\n");
        return(-3);
        }
    if (iobj==22)
        {
        printf("It says:\n"
               "%s,\n"
               "  We have discovered one of CHAOS's secret words.\n"
               "It is:  Bond-007-\n"
               "It is to be used in a -tasteful- situation.\n",gs->name);
        return(-3);
        }
    if (iobj==27)
        {
        printf("It says:  Watch out!  Dangerous!\n");
        return(-3);
        }
    printf("I can't read that.\n");
    return(-3);
    }


static int gamestat_start_object(GAMESTAT *gs,char *word2,int iobj)

    {
    if (!gamestat_object_is_useable(gs,word2,&iobj))
        return(-3);
    if (xstrnicmp(word2,"rec",3))
        {
        printf("I can't start that.\n");
        return(-3);
        }
    if (!gs->battery_inserted || gs->television_connected!=1 || !gs->tape_inserted)
        {
        printf("Nothing happened.\n");
        return(-3);
        }
    printf("The recorder starts up and presents a short message:\n"
           "%s,\n"
           "We have uncovered a number that may help you.\n"
           "That number is:  %s.  Please watch out for hidden traps.\n"
           "Also, there is something in the sculpture.\n",
           gs->name,gs->combination);
    gs->sculpture_openable=1;
    return(-3);
    }
   
 
static int gamestat_break_object(GAMESTAT *gs,char *word2,int iobj)

    {
    if (xstrnicmp(word2,"drawer",3))
        {
        if (!gamestat_object_is_useable(gs,word2,&iobj))
            return(-3);
        printf("I'm trying to break it, but I can't.\n");
        return(-3);
        }
    if (gs->object[6].location!=-1)
        {
        printf("I can't do that yet.\n");
        return(-3);
        }
    if (gs->iloc==5)
        {
        printf("It's hard....but I got it.  Two things fell out.\n");
        gs->object[3].location=gs->iloc;
        gs->object[22].location=gs->iloc;
        gs->object[23].location=gs->iloc;
        return(-3);
        }
    printf("Nothing happens.\n");
    return(-3);
    }


static int gamestat_cut_object(GAMESTAT *gs,char *word2,int iobj)

    {
    if (!gamestat_object_is_useable(gs,word2,&iobj))
        return(-3);
    if (iobj!=15 && iobj!=24)
        {
        printf("I'm trying.  It doesn't work.\n");
        return(-3);
        }
    if (gs->object[25].location!=-1)
        {
        printf("I can't do that yet.\n");
        return(-3);
        }
    if (iobj==15)
        {
        printf("Rip!  The bag goes to pieces, and something falls out!\n");
        gs->object[iobj].location=0;
        gs->object[2].location=gs->iloc;
        return(-3);
        }
    printf("I cut the case and reach in to pull something out.\n");
    gs->object[26].location=-1;
    return(-3);
    }


static int gamestat_throw_object(GAMESTAT *gs,char *word2,int iobj)

    {
    static char buf[128];

    if (!gamestat_object_is_useable(gs,word2,&iobj))
        return(-3);
    if (xstrnicmp(word2,"rop",3))
        {
        printf("I can't throw that.\n");
        return(-3);
        }
    if (gs->object[37].location!=-1)
        {
        printf("I can't do that yet.\n");
        return(-3);
        }
    printf("Tell me, in one word, at what?  ");
    fgets(buf,120,stdin);
    clean_line(buf);
    if (xstrnicmp(buf,"hoo",3))
        {
        printf("O.K.  I threw it.\n");
        gs->object[37].location=gs->iloc;
        return(-3);
        }
    if (gs->iloc!=20)
        {
        printf("I can't do that yet.\n");
        return(-3);
        }
    printf("I threw the rope and it snagged on the hook.\n");
    gs->rope_on_hook=1;
    gs->object[37].location=gs->iloc;
    return(-3);
    }

         
static int gamestat_connect_object(GAMESTAT *gs,char *word2,int iobj)

    {
    if (!gamestat_object_is_useable(gs,word2,&iobj))
        return(-3);
    if (xstrnicmp(word2,"tel",3))
        {
        printf("I can't connect that.\n");
        return(-3);
        }
    if (gs->object[40].location!=gs->iloc)
        {
        printf("I don't see the television here.\n");
        return(-3);
        }
    if (gs->television_connected==1)
        {
        printf("I did that already.\n");
        return(-3);
        }
    if (gs->iloc!=2)
        {
        printf("I can't do that....yet!\n");
        return(-3);
        }
    printf("O.K.  The T.V. is connected.\n");
    gs->television_connected=1;
    return(-3);
    }


static void gamestat_inventory(GAMESTAT *gs)

    {
    int objcount,i;

    printf("We are presently carrying:\n");
    for (objcount=0,i=1;i<=NOBJ2;i++)
        {
        if (gs->object[i].location!=-1)
            continue;
        printf("%s    %s",objcount>0 ? ",\n" : "",gs->object[i].description);
        if (i==45 && gs->wearing_gloves)
            printf(", which I'm wearing");
        objcount++;
        }
    if (objcount==0)
        printf("    Nothing");
    printf(".\n");
    }


static void get_second_word(char *dst,char *src)

    {
    int i,j;

    dst[0]='\0';
    for (i=0;src[i]==' ' || src[i]=='\t';i++);
    if (src[i]=='\0')
        return;
    for (;src[i]!=' ' && src[i]!='\t' && src[i]!='\0';i++);
    if (src[i]=='\0')
        return;
    for (;src[i]==' ' || src[i]=='\t';i++);
    if (src[i]=='\0')
        return;
    for (j=0;src[i]!=' ' && src[i]!='\t' && src[i]!='\0';i++)
        dst[j++]=src[i];
    dst[j]='\0';
    }


static int play_again(void)

    {
    char buf[64];

    printf("Would you like to try again (y/n)?  ");
    fgets(buf,40,stdin);
    return(buf[0]=='y' || buf[0]=='Y');
    }


static int gamestat_moverequest(GAMESTAT *gs,char *buf,char *buf2)

    {
    int ur,i,j;
    static char filename[256];
    FILE *f;

    while (1)
        {
        printf("\nWhat do you think we should do?  ");
        fgets(buf,127,stdin);
        clean_line(buf);
        if ((!xstrnicmp(buf,"l ",2) || !xstrnicmp(buf,"s ",2)) && strlen(buf)>2)
            {
            for (i=2;buf[i]==' ' || buf[i]=='\t';i++);
            for (j=0;buf[i]!=' ' && buf[i]!='\t' && buf[i]!='\0';i++)
                filename[j++]=buf[i];
            filename[j]='\0';
            if (strlen(filename)>0)
                {
                f=fopen(filename,tolower(buf[0])=='s' ? "wb" : "rb");
                if (f!=NULL)
                    {
                    if (tolower(buf[0])=='s')
                        fwrite(gs,sizeof(GAMESTAT),1,f);
                    else
                        fread(gs,sizeof(GAMESTAT),1,f);
                    fclose(f);
                    if (tolower(buf[0])=='l')
                        {
                        for (i=0;i<NOBJECTS+2;i++)
                            {
                            gs->object[i].description = object[i].description;
                            gs->object[i].shortname = object[i].shortname;
                            }
                        for (i=0;i<NLOCATIONS+2;i++)
                            gs->location[i].description = location[i].description;
                        }
                    printf("\nGame status %s file %s.\n\n",
                        tolower(buf[0])=='s' ? "saved to" : "loaded from",
                         filename);
                    continue;
                    }
                }
            printf("\n%s file %s failed!\n\n",
                   tolower(buf[0])=='s' ? "Saving to" : "Loading from",
                   filename);
            continue;
            }
        ur=parse_user_input(buf);
        if (ur>0)
            break;
        if (!ur)
            printf("I don't know how to do that.\n");
        else if (ur==-1)
            printf(mission,gs->name);
        }
    get_second_word(buf2,buf);
    return(ur);
    }


static int parse_user_input(char *buf)

    { 
    int i,j;
    static char buf2[128];
    static char *cmdeq[] =
        {
        "wal","go ","run","go ","tak","get","car","get",
        "lea","dro","pre","pus","exa","loo","put","ins",
        "unl","ope","pla","sta","sma","bre","att","con",
        "lis","inv",""
        };
    static char *cmdeq2[] =
        {
        "n","go north","s","go south","e","go east","w","go west",
        "i","inv","q","quit",""
        };

    for (j=0;buf[j]==' ' || buf[j]=='\t';j++);
    for (;buf[j]!=' ' && buf[j]!='\t' && buf[j]!='\0';j++);
    for (;buf[j]==' ' || buf[j]=='\t';j++);
    for (i=0;buf[i]!='\0' && buf[i]!='\n';i++);
    buf[i]='\0';
    for (i=0;cmdeq2[i][0]!='\0';i+=2)
        if (!xstricmp(cmdeq2[i],buf))
            {
            strcpy(buf,cmdeq2[i+1]);
            break;
            }
    for (i=0;cmdeq[i][0]!='\0';i+=2)
        {
        if (!xstrnicmp(cmdeq[i],buf,3))
            {
            sprintf(buf2,"%s %s",cmdeq[i+1],&buf[j]);
            strcpy(buf,buf2);
            break;
            }
        }
    for (i=0;commandlist[i][0]!='\0';i++)
        if (!xstrnicmp(commandlist[i],buf,3))
            return(i+1);
    if (!xstrnicmp(buf,"ord",3))
        return(-1);
    return(0);
    }

/*
** Returns -1 if should return to describe_location function.
**         -10 if player dies (game over)
**         -2 ask player what to do
**          0 Mission successful
*/
static int gamestat_evaluate_situation(GAMESTAT *gs)

    {
    if (gs->iloc==3 && gs->object[39].location<0)
        {
        printf("The door man looks at me and then throws me out.\n");
        gs->iloc=1;
        return(-1);
        }
    if (gs->iloc==10 && gs->object[42].location!=-1 
                     && gs->object[11].location==gs->iloc)
        {
        printf("The guard looks at me suspiciously, then throws me back.\n");
        gs->iloc=9;
        return(-1);
        }
    if (gs->iloc==6 && gs->monitors_on)
        {
        printf("Sirens go off all around me!\n"
               "Guards run in and shoot me to death!\n");
        return(-10);
        }
    if (gs->iloc==11 && gs->floor_wired)
        {
        printf("The floor is wired with electricity!\n"
               "I'm being electrocuted!\n");
        return(-10);
        }
    if (gs->iloc==10 && gs->object[30].location==-1 && gs->have_drugged_coffee)
        {
        printf("The guard takes my coffee\n"
               "and falls to sleep right away.\n");
        gs->guard_sleep_level = 7 + rand()%10;
        gs->object[11].location=0;
        gs->object[12].location=10;
        gs->have_drugged_coffee=0;
        gs->object[30].location=0;
        return(-2);
        }
    if (gs->guard_sleep_level==0)
        {
        printf("I hear a noise like someone is yawning.\n");
        gs->object[11].location=10;
        gs->object[12].location=0;
        gs->guard_sleep_level=-1;
        gs->guard_status=-2;
        return(-2);
        }
    if (gs->iloc==1 && gs->object[26].location==-1)
        {
        printf("Hooray!  You've recovered the ruby!\n");
        return(0);
        }
    if (gs->turn_number > 375)
        printf("I think they are on to me....I hear noises.\n");
    if (gs->turn_number==400)
        {
        printf("Oh no!  They caught up to me!  Help!  They're pulling out guns!\n");
        return(-10);
        }
    if (gs->turn_number==1)
        printf("Writing on the wall says:\n"
               "If you want instructions type: orders please\n");
    if (gs->iloc==6 && gs->location[6].adjacent_location[1]!=0)
        {
        printf("A secret door slams down behind me!\n");
        gs->location[6].adjacent_location[1]=0;
        return(-2);
        }
    if (gs->iloc==10 && gs->guard_status==-2)
        {
        printf("The guard draws his gun and shoots me!\n");
        return(-10);
        }
    return(-2);
    }


static void gamestat_describe_location(GAMESTAT *gs,int nodir)

    {
    static char *direction[]={"North","South","East","West"};
    int i,count;

    if (!nodir)
        {
        printf("\nWe are %s.\n",gs->location[gs->iloc].description);
        for (i=1;i<=NOBJ2;i++)
            if (gs->object[i].location==gs->iloc)
                printf("I can see %s.\n",gs->object[i].description);
        for (count=0,i=0;i<4;i++)
            if (gs->location[gs->iloc].adjacent_location[i] > 0)
                count++;
        if (count>0)
            {
            printf("We could easily go:  ");
            for (count=0,i=0;i<4;i++)
                if (gs->location[gs->iloc].adjacent_location[i] > 0)
                    printf("%s ",direction[i]);
            printf("\n");
            }
        printf("%s\n",textbar);
        }
    gs->turn_number++;
    if (gs->guard_sleep_level > 0)
        gs->guard_sleep_level--;
    if (gs->turn_number==1)
        {
        printf("Enter your name, partner:  ");
        fgets(gs->name,63,stdin);
        printf("\n");
        clean_line(gs->name);
        if (gs->name[0]=='\0')
            strcpy(gs->name,"Partner");
        }
    }

    
static void gamestat_init(GAMESTAT *gs)

    {
    int i;

    for (i=0;i<NOBJECTS+2;i++)
        gs->object[i] = object[i];
    for (i=0;i<NLOCATIONS+2;i++)
        gs->location[i] = location[i];
    strcpy(gs->name,"Partner");
    gs->elevator_floor=1;
    gs->have_drugged_coffee=0;
    gs->guard_sleep_level=-1;
    gs->turn_number=0;
    gs->monitors_on=1;
    gs->elevator_operational=0;
    gs->sculpture_openable=0;
    gs->battery_inserted=0;
    gs->television_connected=0;
    gs->wearing_gloves=0;
    gs->painting_found=0;
    gs->rope_on_hook=0;
    gs->tape_inserted=0;
    gs->iloc=1;
    gs->nobj=0;
    gs->guard_status=0;
    gs->floor_wired=1;
    for (i=0;i<5;i++)
        gs->combination[i] = rand()%10 + '0';
    gs->combination[i]='\0';
    }


static void time_delay(int seconds)

    {
    time_t t1,t2;

    time(&t1);
    t2=t1;
    while (t2-t1 < seconds+1)
        time(&t2);
    }


static int xstricmp(char *s1,char *s2)

    {
    static char x1[256];
    static char x2[256];

    xstrlwr(x1,s1,255);
    xstrlwr(x2,s2,255);
    return(strcmp(x1,x2));
    }


static int xstrnicmp(char *s1,char *s2,int n)

    {
    static char x1[256];
    static char x2[256];

    xstrlwr(x1,s1,255);
    xstrlwr(x2,s2,255);
    return(strncmp(x1,x2,n));
    }


static void xstrlwr(char *d,char *s,int maxlen)

    {
    int i;

    for (i=0;i<maxlen && s[i]!='\0';i++)
        d[i]=tolower(s[i]);
    d[i]='\0';
    }


static void clean_line(char *buf)

    {
    int     i,j;

    for (i=0;buf[i]!='\n' && buf[i]!='\r' && buf[i]!='\0';i++);
    for (i--;i>=0 && (buf[i]==' ' || buf[i]=='\t');i--);
    buf[i+1]='\0';
    for (i=0;buf[i]==' ' || buf[i]=='\t';i++);
    if (i)
        {
        for (j=0;buf[i]!='\0';j++,i++)
            buf[j]=buf[i];
        buf[j]='\0';
        }
    }

