/*
 *      ADVUTIL.C - Collosal Cave Adventure utility functions
 *      (C) 1986 Ravi Bhavnani
 *      All rights reserved
 *
 *      utilitarian()           calls appropriate utility rtn
 *      say_proc()              says word1
 *      save_proc()             saves game
 *      restore_proc()          restores a saved game
 *      quit_proc()             ends game
 *      find_proc()             hunts for an object
 *      inventory_proc()        displays inventory
 *      brief_proc()            turns on brief mode
 *      score_proc()            displays score
 *      timenow_proc()          displays current time
 *      help_proc()             display help data
 *      hours_proc()            displays open hours
 *      info_proc()             gives detailed info
 *      fast_proc()             sets *fast* mode
 *      full_proc()             resets normal verbose mode
 *      news_proc()             displays news
 *      hint_proc()             handles requests for hints
 *      look_proc()             displays surroundings in detail
 */

#include "adv.h"


utilitarian()
/*
 *      HANDLES UTILITY COMMANDS.
 */
{
	dbg ("utilitarian() ");
        if (debug)
           printf (": arg1 = %d, arg2 = %d\n", arg1, arg2);

        switch (arg1)
        {
          case say:
            say_proc();
            break;
          case timenow:
            timenow_proc();
            break;
          case help:
            help_proc();
            break;
          case news:
            news_proc();
            break;
          case hours:
            hours_proc();
            break;
          case info:
            info_proc();
            break;
          case inventory:
            inventory_proc();
            break;
          case brief:
            brief_proc();
            break;
          case fast:
            fast_proc();
            break;
          case full:
            full_proc();
            break;
          case find:
            find_proc();
            break;
          case qquit:
            quit_proc();
            break;
          case score:
            score_proc();
            break;
          case hint:
            hint_proc();
            break;
          case save:
            save_proc();
            break;
          case restore:
            restore_proc();
            break;
          default:
            printf ("Command %d (%s %s) not installed\n", arg1, word1, word2);
            break;
        }
	RETURN;
}
          
say_proc()
/*
 *      ECHO INPUT.
 */
{
	dbg ("say_proc()\n");

        if (inword == 2)
           if (arg1==196 || arg2==196) /* fuck */
              retort();
           else
              mtext (said, word2);
        else
           {
             mword (clarify, say);
             context = say;
           }
	RETURN;
}

save_proc()
{
char	savefile [256],
	tmpfile[256];
FILE	*savefile_fp;
int	derf;
static $DESCRIPTOR (resultdesc, "");
static int len;

	dbg ("save_proc()\n");

	/* GET FILENAME */

	if (inword==2)
	   strcpy (savefile, word2);
	else
	   {
	     printf ("Please type a filename in which to save the game, or press RETURN to cancel\n");
	     printf ("the SAVE command.\n");
	     printf ("> ");
	     gets (savefile);
	     strupr (savefile);
	     if (!strlen(savefile))
	        {
	          printf (" \n");
	          printf ("SAVE command cancelled.\n");
	          RETURN;
	        }
	   }

	/* CREATE FILE */

	resultdesc.dsc$a_pointer = sav_dir;
	resultdesc.dsc$w_length = STRINGLEN;	
	if (lib$sys_trnlog (&adv$sav, &len, &resultdesc, 0, 0, 0) == SS$_NORMAL)
	   sav_dir[len] = '\0';
	else
	   strcpy (sav_dir, "");
	strcpy (tmpfile, sav_dir);
	strcat (tmpfile, savefile);
	strcpy (savefile, tmpfile);

	if ((savefile_fp = fopen (savefile, "w")) == NULL)
	   {
	     printf (" \n");
	     msay (cant_save);
	     printf ("%s.\n", savefile);
	     RETURN;
	   }

	/* WRITE VERSION */

	fwrite (&major,		sizeof(int), 1, savefile_fp);
	fwrite (&minor,		sizeof(int), 1, savefile_fp);
	fwrite (&release,	sizeof(int), 1, savefile_fp);

	/* WRITE VARIABLES - ALFA ORDER */

	fwrite (&arg1, 		sizeof(int), 1, savefile_fp);
	fwrite (&arg2, 		sizeof(int), 1, savefile_fp);
	fwrite (&briefmode, 	sizeof(int), 1, savefile_fp);
	fwrite (&cameotime, 	sizeof(int), 1, savefile_fp);
	fwrite (&clock, 	sizeof(int), 1, savefile_fp);
	fwrite (&closure, 	sizeof(int), 1, savefile_fp);
	fwrite (&context, 	sizeof(int), 1, savefile_fp);
	fwrite (&deaths, 	sizeof(int), 1, savefile_fp);
	fwrite (&debug, 	sizeof(int), 1, savefile_fp);
	fwrite (&demo, 		sizeof(int), 1, savefile_fp);
	fwrite (&derf, 		sizeof(int), 1, savefile_fp);
	fwrite (&dragtime, 	sizeof(int), 1, savefile_fp);
	fwrite (&dwarfcount, 	sizeof(int), 1, savefile_fp);
	fwrite (&dwarrows, 	sizeof(int), 1, savefile_fp);
	fwrite (&escap, 	sizeof(int), 1, savefile_fp);
	fwrite (&fastmode, 	sizeof(int), 1, savefile_fp);
	fwrite (&foobar, 	sizeof(int), 1, savefile_fp);
	fwrite (&here, 		sizeof(int), 1, savefile_fp);
	fwrite (&hintime, 	sizeof(int), 1, savefile_fp);
	fwrite (&invct, 	sizeof(int), 1, savefile_fp);
	fwrite (&inword, 	sizeof(int), 1, savefile_fp);
	fwrite (&justdied, 	sizeof(int), 1, savefile_fp);
	fwrite (&knives, 	sizeof(int), 1, savefile_fp);
	fwrite (&lamplife, 	sizeof(int), 1, savefile_fp);
	fwrite (&lastclock, 	sizeof(int), 1, savefile_fp);
	fwrite (&lighted, 	sizeof(int), 1, savefile_fp);
	fwrite (&loc, 		sizeof(int), 1, savefile_fp);
	fwrite (&margin, 	sizeof(int), 1, savefile_fp);
	fwrite (&maxscore, 	sizeof(int), 1, savefile_fp);
	fwrite (&moved, 	sizeof(int), 1, savefile_fp);
	fwrite (&mushtime, 	sizeof(int), 1, savefile_fp);
	fwrite (&nlongs, 	sizeof(int), 1, savefile_fp);
	fwrite (&nmoves, 	sizeof(int), 1, savefile_fp);
	fwrite (&nmsgs, 	sizeof(int), 1, savefile_fp);
	fwrite (&nobj, 		sizeof(int), 1, savefile_fp);
	fwrite (&nomagic, 	sizeof(int), 1, savefile_fp);
	fwrite (&nretort, 	sizeof(int), 1, savefile_fp);
	fwrite (&nshorts, 	sizeof(int), 1, savefile_fp);
	fwrite (&nturns, 	sizeof(int), 1, savefile_fp);
	fwrite (&nvocab, 	sizeof(int), 1, savefile_fp);
	fwrite (&ok2desc, 	sizeof(int), 1, savefile_fp);
	fwrite (&olorin, 	sizeof(int), 1, savefile_fp);
	fwrite (&paniced, 	sizeof(int), 1, savefile_fp);
	fwrite (&password, 	sizeof(int), 1, savefile_fp);
	fwrite (&penalties, 	sizeof(int), 1, savefile_fp);
	fwrite (&prevloc, 	sizeof(int), 1, savefile_fp);
	fwrite (&quitting, 	sizeof(int), 1, savefile_fp);
	fwrite (&ranout, 	sizeof(int), 1, savefile_fp);
	fwrite (&safeexit, 	sizeof(int), 1, savefile_fp);
	fwrite (&saidxyzzyplugh,sizeof(int), 1, savefile_fp);
	fwrite (&scorex, 	sizeof(int), 1, savefile_fp);
	fwrite (&strength, 	sizeof(int), 1, savefile_fp);
	fwrite (&thing, 	sizeof(int), 1, savefile_fp);
	fwrite (&ticker, 	sizeof(int), 1, savefile_fp);
	fwrite (&waterphuggg, 	sizeof(int), 1, savefile_fp);

	fwrite (word1, sizeof(string), 1, savefile_fp);
	fwrite (word2, sizeof(string), 1, savefile_fp);

	fwrite (visited,  sizeof(parray), 1, savefile_fp);
	fwrite (hintable, sizeof(parray), 1, savefile_fp);

	fwrite (seen,     sizeof(oarray), 1, savefile_fp);
	fwrite (where_is, sizeof(oarray), 1, savefile_fp);
	fwrite (special1, sizeof(oarray), 1, savefile_fp);
	fwrite (special2, sizeof(oarray), 1, savefile_fp);
	fwrite (val,      sizeof(oarray), 1, savefile_fp);
	fwrite (nodesc,   sizeof(oarray), 1, savefile_fp);
	fwrite (invisible,sizeof(oarray), 1, savefile_fp);

	/* CLOSE FILE */

	fgetname (savefile_fp, savefile);
	strupr (savefile);
	printf (" \n");
	printf ("Your game has been saved in %s.\n", savefile);
	fclose (savefile_fp);
	RETURN;
}

restore_proc()
{
static $DESCRIPTOR (resultdesc, "");
static int len;
static int
	temp_nlongs,
	temp_nmoves,
	temp_nmsgs,
	temp_nobj,
	temp_nshorts,
	temp_nvocab,
	temp_major,
	temp_minor,
	temp_release;
char	savefile [256],
	tmpfile[256];
FILE	*savefile_fp;
int	derf;

	dbg ("restore_proc()\n");

	/* GET FILENAME */

	if (inword==2)
	   strcpy (savefile, word2);
	else
	   {
	     printf ("Please type the name of the saved game file, or press RETURN to cancel\n");
	     printf ("the RESTORE command.\n");
	     printf ("> ");
	     gets (savefile);
	     strupr (savefile);
	     if (!strlen(savefile))
	        {
	          printf (" \n");
	          printf ("RESTORE command cancelled.\n");
	          RETURN;
	        }
	   }

	/* OPEN FILE */

	resultdesc.dsc$a_pointer = sav_dir;
	resultdesc.dsc$w_length = STRINGLEN;	
	if (lib$sys_trnlog (&adv$sav, &len, &resultdesc, 0, 0, 0) == SS$_NORMAL)
	   sav_dir[len] = '\0';
	else
	   strcpy (sav_dir, "");
	strcpy (tmpfile, sav_dir);
	strcat (tmpfile, savefile);
	strcpy (savefile, tmpfile);

	if ((savefile_fp = fopen (savefile, "r")) == NULL)
	   {
	     printf (" \n");
	     printf ("I'm afraid I can't restore your saved game - I can't open the game file\n");
	     printf ("%s.\n", savefile);
	     RETURN;
	   }

	/* SAVE CURRENT DATABASE SIZE */

	temp_nlongs	= nlongs;
	temp_nmoves	= nmoves;
	temp_nmsgs	= nmsgs;
	temp_nobj	= nobj;
	temp_nshorts	= nshorts;
	temp_nvocab	= nvocab;

	/* READ VERSION */

	fread (&temp_major,	sizeof(int), 1, savefile_fp);
	fread (&temp_minor,	sizeof(int), 1, savefile_fp);
	fread (&temp_release,	sizeof(int), 1, savefile_fp);

	if ((temp_major*1000 + temp_minor*100 + temp_release) < COMPATIBLE)
	   {
	     fgetname (savefile_fp, savefile);
	     printf (" \n");
	     printf ("I'm sorry but I can't restore your game.  The game saved in the file\n");
	     printf ("%s is not compatible with\n", savefile);
	     printf ("this version of New Adventure.\n\n");
	     fclose (savefile_fp);
	     moved = 1;
	     RETURN;
	   }

	/* READ VARIABLES - ALFA ORDER */

	fread (&arg1, 		sizeof(int), 1, savefile_fp);
	fread (&arg2, 		sizeof(int), 1, savefile_fp);
	fread (&briefmode, 	sizeof(int), 1, savefile_fp);
	fread (&cameotime, 	sizeof(int), 1, savefile_fp);
	fread (&clock, 		sizeof(int), 1, savefile_fp);
	fread (&closure, 	sizeof(int), 1, savefile_fp);
	fread (&context, 	sizeof(int), 1, savefile_fp);
	fread (&deaths, 	sizeof(int), 1, savefile_fp);
	fread (&debug, 		sizeof(int), 1, savefile_fp);
	fread (&demo, 		sizeof(int), 1, savefile_fp);
	fread (&derf, 		sizeof(int), 1, savefile_fp);
	fread (&dragtime, 	sizeof(int), 1, savefile_fp);
	fread (&dwarfcount, 	sizeof(int), 1, savefile_fp);
	fread (&dwarrows, 	sizeof(int), 1, savefile_fp);
	fread (&escap, 		sizeof(int), 1, savefile_fp);
	fread (&fastmode, 	sizeof(int), 1, savefile_fp);
	fread (&foobar, 	sizeof(int), 1, savefile_fp);
	fread (&here, 		sizeof(int), 1, savefile_fp);
	fread (&hintime, 	sizeof(int), 1, savefile_fp);
	fread (&invct, 		sizeof(int), 1, savefile_fp);
	fread (&inword, 	sizeof(int), 1, savefile_fp);
	fread (&justdied, 	sizeof(int), 1, savefile_fp);
	fread (&knives, 	sizeof(int), 1, savefile_fp);
	fread (&lamplife, 	sizeof(int), 1, savefile_fp);
	fread (&lastclock, 	sizeof(int), 1, savefile_fp);
	fread (&lighted, 	sizeof(int), 1, savefile_fp);
	fread (&loc, 		sizeof(int), 1, savefile_fp);
	fread (&margin, 	sizeof(int), 1, savefile_fp);
	fread (&maxscore, 	sizeof(int), 1, savefile_fp);
	fread (&moved,		sizeof(int), 1, savefile_fp);
	fread (&mushtime, 	sizeof(int), 1, savefile_fp);
	fread (&nlongs, 	sizeof(int), 1, savefile_fp);
	fread (&nmoves, 	sizeof(int), 1, savefile_fp);
	fread (&nmsgs, 		sizeof(int), 1, savefile_fp);
	fread (&nobj, 		sizeof(int), 1, savefile_fp);
	fread (&nomagic, 	sizeof(int), 1, savefile_fp);
	fread (&nretort, 	sizeof(int), 1, savefile_fp);
	fread (&nshorts, 	sizeof(int), 1, savefile_fp);
	fread (&nturns, 	sizeof(int), 1, savefile_fp);
	fread (&nvocab, 	sizeof(int), 1, savefile_fp);
	fread (&ok2desc, 	sizeof(int), 1, savefile_fp);
	fread (&olorin, 	sizeof(int), 1, savefile_fp);
	fread (&paniced, 	sizeof(int), 1, savefile_fp);
	fread (&password, 	sizeof(int), 1, savefile_fp);
	fread (&penalties, 	sizeof(int), 1, savefile_fp);
	fread (&prevloc, 	sizeof(int), 1, savefile_fp);
	fread (&quitting, 	sizeof(int), 1, savefile_fp);
	fread (&ranout, 	sizeof(int), 1, savefile_fp);
	fread (&safeexit, 	sizeof(int), 1, savefile_fp);
	fread (&saidxyzzyplugh,	sizeof(int), 1, savefile_fp);
	fread (&scorex, 	sizeof(int), 1, savefile_fp);
	fread (&strength, 	sizeof(int), 1, savefile_fp);
	fread (&thing,		sizeof(int), 1, savefile_fp);
	fread (&ticker, 	sizeof(int), 1, savefile_fp);
	fread (&waterphuggg, 	sizeof(int), 1, savefile_fp);

	fread (word1, sizeof(string), 1, savefile_fp);
	fread (word2, sizeof(string), 1, savefile_fp);

	fread (visited,  sizeof(parray), 1, savefile_fp);
	fread (hintable, sizeof(parray), 1, savefile_fp);

	fread (seen,     sizeof(oarray), 1, savefile_fp);
	fread (where_is, sizeof(oarray), 1, savefile_fp);
	fread (special1, sizeof(oarray), 1, savefile_fp);
	fread (special2, sizeof(oarray), 1, savefile_fp);
	fread (val,      sizeof(oarray), 1, savefile_fp);
	fread (nodesc,   sizeof(oarray), 1, savefile_fp);
	fread (invisible,sizeof(oarray), 1, savefile_fp);

	/* CLOSE FILE */

	fgetname (savefile_fp, savefile);
	strupr (savefile);
	printf (" \n");
	printf ("Your game has been restored from %s.\n\n", savefile);
	fclose (savefile_fp);

	/* FAKE A MOVE SO WE DESCRIBE EVERYTHING */

	moved = 1;
	RETURN;
}

quit_proc()
{
	dbg ("quit_proc()\n");
        if (query(wanttoquit))
           {
             quitting = 1;
             finis();
           }
        msay (ok);
	RETURN;
}

find_proc()
{
int     derf;

	dbg ("find_proc()\n");
        if (inword == 1)
           if (lit[here] || (near(lamp) && val[lamp]==1))
              {
                mword (clarify, find);
                context = find;
              }
           else
              msay (cant_see_anything);
        else
           if (!isobj(arg2))
              msay (what);
           else
              if (carrying(arg2))
                 msay (youhaveit);
              else
                 if (mortal[arg2] || !portable[arg2])
                    msay (beserious);
                 else
                    if (lit[here] || (near(lamp) && val[lamp]==1))
                       if (where_is[arg2] == here)
                          osay (arg2, val[arg2]);
                       else
                          mword (idontsee, arg2);
                    else
                       {
                         derf = (invct-strength)*50 + 60;
                         if (chance(derf))
                            {
                              mword (grope_fail, arg2);
                              coroner();
                            }
                         else
                            if (chance(50) || !near(arg2))
                               mword (grope_miss, arg2);
                            else
                               mword (grope_find, arg2);
                       }
	RETURN;
}

inventory_proc()
{
int     derf;

	dbg ("inventory_proc()\n");
        for (derf=0,thing=MINOBJECTS; (thing <= MAXOBJECTS); thing++)
            if (carrying(thing) && thing!=bear)
               {
                 if (!derf)
                    {
                      derf = 1;
                      msay (younowhave);
                    }
                 isay (thing);
               }

	if (carrying(bear))
	   {
	     msay (blank);
	     msay (i_c_a_bear);
	     derf++;
	   }
       if (!derf)
          msay (armsareempty);
       else
          printf ("\n");

	RETURN;
}

score_proc()
{
	dbg ("score_proc()\n");
        getscore();
        mval (ifyouquit, scorex);
        mval (ifyouquit2, maxscore);
	RETURN;
}

brief_proc()
{
	dbg ("brief_proc()\n");
        briefmode = 1;
        fastmode = 0;
        msay (brief_ok);
	RETURN;
}

hours_proc()
{
	dbg ("hours_proc()\n");
        msay (hours_are);
	RETURN;
}

timenow_proc()
/*
 *      TELL HIM WHAT TIME IT IS.
 */
{
int     hrs,
        mins;

	dbg ("timenow_proc()\n");

        time (&nowtime);
        strcpy (str, ctime (&nowtime));
        str [strlen(str)-1] = '\0';

        printf ("It's now %s.  You've been playing Adventure for\n", str);

        mins = (nowtime - startplay) / 60;
        hrs = mins / 60;
        mins -= (60*hrs);

        if (hrs)
           {
             printf ("%d hour%s", hrs, (hrs > 1 ? "s" : ""));
             if (mins)
                printf (" and %d minute%s", mins, (mins > 1 ? "s" : ""));
           }
        else
           if (mins)
              printf ("%d minute%s", mins, (mins > 1 ? "s" : ""));
           else
              printf ("less than a minute");

        printf (".\n");
	RETURN;
}

help_proc()
{
	dbg ("help_proc()\n");
        msay (helpdata);
	RETURN;
}

info_proc()
{
	dbg ("info_proc()\n");
        msay (info_2);
	RETURN;
}

fast_proc()
{
	dbg ("fast_proc()\n");
        briefmode = 0;
        fastmode = 1;
        msay (ok);
	RETURN;
}

full_proc()
{
	dbg ("full_proc()\n");
        briefmode = 0;
        fastmode = 0;
        msay (ok);
	RETURN;
}

news_proc()
{
	dbg ("news_proc()\n");
	printf ("New Adventure FT%d.%d-%d (released %s) is the brand-spanking-new\n",
	        MAJOR, MINOR, RELEASE, RELEASED);
        msay (newsdata);
	RETURN;
}

hint_proc()
/*
 *      PLAYER HAS ASKED FOR A HINT.
 */
{
int     derf;

	dbg ("hint_proc()\n");

        if (nturns < 5)
           {
             msay (431);  /* earlyhint */
             RETURN;
           }
	else
	   if (!hintable[here])
	      {
                msay (432);  /* nohinthere */
	        RETURN;
	      }

	hint_logic();
}

look_proc()
/*
 *      DISPLAYS SURROUNDING IN DETAIL (ASSUMING YOU HAVE LIGHT HERE).
 */
{
int     derf;

	dbg ("look_proc()\n");

	/* DESCRIBE FOG/GLOW */

	if (near(glow) || near(fog))
	   {
	     if (near(glow))
	        osay (glow, val[glow]);
	     else
	        if (val[fog] < 8)
	           osay (fog, val[fog]);
	        else
	           printf ("<GLITCH!> look_proc() could not describe anything\n");
	     RETURN;
	   }

        if (near(lamp) && val[lamp]==1 || lit[here])
           {

             /* DESCRIBE LOCATION */

	     if ((arg1 != look) && fastmode)
	        ssay (here);	/* lamp has just been turned	*/
	     else		/* on while in fast mode	*/
                lsay (here);
             visited [here]++;

             /* DESCRIBE PRIMARY OBJECTS */

             derf = 0;
             for (thing=MINOBJECTS; (thing <= MAXOBJECTS); thing++)
                 if (firstdesc[thing] && where_is[thing]==here && !invisible[thing] && !nodesc[thing])
                    {
                      if (!derf)
                         {
                           printf ("\n");
                           derf = 1;
                         }

                      osay (thing, val[thing]);
                    }

             /* DESCRIBE OTHER STUFF */

             derf = 0;
             for (thing=MINOBJECTS; (thing<=MAXOBJECTS); thing++)
                 if (!nodesc[thing])
                    if (near(thing) && !carrying(thing))
                       if (!invisible[thing] && !firstdesc[thing])
                          {
                            if (!derf)
                               {
                                 printf ("\n");
                                 derf = 1;
                               }
                            osay (thing, val[thing]);
                            seen [thing]++;
                          }

             /* TELL HIM ABOUT THE BEAR AND DWARVES, IF ANY */

              if (carrying(bear))
                 {
                   msay (blank);
                   msay (i_c_a_bear);
                   msay (blank);
                 }

             if (near(dwarf))
                {
	          msay (blank);
                  if (dwarrows == 1)
                     msay (dwarfhere);
                  else
                     mval (dwarveshere, dwarrows);
                  msay (blank);
                }

           }
        else
           msay (nolighthere);
	RETURN;
}
