/*
 *      ADVIO.C - I/O routines for Collosal Cave Adventure
 *      (C) 1986 Ravi Bhavnani
 *      All rights reserved
 *
 *      query (prompt)
 *        - gets y/n answer to <prompt>
 *      isay (obj)
 *        - prints inventory description of <obj>
 *      osay (obj, state)
 *        - prints <state>th description of <obj>
 *      ssay (loc)
 *        - prints short description of <loc>
 *      lsay (loc)
 *        - prints long description of <loc>
 *      msay (msg)
 *        - prints message <msg>
 *      mtext (msg, text)
 *        - prints message <msg> with context <text>
 *      mword (msg, vword)
 *        - prints message <msg> with vocabulary word context <vword>
 *      mval (msg, val)
 *        - prints message <msg> with numeric context <val>
 *      get_command()
 *        - returns parsed user input in arg1,2
 *	cls()
 *	  - clears screen
 *	strlwr (s)
 *	  - converts string s to all lowercase
 *	strupr (s)
 *	  - converts string s to all uppercase
 */

#include "adv.h"

query (prompt)
int     prompt;
/*
 *      PRINTS MESSAGE prompt AND RETURNS 1 IF yes, 0 IF NO.
 */
{
int     bad,
	stat;

        if (prompt > nmsgs)
           {
             fprintf (stderr, "query (%d)\n", prompt);
             bug (BADQUERY);
           }

        bad = 0;
        msay (prompt);
        do
        {
	  strcpy (input, "");
	  userinput.dsc$a_pointer = input;
	  userinput.dsc$w_length = STRINGLEN-1;
          stat = smg$read_composed_line (&kbd_id, &ktbl_id, &userinput, &advprompt);

	  /* ^Z IMPLIES NO */

	  if (stat == SMG$_EOF)
	     {
	       printf (" \n");
	       return (0);
	     }
	  else
	     for (stat=strlen(input)-1; (isspace(input[stat])); stat--)
	         input[stat] = '\0';

	  if (strlen(input))
             {
               printf ("\n");
               strupr (input);
               if (!strcmp(input,"YES") || !strcmp(input,"Y"))
                  return (1);
               else
                  if (!strcmp(input,"NO") || !strcmp(input,"N"))
                     return (0);
             }
          else
             printf ("\n");

          bad++;
          if (bad == 6)
             bad = 1;
          switch (bad)
          {
            case 1:
              printf ("Please answer the question.\n");
              break;
            case 2:
              printf ("Please answer YES or NO.\n");
              break;
            case 3:
              printf ("An answer of YES or NO (or Y or N) would be appreciated.\n");
              break;
            case 4:
              printf ("Really, now...\n");
              break;
            case 5:
            default:
              printf ("Please answer the question by entering YES or NO.\n");
              break;
          }
        }
        forever;
}


isay (objectnum)
int     objectnum;
/*
 *      PRINT THE INVENTORY DESCRIPTION OF OBJECT objectnum.
 */
{
        printf ("\t%s\n", obj[objectnum].invdesc);
}


osay (objectnum, objectstate)
int     objectnum,
        objectstate;
/*
 *      PRINT THE TEXT CORRESPONDING TO OBJECT objectnum BEING IN
 *      STATE objectstate.
 */
{
t_struct        *tptr;

        tptr = (t_struct *) &(obj[objectnum].vdesc[objectstate]);

	if (tptr==NULL)	/* for objects that have no description for this state */
	   return;

	/* BUG CHECK */

	if (tptr->line == NULL)
	   {
	     printf ("<GLITCH!> Internal error trap in osay(%d,%d) at %d\n",
	             objectnum, objectstate, here);
	     printf ("Please report this bug - thanks.\n");
	     return;
	   }

        if (!strlen(tptr->line) && (tptr->next == NULL))
           ; /* blank line description - do nothing */
        else
           while (tptr)
                 {
	           if (tptr->line == NULL)
	              {
	                printf ("<GLITCH!> Internal error trap in osay(%d,%d) at %d\n", objectnum, objectstate, here);
	                printf ("Please report this bug - thanks.\n");
	                return;
	              }

                   printf ("%s\n", tptr->line);
                   tptr = tptr->next;
                 }
}


ssay (placenum)
int     placenum;
/*
 *      PRINT SHORT DESCRIPTION OF LOCATION placenum.
 */
{
t_struct        *tptr;
int             derf;

        derf = 0;
        tptr = &(shortp [placenum]);
        while (tptr != NULL)
            {
              /* IF PLACE DESCRIPTION STARTS WITH A LEADING BLANK LINE
               * IT'S A NULL DESCRIPTION, SO QUIT */

              if (!derf && !tptr->line)
                 return;
              else
                 derf = 1;

              printf ("%s\n", tptr->line);
              tptr = tptr->next;
            }
}


lsay (placenum)
int     placenum;
/*
 *      PRINT LONG DESCRIPTION OF LOCATION placenum.
 */
{
t_struct        *tptr;
int             derf;

        derf = 0;
        tptr = &(longp [placenum]);
        while (tptr != NULL)
            {
              /* IF PLACE DESCRIPTION STARTS WITH A LEADING BLANK LINE
               * IT'S A NULL DESCRIPTION, SO QUIT */

              if (!derf && !tptr->line)
                 return;
              else
                 derf = 1;

              printf ("%s\n", tptr->line);
              tptr = tptr->next;
            }
}


msay (msgnum)
int     msgnum;
/*
 *      PRINT MESSAGE msgnum.
 */
{
t_struct        *tptr;
int             bar;
string		s;

        for (bar=0, tptr = &(msg [msgnum]); (tptr); bar++, tptr = tptr->next)
            {
              if (bar && !(bar % 23))
                 {
                   printf ("--MORE--");
#ifdef msdos
                   getch();
                   printf ("\015        \015");
#endif
#ifdef vms
	           gets (s);
	           printf ("\n\n");
#endif
                 }
              printf ("%s\n", tptr->line);
            }
}


mtext (msgnum, text)
int     msgnum;
char    *text;
/*
 *      PRINT MESSAGE msgnum REPLACING EVERY OCCURENCE OF %s WITH TEXT.
 *      NOTE:  (1) THE PRESENCE OF A % SIGN IMPLIES %s.  (2) THERE MUST
 *      BE ONLY *ONE* %s IN EACH LINE OF THE MESSAGE.
 */
{
t_struct        *tptr;
int             derf,
                slen;
char	temp [128];

        tptr = &(msg [msgnum]);
        while (tptr != NULL)
            {
              strcpy (str, tptr->line);
              slen = strlen (str);
              for (derf=0; (derf < slen); derf++)
                  if (str[derf] == '%')
                     break;
	      strcpy (temp, str);
              if (derf < slen)
                 sprintf (str, temp, text);
              printf ("%s\n", str);
              tptr = tptr->next;
            }
}


mval (msgnum, val)
int     msgnum,
        val;
/*
 *      JUST LIKE mtext(), EXCEPT WORKS WITH AN INTEGER VALUE val.
 */
{
t_struct        *tptr;
int             derf,
                slen;
char	temp[128];

        tptr = &(msg [msgnum]);
        while (tptr != NULL)
            {
              strcpy (str, tptr->line);
              slen = strlen (str);
              for (derf=0; (derf < slen); derf++)
                  if (str[derf] == '%')
                     break;
	      strcpy (temp, str);
              if (derf < slen)
                 sprintf (str, temp, val);
              printf ("%s\n", str);
              tptr = tptr->next;
            }
}


mword (msgnum, vword)
int     msgnum,
        vword;
/*
 *      JUST LIKE mtext(), EXCEPT WORKS WITH TEXTUAL REPRESENTATION
 *      OF VOCABULARY WORD vword.
 */
{
t_struct        *tptr;
int             derf,
                bar,
                slen;
char	temp[128];

        for (bar=0; (bar < nvocab); bar++)
            if (vocab[bar].meaning == vword)
               break;
        if (bar == nvocab)
           {
             printf ("GLITCH! mword() called with %d, %d", msgnum, vword);
             exit();
           }

        tptr = &(msg [msgnum]);
        while (tptr != NULL)
            {
              strcpy (str, tptr->line);
              slen = strlen (str);
              for (derf=0; (derf < slen); derf++)
                  if (str[derf] == '%')
                     break;
	      strcpy (temp, str);
              if (derf < slen)
                 sprintf (str, temp, vocab[bar].word);
              printf ("%s\n", str);
              tptr = tptr->next;
            }
}


get_command()
/*
 *      RETURNS PARSED INPUT IN arg1 AND arg2.
 */
{
static char
	codeword1 [64],
	codeword2 [64];

int     start,
        end,
        slen,
        indx,
	stat;

	dbg ("get_command()\n");
        do
        {

        /* READ INPUT, CHECK FOR NULL LINE */

loop:
        inword = 0;
        word1 [0] = '\0';
        word2 [0] = '\0';

	strcpy (input, "");
	userinput.dsc$a_pointer = input;
	userinput.dsc$w_length = STRINGLEN-1;
	stat = smg$read_composed_line (&kbd_id, &ktbl_id, &userinput, &advprompt);

	/* ^Z IMPLIES QUIT */

	if (stat == SMG$_EOF)
	   {
	     inword = 1;
	     context = null;
	     arg1 = qquit;
	     arg2 = null;
	     strcpy (word1, "^Z");
	     strcpy (word2, "");
	     printf (" \n");
	     RETURN;
	   }
	else
           for (stat=strlen(input)-1; (isspace(input[stat])); stat--)
               input[stat] = '\0';

        if (!(slen = strlen(input)))
           {
             arg1 = null;
             arg2 = null;
             if (context != null)
                {
                  arg1 = context;
                  context = null;
                }
             if (debug)
                printf ("Word1 = /%s/ (%d), Word2 = /%s/ (%d), Context = null\n", word1, arg1, word2, arg2);
             printf ("\n");
             RETURN;
           }

        /* KILL INVALID CHARS, GET TRUE START & END OF INPUT */

        for (end=slen-1; (end >= 0); end--)
            if (isalnum (input[end]))
               break;
        if (end < 0)
           {
             printf ("\nI don't understand that!\n");
             goto loop;
           }
        for (start=0; (start < end); start++)
            if (isalnum (input[start]))
               break;

        /* GARBAGE IN COMMAND LINE? */

        for (indx=start; (indx <= end); indx++)
            if (!(isalnum(input[indx])) && !isspace(input[indx]))
               {
                 printf ("\nI don't understand that!\n");
                 goto loop;
               }

/*
        if (debug)
           printf ("Start = %d\nEnd = %d\n", start, end);
*/

        /* EXTRACT WORD1 */

        for (indx=start; (indx<=end && input[indx]!=' '); indx++)
            word1 [indx - start] = input [indx];
        word1 [indx - start] = '\0';
        inword = 1;

        /* ID THERE'S MORE, EXTRACT WORD2 */

        if (indx < end)
           {
             do
               indx++;
             while (input [indx] == ' ');
             for (start=indx; (indx<=end && input[indx]!=' '); indx++)
                 word2 [indx - start] = input [indx];
             word2 [indx - start] = '\0';
             inword = 2;
           }

        /* IF THERE'S MORE, SCREAM */

        if (indx < end)
           {
             printf ("\nSorry, I don't understand that.\n");
             continue;
           }

        /* LOWERCASE EVERYTHING & SEARCH VOCABULARY */

        strlwr (word1);
        strlwr (word2);
        arg1 = null;
        arg2 = null;

        /* GET arg1 */

	strcpy (codeword1, word1);
        for (indx=0; (indx <= nvocab); indx++)
            if (!strcmp (codeword1, vocab[indx].word))
               {
                 arg1 = vocab[indx].meaning;
                 break;
               }
        if (arg1 == null)
           arg1 = errword;

        /* GET arg2 AND APPLY context TO arg1,2 */

        if (inword == 2)
           {
             context = null;
	     strcpy (codeword2, word2);
             for (indx=0; (indx <= nvocab); indx++)
                 if (!strcmp (codeword2, vocab[indx].word))
                    {
                      arg2 = vocab[indx].meaning;
                      break;
                    }
             if (arg2 == null)
                arg2 = errword;
             else
                if (isobj(arg1))
                   {
                     context = arg2;
                     arg2 = arg1;
                     arg1 = context;
                     context = null;
                   }
           }
        else
           if (context != null)
              {
                if (isobj(context))
                   if (isverb(arg1) || isutil(arg1))
                      {
                        arg2 = context;
                        inword = 2;
                        context = null;
                      }
                   else
                      context = null;
                else
                   if ( isverb(context) && (isobj(arg1) || isdir(arg1)) ||
                        isutil(context) && isobj(arg1))
                      {
                        arg2 = arg1;
                        arg1 = context;
                        context = null;
                        inword = 2;
                      }
                   else
                      context = null;
              }

        /* CHECK FOR PROFANITY */

        if (arg1==obscenity || arg2==obscenity)
           {
             context = null;
             arg1 = obscenity;
             arg2 = null;
           }

        if (debug)
           printf ("Word1 = /%s/ (%d), Word2 = /%s/ (%d), Context = %d\n",
                   word1, arg1, word2, arg2, context);

        printf ("\n");
        RETURN;

        }
        forever;
}


cls()
/*
 *	CLEARS THE SCREEN.
 */
{
	printf ("\033[2J\033[H");
}


strlwr (s)
char	s[];
/*
 *	CONVERT s TO LOWERCASE.
 */
{
int	derf;

	for (derf=0; s[derf]; derf++)
	    if (isupper(s[derf]))
	       s[derf] = tolower(s[derf]);
}


strupr (s)
char	s[];
/*
 *	CONVERT s TO UPPERCASE.
 */
{
int	derf;

	for (derf=0; s[derf]; derf++)
	    if (islower(s[derf]))
	       s[derf] = toupper(s[derf]);
}
