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

#include "adventur.h"
#include "adv_common.h"
#include "adv_wizcom.h"

#include "adv_func.h"
#include "adv_io.h"
#include "adv_magic.h"
#include "adv_misc.h"
#include "adv_readdb.h"
#include "adv_setup.h"  
#include "adv_struc.h"  
#include "adv_util.h"
#include "adven2.h"
 

// ADVENTURES
int main(int argc, char *argv[])
{
// CURRENT LIMITS:
//     9650 WORDS OF MESSAGE TEXT (LINES, LINSIZ).
//    750 TRAVEL OPTIONS (TRAVEL, TRVSIZ).
//    300 VOCABULARY WORDS (KTAB, ATAB, TABSIZ).
//    150 LOCATIONS (LTEXT, STEXT, KEY, COND, ABB, ATLOC, LOCSIZ).
//    100 OBJECTS (PLAC, PLACE, FIXD, FIXED, LINK (TWICE), PTEXT, PROP).
//     35 "ACTION" VERBS (ACTSPK, VRBSIZ).
//    205 RANDOM MESSAGES (RTEXT, RTXSIZ).
//     12 DIFFERENT PLAYER CLASSIFICATIONS (CTEXT, CVAL, CLSMAX).
//     20 HINTS, LESS 3 (HINTLC, HINTED, HINTS, HNTSIZ).
//     35 MAGIC MESSAGES (MTEXT, MAGSIZ).
// THERE ARE ALSO LIMITS WHICH CANNOT BE EXCEEDED DUE TO THE STRUCTURE OF
// THE DATABASE.  (E.G., THE VOCABULARY USES N/1000 TO DETERMINE WORD TYPE,
// SO THERE CAN"T BE MORE THAN 1000 WORDS.)  THESE UPPER LIMITS ARE:
//    1000 NON-SYNONYMOUS VOCABULARY WORDS
//    300 LOCATIONS
//    100 OBJECTS
//
      int yea, i, k, rcode;
      BOOL restored_game = FALSE;

      if (argc > 2) printf("TOO MANY OPTIONS, WILL IGNORE THEM ALL!\n");
      else if (argc == 1) gm.setup = 0;    // no args, normal setup
      else
      {
        // one argument - may be restore request
        if (strequ(argv[1],"-r") || strequ(argv[1],"--restore"))
        {
          printf("RESTORING SAVED GAME ... ");
          gm.setup = restore_game();   // will be -1 when really restoring,
                                       //   0 if we can't restore 
        }  
        else printf("UNKNOWN OPTION \"%s\" - IGNORED!\n",argv[1]);
      } 
      
      if (gm.setup == 0)
        read_db();     // this sets "gm.setup" to 1 on normal startup

// FINISH CONSTRUCTING INTERNAL DATA FORMAT

// IF SETUP = 2 WE DON"T NEED TO DO THIS.  IT"S ONLY NECESSARY IF WE HAVEN"T DONE
// IT AT ALL OR IF THE PROGRAM HAS BEEN RUN SINCE THEN.
// Don't think we can get to "setup == 2" any more. This looks like some OS-specific
//   feature to re-run the game without reloading 

      if (gm.setup == 1) 
      {
        // for (ix=1;ix<=gm.tabndx;ix++)
        finish_setup();
        gm.oldloc = gm.oldlc2 = gm.loc = gm.newloc = 1;  // never been anywhere else (for "gm.back")
        gm.demo = start();
      }
      else if (gm.setup == -1)    // do some restart stuff
      {
        yea = start();
        gm.setup = 3;
        gm.saved = -1;            // for now, just do this - eases dwarf problems
        k = 0;
        restored_game  = TRUE;    // note we can skip the inital "do you want instructions"
        gm.described_loc = -1;       // show 1st loc even though he was there before the "save"
        gm.abb[gm.loc] = 0;          // force long description of this location
        // compute_new_loc();
      }
      else gm.demo = start();  // all other cases, just check hours, etc.

 // all setup done, drop through to main program loop

// statement 1
      show_motd(FALSE);
      i = ran(1);
      if (!restored_game)  // skip stuff only needed at FIRST startup
      { 
        gm.hinted[3] = yes(65,1,0);
        if (gm.hinted[3]) gm.limit = 1000;
        else gm.limit = 330;
      }
      gm.is_dead = FALSE;
      gm.setup = 3;
      // set up temporary sequencing flags (until structuring is done)
      gm.skip_user_input = FALSE;
      gm.skip_prelim_proc = FALSE;
      // describe_loc();

// statement 2600    -- this is the top of the main loop (I think??)
// lb2600:  // leave label so stuff outside loop can get back in!
  while (FOREVER)
  {
    if (gm.loc != gm.described_loc) // inhibit descrition on non-move commands
    {
      rcode = describe_loc();
      gm.described_loc = gm.loc;    
      if (rcode == 99)
      {
        hes_dead_jim();           // he got killed!
        continue;
      }
    }
    if (gm.skip_prelim_proc) 
    {
      gm.skip_prelim_proc = FALSE; // skip to gm.verb_class switch 
      // this assumes that "gm.verb" and "gm.obj" are all set and uses them
    }
    else
    {
      if (gm.skip_user_input)
      {
        gm.skip_user_input = FALSE; // reprocess previous input 
        // this assumes that gm.wd1, gm.wd2, etc. are set, and derives "gm.verb" and "gm.obj"
      }
      else
      {
        // full processing - preliminary stuff, then get user input
        //
        // CHECK IF THIS LOC IS ELIGIBLE FOR ANY HINTS.  IF BEEN HERE LONG ENOUGH,
        // BRANCH TO HELP SECTION (ON LATER PAGE).  HINTS ALL COME BACK HERE EVENTUALLY
        // TO FINISH THE LOOP.  IGNORE "HINTS" < 4 (SPECIAL STUFF, SEE DATABASE NOTES).
        gm.verb = 0;    // clear these two every time (all but two did anyway)
        gm.obj = 0;
        hint_check();

        // KICK THE RANDOM NUMBER GENERATOR JUST TO ADD VARIETY TO THE CHASE.  ALSO,
        // IF CLOSING TIME, CHECK FOR ANY OBJECTS BEING TOTED WITH PROP < 0 AND SET
        // THE PROP TO -1-PROP.  THIS WAY OBJECTS WON"T BE DESCRIBED UNTIL THEY"VE
        // BEEN PICKED UP AND PUT DOWN SEPARATE FROM THEIR RESPECTIVE PILES.  DON"T
        // TICK CLOCK1 UNLESS WELL INTO CAVE (AND NOT AT Y2).
        if (gm.closed)
        {
          if (gm.prop[gm.oyster] < 0 && toting(gm.oyster)) pspeak(gm.oyster,1);
          for (i=1;i<=100;i++)
            if (toting(i) && gm.prop[i] < 0)
              gm.prop[i] = -1-gm.prop[i];
        }
        gm.wzdark = dark();
        if (gm.knfloc > 0 && gm.knfloc != gm.loc) 
          gm.knfloc = 0;  // dropped knife vanishes??
        i = ran(1);
      
        // *********************************************************************** 
        // ********************* main user input prompt **************************
        // *********************************************************************** 
        // put a "?> " prompt, then read user command
        printf("?> ");     // **NO** newline
        getin(gm.wd1,gm.wd1x,gm.wd2,gm.wd2x);
      }  // end "skip user input" 

      // we have input - new, or rehashed from last time we read input
      gm.verb = vocab(gm.wd1,0);                  // try motion gm.verbs
      if (gm.verb == -1) gm.verb = vocab(gm.wd1,2);  // if not found, try action verbs
      if (gm.verb == -1) gm.verb = vocab(gm.wd1,3);  // special gm.verbs
      if (gm.verb == -1) gm.verb = vocab(gm.wd1,-1); // OK, settle for ANY meaning

      if (gm.wd2[0] == '\0') gm.obj = 0;          // no second word typed
      else
      {
        gm.obj = vocab(gm.wd2,1);                 // try for gm.object words first
        if (gm.obj == -1) gm.obj = vocab(gm.wd2,-1); // settle for anything else
        // leave the -1 to distinguish unknown word from omitted word
        if (gm.obj != -1) gm.obj = gm.obj%1000;      // take it mod 1000

        // some special handling of objects.  
        if (gm.obj == gm.rod && here(gm.rod2) && !here(gm.rod))
          gm.obj = gm.rod2;       // he's really after the "rod2"
      }

      if (gm.turns == 0 && strequ(gm.wd1,"MAGIC") && strequ(gm.wd2,"MODE"))
      {
        maint();
        ciao();
      } 

      // take care of all the easy answers, wisecracks, etc.
      //   if return == TRUE, we're done and go gm.back for more input
      //   if return == FALSE, it wasn't a quick one so keep going 
      if (snide_comments(gm.verb,gm.obj)) continue;  // lb2600 loop

      // take care of commands like "go east" or "gm.walk south" or "go building"
      //   transform them to use the segm.cond word as the gm.verb, no gm.object, 
      //   just as if the user typed "east" or "building"
      if (gm.verb == gm.walk && gm.obj != 0)
      {
        strcpy(gm.wd1,gm.wd2); strcpy(gm.wd1x,gm.wd2x); gm.wd2[0] = '\0';
        gm.verb = gm.obj; gm.obj = 0;
        // guess what "go quit" will do??
      }  

      // special case using PLOVER as an object

      if (strequ(gm.wd1,"QUIT"))   // temporary - need a safe and sure exit for debug
      {
        printf("GIVING UP SO EASILY, HUH? OK! SCRAM! BEAT IT!\n");
        gm.gaveup = TRUE;
        calculate_score(FALSE); 
        exit(0);
      }

      // process user input

      // EVERY INPUT, CHECK "FOOBAR" FLAG.  IF ZERO, NOTHING"S GOING ON.  IF POS,
      // MAKE NEG.  IF NEG, HE SKIPPED A WORD, SO MAKE IT ZERO.
      // the "foobar" flag controls the fee, fie, foe, foo sequence
      gm.foobar = (gm.foobar > 0) ? -gm.foobar : 0;
      gm.turns++;
      if (gm.demo && gm.turns >=  wizcom.shortgm)
      {
        // AND, OF COURSE, DEMO GAMES ARE ENDED BY THE WIZARD.
        mspeak(1);
        calculate_score(FALSE); 
        exit(0);
      }

      // clock processing (gm.clock1 and gm.clock2)
      if (gm.tally == 0 && gm.loc >=  15 && gm.loc != 33) gm.clock1--;
      if (gm.clock1 == 0)
        cave_closing();
      else  // gm.clock1 != 0
      {
        if (gm.clock1 < 0) gm.clock2--;
        if (gm.clock2 == 0)
        {
          // setting up the storage mroom has been moved to a seperate function
          setup_stg_room();
          check_closing();   // CAN"T LEAVE CAVE ONCE IT"S CLOSING (EXCEPT BY MAIN OFFICE).
          dwarf_stuff();     // check for dwarves at his gm.loc, and process them 
          continue;  // lb2600 loop
        }
        else  // gm.clock2 != 0
          check_lamp();
      }  // end gm.clock1 != 0

      if (gm.verb == gm.enter && gm.wd2[0] != '\0')
      {  
        // GET SECOND WORD FOR ANALYSIS.
        strcpy(gm.wd1,gm.wd2); strcpy(gm.wd1x,gm.wd2x); gm.wd2[0] = '\0';
        gm.skip_user_input = TRUE;
        gm.newloc = gm.loc;
        continue;  // lb2600 loop
      }
      if ( (strequ(gm.wd1,"WATER") || strequ(gm.wd1,"OIL")) &&
           (strequ(gm.wd2,"PLANT") || strequ(gm.wd2,"DOOR")) )
      {
        if (at(vocab(gm.wd2,1)%1000))
        {
          // change gm.water/gm.oil-as-gm.verb to gm.water/gm.oil-as-gm.object
          strcpy(gm.wd2,gm.wd1); strcpy(gm.wd1,"POUR"); // wd1x, wd2x are empty
          gm.skip_user_input = TRUE;   // want to parse the words we just changed
          gm.newloc = gm.loc;
          continue;  // lb2600 loop
        }
      }
    }

    gm.verb_base = (gm.verb%1000);    // base portion of gm.verb (mod 1000)
    gm.verb_class = gm.verb/1000+1;          // gm.verb "class" 

    switch (gm.verb_class)
    {
      case 1:  // travel verbs - east, west, in, out, building, etc.         
        compute_new_loc();
        check_closing();   // CAN"T LEAVE CAVE ONCE IT"S CLOSING (EXCEPT BY MAIN OFFICE).
        dwarf_stuff();     // check for dwarves at his gm.loc, and process them 
        break;
      case 2:  // objects
        do_obj_as_verb();
        check_closing();   // CAN"T LEAVE CAVE ONCE IT"S CLOSING (EXCEPT BY MAIN OFFICE).
        dwarf_stuff();     // check for dwarves at his gm.loc, and process them 
        break;
      case 3:  // action verbs - get, drop, kill, etc.
        analyze_verb(); 
        break;
      case 4:  // special verbs
        gm.spk = gm.verb_base; 
        rspeak(gm.spk);
        break;
      default: bug(22);
    }
    continue;  // lb2600 loop
    // we will never really get here unless we change some logic
    //   but guess what? we HAVE changed it to permit fall-through!
  }  // end of "lb2600" while(FOREVER) loop

}  // end of "main"

