/*----------------------------------------------------------------------*/
/*                                                                      */
/*  File    :   CHIMAERA.C                                              */
/*  Author  :   Chris Newall                                            */
/*  Date    :   31st January 2002                                       */
/*  Function:   CHIMAERA, an infinite adventure                         */
/*  Version :   C1.001A                                                 */
/*                                                                      */
/*---- Program Summary -------------------------------------------------*/
/*                                                                      */
/*  An adventure program using automatic text generation and with       */
/*  consistent but unpredictable moves generated by  an integer         */
/*  function in subroutine LOCATE.                                      */
/*                                                                      */
/*  This version is a conversion into ANSI C of the original program    */
/*  written in the Prime dialect of Fortran IV with Glaxo specific      */
/*   library routines.                                                  */
/*                                                                      */
/*    *****************************************                         */
/*    *                                       *                         */
/*    *  Written by Nicholas Perre-Wetherall  *                         */
/*    *         [aka Chris Newall]            *                         */
/*    *          Copyright 1984               *                         */
/*    *        All rights reserved            *                         */
/*    *                                       *                         */
/*    *****************************************                         */
/*                                                                      */
/*----------------------------------------------------------------------*/
/*  Note that in order to clarify the coding and simplify debugging     */
/*  and maintenance some substantial blocks of code are located in      */
/*  functions which are called only once.                               */
/*                                                                      */
/*  ***  Revision History  ***                                          */
/*                                                                      */
/*  Version C1.001A                                                      */
/*  12 May 2003 Modified restore() token buffer to                      */
/*              char token[MAXREST][16]; to accommodate longer tokens   */
/*                                                                      */
/*---- Include Files ---------------------------------------------------*/
#include    <ctype.h>       /*  Definitions for the ctype macros        */
#include    <stdio.h>       /*  Definitions for stream input/output     */
#include    <stdlib.h>      /*  Definitions for common types, variables */
                            /*  and functions                           */
#include    <string.h>      /*  Defines memory and string functions     */
#include    <math.h>        /*  Defines maths functions                 */
#include    <time.h>        /*  Date and time definitions               */
#include    "chimaera.h"    /*  CHIMAERA variables, arrays and          */
                            /*  structures                              */
/*---- Main Function ---------------------------------------------------*/

struct tm *tptr;                   /* Time and date structure      */
time_t lt;                         /* Time as type time_t          */
char timebuff[80];                 /* Buffer for time string       */

int main()
   {
    int i, j, k, len, iresp, itest, forever;
    int seed;                          /* Seed for srand()             */
    int itmp, jtmp, ktmp;              /* Temporary variables          */
    int apoint;                        /* Index to dicact[]            */
/*    int tpoint;                        /* Index to thing[]             */
    int opoint;                        /* Index to object              */
    int mpoint;                        /* Index to move                */
    int monstpoint;                    /* Index to monster             */

    forever = 1;              /* Dummy condition for eternal while loop */
    memset(&display,'\0',MAXDISPLAY);        /* Clear display buffer */

    if (LOGGING)
      {
       if ((log_file = fopen("chimaera.log","w")) == NULL)
         {
          printf("Unable to open session logging file 'chimaera.log'");
         }
       else
         {
          printf("[Session logging is ON]\n");
         }
      }

/*---- Display the welcome screen and initialise all arrays ----*/
    welcome();
    initialise();               /* Initialise arrays */
    worth();                    /* Initialise object values */
    news();                     /* Display the news screen at random 1:4 */
    tonl(1);

/*---- Display the instructions if asked to do so ----*/
    tnoua("Do you want instructions? ");
    showtext();
    if (yesno() == 1)
      {
       instructions(0);
       tnoua("Continue? ");
       showtext();
       while (yesno() != 1) { }
      }
    hint("");
    tonl(1);

/*---- Establish the starting point by setting advno ----*/
    tnou("There are eleven starting points, 1-10 are standard, 0 is random. ");
    showtext();
    do {
        itest = 1;
        tnoua("Choose one (0 - 10) ");
        showtext();
        len = inpline();        /* Get input line and convert it to upper case */
        if (len == 0) { itest = 0; continue; }
        if (!isdigit(inbuff[0])) { itest = 0; continue; }
        advno = atoi(inbuff);
        if (advno < 0) { itest = 0; continue; }
        if (advno > 10) { itest = 0; continue; }
       } while (itest == 0);

/*---- Seed the random number generator --------------------------------*/
/* Use the system time to calculate a seed for the random adventure     */

    if (advno == 0)
      {
       lt = time(NULL);               /* Get the system time            */
       tptr = localtime(&lt);
       strftime(timebuff,80,"%S",tptr);  /* Extract the number of seconds  */
       seed = atoi(timebuff) + 1;           /* convert it to an integer       */
      } else seed = advno;

    srand(seed);                  /* Seed random number generator  */
    values[SEED] = rand();        /* use it to get a random number */
    srand(values[SEED]);          /* and reseed the generator      */
    memset(&dicact[35][4],dicact[38][1],1);

    locwun();         /* Initialise object locations */

    values[DWFNUM] = rnd(4) + 2;    /* Initialise the  dwarf population   */
    values[MONCOUNT] = 0;           /* Monsters not active yet            */

/*---- Get date and day of month and print them ------------------------*/

    values[MONTH] = rnd(12);                    /* Set the month,                */
    values[DAWN] = dawn[values[MONTH]];         /* Set the time of dawn          */
    values[DUSK] = dusk[values[MONTH]];         /* Set the time of dusk          */
    values[DAY] = rnd(mdays[values[MONTH]]);    /* Set the day                   */
    values[WEEKDAY] = rnd(7);                   /* and day of the week           */
    tonl(1);
    tnoua("It is ");
    itmp = rnd(20);
    switch (itmp)
      {
       case 13 : {
                  flags[FR13] = 1; values[DAY] = 13; values[WEEKDAY] = 5;
                  tnoua("Friday 13th ");
                  tnoua(months[values[MONTH]]); break;
                 }
       case 10 : {
                  flags[HALLOW] = 1; values[DAY] = 31; values[MONTH] = 10;
                  tnoua(weekdays[values[WEEKDAY]]);
                  tnoua(" 31st October, Halloween! "); break;
                 }
       default : {
                  tnoua(weekdays[values[WEEKDAY]]);
                  tnoua(" ");
                  tnoint(values[DAY]);
                  switch (values[DAY])
                    {
                     case 1  :
                     case 21 :
                     case 31 : tnoua("st"); break;
                     case 2  :
                     case 22 : tnoua("nd"); break;
                     case 3  :
                     case 23 : tnoua("rd"); break;
                     default : tnoua("th"); break;
                    }
                  tnoua(" ");
                  tnoua(months[values[MONTH]]);
                  break;
                 }
      }
    tnou(". The sun shines blood red through the dawn! ");
    showtext();
    values[DAYTIME] = values[DAWN];
    memset(&dicact[35][3],dicact[15][1],1);
    flags[NIGHT] = 0;
/*---- Calculate the co-ordinates of the starting point and base camp --*/
    if (advno != 0)
      {
       x = advno * 10; y = 1500 / x;          /* Standard location */
      }
    else
      {
       x = rnd(15) * 15 + 15; y = 2000 / x;   /* Random location */
      }
    z = 1;
    here = locate(x,y,z);
    values[FIRSTX] = x + rnd(10) - 5; values[FIRSTY] = y + rnd(10) - 5;
    memset(&dicact[35][1],dicact[26][3],1);
    values[BASE] = locate(values[FIRSTX],values[FIRSTY],1);

/*--- First move, set the move counter and print the first move text ---*/
    moveno = 0;
    memset(&dicact[35][0],dicact[47][3],1);
    values[HELD] = 0; values[MAGONE] = 1; values[LIGHT] =100;
    cow = rnd(8); cat = rnd(3);
    memset(&dicact[35][2],dicact[18][2],1);
    values[LUCK] = rnd(40) + 10;
    if (flags[FR13] == 1) values[LUCK] = rnd(10);
    for (i=1;i<15;i++)
      {
       if (i < 9) ways[i] = 1; else ways[i] = 0;
      }
    tonl(1);
    tnoua("You are standing on a wide grassy plain, far off the snow clad ");
    tnoua("tops of distant mountains gleam in the rays of the rising sun. ");
    tnoua("Isolated trees are dotted about the landscape and groups ");
    tnou("of animals can dimly be seen moving about some way off. ");
    if (values[BASE] == here)
      {
       tonl(1);
       tnou("You are at base camp, your tent stands close by. ");
       flags[HOME] = 1;
      }
    showtext();

    values[HINTPTR] = 1;  /* Hint about sleeping safely */

/*---- All set up, now for the main loop -------------------------------*/
    while (forever == 1)
      {
       memset(&lastaction[0],'\0',11);
       memset(&lastobject[0],'\0',11);
       strcat(lastaction,action);                            /* Remember the last action verb */
       strcat(lastobject,object);                            /* Remember the last object noun */

       /*---- Make sure everything is set up correctly -----------------*/
       if (flags[INTENT])
          {
           for (i=1;i<15;i++) ways[i] = 0; ways[OUT] = 1;
          }

       if (flags[AUTOHINT])
         {
          if (rnd(5) == 1 && !hintsdone[values[HINTPTR]]) hint("");  /* Maybe show the current hint   */
         }
       tonl(1);
       tnoua("> ");                                       /* Get and parse an input line */
       showtext();
       len = inpline();
       if (len == 0) continue; else i = parse();             /* Loop if input is null */

       /*---- Check the input against the dictionary ----*/
       apoint = opoint = monstpoint = 0;
/*       tpoint = 0;  */
       if (strlen(action) > 0)
         {
          for (i=1;i<MAXACT;i++)
            {
             if (strstr(dicact[i],action) != NULL) apoint = i;
             if (apoint > 0 ) break;
            }
/*          /* If action[] is an object[], reset object[] and nullify action[]                    */
/*          CODE COMMENTED OUT PRO TEM                                                            */
/*          if (strlen(object) == 0)                                                              */
/*            {                                                                                   */
/*             for (i=1;i<MAXOBJ;i++)                                                             */
/*               {                                                                                */
/*                if (strstr(thing[i],action) != NULL) tpoint = i;                                */
/*                if (tpoint > 0 ) break;                                                         */
/*               }                                                                                */
/*             if (tpoint > 0)                                                                    */
/*               {                                                                                */
/*                memset(&object[0],'\0',11); strcat(object,action); memset(&action[0],'\0',11);  */
/*               }                                                                                */
/*            }                                                                                   */
         }
       if (strlen(object) > 0)
         {
          for (i=1;i<MAXOBJ;i++)
            {
             if (strstr(thing[i],object) != NULL) opoint = i;
             if (opoint > 0 ) break;
            }
         }
       else opoint = 0;
       /* Is the object a monster? */
       if (strlen(object) > 0)
         {
          for (i=1;i<MAXMON;i++)
            {
             if (strstr(beasts[i],object) != NULL) monstpoint = i;
             if (monstpoint > 0) break;
            }
         }
       else monstpoint = 0;
       apoint = apoint % MOVMOD;
       if (apoint + opoint + monstpoint == 0)
         {
          unknown();    /* Unknown response from the player */
         }
       else
         {
          mpoint = apoint;
          if (mpoint > 0 && mpoint < 13)
            {
             move(mpoint);
             if (described == 0)
               {
                describe(mpoint);              /* Describe where we are             */
                showthings();                  /* Describe any objects found here   */
                mon_start();                   /* Activate monsters                 */
                monsters();                    /* Display active monsters           */
               }
            }
          else
            {
             if (apoint != 15 && monstr[DRAGON] > 0)
               {
                tnou("The dragon breathes a blast of fire, burning you to a frazzle! ");
                showtext();
                dead();
                continue;
               }
             switch (apoint) /*---- Execute the next command -----------------------*/
               {
                case 13 : onlamp(); break;                     /* Light lamp        */
                case 14 : take(opoint); break;                 /* Take or get       */
                case 15 : kill(monstpoint); break;             /* Kill something    */
                case 17 : look(); break;                       /* Look around you   */
                case 18 : chase(); break;                      /* Chase something   */
                case 19 : shangrila(); break;                  /* Visits Shangri La */
                case 21 : eat(opoint); break;                  /* Eat something     */
                case 22 : cheat(); break;                      /* Wizard cheats     */
                case 24 : throw(opoint); break;                /* Throw something   */
                case 25 : wave(opoint); break;                 /* Wave              */
                case 26 : stamp(monstpoint); break;            /* Stamp on a dwarf  */
                case 27 : put(apoint, opoint); break;          /* Put               */
                case 28 : put(apoint, opoint); break;          /* Drop              */
                case 29 : offlamp(); break;                    /* Extinguish lamp   */
                case 30 : rub(opoint); break;                  /* Rub               */
                case 31 : fill(opoint); break;                 /* Fill something    */
                case 32 : play(opoint); break;                 /* Play the flute    */
                case 33 : readit(opoint); break;               /* Read              */
                case 34 : find(opoint); break;                 /* Find something    */
                case 35 : magic(); break;                      /* Magic word        */
                case 36 : inventory(); break;                  /* Inventory         */
                case 37 : help(); break;                       /* Help              */
                case 38 : scores(); break;                     /* Score             */
                case 39 : quit(1); break;                      /* Quit              */
                case 40 : drink(opoint); break;                /* Drink something   */
                case 41 : openit(opoint); break;               /* Open something    */
                case 42 : closeit(opoint); break;              /* Close something   */
                case 43 : lockit(opoint); break;               /* Lock something    */
                case 44 : unlock(opoint); break;               /* Unlock something  */
                case 45 : callhim(); break;                    /* Call someone      */
                case 46 : instructions(0); break;           /* Display instructions */
                case 47 : plugh(); break;                      /* He says PLUGH     */
                case 48 : gamic(); break;                      /* Section in Gamic  */
                case 49 : slumber(); break;                    /* Sleep             */
                case 50 : timdat(z); break;                    /* Time              */
                case 51 : lookwhere("your base camp"); break;  /* Where             */
                case 52 : adventure(); break;                  /* Adventure         */
                case 53 : examine(opoint); break;              /* Examine something */
                case 54 : hint(object); break;                 /* Hint              */
                case 58 : savegame(); break;                   /* Save the game     */
                case 59 : restore(); break;                    /* Restore saved game*/
               }
            }
         }
      }
    return(0);
   }  /* End of function main()                                         */
/* =============== Utility routines ====================================*/
void describe( int mpoint)             /* Describe the current location */
   {
    int i,
        bit18;          /* Mask for tree logic */
    int ddown;          /* Mask for hole logic */
    long below;         /* Test location underneath for UP */

/*---- Variables for establishing underground move directions -----*/
   int waynum,        /* Underground way direction                 */
       waytot,        /* Number of possible directions underground */
       xnext,         /* x of possible next direction              */
       ynext,         /* y of possible next direction              */
       znext;         /* z of possible next direction              */
   int word1, word2, word3,
       word4, word5, word6;                /* Word pointers        */
   int sumxyz,                             /* x + y + z            */
       count,
       wayless;
   long there,        /* Code of possible next location            */
        bitcheck,     /* Value of waybit                           */
        moveok,       /* flag for move check                       */
        xyz,          /* x * y * z                                 */
        tenbit;       /* Bit pattern for matching                  */


    if (here == 0) /*---- First Shangri La, a special place ------------*/
      {
       tnoua("You go up the steps and through the doorway, inside is a small chamber. ");
       tnoua("A sign labelled \"To Shangri La\" points to a spiral staircase leading ");
       tnoua("to the top of the tower. As you climb the stairs all sense of time ");
       tnoua("and space vanishes like a dream. Mists arise and a dim blue light ");
       tnoua("surrounds you. Eventually you arrive at a mystic place, where everything ");
       tnoua("is pervaded by a sense of serenity and utter peace. You sit down ");
       tnou("in the lotus position and fall into a deep meditative trance. ");
       showtext();
       sleep(10);
       tonl(1);
       tnoua("At dawn the next day you awaken feeling refreshed and reinvigourated ");
       tnou("and are surprised to find yourself inside the tent at your base camp. ");
       x = values[FIRSTX]; y = values[FIRSTY]; z = 1; here = locate(x,y,z);
       flags[INTENT] = 1; flags[HOME] = 1;
       newday();                                     /* Increment the date */
       values[DAYTIME] = values[DAWN];               /* and set the time   */
       for (i=1;i<15;i++) ways[i] = 0; ways[OUT] = 1;
       score += 25;
       showtext();
       return;
      }

    switch(z)
      {
       case  0 : /*---- Up a tree --------------------------------------*/
       for (i=1;i<15;i++) ways[i] = 0;
       ways[DOWN] = 1;
       if (flags[DARK])
         {
          tnou("It is very dark, if you move about you are likely to fall. ");
          break;
         }
       if (flags[NIGHT])
         {
          tnoua("You are at the top of the tree but your lamp is not powerful ");
          tnou("enough for you to see anything except your immediate surroundings. ");
          break;
         }
       else
         {
          tnoua("From the top of the tree you can see miles in every direction. The ");
          tnoua("mountains are still a long way off and there is no chance of reaching ");
          tnoua("them before nightfall. ");
          lookwhere(" a large clearing in the forest");
          if (distance >= 3)
            {
             tnoua(" A thin spiral of smoke rises from the clearing but you are too far");
             tnou(" away to see anything else. ");
            }
          else
            {
             tnou("You can see your base camp in the clearing. ");
            }
         }
       if (flags[SEEN] && flags[CARNIV])
         {
          switch (cat)
            {
             case LEOPARD :
                tnoua(" A leopard climbs up the tree after you. You try to escape ");
                tnoua("by crawling out along a branch but it is rotten and snaps. ");
                tnou("You fall to the ground and break your neck! ");
                showtext();
                dead();
                break;
             default:
                tnoua(" The ");
                tnoua(cats[cat]);
                tnoua(" prowls by the foot of the tree without seeing you. It eventually wanders off. ");
                flags[SEEN] = 0;
                flags[CARNIV] = 0;
                score++;                  /* Small reward for avoiding cat */
                break;
            }
         }
       break;

       case  1 : /*---- At ground level --------------------------------*/
       if (!flags[NIGHT]) flags[DARK] = 0;
       for (i=1;i<15;i++) { if (i < 9) ways[i] = 1; else ways[i] = 0; }
       if (here == values[BASE] ) flags[HOME] = 1; else flags[HOME] = 0;
       flags[TREE] = 0;
       if (mpoint == 0) return;  /* Skip text */

       /*---- Special case, you can go UP to Shangri La ----------------*/
       if (x == 0 && y == 0)                     
         {
          tnoua("You are standing in a small clearing in the centre of which stands a tall tower. ");
          tnoua("A flight of steps leads up to a doorway through which shines a dim blue ");
          tnou("light, illuminating the bottom of a spiral stair case. ");
          ways[UP] = 1;
          showtext();
          return;
         }
       /*---- Special case, at your base camp --------------------------*/
       if (flags[HOME])
         {
          if (!flags[INTENT])
            {
             tonl(1);
             tnou("You are at base camp, your tent stands close by. ");
             for (i=1;i<9;i++) ways[i] = 1;
             ways[IN] = 1;
             showtext();
             return;
            }
          else
            {
             tnoua("You are in the tent, a few torn and useless clothes lie scattered ");
             tnou("about on your camp bed. ");
             for (i=1;i<15;i++) ways[i] = 0;
             ways[OUT] = 1;
             showtext();
             return;
            }
         }
       /*---- Is there a tree or hole in ground ------------------------*/
       bit18 = here & 0x12;
       if (bit18 == 18 && !flags[HOME])          /* There could be a tree here */
         {
          flags[TREE] = 1; ways[UP] = 1;
         }
       ddown = waybit[DOWN];                     /* Is there a hole here? */
       if ((here & ddown) == ddown) ways[DOWN] = 1;
       if (flags[HOME])                          /* No tree or hole at base camp */
         {
          flags[TREE] = 0; ways[UP] = 0; ways[DOWN] = 0;
         }
       if (ways[DOWN]) { flags[TREE] = 0; ways[UP] = 0; }    /* No tree by a hole */

       /*---- Establish the terrain and whether there are animals about */
       if (rnd(8) == 5) flags[ANIMAL] = 1;  /* 1 in 8 chance of seeing an animal */
       flags[HERD] = 1; if (rnd(4) == 2) flags[HERD] = 0; 
       flags[CARNIV] = rnd(5);              /* 1 in 5 chance of carnivore */
       flags[ROLING] = 0; if ((here & 72) != 72) flags[ROLING] = 1; 
       flags[HIGRAS] = 0; if ((here & 40) == 40)
         {
          flags[HIGRAS] = 1; flags[ROLING] = 0;
         }
       if (!flags[ANIMAL]) /* Set animal species if none is active at present */
         {
          cow = rnd(7);   /* Herbivore */
          cat = rnd(4);   /* Carnivore */
         }

       /*---- Everything set up, display the text ----------------------*/

       if (!flags[NIGHT]) /*---- Day, the player can see everywhere ----*/
         {
          tnoua("You are standing on the plain");
          if (flags[ROLING])
            {
             tnoua(", rolling grassland stretches to the horizon");
            }
          if (flags[HIGRAS])
            {
             tnoua(", the grass is very high here");
             if (flags[ANIMAL])
               {
                tnoua(" and you can hear large animals moving about");
                if (rnd(3) == 1)
                  {
                   tnoua(". You have the feeling that you are being ");
                   if (rnd(3) == 1) tnoua("watched"); else tnoua("tracked ");
                   tnoua(" by something large and hungry");
                  }
               }
             else
               {
                if (ways[DOWN] && flags[RABBIT] && (rnd(3) == 2))
                  {
                   tnoua(". A white rabbit scurries out of some long grass, consults his pocket-watch, exclaims ");
                   tnoua("\"Oh my ears and whiskers!\" and disappears down a nearby hole");
                   flags[RABBIT] = 0;
                  }
               }
            }
          if (flags[ANIMAL] && !flags[HIGRAS])
            {
             if (flags[HERD])
               {
                tnoua(", herds of ");
                switch(cow)
                  {
                   case ANTELOPE   : tnoua("antelope"); break;
                   case WILDEBEEST : tnoua("wildebeest"); break;
                   case ZEBRA      : tnoua("zebra"); break;
                   case GAZELLE    : tnoua("gazelles"); break;
                   case DEER       : tnoua("deer"); break;
                   case ELEPHANT   : tnoua("elephants"); break;
                   case BUFFALO    : tnoua("buffalo"); break;
                   default         : tnoua("animals"); break;
                  }
               }
             else
               {
                tnoua(", isolated ");
                switch(cow)
                  {
                   case ANTELOPE   : tnoua("antelope"); break;
                   case WILDEBEEST : tnoua("wildebeest"); break;
                   case ZEBRA      : tnoua("zebra"); break;
                   case GAZELLE    : tnoua("gazelles"); break;
                   case DEER       : tnoua("deer"); break;
                   case ELEPHANT   : tnoua("elephants"); break;
                   case BUFFALO    : tnoua("buffalo"); break;
                   default         : tnoua("animals"); break;
                  }
               }
             tnoua(" are roaming about");
            }
          tnoua(". ");
          /*---- Are there carnivores about and do they attack? -----------*/
          if (rnd(5) == 1) flags[CARNIV] = 1;                                  /* ALREADY SET - DO WE NEED THIS? */
          if (rnd(8) == 3) flags[CARNIV] = 0;
          if (flags[UNDEAD]) flags[CARNIV] = 0;      /* No cats if the player is undead */
          if (rnd(4) == 2) flags[ANIMAL] = 0;        /* All animals disappear           */
          if (flags[CARNIV])                         /* There is a carnivore here       */
            {
             if (flags[SEEN])                        /* It has seen you                 */
               {
                if (rnd(5) == 1 && flags[HIGRAS])   /* and attacks (only in high grass */
                  {
                   tnoua(" A ");
                   switch(cat)
                     {
                      case LEOPARD : tnoua("leopard"); break;
                      case TIGER   : tnoua("tiger"); break;
                      case LION    : tnoua("lion"); break;
                      case LYNX    : tnoua("lynx"); break;
                     }
                   tnoua(" leaps at you from amongst the long grass. ");
                   if (cat == LYNX || values[LUCK] > 20)
                     {
                      tnou("You avoid it adroitly and it slinks away.");
                      values[RUNOUT] = moveno;
                      values[LUCK] -= 5;
                     }
                   else
                     {
                      tnou("It gets you!");
                      showtext();
                      dead();
                      return;
                     }
                  }
               }            
             else
               {
                if (rnd(5) == 2)
                  {
                   flags[SEEN] = 1;
                   values[HINTPTR] = 2;  /* Hint about carnivore attacks */
                   tnoua("A ");
                   switch(cat)
                     {
                      case LEOPARD : tnoua("leopard"); break;
                      case TIGER   : tnoua("tiger"); break;
                      case LION    : tnoua("lion"); break;
                      case LYNX    : tnoua("lynx"); break;
                     }
                   tnoua(" eyes you hungrily from some long grass.");
                  }
               }
            }
          if (flags[TREE])
            {
             tnoua(" There is a tall tree standing nearby. ");
             if (rnd(5) == 3 && flags[SHANGRI] == 0)
               {
                tnou("A notice pinned to the trunk reads: ");
                tnou("\tFor a once in a lifetime experience visit Shangri La! ");
                tnou("\t[For details call Shangri Enterprises] ");
               }
            }
          if (ways[DOWN])
            {
             below = locate(x,y,z+1); flags[NOTUP] = 1; 
             if ((below & waybit[UP]) == waybit[UP]) flags[NOTUP] = 0; /* He can get out again */
             tnoua(" There is a deep hole at your feet");
             if (flags[NOTUP])
               {
                tnoua(", if you go down it you won't be able to get back up");
               }
             tnoua(". ");
            }
          tonl(1);
          if ((values[DUSK] - values[DAYTIME]) == 1) tnou("The sun is getting low.");
          if (values[DAYTIME] == values[DUSK]) tnou("The sun is sinking in the west.");
         }
       else  /*---- Night, can only see if the lamp is lit -------------*/
         {
          if ((values[DAYTIME] - values[DUSK]) == 1) tnoua("The sun has just set, it is night! ");
          if (!flags[DARK]) /*---- Night but not dark ------------------*/
            {
             tnoua("You are standing on the plain. It is night and you can see nothing beyond ");
             tnou("the small area illuminated by the rays of your lamp. ");
            }
          else /*---- Night and dark - bad news! -----------------------*/
            {
             if (ways[DOWN])                /* Kill the player */
               {
                tnou("Stumbling about the plain in the dark, you have fallen into a deep hole and broken your neck! ");
                showtext();
                dead();
                return;
               } 
             else
               {
                tnoua("You are standing on the plain. It is very dark, if you move ");
                tnou("about you are likely to fall into a pit.");
               }
            }
         }

       if (moveno > 0 && values[DAYTIME] == values[DAWN]) tnou("The sun is rising in the east.");
       break;

       default : /*---- Underground ------------------------------------*/
       /* Calculate the the possible move directions */
       waynum = 0; waytot = 0;
       for (i=1;i<15;i++) ways[i] = 0;  /* First unset all directions */
       for (i=1;i<11;i++)
         {
          xnext = x + xinc[i]; ynext = y + yinc[i]; znext = z + zinc[i];
          there = locate(xnext,ynext,znext);
          bitcheck = waybit[i];
          moveok = here & there & bitcheck;
          if (moveok == bitcheck)
            {
             ways[i] = 1; waytot++;
             if (i < 9) waynum++;
            }
         }
       if (waytot == 0)
         {
          tnoua("You were warned, there is no way out! ");
          tnoua("You are trapped and scrabble desperately at the walls but ");
          tnoua("there is no escape! The air becomes progressively stuffy and ");
          tnou("you begin to gasp for breath . . .");
          sleep(5);
          tnou(". eventually the air runs out and you are finished. ");
          showtext();
          dead();
          return;
         }
       /*---- Calculate the word pointers and display the location ----*/
       if (ways[DOWN] && flags[DARK])
         {
          tnou("Stumbling around in the dark you have fallen down a deep hole and broken your neck! ");
          showtext();
          dead();
          return;
         }
       if (flags[DARK])
         {
          tnou("It is pitch dark and you can't see a thing, if you move you are likely to fall into a pit! ");
          showtext();
          return;
         }
       if ((here % 200) <= 10) flags[DRIP] = 1;  /* Water drips */
       xyz = x * y * z;
       tenbit = xyz & 1023;
       word2 = (int)sqrt(tenbit/4) + 1;
       word3 = (int)sqrt(tenbit/8) + 1;
       word4 = (int)sqrt((xyz & 255)) + 1;
       flags[SMALL] = flags[LARGE] = flags[SWITCH] = 0;

       if ((here & 512) == 512) flags[SWITCH] = 1;
       if (word2 ==  5) flags[SMALL] = 1;
       if (word2 ==  7) flags[SMALL] = 1;
       if (word2 ==  9) flags[SMALL] = 1;
       if (word2 == 11) flags[SMALL] = 1;
       if (word2 == 13) flags[SMALL] = 1;
       if (word2 == 15) flags[SMALL] = 1;
       if (word2 ==  6) flags[LARGE] = 1;
       if (word2 ==  8) flags[LARGE] = 1;
       if (word2 == 10) flags[LARGE] = 1;
       if (word2 == 12) flags[LARGE] = 1;
       if (word2 == 14) flags[LARGE] = 1;
       if (word2 == 16) flags[LARGE] = 1;

       word1 = 1;  /* Default value of word1 */
       flags[SHAFT] = 0;
       if (ways[UP] && ways[DOWN]) flags[SHAFT] = 1;    /* In a shaft */
       if (flags[SHAFT])
         {
          word2 = (tenbit % 6) + 11;
          word4 = 17;
          if (flags[SWITCH]) word4 = 18;
          tnoua("You are climbing ");
          tnoua(adject1[word2]);
          tnoua(" ");
          tnoua(nouns[word4]);
          if (flags[SWITCH])
            {
             tnoua(". Stairs ");
            }
          else
            {
             tnoua(". Steps ");
            }
          if (flags[SMALL])
            {
             tnoua("go ");
            }
          else
            {
             tnoua("lead ");
            }
          tnoua("up and down from here. ");
         }

       if (word4 < 5) /* Cells */
         {
          if (flags[SMALL] && flags[SWITCH]) word1 = 2;
          if (flags[SMALL] && !flags[SWITCH]) word1 = 5;
         }

       if (word4 == 9 || word4 == 11 || word4 == 13 || word4 == 15) /* Passages */
         {
          word1 = 3;
          if (waytot < 2) word4 = word4 + 1;
          if (flags[SMALL] && flags[SWITCH]) word1 = 5;
          if (flags[SMALL] && !flags[SWITCH]) word1 = 6;
          if (flags[LARGE] && flags[SWITCH]) word1 = 4;
         }

       if (word4 == 12 || word4 == 14 || word4 == 16) /* Rooms */
         {
          if (flags[SMALL] && flags[SWITCH]) word1 = 5;
          if (flags[LARGE] && flags[SWITCH]) word1 = 3;
         }

       if (word4 == 5) if (flags[SMALL]) word1 = 2; /* Alcove */

       /* Caves */
       if (flags[SMALL] && flags[SWITCH]) word1 = 2;
       if (flags[SMALL] && !flags[SWITCH]) word1 = 6;
       if (flags[LARGE] && flags[SWITCH]) word1 = 3;

       sumxyz = x + y + z;
       if ((sumxyz % 100) <= 10) flags[GLOW] = 1;
       if (flags[SHAFT]) flags[GLOW] = 0;          /* No glow in shafts */
       flags[WAVER] = (flags[GLOW] && (flags[WAVER] || (rnd(4) == 2)));
       flags[DARK] = 1;
       if (flags[GLOW] || flags[LAMPON]) flags[DARK] = 0;
       if (flags[UNDEAD]) flags[DARK] = 0;                 /* The undead can always see! */
       if (flags[GLOW]) tnoua("The whole scene is bathed in an eerie");
       if (flags[WAVER]) tnoua(", wavering");
       if (flags[GLOW]) tnoua(" glow. ");

       if (!flags[SHAFT])
         {
          tnoua("You are ");
          tnoua(verbs[word1]);
          tnoua(" ");
          tnoua(adject1[word2]);
          tnoua(adject2[word3]);
          tnoua(" ");
          tnoua(nouns[word4]);
          tnoua(". ");
         }
       /*---- Now calculate and display where you can go next. On the level first, stairs later. ----*/
       count = 0;
       for (i=1;i<9;i++)
         {
          if (ways[i])
            {
             count++;
             xnext = abs(x + xinc[i]); ynext = abs(y + yinc[i]); znext = abs(z + zinc[i]);
             there = locate(xnext,ynext,znext);
             xyz = xnext * ynext * znext;
             tenbit = (xyz & 1023);
             word5 = (int)sqrt(tenbit/4) + 1;
             word6 = (int)sqrt(xyz & 255) + 1;
             if (count == 1) tnoua("There is ");
             tnoua(adject1[word5]);

             tnoua(" ");
             tnoua(nouns[word6]);
             tnoua(" to the ");
             tnoua(routes[i]);
             if (count == waynum) break;
               {
                wayless = waynum - 1;
                if (count < wayless) tnoua(", ");
                if (count == wayless) tnoua (" and ");
               }
            }
         }
       if (count > 0) tnoua(". ");
       if (!flags[SHAFT])  /* If in a shaft the text has already been displayed */
         {
          if (ways[UP] || ways[DOWN])
            {
             if (!flags[SMALL] && !flags[LARGE])
               {
                tnoua("A steep ladder");
                flags[SWITCH] = 1;
               }
             if (flags[SMALL] || flags[LARGE])
               {
                if (flags[SMALL] && flags[SWITCH])  tnoua("A winding stair");
                if (flags[SMALL] && !flags[SWITCH]) tnoua("Rickety steps");
                if (flags[LARGE] && flags[SWITCH])  tnoua("A spiral stair");
                if (flags[LARGE] && !flags[SWITCH]) tnoua("Broad stairs");
                if (flags[SWITCH] && (xyz & 1024 == 1024)) tnoua("case");
               }
             if ((tenbit & 256) == 256) flags[LEAD] = 1; else flags[LEAD] = 0;
             if (flags[LEAD])
                {
                 tnoua(" lead");
                }
             else
                {
                 tnoua(" disappear");
                }
             if (flags[SWITCH]) tnoua("s ");
             if (ways[UP]) tnoua(" up");
             if (ways[DOWN]) tnoua(" down");
             if ((xyz & 2048) == 2048) tnoua("wards");
             tnoua(". ");
            }
         }
       if (!flags[DARK])
         {
          if (flags[DRIP])
            {
             values[POOL] = x % 3;
             if (flags[SHAFT]) values[POOL] = 0;
             tnoua("Water drips from above");
             switch (values[POOL])
               {
                case 0 : tnoua(". "); break;
                case 1 : tnoua(", disappearing into small fissures in the floor. "); break;
                case 2 : tnoua(", collecting in a small pool at your feet. "); break;
               }
            }
         }
       break;
      }
    if (values[BRKBOT] == here || values[BRKVAS] == here ||values[BRKGOB] == here ||values[BRKMIR] == here)
      {
       tnou("The ground is littered with tiny fragments of glass. ");
      }
    if (flags[LAMPON])                 /* Is the lamp nearly exhausted? */
      {
       if (values[LIGHT] < 20 && (values[LIGHT] % 4) == 3)
         {
          tonl(1);
          tnoua("Your lamp is getting dim. ");
         }
       if (values[LIGHT] < 1)
         {
          tonl(1);
          tnoua("Your lamp flickers and goes out! ");
          flags[LAMPON] = 0;
          values[FLICK]++;
         }
      }
    if (z > 1)
      {
       if ((here % 50) == 23 && rnd(3) == 1)
         {
          tonl(1);
          tnou("A hollow voice says \"Plugh!\"");
         }
      }
    if (values[THIRST] > 50)
      {
       values[HINTPTR] = 3;   /* Hint about the connection between thirst and luck */
       if (rnd(6) == 4)
         {
          tonl(1);
          tnoua("You feel very thirsty");
          values[LUCK]--;
          if (rnd(2) == 1) tnoua(", maybe a little drink will bring you luck");
          tnou(". ");
         }
      }
    showtext();                       /* Display the text             */
    described = 1;
   }
/*----------------------------------------------------------------------*/
int inpline(void)                      /* Get a line of input           */
   {
    int i,len;
    fgets(inbuff,80,stdin);
    if (LOGGING) fprintf(log_file,"%s",inbuff);
    len = strlen(inbuff);
    for (i=0;i<len;i++) memset(&inbuff[i],toupper(inbuff[i]),1); /* Convert to uppercase */
    memset(&inbuff[len-1],'\0',1);                               /* Strip newline char   */
    return(len);
   }
/*----------------------------------------------------------------------*/
void initialise(void)
   {
    int i;
    score = 0;
    pseudorand = 1;
    helpno = 0;               /* Help system not used yet */
    values[THIRST] =  0;      /* Not thirsty yet */
    values[BRKBOT] = -1;      /* Location of smashed bottle */
    values[BRKVAS] = -1;      /* Location of smashed vase */
    values[BRKGOB] = -1;      /* Location of smashed goblet */
    values[BRKMIR] = -1;      /* Location of smashed mirror */
    values[DWFNOW] =  0;      /* No dwarves active yet */
    values[GORLOC] = -1;      /* Gorgon has no location yet */
    values[SEED]   = -1;      /* Initialise for use as flag first */
    values[FLICK]  =  0;      /* Lamp not flickering yet */
    values[RNDCOUNT] = 0;     /* No calls to rnd(n) yet */

    flags[WIZARD]    = 0;   /* The player is not a wizard              */
    flags[COPRNT]    = 0;   /* ? not used ?                            */
    flags[FR13]      = 0;   /* It is not Friday 13th                   */
    flags[HALLOW]    = 0;   /* It is not Halloween                     */
    flags[LIFE]      = 1;   /* ? not used ?                            */
    flags[HOME]      = 0;   /* The player is not at base camp          */
    flags[DARK]      = 0;   /* It is not dark                          */
    flags[NIGHT]     = 0;   /* It is not night                         */
    flags[LAMPON]    = 0;   /* The lamp is not on                      */
    flags[INTENT]    = 0;   /* The player is not in his tent           */
    flags[HIGRAS]    = 0;   /* The grass on the plain is not high      */
    flags[ANIMAL]    = 0;   /* There are no animals in view            */
    flags[HERD]      = 1;   /* The herbivores are in a herd            */
    flags[CARNIV]    = 0;   /* The carnivores are not active yet       */
    flags[SEEN]      = 0;   /* The carnivores have not seen the player */
    flags[BOXLOK]    = 1;   /* Pandora's box is locked                 */
    flags[DORLOK]    = 1;   /* The door is locked                      */
    flags[UNDEAD]    = 0;   /* The player is not yet a vampire         */
    flags[GENIE]     = 0;   /* The genie is still in the bottle        */
    flags[ELIXIR]    = 0;   /* The elixir of life has not been drunk   */
    flags[EMPTY]     = 1;   /* The water bottle is empty               */
    flags[GLOW]      = 0;   /* There is no glow in the caves           */
    flags[WAVER]     = 0;   /* The glow is not wavering                */
    flags[SHAFT]     = 0;   /* The player is not in a shaft            */
    flags[HANDSFULL] = 0;   /* The player's hands are not full         */
    flags[AUTOHINT]  = -1;  /* Set for first (free) hint               */
    flags[RABBIT]    = 1;   /* The white rabbit has not been seen yet  */
    flags[EXCALIBER] = 1;   /* The first sword picked up is Excaliber  */
    flags[RINGON]    = 0;   /* The player is not wearing the ring      */
    flags[SHANGRI]   = 0;   /* Shangri La not visited yet in this life */
    flags[OVERDRAWN] = 0;   /* Account is overdrawn (score < 0)        */

    for (i=1;i<MAXOBJ;i++)
      {    
       secure[i] = 0;       /* There are no objects in the tent, */
       gone[i] = 0;         /* none have been destroyed          */
       obhere[i] = 0;       /* and the player is holding none    */
      }
    /* The initial state of each monster is -1, this is exchanged for a */
    /* positive value when the monster is activated                     */
    for (i=1;i<MAXMON;i++) monstr[i] = -1;

    /* Each hint can only be shown once */
    for (i=0;i<MAXHINT;i++) hintsdone[i] = 0;
   }
/*----------------------------------------------------------------------*/
int instructions(int i)  /*  User instructions */
   {
    tonl(1);
    tnoua("Use simple commands with one or two words to direct me. Thus,  NORTH or GO ");
    tnoua("NORTH or N will move you to the North, assuming that you can go that way. ");
    tnoua("Similarly, GET or TAKE OBJECT will enable you to pick up an OBJECT ");
    tnoua("if it can be carried, provided that you have the strength to lift it. ");
    tnoua("Some other useful commands are INVENTORY, SCORE, TIME, QUIT, LOOK, ");
    tnoua("and WHERE. Most, but not all, commands can be abbreviated but don't ");
    tnoua("overdo this as the results can be unpredictable. Using the first four ");
    tnoua("letters is usually safe enough. The main directions are exceptions to ");
    tnou("the general rule and may be abbreviated to N, S, SE, SW, etc.");
    tonl(1);
    tnoua("Try to get all the treasure you find into the tent at your base camp, but ");
    tnou("be careful, there may be some nasty surprises for you. ");
    tonl(1);
    tnou("See how quickly you can become a Supreme Champion, there is no maximum score. ");
    tonl(1);
    tnou("Good luck, you'll need it!!!");
    if(i == 1)
      {
       i = 0;
       tonl(1);
       tnoua("n.b. Commands are not case sensitive and may be typed in");
       tnou("UPPER, lower or MiXeD case.");
       tonl(1);
      }
     showtext();
     return(i);
    }
/*----------------------------------------------------------------------*/
long locate(int xx, int yy, int zz)         /* Calculate location       */
/* Calculates a location code from the X,Y and Z co-ordinates           */
   {
    long xyz;
    xyz = (xx * yy * zz + xx* 17 + yy * 19 + zz * 23);
    return(xyz);
   }
/*----------------------------------------------------------------------*/
void locwun(void)    /* Initialise object locations                     */

/* The initial positions of object will be different in each of the 11  */
/* games. The first 10 objects are distributed about on the plain, the  */
/* probability of finding any one of them in any location is about 20:1 */
/* The remaining objects are distributed underground at a probability   */
/* of about 60:1
/* Objects (except the plant) are virtual and exist in many locations   */
/* until picked up. The more plants can be encountered after the player */
/* has picked them up - some are poisonous, some are not.               */

/* The array objloc[] contains negative values for virtual objects,     */
/* once objects become unique objloc[] holds either their location or   */
/* 0 if they are held by the player                                     */
/* Destroyed objects are in objloc[] = -2000                            */

   {
    /*---- The first ten (utility) objects are placed on the plain ----*/
    int i,a,b,c,p;
    for (i=1;i<11;i++) objloc[i] = i - 15; /* range -5 to -14 */
    for (i=0;i<100;i++)                    /* Now scramble them */
       {
        a = rnd(10); b = rnd(10);
        c = objloc[a]; objloc[a] = objloc[b]; objloc[b] = c;
       }
    /*---- The rest are placed underground ----*/
    for (i=11;i<MAXOBJ;i++) objloc[i] = i - 66; /* range -54 to MAXOBJ-66 */

    p = MAXOBJ - 11;
    for (i=0;i<20;i++)     /* Scramble some of these (about 20) */
      {
       a = rnd(p) + 10; b = rnd(p) + 10;
        c = objloc[a]; objloc[a] = objloc[b]; objloc[b] = c;
      }

    for (i=1;i<MAXOBJ;i++)  /* Ensure that objloc[x] is not zero */
      {
       if (objloc[i] == 0) objloc[i] = -rnd(20);
      }

/*    Special objects which do not exist yet  */
      objloc[DIAMOND]    = -2000;   /*  Diamond  */
      objloc[BRICKBATS]  = -2000;   /*  Brickbats  */
      objloc[GNOME]      = -2000;   /*  Gnome  */
      objloc[SERPENTINE] = -2000;   /*  Serpentine  */
      objloc[VENUS]      = -2000;   /*  Venus-de-Milo  */
   }
/*----------------------------------------------------------------------*/
void mon_start(void)                               /* Activate monsters */
/* Inactive monsters have negative values for monstr[]                  */
/* Active monsters have positive values for monstr[], in general the    */
/* higher the value the more dangerous the monster has become.          */
/* Dead monsters have monstr[] = 0                                      */
   {
    int i, mflag = 0;
                                         /* Do any start now?                 */
    if (flags[UNDEAD]) return;           /* An undead player sees no monsters */
    if (z < 2) return;                   /* No monsters start above ground    */
    if (flags[DARK]) return;             /* or in the dark                    */
    if (values[MONCOUNT] > 3) return;    /* Not more than three at any time   */
    for (i=1;i<MAXMON;i++)
      {
       switch (i)
         {
          case BATS    :
             if (monstr[BATS] > 0) break;     /* Already active         */
             if (flags[SMALL] == 0) break;    /* Not in small places    */
             if (flags[GLOW] == 0) break;     /* or with glowing lights */
             if (rnd(20) == 7)
               {
                monstr[BATS] = abs(monstr[BATS]);
                mflag++;
               }
             break;
          case DWARF   :
             if (values[DWFNUM] == 0) break; /* No dwarves left */
             if (rnd(20) == 9)
               {
                monstr[DWARF] = abs(monstr[DWARF]);
                mflag++;
               }
             break;
          case SNAKE   :
             if (monstr[SNAKE] > 0) break;     /* Already active */
             if (rnd(50) == 42)
               {
                monstr[SNAKE] = abs(monstr[SNAKE]);
                mflag++;
               }
             break;
          case GORGON  :
             if (monstr[GORGON] == 0) break;  /* The gorgon is dead */
             if (flags[LARGE] == 1) break;    /* Not here */
             if (values[GORLOC] > 0) break;   /* Got location already */
             if ((here % 100) == 87)
               {
                values[GORLOC] = here;
                monstr[GORGON] = abs(monstr[GORGON]);
                mflag++;
               }
             break;
          case ELF     :
             if (monstr[ELF] > 0) break;     /* Already active */
             if (rnd(20) == 7)
               {
                monstr[ELF] = abs(monstr[ELF]);
                mflag++;
               }
             break;
          case TROLL   :
             if (monstr[TROLL] > 0) break;     /* Already active          */
             if (flags[GLOW] == 0) break;      /* Not with glowing lights */
             if (rnd(40) == 23)
               {
                monstr[TROLL] = abs(monstr[TROLL]);
                mflag++;
               }
             break;
          case DRAGON  :
             if (monstr[DRAGON] > 0) break;     /* Already active      */
             if (flags[LARGE] == 0) break;      /* Place must be large */
             if (monstr[DRAGON] == 1 && rnd(3)!= 1)
               {
                monstr[DRAGON] = -1;  /* Gives 1/30 chance of first encounter */
               }
             if (rnd(10) == 6)
               {
                monstr[DRAGON] = abs(monstr[DRAGON]);
                mflag++;
               }
             break;
          case VAMPIRE :
             if (monstr[VAMPIRE] > 0) break;     /* Already active       */
             if (flags[NIGHT] == 0) break;       /* Only active at night */
             if (rnd(50) == 23)
               {
                monstr[VAMPIRE] = abs(monstr[VAMPIRE]);
                mflag++;
               }
             break;
          default      : 
             break;
         }
       if (mflag > 0) break;
      }
    if (mflag > 0) values[MONCOUNT]++;
   }
/*----------------------------------------------------------------------*/
void monsters(void)                     /* Display active monsters      */
   {
    int monsterpoint, i;

    for (monsterpoint=1;monsterpoint<MAXMON;monsterpoint++)
      {
       switch (monsterpoint)
         {
          case BATS :
            {
             if (monstr[BATS] <= 0) break;            /* The bats are not active */
             if (monstr[VAMPIRE] > 0) break;          /* and avoid the vampire   */
             if (monstr[DRAGON] > 0) break;           /* and the dragon          */
             if (flags[NIGHT] == 0) break;            /* The bats are nocturnal  */
             if (z < 2) break;
             tonl(1);
             switch (monstr[BATS])
               {
                case 1 :
                   tnou("You have disturbed hundreds of roosting bats, they wheel and swoop around you. ");
                   break;
                case 2 :
                   tnou("Hundreds of large bats are flying about. ");
                   break;
                case 3 :
                   tnou("A cloud of bats sweeps past you and disappears into the darkness. ");
                   break;
               }
             monstr[BATS] = -rnd(3);
             values[MONCOUNT]--;
            }
          break;
          case ELF :
            {
             if (monstr[ELF] <= 0) break;
             if (z > 1)                     /* Elf only active underground      */
               {
                tonl(1);
                if (monstr[ELF] == 1)
                  {
                   tnou("A slender elf strolls past as if looking for something and disappears round a corner. ");
                  }
                else
                  {
                   int objptr = 0;
                   for (i=1;i<MAXOBJ;i++) { if (obhere[i] == 1) { objptr = i; break; } }
                   if (objptr == 0)
                     {
                      tnou("The elf appears, looks about and seeing nothing to interest him wanders off. ");
                     }
                   else
                     {
                      int posloc;
                      tnoua("The elf appears, says \"Ha, just what I wanted!\" and runs out, taking the ");
                      tnoulca(thing[objptr]);
                      tnou(" with him.");
                      obhere[objptr] = 0;
                      posloc = rnd(60);
                      if ((here % 60) == posloc) posloc++;  /* Make sure it isn't put down here */
                      objloc[objptr] = -posloc;
                     }
                  }
                monstr[ELF] = -2;
                values[MONCOUNT]--;
               }
            }
          break;
          case GORGON :
            {
             if (monstr[GORGON] <= 0) break;           /* Gorgon is not active */
             if (values[GORLOC] != here) break;        /* Gorgon is not here   */
             tonl(1);
             switch (monstr[GORGON])
               {
                case 1 :
                   tnoua("A sleeping woman lies chained to a rock, her hair is a seething mass ");
                   tnoua("of snakes. She stirs, awakens and slowly turns towards you. ");
                   monstr[GORGON] = 2;
                   break;
                default :
                   if (monstr[BATS] > 0)
                     {
                      tnoua("The gorgon glares at the bats wheeling overhead, they instantly ");
                      tnoua("fall to the ground as a shower of brickbats. ");
                      monstr[BATS] = 0;
                      objloc[BRICKBATS] = here;
                      secure[BRICKBATS] = 0;
                      gone[BRICKBATS] = 0;
                      values[MONCOUNT]--;
                      break;
                     }
                   if (monstr[DWARF] > 0)
                     {
                      if (values[DWFNOW] == 1)
                        {
                         tnoua("The gorgon glares at the dwarf");
                        }
                      else
                        {
                         tnoua("The gorgon glares at one of the dwarves");
                        }
                      tnoua(", turning it into a pottery gnome. ");
                      values[DWFNOW]--;
                      monstr[DWARF]--;
                      values[MONCOUNT]--;
                      objloc[GNOME] = here;
                      secure[GNOME] = 0;
                      gone[GNOME] = 0;
                      break;
                     }
                   if (monstr[SNAKE] > 0)
                     {
                      tnoua("The gorgon stares hard at the snake, which slowly turns into a block of serpentine. ");
                      monstr[SNAKE] = 0;
                      objloc[SERPENTINE] = here;
                      secure[SERPENTINE] = 0;
                      gone[SERPENTINE] = 0;
                      values[MONCOUNT]--;
                      break;
                     }
                   if (objloc[MIRROR] == 0)
                     {
                      tnoua("The gorgon catches her own gaze in the mirror and is instantly transformed ");
                      tnoua("into a statue of the Venus de Milo! ");
                      values[GORLOC] = -1;
                      monstr[GORGON] = 0;
                      score +=100;
                      objloc[VENUS] = here;
                      secure[VENUS] = 0;
                      gone[VENUS] = 0;
                      values[MONCOUNT]--;
                      break;
                     }
                   tnoua("The gorgon glares at you and you are immediately turned into stone!! ");
                   showtext();
                   dead();
                   return;
               }             
            }
          break;
          case SNAKE :
            {
             if (monstr[SNAKE] <= 0) break;           /* Snake is not active    */
             if (monstr[VAMPIRE] > 0) break;          /* and avoids the vampire */
             if (monstr[DRAGON] > 0) break;           /* and the dragon         */
             tonl(1);
             switch(monstr[SNAKE])
               {
                case 1 :
                   tnoua("An enormous snake appears and hisses angrily at you. ");
                   break;
                case 2 :
                   tnoua("You are being followed by a large green snake. ");
                   break;
                case 3 :
                   tnoua("The snake is getting close and is trying to hypnotise you, I don't give ");
                   tnoua("much for your chances if it succeeds. ");
                   break;
                case 4 :
                   tnoua("The snake strikes at you but you leap back just in time. ");
                   break;
                default :
                   tnoua("The snake suddenly strikes at you, you spring back but two small marks ");
                   tnoua("on your arm show where its poison was injected. ");
                   if (objloc[CHARM] == 0)
                     {
                      tnoua("By good luck there seem to be no ill effects - this time!");
                      if (!flags[ELIXIR]) values[LUCK] -= 10;
                      monstr[SNAKE] = -2;
                     }
                   else
                     {
                      sleep(5);
                      tonl(1);
                      tnoua("Your arm swells up and goes black, you feel muzzy from the effects of the poison!! ");
                      sleep(5);
                      if (flags[ELIXIR])
                        {
                         tonl(1);
                         tnoua("After a while your head clears and within a few minutes the swelling has ");
                         tnoua("gone down and your arm is as good as new. Meanwhile, the snake has disappeared. ");
                         monstr[SNAKE] = -2;
                         break;
                        }
                      else
                        {
                         showtext();
                         dead();
                         return;
                        }
                     }
                   break;
               }
             monstr[SNAKE] += rnd(2);
             if (rnd(5) == 3) monstr[SNAKE] = -rnd(4);
             if (monstr[SNAKE] < 0) values[MONCOUNT]--;
            }
          break;
          case DWARF :
            {
             if (monstr[DWARF] <= 0) break;           /* Dwarves are not active */
             if (monstr[VAMPIRE] > 0) break;          /* and avoid the vampire  */
             if (monstr[DRAGON] > 0) break;           /* and the dragon         */
             if (z < 2) break;                        /* Only seen underground  */
             tonl(1);
             if (rnd(4) == 3) values[DWFNOW]++;
             if (rnd(5) == 1) values[DWFNOW]--;
             if (values[DWFNOW] > values[DWFNUM]) values[DWFNOW] = values[DWFNUM]; /* Can't exceed total population */
             if (values[DWFNOW] > 5) values[DWFNOW] = 5;                           /* No more than 5 at a time      */
             if (values[DWFNOW] == 0) break;
             if (values[DWFNOW] == 1)
               {
                switch(monstr[DWARF])
                  {
                   case 1 :
                      tnoua("There is an angry little dwarf in here with you. ");
                      break;
                   case 2 :
                      tnoua("The little dwarf is furious. ");
                      break;
                   default :
                      tnoua("The infuriated dwarf shoots a tiny dart ");
                      if (rnd(3) == 2)
                        {
                         tnoua("at you but misses. ");
                        }
                      else
                        {
                         tnoua("which hits you and smarts painfully for a while. ");
                         values[LUCK]--;
                         if (values[LUCK] < 15) lucky();
                        }
                      break;
                  }
               }
             else
               {
                switch(monstr[DWARF])
                  {
                   case 1 :
                      tnoua("There are ");
                      tnoua(numerals[values[DWFNOW]]);
                      tnoua(" angry little dwarves in here with you. ");
                      break;
                   case 2 :
                      tnoua("The dwarves are furious. ");
                      break;
                   default :
                      tnoua("The infuriated dwarves fire a hail of tiny darts, some of them hit ");
                      tnoua("you and smart painfully like wasp stings.");
                      values[LUCK] -= values[DWFNOW];
                      if (values[LUCK] < 15) lucky();
                      break;
                  }
               }
             if (rnd(3) == 2) monstr[DWARF]++;
             if (rnd(5) == 1) monstr[DWARF] = -1;
             if (monstr[DWARF] < 0) values[MONCOUNT]--;
            }
          break;
          case TROLL :
            {
             if (monstr[TROLL] <= 0) break;
             tonl(1);
             if (z < 2 && flags[NIGHT] == 0)
               {
                tnoua("The sunlight catches the troll, it gives a piercing scream and tumbles ");
                tnoua("to the ground as an inert lump of rock. ");
                monstr[TROLL] = 0;
                values[MONCOUNT]--;
                score += 50;
                break;
               }
             switch (monstr[TROLL])
               {
                case 1 :
                   tnoua("A large troll steps out of the shadows and lumbers menacingly after you. ");
                   break;
                case 2 :
                   tnoua("The troll lumbers after you. ");
                   break;
                case 3 :
                   tnoua("The troll tries to corner you, but you manage to avoid him. ");
                   break;
                default :
                   if (monstr[DWARF] > 0)
                     {
                      tnoua("The troll lumbers towards you, you try to dodge but trip over a little dwarf. ");
                      tnoua("The troll stamps both of you to death! ");
                     }
                   else
                     {
                      tnoua("The troll corners you, you try to escape but cannot squeeze past him. ");
                      tnoua("Slowly he crushes you to a pulp! ");
                     }
                   showtext();
                   dead();
                   return;
               }
             if (rnd(2) == 2) monstr[TROLL]++;
             if (rnd(3) == 2) monstr[TROLL] = 2;
             if (rnd(15) == 6) monstr[TROLL] = 1;
             if (rnd(6) == 4) monstr[TROLL] = -monstr[TROLL];
             if (monstr[TROLL] < 0) values[MONCOUNT]--;
            }
          break;
          case DRAGON :
            {
             int randno;
             if (monstr[DRAGON] <= 0) break;
             randno = rnd(2) + 1;       /*  Range 2 - 3 */
             if (z < 2) monstr[DRAGON] = -randno;              /* Dragon is only active underground */
             if (flags[LARGE] == 0) monstr[DRAGON] = -randno;  /* Only active if location is large  */
             if (flags[SHAFT] == 1) monstr[DRAGON] = -randno;  /* Not active in shafts              */
             if (monstr[DRAGON] < 0)
               {
                values[MONCOUNT]--;
               }
             else                   /* OK - we have a dragon problem here */
               {
                tonl(1);
                switch (monstr[DRAGON])
                  {
                   case 1 :
                      tnoua("A huge dragon lies before you. Feeling your presence it heaves itself to ");
                      tnou("its feet and prepares to attack. ");
                      break;
                   case 2 :
                      tnoua("The dragon confronts you breathing fire and smoke. You had better get out of here fast! ");
                      break;
                   case 3 :
                      tnoua("The dragon thunders after you! ");
                      break;
                   case 4 :
                      tnoua("The dragon breathes a blast of fire");
                      randno = rnd(4);
                      switch (randno)
                        {
                         case 1 :
                            tnou(" which burns you to a cinder!");
                            break;
                         case 2 :
                            tnou(", you leap aside but are laid low by its lashing tail. It devours you in an instant!");
                            break;
                         default :
                            tnou(", you dodge just in time.");
                            break;
                        }
                      if (randno < 3)
                        {
                         showtext();
                         dead();
                         return;
                        }
                      break;
                  }
                showtext();
                monstr[DRAGON] = rnd(2) + 2;
               }
            }
          break;
          case VAMPIRE :
            {
             int vampiredead = 0;
             int vampiregetsyou = 0;
             if (monstr[VAMPIRE] <= 0) break;
             if (flags[NIGHT] == 0)
               {
                monstr[VAMPIRE] = -abs(monstr[VAMPIRE]);
                values[MONCOUNT]--;
               }
             tonl(1);
             switch(monstr[VAMPIRE])
               {
                case 1 :
                   tnou("A cadaverous man with red eyes sidles up behind you. ");
                   monstr[VAMPIRE] = 2;
                   break;
                case 2 :
                   tnou("The red-eyed man is close behind you. ");
                   if (rnd(4) == 2) monstr[VAMPIRE] = 3;
                   break;
                case 3 :
                   tnoua("You turn to confront your follower, his red eyes gaze into yours and your ");
                   tnou("head swims. With a great effort of will you recover your senses. ");
                   monstr[VAMPIRE] = 5 - rnd(3);
                case 4 :
                   tnoua("The cadaverous man leaps from behind and tries to bite your throat");
                   if (gone[GARLIC] == 1)
                     {
                      vampiredead = 1;
                      break;
                     }
                   else
                     {
                      if (rnd(3) == 2)
                        {
                         vampiregetsyou = 1;
                        }
                      else
                        {
                         tnou(", you break free just in time. ");
                         if (rnd(3) == 1) monstr[VAMPIRE] = 5;
                        }
                     }
                   break;
                case 5 :
                   tnoua("The corpse-like man has disappeared but a large bat hovers nearby. ");
                   if (rnd(4) == 2) monstr[VAMPIRE] = 6;
                   break;
                case 6 :
                   tnoua("A large bat swoops down ");
                   if (gone[GARLIC] == 1)
                     {
                      vampiredead = 1;
                      break;
                     }
                   else
                     {
                      int k = rnd(3);
                      switch (k)
                        {
                         case 1 :
                            tnou(", you break free just in time. ");
                            break;
                         case 2 :
                            tnoua(" and bites your throat. ");
                            break;
                         case 3 :
                            monstr[VAMPIRE] = 4 + rnd(2);
                            break;
                        }
                     }
                   break;
               }
             if (vampiredead == 1)
                {
                 tnoua(" but is repelled by the smell of your breath and vanishes in a cloud of dust ");
                 tnou("specks which dance before your eyes and slowly disappear. ");
                 monstr[VAMPIRE] = 0;
                 score += 50;
                 values[MONCOUNT]--;
                }
             if (vampiregetsyou == 1)
                {
                 tnoua(". Cold talons grasp you and you feel his sweet, foul breath as he draws the life-blood ");
                 tnoua("from you. ");
                 showtext();
                 sleep(5);
                 tonl(1);
                 tnoua("You pass out for a while, when you recover you have a raging thirst which cannot be satisfied. ");
                 tnou("Everything appears dim and misty and you are no longer interested in material things. ");
                 tnoua("");
                 score = 0;
                 flags[UNDEAD] = 1;
                 for (i=1;i<MAXMON;i++) monstr[i] = 0;      /* Permanently deactivate all monsters */
                 for (i=1;i<MAXOBJ;i++) objloc[i] = here;   /* Drop everything here                */
                 values[HELD] = 0; values[DWFNUM] = 0; values[DWFNOW] = 0; values[MONCOUNT] =0;
                }
             if (rnd(20) == 13) monstr[VAMPIRE] = -monstr[VAMPIRE];
             if (monstr[VAMPIRE] == -3) monstr[VAMPIRE] = -2;
             if (monstr[VAMPIRE] < 0) values[MONCOUNT]--;
            }
         }
      }
    showtext();
   }
/*----

----*/
/*----------------------------------------------------------------------*/
void move(int mpoint)            /* Make a move if possible             */
   {
    int i;
    if (ways[mpoint] == 0)
      {
       tnou("You cannot go in that direction!");
       showtext();
       return;
      }
    if (values[BASE] == here) /*---- At base camp -----------------------*/
      {
       flags[HOME] = 1;
       described = 0;
       if (mpoint == IN)  { flags[INTENT] = 1; return; }
       if (mpoint == OUT) { flags[INTENT] = 0; return; }
      } else flags[HOME] = 0;
    x = abs(x + xinc[mpoint] * ways[mpoint]);
    y = abs(y + yinc[mpoint] * ways[mpoint]);
    z = abs(z + zinc[mpoint] * ways[mpoint]);
    here = locate(x,y,z);
    described = 0;
    for (i=1;i<MAXOBJ;i++) obhere[i] = 0;                  /* Unset all object here flags     */
    moveno++;                                              /* Increment the move number       */
    values[DAYTIME]++;                                     /* Increment the time              */
    if (values[DAYTIME] > 48) newday();                    /* Start a new day                 */
    values[POOL] = -1;
    flags[NIGHT] = flags[DRIP] = flags[SHAFT] = 0;
    if (values[DAYTIME] < values[DAWN]) flags[NIGHT] = 1;      /* It is night                          */
    if (values[DAYTIME] > values[DUSK]) flags[NIGHT] = 1;      /* It is night                          */
    if (flags[NIGHT] && !flags[LAMPON]) flags[DARK] = 1;       /* It is dark at night  and             */
    if (z > 1 && !flags[LAMPON]) flags[DARK] = 1;              /* underground with no light            */
    if (!flags[UNDEAD]) values[THIRST]++;                      /* Exploring is thirsty work            */
    if (objloc[LAMP] != 0) flags[LAMPON] = 0;                  /* The lamp is not lit unless held      */
    if (flags[LAMPON] && objloc[LAMP] == 0) flags[DARK] = 0;   /* Lamp on, therefore not dark          */
    if (flags[LAMPON]) values[LIGHT]--;                        /* but the battery is being used up     */
    if (score < 0)
      {
       score--;                                    /* Bank charge if account is in the red */
       if (flags[OVERDRAWN] == 0)
         {
          tnoua("Warning: Your account is in the red, you will be charged interest of one point ");
          tnou("per move on your overdraft until you are back in credit! ");
          showtext();
          flags[OVERDRAWN] = 1;
         }
      }
    else
      {
       flags[OVERDRAWN] = 0;
      }
    if (flags[UNDEAD])
      {
       flags[DARK] = 0;                     /* The undead can always see     */
       if (flags[NIGHT])                    /* but must sleep during the day */
         {
          if (z < 2) tnoua("T"); else tnoua("Outside t");
          tnoua("he sun is rising and you fall into a deep slumber from which you do not awake until after nightfall. ");
          sleep(5);
          showtext();
          values[DAYTIME] = values[DUSK];
         }
      }
   }
/*----------------------------------------------------------------------*/
void news()                           /* Display the current news items */
   {
    int r;
    r = rnd(4);
    if (r % 4 == 0)
       {
        tonl(1);
        tnou("==================================================");
        tonl(1);
        tnou("**** CHIMAERA NEWS FLASH ****");
        tonl(1);
        tnou("Having trouble with space and time? If so use");
        tnoua("WHERE and TIME to get a fix!");
        tonl(1);
        tnoua("The dwarves seem more aggressive these days,");
        tnou("you had better find out how to get rid of them!");
        tnoua("Flickering lamps cannot be relit indefinitely,");
        tnou("you must find a more permanent solution!");
        tonl(1);
        tnoua("Help is precious, away from your camp you can only");
        tnoua("use it twice. Save it for real emergencies only or you may ");
        tnoua("get completely stuck underground. There is also a magic");
        tnou("word to assist you, but few people have discovered it!!");
        tonl(1);
        showtext();
       }
   }
/*----------------------------------------------------------------------*/

int parse(void)     /* Parse an input line into tokens[] */
   {
    int i,
        len;          /*  LINE length */
    char token[11],tokens[20][20];
    const char sep[] = " *!";
    char * pt;
    memset(&action[0],'\0',11);
    memset(&object[0],'\0',11);

    len = strlen(inbuff);
    if (len == 0) return(0);

    i=0;
    memset(&tokens[0],'\0',120);
    pt = strtok(inbuff,sep);       /* Get first token */
    while (pt)                   /* Loop until no more tokens */
      {
       strcat(tokens[i],pt);  /* Store current token */
       swearbox(pt);           /* Check the swear box */
       i++;
       pt = strtok(NULL,sep);  /* Get next token */
      }
    memset(&token[0],'\0',11);
    strcat(token,tokens[0]);
    if (strcmp(token,"GO") == 0)
      {
       strcat(action,tokens[1]);
       strcat(object,tokens[2]);
      }
    else
      {
       strcat(action,tokens[0]);
       strcat(object,tokens[1]);
      }
    return(i);
   }

/*----------------------------------------------------------------------*/
void pointr(int n)                      /* Random index creator         */
   {
    int i, a, b, tmp;

    for (i=1;i<n;i++) ipt[i] = i;       /* Preload index array */
    for (i=1;i<1000;i++)                   /* and scramble them   */
      {
       a = rnd(MAXOBJ); b = rnd(MAXOBJ);
       tmp = ipt[a]; ipt[a] = ipt[b]; ipt[b] = tmp;
      }
   }
/*----------------------------------------------------------------------*/
int rnd(int i) /* Return a random integer between 1 and i               */
               /* pseudorand is a pseudo random number from 1 to 5      */
   {
    int r;
    r = ((rand() % i) + 1);  /* Generates a number in the range 1 to i  */
    pseudorand++;
    if (pseudorand > 5) pseudorand = 1;
    values[RNDCOUNT]++;      /* Increment the random call counter */
    return(r);
   }
/*----------------------------------------------------------------------*/
void showthings(void)                   /* Show objects which are here  */
/* Scan all objects to see which are here and convert any such virtual  */
/* objects (except plants) into real objects.                           */
/* Set them to obhere[n] and count them.                                */
   {
    int i, k, len, seeit, posloc, mod20, mod60;
    int kount, ptr;

    if (flags[DARK]) return;  /* Can't see anything in the dark */
    if (flags[INTENT] == 0)   /* Not in the tent */
      {
       if (objloc[SWORD] == here && flags[EXCALIBER] > 1)
         {
          tnou("The hilt of a sword protrudes from a nearby rock. ");
          obhere[SWORD] = 1;
         }
       if (flags[SHAFT] == 0)  /* There are no objects in the shafts */
         {
          seeit = 0;
          mod20 = (int)(here % 20);  /* Above ground objects, probability 1:20 */
          mod60 = (int)(here % 60);  /* Below ground objects, probability 1:60 */
          for (i=1;i<MAXOBJ;i++)
            {
             obhere[i] = 0;
             if (objloc[i] == 0) continue;  /* Object carried by player      */
             if (objloc[i] == here)         /* It was put here by the player */
               {
                obhere[i] = 1;
                if (i == SWORD && flags[EXCALIBER] > 1) continue;
                seeit++;
                if (i == PLANT) continue;   /* The plant remains virtual until picked */
                objloc[i] = here;
                continue;
               }
             if (i > 10 && z < 2) continue;  /* Can't see it here */
             posloc = -objloc[i];
             if ((i > 10) && (z > 1) && (mod20 == posloc))
               {
                seeit++;
                obhere[i] = 1;
                if (i == PLANT) continue;   /* The plant remains virtual until picked */
                objloc[i] = here;
                continue;
               }
             if (mod60 == posloc)
               {
                seeit++;
                obhere[i] = 1;
                if (i == PLANT) continue;   /* The plant remains virtual until picked */
                objloc[i] = here;
                continue;
               }
            }
          /*---- Display the objects in pseudo random order         ----*/
          if (seeit > 0)
            {
             kount = 0;
             for (i=1;i<MAXOBJ;i++)
               {
                if (i == SWORD && flags[EXCALIBER] > 1) continue;
                if (obhere[i])
                  {
                   kount++;
                   if (kount == 1) { tonl(1); tnoua("Here you can see "); }
                   tnoua(thingdesc[i]);
                   if (kount == seeit)
                     {
                      tnou(".");
                     }
                   else
                     {
                      if ((kount + 1) == seeit) tnoua(" and "); else tnoua(", ");
                     }
                  }
               }
            }
         }
      }
    else   /* The player is in the tent, display things differently */
      {
       kount = 0;
       for (i=1;i<MAXOBJ;i++)
         {
          if (secure[i])
            {
             kount++;
             if (kount == 1)
               {
                tnoua("Your other possessions include ");
               }
             tnoua(thingpref[i]);
             tnoulca(thing[i]);
             tnoua(", ");
            }
         }
       if (kount > 0) tnou(" etc.");
      }
    showtext();
   }
/*----------------------------------------------------------------------*/
void showtext(void)                     /* Display the output line      */
   {
    char buffer[201],          /* Display buffer   */
         token[DISPWIDTH];            /* Token string     */
    const char sep[] = " ";    /* Token separator  */
    const char nl[] = "\n";
    char * pt;                 /* strtok() pointer */

    memset(&buffer[0],'\0',201);
    pt = strtok(display,sep);      /* Get the first token */
      while (pt)                   /* Loop until there are no more tokens */
          {
           memset(&token[0],'\0',DISPWIDTH);   /* Reset the token string  */
           strcat(token,pt);            /* Store the current token */
           if (strstr(token,nl))
             {
              if (LOGGING) fprintf(log_file,"%s\n",buffer);
              printf("%s\n",buffer);        /* New line, print and */
              memset(&buffer[0],'\0',201);  /* reset the buffer    */
             }
           else
             {
              strcat(buffer,token);        /* Add it to the display buffer */
              strcat(buffer," ");          /* and append a space           */
              if (strlen(buffer) > (DISPWIDTH - 15))
                 {
                  if (LOGGING) fprintf(log_file,"%s\n",buffer);
                  printf("%s\n",buffer);        /* Print and        */
                  memset(&buffer[0],'\0',201);   /* reset the buffer */
                 }
             }
           pt = strtok(NULL,sep);  /* Get next token */
          }
    if (LOGGING) fprintf(log_file,"%s",buffer);
    printf("%s",buffer);              /* Flush the remaining text to the screen */
    memset(&buffer[0],'\0',201);      /* and reset the buffer to be tidy        */
    memset(&display,'\0',MAXDISPLAY); /* All shown, clear the display buffer    */
   }
/*----------------------------------------------------------------------*/
void tnoua(char *line)              /* Append to a line on the terminal */
   {
    strcat(display,line);
   }
/*----------------------------------------------------------------------*/
void tnou(char *line)                   /* Print a line to the terminal */
   {
    strcat(display,line);
    strcat(display," \n ");
   }
/*----------------------------------------------------------------------*/
void tnoint(long n)                 /* Append a long integer to line    */
   {
    char text[11];
    sprintf(text,"%d",n);
    strcat(display,text);
   }
/*----------------------------------------------------------------------*/
void tnoulca(char * word)               /* Append to line in lowercase  */
   {
    int i;
    char lowercase[21];

    memset(&lowercase,'\0',21);
    strcat(lowercase,word);
    for (i=0;i<strlen(lowercase);i++) memset(&lowercase[i],tolower(lowercase[i]),1);
    tnoua(lowercase);
   }
/*----------------------------------------------------------------------*/
void tonl(int n)               /* Print n blank lines to the terminal */
   {
    int i;
    for (i=0;i<n;i++)
      {
       strcat(display," \n ");
      }
   }
/*----------------------------------------------------------------------*/
void welcome()
   {
    tonl(1);
    tnou("*** Welcome to the world of  CHIMAERA ***");
    tnou("(Created by Nicholas Perre-Wetherall)");
/*    tnou("[Version: C1.001]"); */
    tnoua("[");
    tnoua(version);
    tnoua("]");
    tonl(1);
    tnoua("Command me and I will be your guide. There is treasure to be ");
    tnoua("found but also much danger. Few who venture here escape ");
    tnou("unchanged but you may succeed where others have failed!!");
    showtext();
   }
/*----------------------------------------------------------------------*/
void worth()  /* Load object value array                                */
   {
    int i;
    for(i=0;i<10;i++) points[i] = 5;          /* Common objects (1-10) */
    for(i=10;i<MAXOBJ;i++) points[i] = 20;    /* Uncommon objects      */
 /* Valuables                                         */
    points[NUGGET]   = 25;     /* Gold nugget        */
    points[DIAMOND]   = 30;     /* Diamond            */
    points[JEWELS]    = 40;     /* Jewels             */
    points[PYRAMID]   = 45;     /* Platinum pyramid   */
    points[SAPPHIRE]  = 50;     /* Priceless sapphire */
    points[TREASURE]  = 50;     /* Treasure           */
    points[VENUS]     = 40;     /* Venus-de-Milo      */
    points[GOLDRING]  = 30;     /* Golden ring        */
 /* Objects with a low intrinsic value                */
    points[GARLIC]    =  2;     /* Garlic             */
    points[BOOK]      =  2;     /* Book               */
    points[VIOLETS]   =  2;     /* Violets            */
    points[CHARM]     = 10;     /* Good luck charm    */
    points[OYSTER]    =  2;     /* Oyster             */
    points[CLAM]      =  2;     /* Clam               */
    points[ELIXIR]    =  2;     /* Elixir of life     */
    points[BRICKBATS] =  0;     /* Brickbats          */
    points[GNOME]     =  0;     /* Gnome              */
   }
/*----------------------------------------------------------------------*/
int yesno(void) /* Elicit the answer Yes or No */
   {
    int i, len, resp;
    char yn[21];
    resp = 2;
    do 
       {
        len = strlen(fgets(yn,21,stdin));
        for (i=0;i<len;i++) memset(&yn[i],toupper(yn[i]),1);
        if (yn[0] == 'Y')
          {
           resp= 1;
           if (LOGGING) fprintf(log_file,"y\n");
           return(resp);
          }
        if (yn[0] == 'N')
          {
           resp= 0;
           if (LOGGING) fprintf(log_file,"n\n");
           return(resp);
          }
        tnou("Please answer Yes or No: ");
        showtext();
       } while (resp == 2);
    return(99);
   }
/*==== Miscellaneous Functions =========================================*/
void dead(void)   /* The player has been killed, offer reincarnation    */
                  /* unless his/her luck has run out                    */
   {
    int i, yn;
    tonl(2);
    tnoua("Sorry, you are ");
    if (values[LUCK] < 1) tnoua("permanently ");
    tnou("dead!");
    showtext();
    if (values[LUCK] >= 1)
      {
       tonl(1);
       tnoua("I may be able to reincarnate you, shall I try? ");
       showtext();
       yn = yesno();
       if (yn == 1)
         {
          tnou("O.K., this may hurt a little and will cost you 50 points!");
          tonl(5);
          tnou("There is a blinding flash!!!!");
          sleep(5);
          tonl(1);
          tnou("and");
          sleep(5);
          tonl(5);
          tnou("You recover to find yourself in the tent at your base camp.");
          tonl(1);
          showtext();
          values[LUCK] = values[LUCK] -5;
          score -= 50;
          /* Put the player into the tent */
          for (i=1;i<15;i++) ways[i] = 0; ways[OUT] = 1;  /* Only way from here is OUT */
          x = values[FIRSTX]; y = values[FIRSTY]; z = 1; here = locate(x,y,z);
          flags[INTENT] = 1; flags[HOME] = 1; flags[SHANGRI] = 0;
          flags[ANIMAL] = flags[CARNIV] = flags[NIGHT] = flags[DARK] = flags[LAMPON] = 0;
          newday();  /* Increment the date */
          values[DAYTIME] = values[DAWN];
          flags[GLOW] = flags[WAVER] = flags[SHAFT] = flags[DRIP] = 0;
          values[HELD] = 0;
          locwun();                /* Move all objects into a new set of starting positions */
          for (i=1;i<MAXOBJ;i++)   /* and reset those in the tent or gone forever           */
            {
             if (secure[i] == 1) objloc[i] = -1000;
             if (gone[i] == 1) objloc[i] = -2000;
             if (objloc[i] == -2000) gone[i] = 1;  /* Set by locwun() ??? */
            }
          for (i=1;i<MAXMON;i++)
            {
             if (monstr[i] != 0) monstr[i] = -1;  /* Reinitialise all monsters that still exist */
            }
         } else quit(0);
      } else quit(0);
   }
/*----------------------------------------------------------------------*/
void newday(void)                       /* Increment the date           */
   {
    values[DAYTIME] = 1;
    values[DAY]++;
    if (values[DAY] > mdays[values[MONTH]])        /* Start a new month */
      {
       values[DAY] = 1;
       values[MONTH]++;
       if (values[MONTH] > 12) values[MONTH] = 1;  /* Start a new year  */
       values[DAWN] = dawn[values[MONTH]];
       values[DUSK] = dusk[values[MONTH]];
      }
    values[WEEKDAY]++;
    if (values[WEEKDAY] > 7) values[WEEKDAY] = 1;  /* Start a new week  */
   }
/*----------------------------------------------------------------------*/
long plumb(void)                        /* Locate the bottom of a shaft */
/* Return the address of the bottom of the shaft or a negative number   */
/* the range -20 to -49 if the shaft is more than 20 levels deep       */
   {
    int i, j, znext;
    long thislevel, nextlevel;

    znext = z;
    for (i=0;i<20;i++)
      {
       thislevel = locate(x,y,znext);
       nextlevel = locate(x,y,znext+1);
       if ((thislevel & nextlevel & 128) != 128) /* Found bottom of shaft */
         {
          return (thislevel); /* return the address of the shaft bottom */
         }
       znext++;
      }
    return(rnd(30) - 50);
   }
/*----------------------------------------------------------------------*/
void sleep(int i)                       /* Sleep for a while            */
   {
    int j;
    long k;
    double pi, root;
    pi = 22 / 7;
    for (j=0;j<i;j++)
      {
       for (k=0;k<DELAY;k++) root = sqrt(pi);
       tnoua(".");
       showtext();
      }
    root = root--;
   }
/*----------------------------------------------------------------------*/
void cheat(void)                        /* Display current settings     */
   {
    int i, j, len;
    char cbuff[31];
    char buffer[81], tokens[3][10];
    const char sep[] = " ";
    char * pt;

    status();
    if (flags[WIZARD] == 0) return;   

    printf("[LFPVSOM]> ");
    fgets(cbuff,30,stdin); len = strlen(cbuff);
    for (i=0;i<len;i++) memset(&cbuff[i],toupper(cbuff[i]),1);
    if (strstr(cbuff,"L"))
      {
       int x1, y1;
       x1 = values[FIRSTX]; y1 = values[FIRSTY];
       printf("Location co-ordinates: x=%d y=%d z=%d, ",x,y,z);
       printf("Home base x=%d, y=%d, z=1 ",x1,y1);
       printf("Moves=%d\n",moveno);
       printf("Can move : ");
       for (j=1;j<15;j++)
         {
          if (ways[j] == 1) printf("%s ",dicact[j]);
         }
       printf(" last action=[%s] last object=[%s]\n",lastaction,lastobject);
      }
    if (strstr(cbuff,"F"))
      {
       printf("Flags: Home=%d In tent=%d ",flags [HOME], flags [INTENT]);
       printf("Dark=%d, Night=%d, Lamp on=%d\n", flags[DARK], flags[NIGHT], flags[LAMPON]);
      }
    if (strstr(cbuff,"P"))
      {
       printf("Plain: Rolling=%d Grass=%d",flags[ROLING],flags[HIGRAS]);
       printf(" Animal=%d Herd=%d",flags[ANIMAL],flags[HERD]);
       printf(" Carnivores=%d Seen=%d\n",flags[CARNIV],flags[SEEN]);
      }
    if (strstr(cbuff,"V"))
      {
       printf("Values: ");
       printf("Daytime=%d ", values[DAYTIME]);
       printf("Dawn=%d ", values[DAWN]);
       printf("Dusk=%d ", values[DUSK]);
       printf("Luck=%d ", values[LUCK]);
       printf("Held=%d ",values[HELD]);
       printf("Dwarf num=%d ",values[DWFNUM]);
       printf("Dwarf now=%d ",values[DWFNOW]);
       printf("\n");
       for (i=1;i<MAXMON;i++) printf("%s=%d ",beasts[i],monstr[VAMPIRE]);
       printf("\n");
      }
    if (strstr(cbuff,"S")) /* Go to a defined location */
      {
       printf("Set X, Y Z co-ordinates: ");
       inpline();
       i=0;
       memset(&tokens[0],'\0',30);
       pt = strtok(inbuff,sep);     /* Get first token */
       while (pt)                   /* Loop until no more tokens */
          {
           strcat(tokens[i],pt);   /* Store current token */
           i++;
           pt = strtok(NULL,sep);   /* Get next token */
          }
       x = atoi(tokens[0]); y = atoi(tokens[1]); z = atoi(tokens[2]);
       here = locate(x,y,z);
       describe(1);
       return;
      }
    if (strstr(cbuff,"O"))
      {
       j = 1;
       while (j == 1)
         {
          printf("Object > ");
          inpline();
          if (strlen(inbuff) == 0) return;
          memset(&tokens[0],'\0',30);
          pt = strtok(inbuff,sep);      /* Get first token    */
          strcat(tokens[0],pt);         /* and store it       */
          for (i=1;i<MAXOBJ;i++)
            {
             if (strncmp(thing[i],tokens[0],3) == 0)
               {
                objloc[i] = 0;
                values[HELD]++;
                gone[i] = 0;
                secure[i] = 0;
                obhere[i] = 0;
                printf("Got %s\n",thing[i]);
               }
            }
         }
      }
    if (strstr(cbuff,"M"))
      {
       j = 1;
       while (j == 1)
         {
          printf("Monster > ");
          inpline();
          if (strlen(inbuff) == 0) return;
          memset(&tokens[0],'\0',30);
          pt = strtok(inbuff,sep);      /* Get first token    */
          strcat(tokens[0],pt);         /* and store it       */
          for (i=1;i<MAXMON;i++)
            {
             if (strncmp(beasts[i],tokens[0],3) == 0)
               {
                if (monstr[i] == 0) monstr[i] = -1;
                monstr[i] = abs(monstr[i]);
                if (i == GORGON) values[GORLOC] = here;
                if (monstr[i] > 0) values[MONCOUNT]++;
                printf("%s now active\n",beasts[i]);
               }
            }
         }
      }
   }
/*----------------------------------------------------------------------*/
void swearbox(char * token)   /* Fine for using a naughty word          */
   {
    int i;
    for (i=1;i<MAXEXP;i++)  /* Has a naughty word been used? */
      {
       if (strstr(explet[i],token) != NULL && strlen(explet[i]) == strlen(token))
         {
          tnou("That sort of language is not permitted here, you have been fined 5 points!");
          score -= 5;
         }
      }
   }
/*==== Chimaera Action functions =======================================*/
void callhim(void)               /* Call someone                        */
   {
    tnoua("No one comes");
    if (rnd(3) == 1) tnoua(", servants are so difficult to find these days");
    tnou(". ");
    showtext();
   }
/*----------------------------------------------------------------------*/
void chase(void)                 /* Chase someone or something          */
   {
    int i;

    if (values[RUNOUT] != moveno)
      {
       tnou("Chase what? ");
       showtext();
       return;
      }

    switch (z)
      {
       case 0 :                  /* Can't chase from up a tree */
          tnou("Don't be stupid, you'll fall and break your neck. ");
          break;
       case 1 :                  /* Ground level               */
          tnoua("You set off in pursuit but trip over a tree root and fall heavily");
          if (values[HELD] > 0) tnoua(", scattering your possessions about you");
          tnoua("");
          tnou(". ");
          values[HELD] = 0;
          for (i=1;i<MAXOBJ;i++)
            {
             if (objloc[i] == 0) objloc[i] = here;
            }
          break;
       default :
          switch (rnd(4))
            {
             case 1 :
                tnoua("You step forward but are suddenly overcome with weariness ");
                tnoua("and fall to the ground in a dead faint. After a time you ");
                tnou("recover your senses and your strength rapidly returns. ");
                values[DAYTIME] += rnd(10);
                break;
             case 2 :
                tnoua("You leap forward but some mysterious and irresistable power holds you back. ");
                tnou("After a brief struggle you give up. ");
                break;
             case 3 :
                tnoua("A ghastly figure rises before you. \"Don't do it; I did and this is the ");
                tnoua("result!\" it moans as it slowly crumbles into dust before your very eyes. ");
                tnou("You decide that discretion is the better part of valour. ");
                break;
             case 4 :
                tnoua("You give chase. After a while you pause for breath and look about you. Realising ");
                tnou("that you have run round in circles and are back where you started from you give up. ");
                values[DAYTIME] += rnd(4);
             break;
            }
      }
    if (values[DAYTIME] > 48) newday();
    showtext();
   }
/*----------------------------------------------------------------------*/
void closeit(int objpoint)       /* Close something                     */
   {
    tnoua("I can't do that with the ");
    tnoulca(thing[objpoint]);
    tnou(" yet! ");
    showtext();
   }
/*----------------------------------------------------------------------*/
void drink(int objpoint)         /* Drink various things                */
   {
    if (flags[DRIP])
      {
       if (values[POOL] == 2)
         {
          tnou("You drink cool, clear water from the pool and feel much refreshed.");
          values[THIRST] = 0;
          values[LUCK] += 10;
         }
       else
         {
          tnou("The water drip is too slow to quench your thirst but at least you can moisten your parched lips. ");
          values[THIRST] -= 10;
          values[LUCK] += 2;
         }
       showtext();
       return;
      }
    if (objloc[BOTTLE] != 0 && objloc[ELIXIR] != 0)
      {
       tnou("You have nothing to drink. ");
       showtext();
       return;
      }
    switch (objpoint)
      {
       case 0 :
          tnou("Drink what? ");
          showtext();
          return;
       case ELIXIR :
          if (objloc[ELIXIR] != 0)
            {
             tnou("You haven't got it! ");
            }
          else
            {
             tnoua("You place the phial containing the elixir to your lips and drain every drop. A feeling of renewed ");
             tnou("strength courses through your veins. The empty phial falls to dust in your grasp. ");
             flags[ELIXIR]  = 1;
             values[HELD]--;
             if (flags[HANDSFULL] == 1) flags[HANDSFULL] = 0;
             objloc[ELIXIR] = -2000;
             secure[ELIXIR] = 0;
             gone[ELIXIR] = 1;
             score += 10;
             values[THIRST] = 0;
             values[LUCK] += 50;
            }
          break;
       default :
          if (objloc[BOTTLE] == 0)
            {
             if (flags[EMPTY])
               {
                tnou("Your bottle is empty. ");
               }
             else
               {
                tnou("You drink the contents of the bottle and feel much refreshed.");
                flags[EMPTY] = 1;
                values[THIRST] = 0;
                values[LUCK] += 10;
               }
            }
          break;
      }
    showtext();
   }
/*----------------------------------------------------------------------*/
void eat(int objpoint)           /* Eat various things                  */
   {
    if (objloc[objpoint] != 0)
      {
       tnou("But you haven't got it! ");
       showtext();
       return;
      }
    else
      {
       switch (objpoint)
         {
          case 0 :
             tnou("Eat what? ");
             showtext();
             return;
          case FOOD :
             tnou("Thank you, that was delicious!");
             score += 5;                         /* Give him a few points */
             break;
          case PLANT :
             if (rnd(10) != 5)
               {
                tnoua("It is sustaining but not particularly tasty. You notice a slight euphoria afterwards, ");
                tnoua("possibly due to some alkaloid in the leaves, but there seem to be no permanent ");
                tnou("ill effects. ");
                score += 2;                         /* Give him a few points   */
                if (rnd(10) != 8)
                  {
                   objloc[PLANT] = -rnd(20);                  /* Generate another plant  */
                   values[HELD]--;                            /* decrement his inventory */
                   if (flags[HANDSFULL] == 1) flags[HANDSFULL] = 0;
                   showtext();
                   return;
                  }
               }
             else
               {
                tnoua("You eat the plant but are horrified to find the label \"Aconitum napellus (Monkshood)\" ");
                tnoua("tied to the stem. You spit out what remains in your mouth but it is too late, ");
                tnoua("gradually a numbness spreads over you, followed by a creeping paralysis beginning in your legs. ");
                tnoua("Breathing is difficult and your pulse becomes slow, irregular and weak, although your ");
                tnoua("mind remains perfectly clear. Suddenly you collapse! ");
                showtext();
                if (flags[ELIXIR])
                  {
                   sleep(5);   /* Keep him in suspense for a while */
                   tnou("After a while you miraculously recover.");
                   score += 2;
                  }
                else
                  {
                   dead();
                  }
               }
             break;
          case GARLIC :
             tnoua("With some distaste you eat the garlic. Your breath smells terrible. ");
             score += 15;
             break;
          case VIOLETS :
             tnoua("You nibble at the flowers and are delighted to find that they are crystallised ");
             tnoua("violets preserved in sugar. You eat the lot and the world seems a better ");
             tnoua("and happier place, for a time at least.");
             score += 10;
             break;
          case OYSTER :
             if (values[MONTH] > 4 && values[MONTH] < 9)
               {
                tnoua("Sorry, there is no \"r\" in the month and shellfish, are not in season.");
                showtext();
                return;
               }
             else
               {
                if (objloc[DAGGER] != 0)
                  {
                   tnoua("You have no knife to open it with!");
                   showtext();
                   return;
                  }
                else
                  {
                   tnoua("You use the dagger to prise open the oyster, there ");
                   tnoua("is no pearl inside and you swallow the contents whole. ");
                   tnoua("A penguin dressed as a waiter (how else?) waddles in, takes ");
                   tnoua("the empty shell from you very politely and waddles out. ");
                   values[RUNOUT] = moveno;
                   score += 15;
                 }
               }
             break;
          case CLAM :
             if (values[MONTH] > 4 && values[MONTH] < 9)
               {
                tnoua("Sorry, there is no \"r\" in the month and shellfish, are not in season.");
                showtext();
                return;
               }
             else
               {
                if (objloc[DAGGER] != 0)
                  {
                   tnoua("You have no sword to open it with!");
                   showtext();
                   return;
                  }
                else
                  {
                   tnoua("You force the sword blade between the two halves of the clam's shell and ");
                   tnoua("with a great effort prise it open. An evil looking little dwarf leaps out ");
                   tnoua("of the shell, curses angrily and vanishes out of sight round a corner. ");
                   tnoua("The clam snaps shut with a loud clang before you can eat it! ");
                   values[RUNOUT] = moveno;
                   values[DWFNUM]++;
                   showtext();
                   return;
                  }
               }
          default :
             tnoua("Not ");
             switch (rnd(3))
               {
                case 1 : tnoua("bl**dy "); break;
                case 2 : tnoua("Pygmalion "); break;
               }
             tnou("likely! ");
             break;
         }
      }
    objloc[objpoint] = -2000;           /* Remove the object permanently */
    gone[objpoint] = 1;
    values[HELD]--;                     /* and decrement his inventory   */
    if (flags[HANDSFULL] == 1) flags[HANDSFULL] = 0;
    showtext();
   }
/*----------------------------------------------------------------------*/
void examine(int objpoint)       /* Examine something                   */
   {
    int i;
    switch (objpoint)
      {
       case 0 :
          tnoua("Examinations will be held in June every year, candidates should submit their three ");
          tnoua("best scores, which must be countersigned by an acknowledged wizard, as evidence of their ");
          tnou("competence. The following awards are available: ");
          tonl(1);
          tnou("\tScore \t \tCategory");
          tnou("\t===== \t \t========");
          tnou("\t<100\t\ta rank amateur");
          for (i=1;i<11;i++)
            {
             tnoua("\t");
             if (i < 10)
               {
                tnoint(i * 100);
                tnoua(" - ");
                tnoint(i * 100 + 99);
               }
             else
               {
                tnoua(">1000 \t");
               }
             tnoua("\t");
             tnoua(classes[i]);
             tnou(" adventurer");
            }
          tonl(1);
          tnoua("We regret that we are unable to assist you in this matter, please refer to your ");
          tnou("local Examinations Board for further information. ");
          break;
       default :
          tnoua("Pardon? ");
          break;
      }
    showtext();
   }
/*----
IF (COMP$R(4,ACTION,'EXAM').NE.0) GOTO 470      /* Pardon?
      CALL TNOUA(
     +'',9)
      CALL TNOU(
     +'',23)

----*/
/*----------------------------------------------------------------------*/
void fill(int objpoint)          /* Fill something                      */
   {
    int i, pickup = 0;

    if (objloc[objpoint] != 0)
      {
       tnoua("You don't have the ");
       tnoulca(thing[objpoint]);
       tnou("! ");
       showtext();
       return;
      }
    switch (objpoint)
      {
       case 0 :
          tnou("Fill what? ");
          break;
       case BOTTLE :

          if (flags[EMPTY])
            {
             if (flags[DRIP])
               {
                if (values[POOL] == 2)
                  {
                   tnou("Your bottle is now full of water. ");
                   flags[EMPTY] = 0;
                   break;
                  }
                if (values[POOL] >= 0)
                  {
                   tnoua("The water drip is very slow, it would take for ever to ");
                   tnou("fill anything from it and you quickly give up the attempt.");
                  }
               }
             else
               {
                tnou("There is no water to fill it with! ");
               }
            }
          else
            {
             tnou("It is already full. ");
            }
          break;
       case BASKET :
          if (objloc[BASKET] != 0)
            {
             tnou("What basket? ");
             break;
            }
          if (values[HELD] > 8)
            {
             tnou("Your basket is already full! ");
            }
          else
            {
             for (i=1;i<MAXOBJ;i++)
               {
                if (obhere[i] == 1)
                  {
                   pickup++;
                   tnoua("You put the ");
                   tnoulca(thing[i]);
                   tnou(" into the basket. ");
                   values[HELD]++;
                   objloc[i] = 0;
                   obhere[i] = 0;
                   if (values[HELD] == 9) break;
                  }
                if (pickup == 0) tnou("There is nothing here to put in it. ");
               }
            }
          break;
       case VASE   :
          if (flags[DRIP])
            {
             if (values[POOL] == 2)
               {
                tnou("You attempt to fill the vase with water from the pool, but it pours out of a hole in the bottom. ");
                break;
               }
             if (values[POOL] >= 0)
               {
                tnoua("The water drip is very slow, it would take for ever to ");
                tnou("fill anything from it and you quickly give up the attempt.");
               }
            }
          else

            {
             tnou("There is no water to fill it with! ");
            }
          break;
       case BOX    :
          if (flags[BOXLOK])
            {
             tnou("The box is locked! ");
            }
          else
            {
             tnou("Would that you could put all the ills of mankind back into it. ");
            }
          break;
       case GOBLET :
          if (flags[DRIP])
            {
             if (values[POOL] == 2)
               {
                tnou("You dip the goblet into the pool but it shatters on contact with the ice-cold water. ");
                values[HELD]--;
                if (flags[HANDSFULL] == 1) flags[HANDSFULL] = 0;
                objloc[GOBLET] = -2000;
                secure[GOBLET] = 0;
                gone[GOBLET] = 1;
                score -= 5;
                break;
               }
             if (values[POOL] >= 0)
               {
                tnoua("The water drip is very slow, it would take for ever to ");
                tnou("fill anything from it and you quickly give up the attempt.");
               }
            }
          else
            {
             tnou("There is no water to fill it with! ");
            }
          break;
       default     :
          tnou("But it can't hold anything! ");
          break;
      }
    showtext();
   }
/*----------------------------------------------------------------------*/
void find(int objpoint)              /* Find something                      */
   {
    if (objpoint == 0)
      {
       tnou("Find what? ");
      }
    else
      {
       tnoua("If you can't find it I'm sure that I can't. It could be anywhere ");
       tnou("or may not even exist! ");
      }
    showtext();
   }
/*----------------------------------------------------------------------*/
void take(int objpt)             /* Take or get and object              */
   {
    int i;
    if (flags[UNDEAD])
      {
       tnou("Why bother, you no longer have any interest in these material things. ");
       showtext();
       return;
      }
    if (strlen(object) == 0)
      {
       tnou("What do you want to get?");
       showtext();
       return;
      }
    if (objpt == 0)
      {
       tnou("I can't do that.");
       showtext();
       return;
      }
    if (flags[INTENT])
      {
       if (secure[objpt] == 0)
         {
          tnoua("There is no ");
          tnoulca(thing[objpt]);
          tnou(" here!");
          showtext();
          return;
         }
      }
    else
      {
       if (obhere[objpt] == 0)
         {
          tnoua("I see no ");
          tnoulca(thing[objpt]);
          tnou(" here!");
          showtext();
          return;
         }
      }
    if (objpt == SWORD && flags[EXCALIBER] > 1)
      {
       tnoua("You try to pull the sword from the stone without success, obviously you are ");
       tnou("not Arthur son of Uther Pendragon. ");
       showtext();
       return;
      }
    if (objpt == BASKET) flags[HANDSFULL] = 0; /* Now has the basket so can carry more */
    if (objpt != BASKET && flags[HANDSFULL] == 1)
      {
       if (rnd(2) == 1)
         {
          tnou("Your hands are full!");
         }
       else
         {
          tnou("You can't carry any more, you will have to drop something first!");
         }
       showtext();
       return;
      }
    values[HELD]++;
    if (flags[HANDSFULL] != 1)
      {
       if (objloc[BASKET] == 0)
         {
          if (values[HELD] > 8) flags[HANDSFULL] = 1;  /* Can carry nine objects with the basket */
         }
       else
         {
          if (values[HELD] > 5) flags[HANDSFULL] = 1;  /* Can carry six objects without the basket */
         }
      }
    if (objpt == CHARM) values[LUCK] += 100;                            /* the lucky charm */
    if (objloc[BASKET] == 0)
      {
       if (objpt == LAMP || objpt == SWORD || objpt == STAFF || objpt == CARPET)
         {
          tnoua("You pick up the ");
          tnoulca(thing[objpt]);
          if (objpt == SWORD && flags[EXCALIBER] == 0)
            {
             tnou(", it is lighter and flimsier than it looks but it will have to serve");
            }
          tnou(". ");
         }
       else
         {
          tnoua("You put the ");
          tnoulca(thing[objpt]);
          tnou(" into the basket. ");
         }
      }
    else
      {
       tnoua("You pick up the ");
       tnoulca(thing[objpt]);
       if (objpt == SWORD && flags[EXCALIBER] == 0)
         {
          tnou(", it is rather blunt but will have to do");
         }
       if (objpt == GOLDRING) tnoua(", it might look good on your finger");
       tnou(". ");
      }
    objloc[objpt] = 0;          /* The object is now held   */
    obhere[objpt] = 0;          /* and it is no longer here */
    secure[objpt] = 0;          /* or in the tent           */
    showtext();
   }
/*----------------------------------------------------------------------*/
void gamic(void)                 /* Section in gamic language           */
   {
    int len, forever = 1;

    if (strncmp(action,"GAMIC",5) != 0)
      {
       tnou("I'm afraid I don't understand you.");
       showtext();
       return;
      }
    tnoua("Argg, ywyll slagwyll Gaimykk, ipf wazglytt apfglyjll sqydd 'swalguut.");
    tnou("Hyperrd makargyulaitt zligwik puddhamerr!");
    showtext();
    while (forever == 1)
      {
       tnoua("> ");
       showtext();
       len = inpline();
       if (len == 0) continue; else parse();             /* Loop if input is null */
       if (strncmp(action,"ENGLISH",3) == 0)
         {
          tnou("OK, if you don't want to practise your Gamic we will communicate in English. ");
          showtext();
          forever--;
          return;
         }
       if (strncmp(action,"QUIT",4) == 0)
         {
          quit(1);
         }
       switch (rnd(5))
         {
          case 1 :
             tnou("Dog yogul wyshhg togi speko Eynglyschimuse? ");
             break;

          case 2 :
             tnou("Whotyg hlly yogul tolkien ibooto? ");
             break;
          case 3 :
             tnou("Ipf ywyll wallogg quitog, sayligg soww. ");
             break;
          case 4 :
             tnou("Ig cennocka makig hid norie tallie o' thyso. ");
             break;
          case 5 :
             tnou("Yogul talig o' lodo rybbig. ");
             break;
          default :
             tnou("Ifg doanutt unstlangg, plygickk splagwyll Gaimykk. ");
         }
       showtext();
      }
   }
/*----------------------------------------------------------------------*/
void help(void)                  /* Help                                */
   {
    int i, yn;

    if (flags[HOME])
      {
       tnoua("Would you like to see the instructions, for which there will be no charge? ");
       showtext();
       yn = yesno();
       if (yn == 1) instructions(0);
       return;
      }
    else
      {
       switch (helpno)
         {
          case 0 :
             tnoua("I can get you out of here, the charge will be 10 points, are you sure you need help? ");
             break;
          case 1 :
             tnoua("I can get you out of here, but it will cost you 20 points, do you really need help that much? ");
             break;
          case 2 :
             tnoua("I can rescue you one last time, but the price is now risen to 30 points, can you afford it? ");
             memset(&dicact[37],'\0',4);  /* Delete the help command */
             break;
         }
       showtext();
       yn = yesno();
       if (yn != 1) return;
       helpno++;
       score -= (helpno * 10);
       tonl(1);
       tnoua("A thick mist forms above you, from which a giant hand slowly descends. It lifts you ");
       if (values[HELD] > 0)
         {
          tnoua("and all your possessions ");
         }
       tnoua("into the air and you lose all sense of time and space. After a while the mists clear and ");
       showtext();
       sleep(5);
       values[DAYTIME] = values[DAWN];
       flags[DARK] = 0;
       for (i=1;i<MAXMON;i++) { if (monstr[i] != 0) monstr[i] = -1; } /* Initialise all remaining monsters */
       values[DWFNOW] = 0;                                            /* Remove any current dwarves        */
       x = values[FIRSTX]; y = values[FIRSTY]; z = 1;                 /* Move to base camp                 */
       here = locate(x,y,z);
       flags[HOME] = 1;
       tnou(". you find yourself at your base camp. ");
       if (score < 0)
         {
          tonl(1);
          tnoua("Your account is in the red and a bank charge of 1 point will be made each time you move until you ");
          tnou("are back in credit. We respectfully request that you clear your overdraft as quickly as possible! ");
         }
       showtext();
      }
   }
/*----------------------------------------------------------------------*/
void hint(char *setting)               /* Context sensitive hints       */
   {
    char hinttext[81];

    if (flags[AUTOHINT] == -1)
      {
       tonl(1);
       tnoua("Context sensitive hints are available in certain situations. Each hint ");
       tnoua("costs one point and will be shown once only. The hint engine may be set ");
       tnoua("to show hints automatically (by typing 'HINT AUTO') or on demand (by typing ");
       tnoua("'HINT OFF'), the default setting is HINT OFF. Hints may be requested at any ");
       tnou("time by typing 'HINT'. If no hint is available there will be no charge. ");
       flags[AUTOHINT] = 0;          /* Set to OFF */
       showtext();
       return;
      }
    if (strlen(setting) == 0)                   /* Give him the most relevant hint */
      {
       if (hintsdone[values[HINTPTR]])
         {
          tnou("You have already seen the current hint!");
          showtext();
          return;
         }
       if (values[HINTPTR] == 0)
         {
          tnou("Sorry, nothing relevant is available. There has been no charge.");
          showtext();
          return;
         }
       if (flags[AUTOHINT]) tnoua("\n Hint: ");
       memset(&hinttext[0],'\0',81);
       strcat(hinttext,hints[values[HINTPTR]]);
       tnoua(hinttext);
       tnou(". ");
       hintsdone[values[HINTPTR]] = 1;   /* Flag it as shown           */
       score--;                          /* charge the player 1 point  */
       values[HINTPTR] = 0;              /* and unset the hint pointer */
      }
    else                                  /* Change the hint setting    */
      {
       if (strstr("AUTO",setting) != NULL)
         {
          flags[AUTOHINT] = 1;
          tnou("[Hint setting is AUTO] ");
          showtext();
          return;
         }
       if (strstr("OFF",setting)  != NULL)
         {
          flags[AUTOHINT] = 0;
          tnou("[Hint setting is OFF] ");
          showtext();
          return;
         }
       tnou("Pardon?");
      }
    showtext();
   }
/*----------------------------------------------------------------------*/
void lockit(int objpoint)        /* Lock something                      */
   {
    tnoua("I can't do that with the ");
    tnoulca(thing[objpoint]);
    tnou(" yet! ");
    showtext();
   }
/*----------------------------------------------------------------------*/
void play(int objpt)             /* Play an instrument                  */
   {
    if (objpt == 0)
      {
       tnou("Play what? ");
       showtext();
       return;
      }
    if (objpt != FLUTE && objpt != MUSIC)
      {
       tnou("You can't play that! ");
       showtext();
       return;
      }
    if (objpt == FLUTE || objpt == MUSIC)
      {
       if (objloc[FLUTE] != 0)
         {
          tnou("You have no flute! ");
         }
       else
         {
          if (objloc[MUSIC] != 0)
            {
             tnou("You have no music and cannot play by ear. ");
            }
          else                   /* He has flute and music */
            {
             tnoua("You play the silver flute very badly, ");
             if (monstr[SNAKE] > 0)
               {
                tnoua("the snake is alarmed by the noise and slithers out of sight ");
                tnou("through a crack in the floor, never to return. ");
                values[RUNOUT] = moveno;
                monstr[SNAKE] = 0;
                values[MONCOUNT]--;
                score += 50;
               }
             else
               {
                tnou("nothing remarkable happens. ");
               }
            }
         }
      }
    showtext();
   }
/*----------------------------------------------------------------------*/
void plugh(void)                 /* He says PLUGH                       */
   {
    if (strncmp(action,"PLUGH",5) != 0)
      {
       tnou("Pardon? ");
      }
    else
      {
       tnou("I think you are in the wrong game, try ADVENTURE. ");
      }
    showtext();
   }
/*----------------------------------------------------------------------*/
void put(int apoint, int objpt)  /* Put down or drop something          */
   {
    int i, dropit, plural;
    long bottom;
    if (strlen(object) == 0)
      {
       if (apoint == 27) tnoua("Put down ");
       if (apoint == 28) tnoua("Drop ");
       tnou("what? ");
       showtext();
       return;
      }
    if (objloc[objpt] != 0)
      {
       tnou("But you haven't got it!");
       showtext();
       return;
      }
    tnoua("You ");
    if (apoint == 27) tnoua("put down");
    if (apoint == 28) tnoua("drop");
    tnoua(" the ");
    tnoulca(thing[objpt]);
    if (flags[HANDSFULL] == 1) flags[HANDSFULL] = 0;  /* Dropped something, hands no longer full */
    if (objpt == LAMP && flags[LAMPON])
      {
       tnoua(", it immediately goes out");
       flags[LAMPON] = 0;
       if (z > 1 || flags[NIGHT]) flags[DARK] = 1;
      }
    if (objloc[CUSHION] != here && !flags[INTENT])
      {
       if (objpt == BOTTLE || objpt == VASE || objpt == GOBLET || objpt == MIRROR)
         {
          tnoua(", it smashes into a thousand fragments. ");
          if (here == values[BASE])
            {
             tnoua("A native servant rushes up, sweeps up the pieces and dashes away again. ");
             values[RUNOUT] = moveno;
            }
          else
            {
             if (objpt == BOTTLE) values[BRKBOT] = here;
             if (objpt == VASE)   values[BRKVAS] = here;
             if (objpt == GOBLET) values[BRKGOB] = here;
             if (objpt == MIRROR) values[BRKMIR] = here;
            }
          if (objpt == MIRROR)
            {
             tnoua("Oh dear! You have broken the mirror, be prepared for seven year's bad luck!!");
             values[LUCK] -= 50;
            }
          score -= 10;
          values[HELD]--;
          if (flags[HANDSFULL] == 1) flags[HANDSFULL] = 0;
          objloc[objpt] = -1000;
          showtext();
          return;
         }
      }
    values[HELD]--;
    if (flags[HANDSFULL] == 1) flags[HANDSFULL] = 0;
    objloc[objpt] = here;
    if (objpt == CHARM) values[LUCK] -= 100;  /* No longer has the good luck charm */
    if (flags[INTENT])
      {
       secure[objpt] = 1;
       objloc[objpt] = -1000;
      }
    if (objpt == BASKET)
      {
       dropit = 0;
       for (i=1;i<MAXOBJ;i++)
         {

          if (objloc != 0) continue;
          if (i == LAMP || i == SWORD || i == STAFF || i == CARPET) continue;
          if (i == BASKET) continue; /* Dropped this already */
          dropit++;
          values[HELD]--;
          if (flags[HANDSFULL] == 1) flags[HANDSFULL] = 0;
          objloc[i] = here;
          if (objpt == CHARM) values[LUCK] -= 100;  /* No longer has the good luck charm */
          if (flags[INTENT])
            {
             secure[i] = 1;
             objloc[i] = -1000;
            }
         }
       if (dropit > 0) tnoua(" and everything in it");
      }
    tnoua(". ");
    if (flags[SHAFT])
      {
       plural = 0;
       if (objpt == KEYS || objpt == COINS || objpt == JEWELS) plural++; 
       if (objpt == BANKNOTES || objpt == VIOLETS || objpt == BRICKBATS) plural++; 
       bottom = plumb();
       if (plural == 0)
         {
          tnoua("It falls ");
         }
       else
         {
          tnoua("They fall ");
         }
       tnoua("out of sight down the shaft.");
       for (i=1;i<MAXOBJ;i++)                           /* Locate dropped objects at bottom of shaft */
         {                                              /* or distribute them randomly if it is more */
          if (objloc[i] == here) objloc[i] = bottom;    /* than 20 levels deep                       */
         }
      }
    for (i=1;i<MAXOBJ;i++)
      {
       obhere[i] = 0;
       if (objloc[i] == here) obhere[i] = 1;
       if (flags[INTENT] && secure[i]) obhere[i] = 1;
      }    
    showtext();
   }
/*----------------------------------------------------------------------*/
void shangrila(void)             /* Visit Shangri La                    */
   {
    if (strncmp(action,"SHANGRI",7) != 0)
      {
       tnou("Pardon? ");
       showtext();
       return;
      }
    if (z != 1)
      {
       tnou("I'm sorry, we don't pick up passengers here. Please make your ");
       tnou("own way to the plain, where we may be able to collect you. ");
       showtext();
       return;
      }
    if (flags[SHANGRI] == 0)
      {
       tnoua("A ramshackle mud-spattered bus appears, apparently from nowhere. The driver calls out ");
       tnoua("\"Last bus to Shangri La!\" and you climb on board. After a hair-raising drive across ");
       tnoua("the plain lasting a couple of hours the bus deposits you not far from the foot of the mountains. ");
       tnoua("\"You'll find it about an hour's walk south of here.\" shouts the driver before driving off ");
       tnou("at breakneck speed and disappearing into the distance. ");
       showtext();
       x = 0; y = 2; z = 1;
       here = locate(x,y,z);
       flags[SHANGRI] = 1;
       values[DAYTIME] +=4;
       if (values[DAYTIME] > 48) newday();                   /* Start a new day */
      }
    else
      {
       tnoua("Haven't you been there already? I have no idea where to find it and the ");
       tnou("travel company has gone out of business! ");
      }
    showtext();
   }
/*----------------------------------------------------------------------*/
void throw(int objpt)                  /* Throw something               */
   {
    int i, dropit, plural;
    long bottom;
    if (strlen(object) == 0)
      {
       tnou("Throw what?");
       showtext();
       return;
      }
    if (objloc[objpt] != 0)
      {
       tnou("But you haven't got it!");
       showtext();
       return;
      }
    tnoua("You throw the ");
    tnoulca(thing[objpt]);
    if (objpt == BOTTLE || objpt == VASE || objpt == GOBLET || objpt == MIRROR)
      {
       tnoua(", it smashes into a thousand fragments. ");
       if (here == values[BASE])
         {
          tnoua("A native servant rushes up, sweeps up the pieces and dashes away again. ");
          values[RUNOUT] = moveno;
         }
       else
         {
          if (objpt == BOTTLE) values[BRKBOT] = here;
          if (objpt == VASE)   values[BRKVAS] = here;
          if (objpt == GOBLET) values[BRKGOB] = here;
          if (objpt == MIRROR) values[BRKMIR] = here;
         }
       if (objpt == MIRROR)
         {
          tnoua(" Oh dear! You have broken the mirror, be prepared for seven year's bad luck!!");
          values[LUCK] -= 50;
         }
       score -= 10;
       values[HELD]--;
       if (flags[HANDSFULL] == 1) flags[HANDSFULL] = 0;
       objloc[objpt] = -1000;
       showtext();
       return;
      }
    switch (objpt)
      {
       case SWORD  :
          if (flags[EXCALIBER] == 1)
            {
             if (z < 2)
               {
                tnoua(", as if guided by some unseen power it flies straight as an arrow towards a shimmering lake ");
                tnoua("which has suddenly appeared nearby. But before it hits the surface an arm clothed in white ");
                tnoua("samite, mystic, wonderful rises and catches it by the hilts, brandishes it three times and ");
                tnoua("disappears again below the surface. The lake shimmers briefly, becomes still and fades away. ");
                tnou("You no longer have a sword, let's hope you don't encounter a dragon! ");
                objloc[objpt] = -rnd(15);
                flags[EXCALIBER] = 0;
               }
             else
               {
                tnoua(", it strikes a rock point first and goes through it like a knife through ");
                tnou(" butter leaving only the hilt protruding from the surface. ");
                objloc[objpt] = here;
                flags[EXCALIBER]++;
               }
             showtext();
             values[HELD]--;
             if (flags[HANDSFULL] == 1) flags[HANDSFULL] = 0;
             return;
            }
       case DAGGER :
          tnou(", it hits the ground and disappears in a shower of sparks. ");
          showtext();
          values[HELD]--;
          if (flags[HANDSFULL] == 1) flags[HANDSFULL] = 0;
          objloc[objpt] = -rnd(15);
          return;
       case ROD    :
       case STAFF  :
          tnoua(", it sticks into the ground and immediately sprouts leaves and tiny, scented flowers. ");
          tnou("However, these rapidly shrivel away to nothing. ");
          showtext();
          objloc[objpt] = here;
          values[HELD]--;
          if (flags[HANDSFULL] == 1) flags[HANDSFULL] = 0;
          return;
       case ROPE   :
          if (z < 2 || !flags[GLOW])
            {
             tnou(", it lands on the ground nearby. ");   /* Above ground or mysterious glow */
             break;
            }
          else
            {
             tnoua(", it stands straight up, unsupported!! A fakir scrambles nimbly down, gathers it up and ");
             tnoua("disappears into the shadows. As he goes a small, brilliant object falls from his loincloth ");
             tnou("and rolls away out of sight. ");
             values[RUNOUT] = moveno;
             showtext();
             score += 50;
             objloc[DIAMOND] = -rnd(5);               /* The diamond now exists somewhere nearby */
             gone[DIAMOND] = 0;
             objloc[ROPE] = -2000;
             values[HELD]--;
             if (flags[HANDSFULL] == 1) flags[HANDSFULL] = 0;
             return;
            }
       case COINS  :
          if (values[DWFNUM] == 0)
            {
             tnou(", they land on the ground near you. ");              /* No dwarves to steal the coins */
             break;
            }
          else
            {
             tnoua(". A little dwarf scurries up, grabs the coins and disappears before you can catch him. ");
             values[RUNOUT] = moveno;
             showtext();
             score -= 5;
             values[HELD]--;
             if (flags[HANDSFULL] == 1) flags[HANDSFULL] = 0;
             objloc[COINS] = -rnd(15);
             return;
            }
       case BOOK   :
          if (monstr[TROLL] == 0)
            {
             tnou(", but there is no-one here to throw the book at - except, perhaps, you! ");
             showtext();
             objloc[BOOK] = here;
             values[HELD]--;
             if (flags[HANDSFULL] == 1) flags[HANDSFULL] = 0;
             return;
            }
          else
            {
             tnoua(" The troll catches it and retires to a corner to read it. Suddenly he chortles");
             tnoua(" \"At last I have found how to get rid of them pesky dwarves!\" He lumbers over, ");
             tnou("shakes you roughly by the hand and vanishes forever, taking the book with him. ");
             values[RUNOUT] = moveno;
             monstr[TROLL] = 0;
             score += 50;
             secure[BOOK] = 0; gone[BOOK] = 1; objloc[BOOK] = -2000;
             break;
            }
       default     :
          objloc[objpt] = here;
          break;
      }
    showtext();
    values[HELD]--;
    if (flags[HANDSFULL] == 1) flags[HANDSFULL] = 0;
   }
/*----------------------------------------------------------------------*/
void inventory(void)              /* List the objects currently carried */
   {
    int i, j, penult;
    int count = 0;
    int notinbasket[5] = { 0,LAMP,SWORD,STAFF,CARPET }; /* These don't go into the basket */

    if (values[HELD] == 0)
      {
       tnoua("You are holding nothing");
      }
    else
      {
       penult = values[HELD] - 1;
       tnoua("You are carrying ");
       /* He has the basket, list in the order lamp, staff, sword, carpet, basket, then the remainder in order */
       if (objloc[BASKET] == 0)         
         {
          for (i=1;i<5;i++)
            {
             if (objloc[notinbasket[i]] == 0)
               {
                tnoua(thingpref[i]);
                tnoulca(thing[i]);
                count++;
                if (count == values[HELD]) break;
                if (count < penult) tnoua(", ");
               }
            }
          if (count > 0) tnoua(" and ");
          tnoua("a small wicker basket");
          count++;
          if (count < values[HELD]) tnoua(" containing ");
          for (i=1;i<MAXOBJ;i++)
            {
             if (objloc[i] == 0)
               {
                if (i == LAMP || i == SWORD || i == STAFF || i == CARPET || i == BASKET) continue;
                count++;
                tnoua(thingpref[i]);
                tnoulca(thing[i]);
                if (count == penult) tnoua(" and ");
                if (count < penult) tnoua(", ");
               } 
            }
         }
       else /* No basket, list the objects in their normal order */
         {
          for (i=1;i<MAXOBJ;i++)
            {
             if (objloc[i] == 0)
               {
                count++;
                tnoua(thingpref[i]);
                tnoulca(thing[i]);
                if (count == penult) tnoua(" and ");
                if (count < penult) tnoua(", ");
               } 
            }
         }
      }
    if (flags[RINGON]) tnoua(". You are wearing a golden ring on your finger");
    tnou(". ");
    showtext();
   }
/*----------------------------------------------------------------------*/
void kill(int objpoint)          /* Kill something                      */
   {
    if (monstr[objpoint] < 1)
      {
       tnoua("What ");
       tnoulca(beasts[objpoint]);
       tnou("? ");
       showtext();
       return;
      }
    if (objloc[STAFF] == 0)
      {
       tnou("You flail about you with the staff but hit nothing. ");
       showtext();
       return;
      }
    switch (objpoint)
      {
       case 0 :
          tnou("Kill what? ");
          break;
       case VAMPIRE :
          tnou("You have nothing that could possibly hurt it! ");
          break;
       case DRAGON :
          if (objloc[SWORD] == 0)
            {
             if (flags[EXCALIBER] == 1)
               {
                tnoua("As the dragon rears up you plunge your sword into its breast. It disappears up to the ");
                tnoua("hilt and there is a tremendous explosion which knocks you senseless. When you recover the ");
                tnou("dragon and sword are nowhere to be seen. Wisps of smoke drift about but gradually disperse. ");
                score += 50;
                monstr[DRAGON] = 0;
                values[HELD]--;
                if (flags[HANDSFULL] == 1) flags[HANDSFULL] = 0;
                objloc[SWORD] = -30;   /* Create another, lesser sword for him to find */
                secure[SWORD] = 0;
                flags[EXCALIBER]++;
               }
             else
               {
                tnoua("You strike at the dragon with your sword but it parries your blow with its iron claws. ");
               }
            }
          else
            {
             tnou("You lash out but it easily avoids your blow. ");
            }
          break;
       case TROLL :
          if (objloc[DAGGER] == 0)
            {
             tnoua("You stab the troll with the dagger, shattering the blade on its rock hard hide. ");
             tnou("The troll snatches the haft from you and grinds it to dust.");
             values[HELD]--;
             if (flags[HANDSFULL] == 1) flags[HANDSFULL] = 0;
             objloc[DAGGER] = -2000;
             secure[DAGGER] = 0;
             gone[DAGGER] = 1;
             break;
            }
          if (objloc[SWORD] == 0)
            {
             tnoua("You strike the troll with the sword but the blade bounces back from its stony hide, ");
             tnou("severely jarring your arm. The troll does not even appear to have noticed the blow. ");
            }
          break;
      }
    showtext();
   }
/*----------------------------------------------------------------------*/
void look(void)                  /* Look about you                      */
   {
    describe(1);                   /* Describe where we are             */
    showthings();                  /* Describe any objects found here   */
    monsters();                    /* Display active monsters           */
   }
/*----------------------------------------------------------------------*/
void lucky(void)                 /* Luck messages                       */
   {
    if (values[LUCK] >=30) return;
    else if (values[LUCK] >= 20) tnou(" It must be your lucky day. ");
    else if (values[LUCK] >= 10) tnou(" You are pushing your luck. ");
    else if (values[LUCK] >= 5) tnou(" Your luck won't hold out for ever. ");
    else tnou(" You are almost out of luck! ");
    showtext();
   }
/*----------------------------------------------------------------------*/
void onlamp(void)                /* Light the lamp [also put ring on]   */
   {
    if (objloc[LAMP]== 0)
      {
       if (values[FLICK] > 3)
         {
          tnou("You cannot light it any more!");
          showtext();
          return;
         }
       if (flags[LAMPON])
         {
          tnou("It is already on!");
         }
       else
         {
          tnou("Your lamp is now lit.");
          flags[LAMPON] = 1;
          flags[DARK] = 0;
         }
      }
    else
      {
       if (objloc[GOLDRING] == 0)
         {
          tnou("You put the ring on your finger. ");
          flags[RINGON] = 1;
          values[HELD]--;
          if (flags[HANDSFULL] == 1) flags[HANDSFULL] = 0;
          objloc[GOLDRING] = -1000;
         }
       else
         {
          tnou("You haven't got it!");
         }
      }
    showtext();
   }
/*----------------------------------------------------------------------*/
void offlamp(void)            /* Extinguish the lamp [or take off ring] */
   {
    if (objloc[LAMP] == 0)
      {
       if (flags[LAMPON])
         {
          tnou("Your lamp is now off.");
          flags[LAMPON] = 0;
         }
       else
         {
          tnou("The lamp is already off!");
         }
      }
    else
      {
       if (flags[RINGON])
         {
          if (flags[HANDSFULL])
            {
             tnou("You can't, your hands are full! ");
            }
          else
            {
             tnou("You take the ring off your finger. ");
             flags[RINGON] = 0;
             values[HELD]++;
             objloc[GOLDRING] = 0;
            }
         }
       else
         {
          tnou("You haven't got it!");
         }
      }
    showtext();
   }

/*----------------------------------------------------------------------*/
void openit(int objpoint)        /* Open something                      */
   {

    if (objpoint == 0)
      {
       tnou("Open what? ");
       showtext();
       return;
      }
    if (objloc[objpoint] != 0)
      {
       tnou("But you haven't got it! ");
      }
    else
      {
       switch (objpoint)
         {
          case BOOK   :
             readit(objpoint);
             return;
          case BOX    :
             if (flags[BOXLOK])
               {
                tnou("The box is locked and you have nothing to open it with! ");
               }
             else
               {
                tnou("You open the box, inside the lid is a label addressed : ");
                tnou("\t\"Pandora, c/o Zeus, Mount Olympus\"");
                tnoua("There is a little Hope still left in the bottom but ");
                tnoua("fortunately for you the box is otherwise empty! ");
                tnou("You take some Hope and quickly close it again. ");
               }
             break;
          case OYSTER :
          case CLAM   :
             eat(objpoint);
             return;
          default     :
             tnou("Don't be silly, I can't do that! ");
             break;
         }
      }
    showtext();
   }
/*----------------------------------------------------------------------*/
void quit(int act)                  /* Quit Chimaera                       */
   {
    int ipt, scoral;

    if (act == 1)
      {
       tonl(1);
       tnoua("Do you really want to quit now? ");
       showtext();
       if (yesno() == 0) return;
       tonl(1);
       tnoua("Very well. ");
      }
    while(1)
      {
       if (flags[UNDEAD])
         {
          tnou("Sorry, vampires don't score! ");
          break;
         }
       if (flags[WIZARD])
         {
          tnou("Wizards minds are on higher things and they don't bother to count the score!");
          break;
         }
       scoral = scorit();
       tnoua("You scored ");
       tnoint(scoral);
       tnoua(" points in ");
       tnoint(moveno);
       tnoua(" moves. ");
       if (scoral < 100)
         {
          tnoua("You are obviously a rank amateur");
          if (scoral < 0)
            {
             tnoua(" and a bankrupt to boot. If you don't settle your debts ");
             tnoua("promptly we will be obliged to send the boys round");
            }
          tnou("! ");
         }      
       else
         {
          ipt = scoral / 100;
          if (ipt > 10) ipt = 10;
          tnoua("Your score qualifies you as ");
          tnoulca(classes[ipt]);
          tnoua(" adventurer.");
          if (ipt == 10) tnou(" Congratulations!! ");
         }
       break;
      }      
    tonl(1);
    showtext();
    fclose(log_file);
    exit(0);
   }
/*----------------------------------------------------------------------*/
void readit(int objpoint)        /* Read book, manuscript, music, etc.  */
   {
    if (objpoint == 0)
      {
       tnou("Read what?");
      }
    else
      {
       if (objloc[objpoint] != 0)
         {
          tnou("But you haven't got it!");
         }
       else
         {
          switch (objpoint)
            {
             case MANUSCRIPT :
                tnoua("It is written in old English, apparently by some monk named ");
                tnoua("Bede, but you can't make much of it. You leaf through it and ");
                tnoua("find that someone has written a glowing description of ");
                tnou("the Indian rope trick on a blank page. ");
                break;
             case BOOK       :
                tnoua("Unfortunately the book is written in the Gamic script used by ");
                tnoua("the trolls and you can't understand a word of it. Someone ");
                tnou("has scrawled \"Stamp 'em out!\" across the flyleaf. ");
                break;
             case MUSIC      :
                tnoua("How clever of you to be able to read music! Perhaps ");
                tnou("you should try playing some too? ");
                break;
            }
         }
      }
    showtext();
   }
/*----------------------------------------------------------------------*/
void rub(int objpoint)           /* Rub the lamp                        */
   {
    if (objpoint == 0)
      {
       tnou("What do you want to rub?");
      }
    else
      {
       if (objloc[objpoint] != 0)
         {
          tnou("But you don't have it!");
         }
       else
         {
          switch (objpoint)
            {
             case LAMP :
                if (flags[GENIE])
                  {
                   tnou("Nothing happens.");
                  }
                else
                  {
                   tnoua("You rub the lamp until it gleams. Suddenly a genie appears. ");
                   tnoua("\"Free at last!\", he cries, \"you shall be rewarded with ");
                   tnoua("everlasting light.\" There is a flash and he disappears in a ");
                   tnoua("cloud of acrid smoke which tarnishes the gleaming surface of ");
                   tnou("the now brightly burning lamp.");
                   score += 10;
                   flags[GENIE] = 1; flags[LAMPON] = 1;
                   values[LIGHT] = 1000000; values[FLICK] = 0;
                  }
                break;
             default   :
                tnou("Nothing happens.");
                break;
            }
         }
      }
    showtext();
   }

/*----------------------------------------------------------------------*/
void stamp(int objpoint)         /* Stamp out a dwarf                   */
   {
    if (strcmp(object,"FOOT") == 0)
      {
       tnou("You accidentally stamp on your own foot. This makes you hopping mad. ");
       showtext();
       return;
      }
    if (objpoint == 0)
      {
       tnou("Stamp what? ");
       showtext();
       return;
      }
    if (values[DWFNOW] < 1 || objpoint != DWARF)
      {
       tnou("You stamp on the ground, but nothing happens. ");
       showtext();
       return;
      }
    switch(rnd(3))
      {
       case 1       :
          tnoua("You try to stamp on ");
          if (values[DWFNOW] == 1) tnoua("the "); else tnoua("a ");
          tnou("little dwarf but he dodges out of the way in time. ");
          break;
       default :
          tnoua("You stamp on ");
          if (values[DWFNOW] == 0)
            {
             tnou("the ground but the little dwarf has gone. ");
             break;
            }
          if (values[DWFNOW] == 1) tnoua("the "); else tnoua("a ");
          tnoua("little dwarf and squash him flat. ");
          score += 10;
          values[DWFNOW]--; values[DWFNUM]--;
          if (values[DWFNOW] == 0) monstr[DWARF] = -monstr[DWARF];
          if (values[DWFNUM] == 0) monstr[DWARF]= 0;
          break;
      }
    showtext();        
   }
/*----------------------------------------------------------------------*/
void timdat(int n)                                  /* Display the time */
   {
    int noon, hour;
    tnoua("It is ");
    tnoua(times[values[DAYTIME]]);
    tnoua(" on ");
    tnoua(weekdays[values[WEEKDAY]]);
    tnoua(" ");
    tnoint(values[DAY]);
    switch (values[DAY])
      {
       case 1  :
       case 21 :
       case 31 : tnoua("st"); break;
       case 2  :
       case 22 : tnoua("nd"); break;
       case 3  :
       case 23 : tnoua("rd"); break;
       default : tnoua("th"); break;
      }
    tnoua(" ");
    tnoua(months[values[MONTH]]);
    tnoua(".");
    if (values[DAYTIME] == 25 && n < 2)
      {
       tnou(" Mad dogs and Englishmen go out in the midday sun!");
      }
    showtext();
   }
/*----------------------------------------------------------------------*/
void magic(void)                 /* The magic word was spoken           */
   {
    if (strncmp(action,dicact[35],5) != 0) /* Abbreviation is not allowed */
      {
       tnou("Pardon?");
       showtext();
       return;
      }
    if (values[MAGONE] > 7)                /* All used up */
      {
       tnou("Nothing happens!");
       showtext();
       return;
      }
    values[MAGONE]++;
    if (values[BASE] == here)
      {
       x = values[LASTX]; y = values[LASTY]; z = values[LASTZ]; /* Go to where you were last */
       here = locate(x,y,z);
      }
    else
      {
       values[LASTX] = x; values[LASTY] = y; values[LASTZ] = z; /* Remember where we are */
       x = values[FIRSTX]; y = values[FIRSTY]; z = 1;           /* and go to base camp   */
       here = locate(x,y,z);
      }
    describe(1);
   }
/*----------------------------------------------------------------------*/
void scores(void)                /* Display the current score           */
   {
    int scoral;

    scoral = scorit();
    tnoua("Your current score is ");
    tnoint(scoral);
    tnoua(" in ");
    tnoint(moveno);
    tnoua(" move");
    if (moveno > 1) tnoua("s");
    tnou(". ");
    showtext();
   }

/*----------------------------------------------------------------------*/
int scorit(void)                /* Return the score as a string        */
   {
    int i, scoral;

    scoral = score;
    for (i=1;i<MAXOBJ;i++)
      {
       if (secure[i]) scoral += points[i];
      }
    return(scoral);
   }
/*----------------------------------------------------------------------*/
void slumber(void)               /* Go to sleep                         */
   {
    int i;

    if (flags[HOME] && !flags[INTENT])
      {
       tnoua("You go into the tent. ");
       flags[INTENT] = 1;
       for (i=1;i<15;i++) ways[i] = 0;
       ways[OUT] = 1;
      }
   if (flags[INTENT])
      {
       tnoua("Yawning wearily, you lie down on the bed and fall into a deep, refreshing ");
       tnou("sleep. When you awake it is daybreak.");
       showtext();
       newday();                             /* Increment the date */
       values[DAYTIME] = values[DAWN];       /* and set the time   */
       flags[NIGHT] = 0; flags[DARK] = 0;
       return;
      }
   switch(z)
      {
       case 0 :                       /* Up a tree    */
             tnoua("Wedging yourself against the base of a large, forked branch you fall ");
             tnoua("into an uneasy sleep. ");
          if (rnd(4) == 1)
            {
             tnoua("During the night a leopard climbs up the tree and gets you! ");
             showtext();
             dead();
             return;
            }
          else
            {
             tnou("Fortunately a leopard doesn't visit your tree during the night. The birds arose you at dawn.");
             flags[NIGHT] = 0; flags[DARK] = 0;
             newday();                        /* Increment the date */
             values[DAYTIME] = values[DAWN];  /* and set the time   */
            }
          break;
       case 1 :                       /* On the plain */
          tnoua("You burrow into some long grass nearby and fall asleep, hoping that ");
          tnoua("none of the large cats find you. Whilst you slumber a deadly scorpion ");
          tnoua("crawls down the neck of your shirt. Feeling something scratching you ");
          tnoua("suddenly start up and the scorpion stings you before you can remove ");
          tnou("it. You have no antidote to the poison and rapidly succumb.");
          showtext();
          dead();
          return;
       default :                      /* Underground  */
          if (flags[SHAFT])
            {
             tnou("You are certain to 'drop off' if you fall asleep here, try somewhere else. ");
            }
          else
            {
             tnoua("You prop yourself against a wall and fall into a deep sleep. The elves carry you back to ");
             tnoua("ground level. They then steal all your belongings and run off. Fortunately they soon get ");
             tnou("bored and throw them away. If you hunt about you might find some of them. ");
             flags[NIGHT] = 0; flags[DARK] = 0;
             newday();                        /* Increment the date */
             values[DAYTIME] = values[DAWN];  /* and set the time */
             values[HELD] = 0;
             flags[LAMPON] = 0;
             for (i=1;i>MAXOBJ;i++)
               {
                if (objloc[i] == 0) objloc[i] = -rnd(10); /* Scatter his belongings about but not too far */
               }
             x = values[FIRSTX]; y = values[ FIRSTY]; z = 1;
             here = locate(x,y,z);
             flags[HOME] = 1;
             for (i=1;i<11;i++) ways[i] = 1;
             ways[UP] = ways[DOWN] = 0;
            }
         break;
      }
    showtext();
   }
/*----------------------------------------------------------------------*/
void status(void)                /* Establish a player's status         */
   {
    int len, yn;
    char password[9];


    if (flags[WIZARD]) return;   /* We already know that he is a wizard */
    tonl(1);
    tnoua("Are you in fact a genuine wizard? ");
    showtext();
    yn = yesno();
    if (yn != 1) return;         /* He doesn't claim to be              */
    tonl(1);
    tnoua("Prove it - say the magic word : ");
    showtext();
    len = get_password();
    if (len == 0)
      {
       tonl(1);
       tnou("Chicken!");
       showtext();
       return;
      }
    memset(&password[0],'\0',9);    /* Construct the password */
    sprintf(password,"%.2s%.2s%.2s%02d",times[values[DAYTIME]],months[values[MONTH]],weekdays[values[WEEKDAY]],values[DAY]);
    if (strncmp(password,userpass,8) == 0)
      {
       tnou("I am yours to command Oh Master! ");
       flags[WIZARD] = 1;
       memset(&password[0],'\0',9);  /* Destroy the password */
       memset(&dicact[22],'\0',6);
       memset(&dicact[22],'.',1);
       tonl(1);
       tnoua("The 'WIZARD' command has been replaced by '.', which allows you to examine various parameters, ");
       tnoua("set your location co-ordinates, obtain objects at will and summon monsters. Typing '.' ");
       tnoua("actives the '[LFPVSOM]> ' prompt, following which typing any of the letters L, F, P, etc. ");
       tnoua("displays information or allows you to set or summon things. ");
       tonl(1);
       tnou("Briefly the wizard commands are: ");
       tnou("L[ocation]:  x,y,z co-ordinates, legal move directions and last action and object typed. ");
       tnou("F[lag] status: Home, In tent, Dark, Night, Lamp on ");
       tnou("P[lain] status flags: Rolling, High Grass, Animals, Animal Herd, Carnivores, Seen by carnivores. ");
       tnoua("V[alues]: Daytime, Dawn, Dusk, Luck, Objects held, Dwarf popluation, No. of dwarves active, ");
       tnoua("Activation status of bats, dwarves, snake, gorgon, elf, troll, dragon and vampire ");
       tnou("[active=>0, inactive=<0, dead=0]. ");
       tnou("S[et]: Set x,y,z co-ordinates. ");
       tnou("O[bject]: Fetch objects. ");
       tnou("M[onster]: Activate monsters. ");
       tonl(1);
       tnou("n.b. Wizards, having special powers, can cheat and thus do not get a final score. ");
      }
    else
      {
       tnou("Foo, you are just an imposter! That little piece of deception will cost you 10 points. ");
       score -= 10;
      }
    showtext();
   }
/*----
      SUBROUTINE STATUS(FLAG,SCORE)
C*
      LOGICAL   FLAG              /* Master status flag
      INTEGER*2 SCORE             /* His score so far
C*
      INTEGER*2 MTRX(8)           /* Data for password construction
      INTEGER*2 TMDATA(4)         /* Buffer for TIMDAT
      INTEGER*2 PWRD(3)           /* Buffer for user-supplied password
C*
      DATA MTRX/'ACODUSENHRRDAUUD'/
C*
      IF (FLAG) RETURN            /* We already know that he is a master
      CALL TNOUA('Are you in fact a Perfect Master? ',34)
      CALL YESNO(FLAG)            /* Does he claim to be one?
      IF (.NOT.FLAG) RETURN
      CALL PASSWD('Prove it! Say the magic word',28,PWRD,6)
      IF (PWRD(3).NE.'  ') GOTO 20     /* Ha!
      CALL TIMDAT(TMDATA,4)       /* Get current date
      TMDATA(4)='  '                   /*
      N=NUFRD(TMDATA)                  /* These 3 lines calculate day of week (+
      N=NINDW(N,TMDATA(3))+1           /*
      TMDATA(1)=LT(TMDATA(2),8)+RS(MTRX(N),8)    /* Construct today's
      TMDATA(2)=LS(TMDATA(2),8)+RT(MTRX(N),8)    /*   password
      IF (TMDATA(1).NE.PWRD(1)) GOTO 20
      IF (TMDATA(2).NE.PWRD(2)) GOTO 20
      GOTO 30                     /* He is. (Flag already true)
C*
20    FLAG=.FALSE.                /* Trying to cheat eh?
      CALL TNOU('Foo, you are just an imposter!',30)
      CALL TNOU('That little piece of deception will cost you 10 points.
     +..',57)
      SCORE=SCORE-10
C*
30    TMDATA(1)=0
      TMDATA(2)=0
      TMDATA(3)=0

----*/
/*----------------------------------------------------------------------*/
void adventure(void)             /* Simulate the beginning of ADVENTURE */
   {
    int i, first = 1,len, forever = 1, match;
    char command[21];

    if (strncmp(action,"ADVE",4) != 0)
      {
       tnou("Pardon?");
       showtext();
       return;
      }

    while (forever == 1)
      {
       if (first == 1)
         {
          tonl(1);
          tnoua("You are standing at the end of a road before a small brick building.");
          tnoua("Around you is a forest. A small stream flows out of the building and");
          tnou("down a gully and a wide path leads northwest.");
          tonl(1);
          showtext();
          first = 0;
         }
       tnoua("? ");
       showtext();
       memset(&command,'\0',21); match = 0;
       len = strlen(fgets(command,21,stdin));
       if (len == 0) continue;
       for (i=0;i<len;i++) memset(&command[i],toupper(command[i]),1);
       memset(&command[len - 1],'\0',1);
       if (strcmp(command,"IN") == 0) match = 1;
       if (strcmp(command,"ENTER") == 0) match = 1;
       if (strcmp(command,"PLUGH") == 0) match = 2;
       switch (match)
         {
          case 1 : tonl(1);
             tnoua("You are inside the building, a well house for a large spring ");
             tonl(1);
             tnou("There are some keys on the ground here. ");
             tnou("There is a shiny brass lamp nearby. ");
             tonl(1);
             showtext();
             break;
          case 2 :
            adv_plugh();
            first = 1;
            continue;

          default:
             tonl(1);
             tnoua("A large cloud of green smoke appears in front of you. It clears away ");
             tnoua("to reveal a tall wizard, clothed in grey. He fixes you with a steely ");
             tnoua("glare and declares, \"This adventure has lasted too long.\" With that he ");
             tnoua("makes a single pass over you with his hands, and everything around you ");
             tnou("fades away into a grey nothingness. ");
             showtext();
             sleep(5);
             tonl(1);
             tnoua("You awake as from a bad dream to find yourself in your tent. The sun is rising outside. ");
             tnoua("Everything you were carrying has vanished, perhaps you left it behind when you started ");
             tnou("your adventure. ");
             showtext();
             for (i=1;i<MAXOBJ;i++)
               {
                if (objloc[i] == 0) objloc[i] = here; /* Drop everything here */
               }
             if (objloc[LAMP] == here) objloc[LAMP] = values[BASE]; /* If he has the lamp put it outside the tent */
             flags[HOME] = 1; flags[INTENT] = 1; flags[DARK] = 0;
             x = values[FIRSTX]; y = values[FIRSTY]; z = 1;
             here = locate(x,y,z);
             newday();                                /* Start a new day   */
             values[DAYTIME] = values[DAWN];          /* and set the time  */
             values[LIGHT] = 100; values[HELD] = 0;
             return;
         }
       continue;
      }
   }
/*----------------------------------------------------------------------*/
void adv_plugh(void)             /* Simulate PLUGH command in ADVENTURE */
   {
    int i, len, match, kount = 0, forever = 1 ;
    char command[21];

    tonl(1);
    tnoua("There is a brilliant flash of light and a sudden fanfare of trumpets! ");
    tnou("When your eyes recover from the flash, you find that:");
    tnoua("You are in a large room, with a passage to the south, a passage to the ");
    tnoua("west, and a wall of broken rock to the east. There is a large \"Y2\" on ");
    tnoua("a rock in the room's centre.");
    tonl(1);
    showtext();

    while (forever)
      {
       tnoua("? ");
       showtext();
       memset(&command,'\0',21); kount++;
       len = strlen(fgets(command,21,stdin));
       if (len == 0) continue;
       for (i=0;i<len;i++) memset(&command[i],toupper(command[i]),1);
       memset(&command[len - 1],'\0',1);
       if (strcmp(command,"Y2") == 0) { tonl(1); tnou("That's where you are now!"); showtext(); continue; }
       if (strcmp(command,"PLUGH") == 0) { tonl(1); tnou("OK!"); showtext(); return; }
       if (kount > 20) /* Obviously in trouble, drop a hint */
         {
          tonl(1);;
          tnoua("You seem to be stuck here, but keep plugging away at ");
          tnou("it and you will eventually work out how to escape. ");
          showtext();
          kount -= 5;
          continue;
         }
       switch (rnd(8))
         {
          case 3 : tnou("Sorry, I don't understand that here. "); break;
          case 5 : tnou("I'm afraid that I am temporarily suffering from partial amnesia. "); break;
          case 7 : tnou("If at first you don''t succeed, try, try, try again! "); break;
         }
       showtext();
      }
   }
/*----------------------------------------------------------------------*/
void lookwhere(char *text)       /* Direction and distance of base camp */
   {
    if (here == values[BASE])
      {
       tonl(1);
       if (flags[INTENT])
         {
          tnou("You are in the tent at your base camp.");
         } else tnou("At your base camp.");
       showtext();
       return;
      }
    calcdist();
    if (z > 1)
      {
       tnou("You are in a complex system of underground chambers, passages and shafts.");
       showtext();
       return;
      }
    tnoua("You are ");
    if (distance == 1) tnoua("quite close to ");
    if (distance == 2) tnoua("some distance from ");
    if (distance == 3) tnoua("several miles away from ");
    if (distance > 3) tnoua("many miles away from ");
    tnoua(text);
    tnoua(", which ");

    if (flagxy == 0)
      {
       tnoua("lies due ");
       if (ydist > 0) tnoua("south");
       if (ydist < 0) tnoua("north");
       if (xdist > 0) tnoua("west");
       if (xdist < 0) tnoua("east");
      }
    else
      {
       tnoua("lies to the ");
       if (ydist > 0) tnoua("south");
       if (ydist < 0) tnoua("north");
       if (abs(xdist) != abs(ydist))tnoua(" and ");
       if (xdist > 0) tnoua("west");
       if (xdist < 0) tnoua("east");
      }
    tnou(". ");
    showtext();
   }
/*----------------------------------------------------------------------*/
void calcdist(void)              /* Calculate distance from base camp   */
   {
    xdist = x - values[FIRSTX]; ydist = y - values[FIRSTY];
    flagxy = abs(xdist * ydist);  /* If this is 0 then one of them is zero */
    distance = (int)sqrt(xdist * xdist + ydist * ydist);
   }
/*----------------------------------------------------------------------*/
void unknown (void)              /* Response to an unrecognised command */
   {
    switch (pseudorand)
      {
       case 1 : tnou("What?"); break;
       case 3 : tnou("Sorry, I don't understand."); break;
       default: tnou("Pardon?"); break;
      }
    showtext();
   }
/*----------------------------------------------------------------------*/
void unlock(int objpoint)        /* Unlock something                    */
   {
    if (objpoint == 0)
      {
       tnou("Pardon? ");
       showtext();
       return;
      }
    if (objloc[KEYS] != 0)
      {
       tnou("You haven't any keys! ");
      }
    else
      {
       switch (objpoint)
         {
          case BOX    :
             if (objloc[BOX] != 0)
               {
                tnou("You haven't got the box! ");
                break;
               }
             if (flags[BOXLOK])
               {
                tnou("The box is now unlocked. ");
                flags[BOXLOK] = 0;
               }
             else
               {
                tnou("Why bother, it isn't locked. ");
               }
             break;
          default :
             tnou("You can't unlock that! ");
             break;
         }
      }
    showtext();
   }
/*----------------------------------------------------------------------*/
void wave(int objpoint)          /* Wave the rod and other things       */
   {
    if (objpoint == 0)
      {
       tnou("What do you want to wave?");
      }
    else
      {
       if (objloc[objpoint] != 0)
         {
          tnou("But you haven't got it!");
         }
       else
         {
          switch (objpoint)
            {
             case ROD :
                if (!flags[GLOW] && flags[WAVER])
                  {
                   tnou("Nothing happens!");
                  }
                else
                  {
                   tnoua("A tall elderly wizard dressed in shimmering white ");
                   tnoua("robes appears, takes the rod and thanks you politely ");
                   tnoua("for finding his missing magic wand. ");
                   tnoua("\"Gandalf's magic anagram is convenient\", he says, ");
                   tnoua("\"but you can only use it seven times.\" ");
                   tnou("He vanishes as suddenly as he came. ");
                   values[RUNOUT] = moveno;
                   objloc[ROD] = -2000;
                   gone[ROD] = 1;
                   score += 50;
                   values[HELD]--;
                   if (flags[HANDSFULL] == 1) flags[HANDSFULL] = 0;
                  }
                break;
             default  :
                tnou("Nothing happens!");
                break;
            }
         }
      }
    showtext();
   }
/*----------------------------------------------------------------------*/
void savegame(void)              /* Save a game                         */
   {
    FILE *savefile;
    int i, remainder;
    long sum = 0;
    char filename[81];
    tnoua("Enter the filename: ");
    showtext();
    fgets(filename,80,stdin);
    memset(&filename[strlen(filename) - 1],'\0',1); /* Strip newline char */
    showtext();
    if ((savefile = fopen(filename,"w")) == NULL)
      {
       tnou("Unable to open the output file!");
       showtext();
       return;
      }
    fprintf(savefile,"%s",version);
    values[1] = moveno;
    values[2] = score;
    values[3] = x;
    values[4] = y;
    values[5] = z;
    fprintf(savefile,"\nA: ");
    for (i=1;i<MAXVAL;i++) { fprintf(savefile,"%d ",values[i]); sum += abs(values[i]); }
    fprintf(savefile,"\nB: ");
    for (i=1;i<MAXFLAG;i++) { fprintf(savefile,"%d ",flags[i]); sum += abs(flags[i]); }
    fprintf(savefile,"\nC: ");
    for (i=1;i<MAXOBJ;i++) { fprintf(savefile,"%d ",objloc[i]); sum += abs(objloc[i]); }
    fprintf(savefile,"\nD: ");
    for (i=1;i<MAXOBJ;i++) { fprintf(savefile,"%d ",secure[i]); sum += abs(secure[i]); }
    fprintf(savefile,"\nE: ");
    for (i=1;i<MAXMON;i++) { fprintf(savefile,"%d ",monstr[i]); sum += abs(monstr[i]); }
    fprintf(savefile,"\nF: ");
    remainder = sum % 123;
    fprintf(savefile,"%d ",remainder);
    for (i=1;i<9;i++) fprintf(savefile,"%d ",rnd(123) + remainder);
    fclose(savefile);
    tnoua("Game saved in file ");
    tnou(filename);
    showtext();
   }

/*----------------------------------------------------------------------*/
void restore(void)               /* Restore a game                      */
   {
    FILE *savefile;
    int i, n, r, checksum1, checksum2;
    long sum = 0;
    char filename[81];
    char linebuff[401];
    char token[MAXREST][16];
    const char sep[] = " *!";
    char * pt;
    char *find;
    long rvalues[MAXVAL];
    int rflags[MAXFLAG];
    int robjloc[MAXOBJ];
    int rsecure[MAXOBJ];
    int rmonstr[MAXMON];
    tnoua("Enter the filename: ");
    showtext();
    fgets(filename,80,stdin);
    memset(&filename[strlen(filename) - 1],'\0',1); /* Strip newline char */
    showtext();
    if ((savefile = fopen(filename,"r")) == NULL)
      {
       tnou("Unable to open the restore file!");
       showtext();
       return;
      }
    printf("Restoring...\n");
    memset(&linebuff[0],'\0',401);
    fgets(linebuff,400,savefile);
    find = strchr(linebuff,'\n');   /* Strip the \n from */
    if (find) *find = '\0';         /* the input line    */
    if (strncmp(linebuff,version,12) != 0)
      {
       tnou("Sorry, the game was saved from a different version of Chimaera and cannot be restored.");
       showtext();
       fclose(savefile);
       return;
      }
    /*---- Read the lines into the temporary arrays while the file is checked ----*/
    /* Read values[] - line begins with A: */
    fgets(linebuff,400,savefile);
    i = 0; memset(&token,'\0',MAXREST * 16);
    pt = strtok(linebuff,sep);       /* Get first token */
    while (pt)                       /* Loop until no more tokens */
      {
       strcat(token[i],pt);          /* Store current token */
       i++;
       pt = strtok(NULL,sep);        /* Get next token */
      }
    if (strncmp(linebuff,"A:",2) != 0)
      {
       tnou("Error 1 in file, cannot restore! ");
       showtext();
       fclose(savefile);
       return;
      }
    for (i=1;i<MAXVAL;i++) { rvalues[i] = atoi(token[i]); sum += abs(rvalues[i]); }

    /* Read flags[]  - line begins with B: */
    fgets(linebuff,400,savefile);
    i = 0; memset(&token,'\0',MAXREST * 16);
    pt = strtok(linebuff,sep);       /* Get first token */
    while (pt)                       /* Loop until no more tokens */
      {
       strcat(token[i],pt);          /* Store current token */
       i++;
       pt = strtok(NULL,sep);        /* Get next token */
      }
    if (strncmp(linebuff,"B:",2) != 0)
      {
       tnou("Error 2 in file, cannot restore! ");
       showtext();
       fclose(savefile);
       return;
      }
    for (i=1;i<MAXFLAG;i++) { rflags[i] = atoi(token[i]); sum += abs(rflags[i]); }

    /* Read objloc[] - line begins with C: */
    fgets(linebuff,400,savefile);
    i = 0; memset(&token,'\0',MAXREST * 16);
    pt = strtok(linebuff,sep);       /* Get first token */
    while (pt)                       /* Loop until no more tokens */
      {
       strcat(token[i],pt);          /* Store current token */
       i++;
       pt = strtok(NULL,sep);        /* Get next token */
      }
    if (strncmp(linebuff,"C:",2) != 0)
      {
       tnou("Error 3 in file, cannot restore! ");
       showtext();
       fclose(savefile);
       return;
      }
    for (i=1;i<MAXOBJ;i++) { robjloc[i] = atoi(token[i]); sum += abs(robjloc[i]); }

    /* Read secure[] - line begins with D: */
    fgets(linebuff,400,savefile);
    i = 0; memset(&token,'\0',MAXREST * 16);
    pt = strtok(linebuff,sep);       /* Get first token */
    while (pt)                       /* Loop until no more tokens */
      {
       strcat(token[i],pt);          /* Store current token */
       i++;
       pt = strtok(NULL,sep);        /* Get next token */
      }
    if (strncmp(linebuff,"D:",2) != 0)
      {
       tnou("Error 4 in file, cannot restore! ");
       showtext();
       fclose(savefile);
       return;
      }
    for (i=1;i<MAXOBJ;i++) { rsecure[i] = atoi(token[i]); sum += abs(rsecure[i]); }

    /* Read monstr[] - line begins with E: */
    fgets(linebuff,400,savefile);
    i = 0; memset(&token,'\0',MAXREST * 16);
    pt = strtok(linebuff,sep);       /* Get first token */
    while (pt)                       /* Loop until no more tokens */
      {
       strcat(token[i],pt);          /* Store current token */
       i++;
       pt = strtok(NULL,sep);        /* Get next token */
      }
    if (strncmp(linebuff,"E:",2) != 0)
      {
       tnou("Error 5 in file, cannot restore! ");
       showtext();
       fclose(savefile);
       return;
      }
    for (i=1;i<MAXMON;i++) { rmonstr[i] = atoi(token[i]); sum += abs(rmonstr[i]); }

    /* Examine checksum - line begins with F: */
    fgets(linebuff,400,savefile);
    i = 0; memset(&token,'\0',MAXREST * 16);
    pt = strtok(linebuff,sep);       /* Get first token */
    while (pt)                       /* Loop until no more tokens */
      {
       strcat(token[i],pt);          /* Store current token */
       i++;
       pt = strtok(NULL,sep);        /* Get next token */
      }
    if (strncmp(linebuff,"F:",2) != 0)
      {
       tnou("Error 6 in file, cannot restore! ");
       showtext();
       fclose(savefile);
       return;
      }
    fclose(savefile);
    checksum1 = atoi(token[1]);
    checksum2 = sum % 123;
    if (checksum1 != checksum2)
      {
       tnou("Error 7 in file, cannot restore! ");
       showtext();
       return;
      }
    /*---- All is OK, restore the actual values ----*/
    for (i=1;i<MAXVAL;i++) values[i] = rvalues[i];
    for (i=1;i<MAXFLAG;i++) flags[i] = rflags[i];
    for (i=1;i<MAXOBJ;i++) objloc[i] = robjloc[i];
    for (i=1;i<MAXOBJ;i++) secure[i] = rsecure[i];
    for (i=1;i<MAXMON;i++) monstr[i] = rmonstr[i];
    srand(values[SEED]);            /* Seed the random number generator */
    n = values[RNDCOUNT];
    values[RNDCOUNT] = 0;
    for (i=1;i<n;i++) r = rnd(2);   /* and call rnd() n times           */
    n = r;
    moveno = values[1];
    score = values[2];
    x = values[3];
    y = values[4];
    z = values[5];
    here = locate(x,y,z);
    tnoua("Game restored from ");
    tnou(filename);
    tonl(1);
    tnoua("Whilst you were away the elves may have moved a few things around a bit but ");
    tnou("apart from that everything should be as you left it. ");
    tonl(2);
    showtext();
    describe(1);                   /* Describe where we are             */
    showthings();                  /* Describe any objects found here   */
    mon_start();                   /* Activate monsters                 */
    monsters();                    /* Display active monsters           */
   }
/*----------------------------------------------------------------------*/
int get_password(void)           /* Get a user supplied password        */
/* Get the character string 'userpass' from the player. If desired code */
/* may be added to this function to suppress echo to the screen while   */
/* the password is being typed                                          */
   {
    int len;
    len = strlen(fgets(userpass,21,stdin));
    memset(&userpass[len - 1],'\0',1);
    return(len);
   }
/*----------------------------------------------------------------------*/
