// DoVerb.cpp : Handler for general commands
//

#include "stdafx.h"
#include "string.h"

#include "AdvDebug.h"
#include "AdvIO.h"
#include "AdvMain.h"
#include "AdvUtil.h"
#include "DoVerb.h"
#include "Drop.h"
#include "Get.h"
#include "OpenClose.h"
#include "Pour.h"
#include "Retort.h"
#include "Throw.h"
#include "Travel.h"
#include "Utilitarian.h"

/////////////////////
// Forward references
void blastProc (AdvGlobalContext& gc);
void breakProc (AdvGlobalContext& gc);
void digProc (AdvGlobalContext& gc);
void drinkProc (AdvGlobalContext& gc);
void eatProc (AdvGlobalContext& gc);
void feedProc (AdvGlobalContext& gc);
void fillProc (AdvGlobalContext& gc);
void fixProc (AdvGlobalContext& gc);
void fuckProc (AdvGlobalContext& gc);
void killProc (AdvGlobalContext& gc);
void lostProc (AdvGlobalContext& gc);
void mistProc (AdvGlobalContext& gc);
void offProc (AdvGlobalContext& gc);
void onProc (AdvGlobalContext& gc);
void peruseProc (AdvGlobalContext& gc);
void placateProc (AdvGlobalContext& gc);
void pushProc (AdvGlobalContext& gc);
void rubProc (AdvGlobalContext& gc);
void screamProc (AdvGlobalContext& gc);
void throwProc (AdvGlobalContext& gc);
void waveProc (AdvGlobalContext& gc);
void wizardProc (AdvGlobalContext& gc);

///////////////////
// Public functions

void doVerb
  (AdvGlobalContext& gc)   // global context
//
//  Handler for general commands
//
{
  switch (gc.m_nArg1)
  {
    case blast:
      blastProc (gc);
      break;
    case breakit:
      breakProc (gc);
      break;
    case climb:
      climbProc (gc);
      break;
    case dig:
      digProc (gc);
      break;
    case drink:
      drinkProc (gc);
      break;
    case drop:
      dropProc (gc);
      break;
    case eat:
      eatProc (gc);
      break;
    case feed:
      feedProc (gc);
      break;
    case fill:
      fillProc (gc);
      break;
    case fix:
      fixProc (gc);
      break;
    case fuck:
      fuckProc (gc);
      break;
    case jump:
      jumpProc (gc);
      break;
    case kill:
      killProc (gc);
      break;
    case lock:
      closeProc (gc);
      break;
    case look:
      // "Sorry, but I am not allowed to give more detail..."
      sayMessage (gc, nocanlook);
      lookProc (gc);
      break;
    case lost:
      lostProc (gc);
      break;
    case lpsd:
      advDebug (gc);
      break;
    case mist:
      mistProc (gc);
      break;
    case obtain:
      getProc (gc);
      break;
    case off:
      offProc (gc);
      break;
    case on:
      onProc (gc);
      break;
	  case peruse:
	    peruseProc (gc);
	    break;
	  case placate:
	    placateProc (gc);
	    break;
	  case pour:
	    pourProc (gc);
	    break;
	  case push:
	    pushProc (gc);
	    break;
	  case ride:
	    rideProc (gc);
	    break;
	  case rub:
	    rubProc (gc);
	    break;
	  case scream:
	    screamProc (gc);
	    break;
	  case silly:
	    sillyProc (gc);
	    break;
	  case swim:
	    swimProc (gc);
	    break;
	  case throw_it:
	    throwProc (gc);
	    break;
	  case unlock:
	    openProc (gc);
	    break;
	  case wave:
	    waveProc (gc);
	    break;
	  case wizard:
	    wizardProc (gc);
	    break;

    default:
      printf ("<GLITCH!> Verb not handled for arg1=%d, nArg2=%d, context=%d\n",
              gc.m_nArg1, gc.m_nArg2, gc.m_nContext);
      printf ("Please report this bug to ravib@ravib.com.  Thanks!\n");
      break;
  }
}

void lookProc
  (AdvGlobalContext& gc)   // global context
//
//  Handler for "look".
//
{
  // Describe fog/glow
  if (near (glow) || near (fog))
     {
       if (near (glow))
          describeObject (gc, glow, gc.m_nState [glow]);
       else
          if (gc.m_nState [fog] < 8)
             describeObject (gc, fog, gc.m_nState [fog]);
          else
             {
               printf ("<GLITCH!> lookProc() could not describe anynObject\n");
               return;
             }
     }

  // If there's light gc.m_nHere ...
  bool bDescribedObject = false;
  long nObject;
  if ((near (lamp) && (gc.m_nState [lamp]==1)) || gc.m_lit [gc.m_nHere])
     {
       // Describe location
       if ((gc.m_nArg1 != look) && gc.m_bFastMode)
          describePlace (gc, gc.m_nHere, false);  // lamp has just been turned
       else                                       // on while in fast mode
          describePlace (gc, gc.m_nHere, true);
       gc.m_visited [gc.m_nHere]++;

       // Describe primary objects
       for (nObject=MINOBJECTS; (nObject <= MAXOBJECTS); nObject++)
           if (gc.m_firstDesc [nObject] &&
               (gc.m_nWhereIs [nObject] == gc.m_nHere) &&
               !gc.m_invisible [nObject] &&
               !gc.m_noDesc [nObject])
              {
                if (!bDescribedObject)
                   {
                     printf ("\n");
                     bDescribedObject = true;
                   }
                describeObject (gc, nObject, gc.m_nState [nObject]);
              }

       // Describe other stuff
       bDescribedObject = false;
       for (nObject=MINOBJECTS; (nObject <= MAXOBJECTS); nObject++)
           if (!gc.m_noDesc [nObject])
              if (near(nObject) && !carrying(nObject))
                 if (!gc.m_invisible [nObject] && !gc.m_firstDesc [nObject])
                    {
                      if (!bDescribedObject)
                         {
                           printf ("\n");
                           bDescribedObject = true;
                         }
                      describeObject (gc, nObject, gc.m_nState [nObject]);
                      gc.m_seen [nObject] = true;
                    }

       // Tell him about the bear and dwarves, if any
       if (carrying(bear))
          {
            sayMessage (gc, blank);
            sayMessage (gc, i_c_a_bear);
            sayMessage (gc, blank);
          }

       if (near(dwarf))
          {
            sayMessage (gc, blank);
            if (gc.m_nDwarvesInRoom == 1)
               sayMessage (gc, dwarfhere);
            else
               sayMessageValue (gc, dwarveshere, gc.m_nDwarvesInRoom);
            sayMessage (gc, blank);
          }
     }
  else
     sayMessage (gc, nolighthere);
}

void mistProc
  (AdvGlobalContext& gc)   // global context
//
//  Handler for "mist".
//
{
  if (at(pit) || at(mists) || at(eastoffissur) || at(westoffissur) ||
      at(window) || at(window2) || at(wendmists) || at(misty) ||
      at(mirrorcnyn) || at(reservoir) || at(reservoir_n) || at(warm) ||
      at(swofchasm) || at(neofchasm))
     sayMessage (gc, thisismist);
  else
     sayMessageWord (gc, idontsee, mist);
}

void sillyProc
  (AdvGlobalContext& gc)   // global context
//
//  Handles silly requests.
//
{
  if (chance (33))
     sayMessage (gc, silly1);
  else
     if (chance(50))
        sayMessage (gc, silly2);
     else
        sayMessage (gc, silly3);
}

////////////////////
// Private functions

void blastProc
  (AdvGlobalContext& gc)   // global context
//
//  Handler for "blast".
//
{
  if (gc.m_nCmdWords != 1)
     sayMessage (gc, what);
  else
     sayMessage (gc, needdynamite);
}

void breakProc
  (AdvGlobalContext& gc)   // global context
//
//  Handler for "break".
//
{
  if (gc.m_nCmdWords == 1)
     {
       gc.m_nContext = breakit;
       sayMessageWord (gc, clarify, breakit);
     }
  else
     if (!isObject (gc.m_nArg2))
        sayMessage (gc, what);
     else
        if (!near (gc.m_nArg2) && (gc.m_nArg2 != mirror))
           sayMessageWord (gc, idontsee, gc.m_nArg2);
        else
           if (gc.m_mortal [gc.m_nArg2] || (gc.m_nArg2 == shards))
              if (chance (75))
                 sayMessage (gc, beserious);
              else
                 sayMessage (gc, iamgame);
           else
              switch (gc.m_nArg2)
              {
                case mirror:
                  if (near (mirror))
                     describeObject (gc, mirror, gc.m_nState [mirror]);
                  else
                     if (near (mirror2))
                        if (carrying(axe) || carrying(shovel) || carrying(sword))
                           if (gc.m_nState [mirror2])
                              sayMessage (gc, nothing);
                           else
                              {
                                describeObject (gc, mirror2, gc.m_nState [mirror2]);
                                gc.m_nState [mirror2] = 1 + random (2);
                                describeObject (gc, mirror2, gc.m_nState [mirror2]);
                                gc.m_noDesc [mirror2] = false;
                              }
                           else
                              sayMessage (gc, iamgame);
                        else
                           sayMessageWord (gc, idontsee, mirror);
                  break;

                case vase:
                  sayMessage (gc, throw_vase);
                  apport (vase, limbo);
                  apport (shards, gc.m_nHere);
                  break;

                case vial:
                  breakVial (gc);
                  break;

                default:
                  sayMessage (gc, no_can_fix);
                  break;
              }
}

void digProc
  (AdvGlobalContext& gc)   // global context
//
//  Handler for "dig".
//
{
  if (gc.m_nArg2 == errword)
     sayMessage (gc, huh);
  else
     sayMessage (gc, needshovel);
}

void drinkProc
  (AdvGlobalContext& gc)   // global context
//
//  Handler for "drink".
//
{
  if ((gc.m_nCmdWords == 1) || (gc.m_nArg2 == water))
     {
       if (gc.m_waterHere [gc.m_nHere])
          {
            sayMessage (gc, slurp);
            return;
          }
       else
          if (near (bottle) && (gc.m_nState [bottle] == 0))
             {
               sayMessage (gc, watergone);
               apport (water, limbo);
               gc.m_nState [bottle] = 1;
               return;
             }
       if (gc.m_nArg2 == water)
          sayMessageWord (gc, idontsee, water);
       else
          sayMessage (gc, cantdrink);
       return;
     }

  if (isObject (gc.m_nArg2))
     if (near (gc.m_nArg2))
        if (chance (50))
           sayMessage (gc, hah);
        else
           sayMessage (gc, beserious);
     else
        sayMessageWord (gc, idontsee, gc.m_nArg2);
  else
     sayMessage (gc, what);
}

void eatProc
  (AdvGlobalContext& gc)   // global context
//
//  Handler for "eat".
//
{
  if (near (mushroom) && ((gc.m_nCmdWords == 1) || (gc.m_nArg2 == mushroom)))
     {
       if (carrying (mushroom))
          dropIt (mushroom);
       gc.m_nState [mushroom] = 2;
       describeObject (gc, mushroom, gc.m_nState [mushroom]);
       gc.m_nMushTime = gc.m_nLastClock + 30;
       apport (mushroom, limbo);
       gc.m_nStrength = 12;
       return;
     }
  else
     if (near (food) && ((gc.m_nCmdWords == 1) || (gc.m_nArg2 == food)))
        {
          gc.m_nState [food] = 1;
          apport (food, limbo);
          sayMessage (gc, urrp);
          return;
        }
     else
        if (gc.m_nCmdWords == 1)
           {
             sayMessage (gc, no_food);
             return;
           }
        else
           if (!isObject (gc.m_nArg2))
              {
                sayMessage (gc, what);
                return;
              }
           else
              if (!near (gc.m_nArg2))
                 {
                   sayMessageWord (gc, idontsee, gc.m_nArg2);
                   return;
                 }

  // He wants to eat an object (not food or mushroom) that *is* gc.m_nHere
  if (gc.m_mortal [gc.m_nArg2])
     switch (gc.m_nArg2)
     {
       case bird:
       case snake:
       case plant:
       case dragon:
       case basilisk:
         sayMessage (gc, bleah);
         return;
       default:
         sayMessage (gc, repulsive);
        return;
     }
  else
     if (chance (65))
        sayMessage (gc, bleah);
     else
        sayMessage (gc, beserious);
  return;
}

void feedProc
  (AdvGlobalContext& gc)   // global context
//
//  Handler for "feed".
//
{
  // First, the obvious cases ...
  if (gc.m_nCmdWords == 1)
     {
       gc.m_nContext = feed;
       sayMessageWord (gc, clarify, feed);
       return;
     }
  if (!isObject (gc.m_nArg2))
     {
       sayMessage (gc, what);
       return;
     }
  if (!near (gc.m_nArg2))
     {
       sayMessageWord (gc, idontsee, gc.m_nArg2);
       return;
     }
  if (!gc.m_mortal [gc.m_nArg2])
     {
       sayMessage (gc, hah);
       return;
     }

  // Next, the special cases
  switch (gc.m_nArg2)
  {
    case bear:
      if (near (food))
         {
           sayMessage (gc, bear_urrp);
           gc.m_nState [bear] = 1;
           apport (food, limbo);
           if (gc.m_nState [axe] == 1)
              gc.m_nState [axe] = 0;
         }
      else
         sayMessage (gc, snakewonteat);
      break;

    case troll:
      sayMessage (gc, feed_troll);
      break;

    case snake:
      if (carrying (bird))
         {
           sayMessage (gc, snake_bird);
           apport (bird, limbo);
         }
      else
         sayMessage (gc, snakewonteat);
      break;

    case dwarf:
      sayMessage (gc, fed_dwarf);
      gc.m_special2 [dwarf] = true;
      break;

    case bird:
      sayMessage (gc, birdseed);
      break;

    case dragon:
      sayMessage (gc, gc.m_nState [dragon] ? it_is_dead : snakewonteat);
      break;

    case basilisk:
      sayMessage (gc, gc.m_nState [basilisk] < 2 ? snakewonteat : it_is_dead);
      break;

    case goblins:
      sayMessage (gc, gobl_eat_you);
      break;

    default:
      sayMessage (gc, hah);
  }
}

void fillProc
  (AdvGlobalContext& gc)   // global context
//
//  Handler for "fill".
//
{
  if (gc.m_nCmdWords == 1)
     {
       gc.m_nContext = fill;
       sayMessageWord (gc, clarify, fill);
       return;
     }
  if (!isObject (gc.m_nArg2))
     sayMessage (gc, what);
  else
     if (!near (gc.m_nArg2))
        sayMessageWord (gc, idontsee, gc.m_nArg2);
     else
        if (gc.m_mortal [gc.m_nArg2])
           sayMessage (gc, repulsive);
        else
           switch (gc.m_nArg2)
           {
             case bottle:
               if (gc.m_nState [bottle] == 1)
                  if (gc.m_waterHere [gc.m_nHere])
                     {
                       sayMessage (gc, bottle_h2o);
                       gc.m_nState [bottle] = 0;
                       if (carrying(bottle))
                          getIt (water);
                     }
                  else
                     if (at (eastpit))
                        {
                          sayMessage (gc, bottle_oil);
                          gc.m_nState [bottle] = 2;
                          if (carrying (bottle))
                             getIt (oil);
                        }
                     else
                        sayMessage (gc, nothing2fill);
               else
                  sayMessage (gc, bottlewasfull);
               break;

             case vase:
               if (gc.m_waterHere [gc.m_nHere] || at (eastpit))
                  {
                    sayMessage (gc, shatter_vase);
                    apport (vase, limbo);
                    apport (shards, gc.m_nArg2);
                  }
               else
                  sayMessage (gc, nothing_vase);
               break;

             default:
               sayMessage (gc, cantfillthat);
               break;
           }
}

void fixProc
  (AdvGlobalContext& gc)   // global context
//
//  Handler for "fix".
//
{
  if (gc.m_nCmdWords == 1)
     {
       sayMessageWord (gc, clarify, fix);
       return;
     }

  if (!isObject (gc.m_nArg2))
     sayMessage (gc, what);
  else
     if (gc.m_nArg2!=vase && !near(gc.m_nArg2))
        sayMessageWord (gc, idontsee, gc.m_nArg2);
     else
        if (gc.m_mortal [gc.m_nArg2])
           sayMessage (gc, beserious);
        else
           if ((gc.m_nArg2 == vase) || (gc.m_nArg2 == shards))
              if (near (vase) || near (shards))
                 sayMessage (gc, no_can_fix);
              else
                 sayMessageWord (gc, idontsee, gc.m_nArg2);
           else
              sayMessageWord (gc, dunno_hao, fix);
}

void fuckProc
  (AdvGlobalContext& gc)   // global context
//
//  Handler for "fuck".
//
{
  if ((gc.m_nArg2 == null) || !isObject (gc.m_nArg2))
     {
       retort (gc);
       return;
     }

  if (!near (gc.m_nArg2))
     {
       sayMessageWord (gc, not_here, gc.m_nArg2);
       return;
     }

  if (gc.m_mortal [gc.m_nArg2])
     if (chance (50))
        sayMessage (gc, repulsive);
     else
        sayMessage (gc, hah);
  else
     if (chance (70))
        sayMessage (gc, hah);
     else
        sayMessage (gc, iamgame);
}

void killProc
  (AdvGlobalContext& gc)   // global context
//
//  Handler for "kill".
//
{
  // Figure out what he wants to kill
  if (gc.m_nCmdWords == 1)
     {
       long   nTarget = -1;
       for (long nObject=MINOBJECTS; (nObject <= MAXOBJECTS); nObject++)
           if (gc.m_mortal [nObject] &&  near (nObject))
              if (nTarget == -1)
                 nTarget = nObject;
              else
                 if (nTarget < 0)
                    nTarget = -2;
       if (nTarget == -1)
          {
            sayMessage (gc, pacifist);
            return;
          }
       if (nTarget == -2)
          {
            sayMessageWord (gc, clarify, kill);
            return;
          }
       gc.m_nArg2 = nTarget;
     }

  if (!near (gc.m_nArg2))
     sayMessageWord (gc, idontsee, gc.m_nArg2);
  else
     if (!gc.m_mortal [gc.m_nArg2])
        sayMessage (gc, hah);
     else
        switch (gc.m_nArg2)
        {
          case troll:
            sayMessage (gc, troll_data);
            break;

          case dwarf:
            if (yes (gc, withwhat))
               {
                 long nSurvival = (gc.m_nStrength - gc.m_nInventory + 2) * 10;
                 if (chance (nSurvival))
                    sayMessage (gc, dwarfdodges);
                 else
                    {
                      sayMessage (gc, dwarfstabs);
                      coroner (gc);
                      return;
                    }
               }
            else
               sayMessage (gc, ok);
            break;

          case dragon:
            if (gc.m_nState [dragon] > 0)
               sayMessage (gc, it_is_dead);
            else
               if (yes (gc, withwhat))
                  {
                    gc.m_nState [dragon] = 1;         // dying dragon's
                    describeObject (gc, dragon, 1);   // teeth fall out
                    gc.m_nState [dragon] = 2;         // dead dragon
                    gc.m_nState [rug] = 1;            // rug can be taken
                    apport (teeth, gc.m_nHere);       // so can teeth
                  }
               else
                  sayMessage (gc, ok);
            break;

          case snake:
            sayMessage (gc, cantkillsnake);
            break;

          case blob:
            sayMessage (gc, bounce_blob);                  
            break;

          case bear:
            if (gc.m_nState [bear] == 0)
               sayMessage (gc, kill_bear);
            else
               sayMessage (gc, bear_puzzled);
            break;

          case clam:
          case oyster:
            sayMessage (gc, kill_oyster);
            break;

          case ogre:
            if (yes (gc, withwhat))
               if (chance (50))
                  sayMessage (gc, ogre_too_tough);
               else
                  {
                    sayMessage (gc, ogre_rips_head_off);
                    coroner (gc);
                    return;
                  }
            else
               sayMessage (gc, ok);
            break;

          case bird:
            if (gc.m_nClosure < 3)
               {
                 apport (bird, limbo);
                 sayMessage (gc, birdisdead);
               }
            else
               sayMessage (gc, leave_bird);
            break;

          case djinn:
            sayMessage (gc, tough_djinn);
            break;

          case goblins:
            sayMessage (gc, kill_goblins);
            coroner (gc);
            return;
            break;

          case basilisk:
            if (gc.m_nState [basilisk] < 2)
               {
                 sayMessage (gc, hit_basilisk);
                 coroner (gc);
                 return;
               }
            else
               sayMessage (gc, it_is_dead);
            break;

          case gong:
            if (near (turtle))
               sayMessage (gc, gong_rings);
            else
               {
                 sayMessage (gc, gong_fetch);
                 apport (turtle, gc.m_nHere);
               }
            break;

          case turtle:
            sayMessage (gc, beserious);
            break;

          default:
            printf ("GLITCH!  killProc() called with mortal %d\n", gc.m_nArg2);
            printf ("Please submit a bug report to ravib@ravib.com.  Thanks!\n");
            break;
        }
}

void lostProc
  (AdvGlobalContext& gc)   // global context
//
//  Handler for "lost".
//
{
  sayMessage (gc, imconfused);
}

void offProc
  (AdvGlobalContext& gc)   // global context
//
//  Handler for switching off nObjects.
//
{
  if ((gc.m_nArg2 == lamp) || (gc.m_nArg2 == null))
     {
       if (near (lamp))
          if (gc.m_nState [lamp] == 0)
             sayMessage (gc, lampwasoff);
          else
             {
               gc.m_nState [lamp] = 0;
               if (!gc.m_lit [gc.m_nHere])
                  sayMessage (gc, itisnowdark);
               else
                  sayMessage (gc, lampnowoff);
               phog (gc);
             }
       else
          if (gc.m_nArg2 == lamp)
             sayMessageWord (gc, idontsee, lamp);
          else
             sayMessage (gc, nolighthere);
     }
  else
     if (gc.m_nArg2 == stove)
        sayMessage (gc, stoveoff);
     else
        sayMessage (gc, hah);
}

void onProc
  (AdvGlobalContext& gc)   // global context
//
//  Handler for switching on objects.
//
{
  if (gc.m_nArg2 == lamp)
     if (near (lamp))
        {
          if ((gc.m_nLampLife < 40) && (near (batteries)) && (gc.m_nState [batteries] == 0))
             {
               sayMessage (gc, new_batteries);
               gc.m_nState [batteries] = 1;
               gc.m_nLampLife += 300;
               gc.m_special1 [lamp] = 0;
             }

          if (gc.m_nLampLife > 0)
             {
               sayMessage (gc, lampnowon);
               if (gc.m_nState [lamp] < 1)
                  if (!gc.m_lit [gc.m_nHere])
                     {
                       gc.m_nState [lamp] = 1;
                       sayMessage (gc, blank);
                       lookProc (gc);
                     }
               gc.m_nState [lamp] = 1;
               phog (gc);
             }
          else
             sayMessage (gc, lamp_is_dead);
        }
     else
        sayMessageWord (gc, idontsee, lamp);
  else
     if (gc.m_nCmdWords == 1)
        if (near (lamp))
           {
             if (gc.m_nLampLife < 40)
                if (near (batteries) && (gc.m_nState [batteries] == 0))
                   {
                     sayMessage (gc, new_batteries);
                     gc.m_nState [batteries] = 1;
                     gc.m_nLampLife += 300;
                     gc.m_special1 [lamp] = false;
                   }

             if (gc.m_nLampLife > 0)
                {
                  if (gc.m_nState [lamp] < 1)
                     {
                       sayMessage (gc, lampnowon);
                       gc.m_nState [lamp] = 1;
                       phog (gc);
                       if (!gc.m_lit [gc.m_nHere])
                          {
                            sayMessage (gc, blank);
                            lookProc (gc);
                          }
                     }
                  else
                     sayMessage (gc, lampwason);
                }
             else
                sayMessage (gc, lamp_is_dead);
           }
        else
           sayMessage (gc, nolighthere);
     else
        if (gc.m_nArg2 == stove)
           if (near (stove))
              if (gc.m_nState [scroll] == 0)
                 {
                   gc.m_special2 [stove] = true;    // stove is lit
                   describeObject (gc, stove, 4);
                   gc.m_nState [scroll] = 1;        // burned
                 }
              else
                 sayMessage (gc, nothing);
           else
              sayMessageWord (gc, idontsee, stove);
        else
           sayMessage (gc, hah);
}

void peruseProc
  (AdvGlobalContext& gc)   // global context
//
//  Handler for "read".
//
{
  if (gc.m_nCmdWords == 1)
     {
       gc.m_nContext = peruse;
       sayMessageWord (gc, clarify, peruse);
       return;
     }

  if (!isObject (gc.m_nArg2))
     sayMessage (gc, what);
  else
     if (!near (gc.m_nArg2) || gc.m_invisible [gc.m_nArg2])
        sayMessageWord (gc, idontsee, gc.m_nArg2);
     else
        if (gc.m_mortal [gc.m_nArg2])
           sayMessage (gc, hah);
        else
           switch (gc.m_nArg2)
           {
             case scroll:
               if (gc.m_nState [scroll] == 1)
                  sayMessage (gc, cant_read_scroll);
               else
                  sayMessage (gc, read_scroll);
               break;

             case magazines:
               sayMessage (gc, mag_dwarvish);
               break;

             case message:
               sayMessage (gc, chest_elsewhere);
               break;

             case tablet:
               sayMessage (gc, dark_room);
               break;

             case machine:
               sayMessage (gc, machine_sign);
               break;

             default:
               sayMessageWord (gc, dunno_hao, peruse);
               break;
           }
}

void placateProc
  (AdvGlobalContext& gc)   // global context
//
//  Handler for "placate".
//
{
  switch (gc.m_nArg2)
  {
    case dwarf:
    case snake:
    case bird:
    case dragon:
    case troll:
    case bear:
    case pirate:
    case ogre:
    case basilisk:
    case goblins:
      if (near (gc.m_nArg2))
         sayMessage (gc, iamgame);
      else
         sayMessageWord (gc, idontsee, gc.m_nArg2);
      break;
    default:
      sayMessage (gc, what);
  }
}

void pushProc
  (AdvGlobalContext& gc)   // global context
//
//  Handler for "push".
//
{
  if ((gc.m_nCmdWords == 1) || !isObject (gc.m_nArg2))
     sayMessage (gc, what);
  else
     if (gc.m_mortal [gc.m_nArg2])
        sayMessage (gc, chance (50) ? hah : beserious);
     else
        if (gc.m_nArg2 != stove)
           sayMessage (gc, what);
        else
           if ((gc.m_nState [mushroom] == 2) || (gc.m_nState [food] == 1))  // eaten
              {
                if (gc.m_nState [stove] == 0)   // covering trapdoor
                   {
                     describeObject (gc, stove, 1);
                     gc.m_nState [stove] = 2;
                   }
                else
                   {
                     describeObject (gc, stove, 3);
                     gc.m_nState [stove] = 0;
                   }
                gc.m_invisible [trapdoor] = !gc.m_invisible [trapdoor];
              }
           else
              sayMessage (gc, stove_rocks);
}

void rubProc
  (AdvGlobalContext& gc)   // global context
//
//  Handles rubbing.
//
{
  // First, the obvious situations ...
  if (gc.m_nCmdWords == 1)
     {
       gc.m_nContext = rub;
       sayMessageWord (gc, clarify, rub);
       return;
     }
  if (!isObject (gc.m_nArg2))
     {
       sayMessage (gc, what);
       return;
      }
  if (!near (gc.m_nArg2))
     {
       sayMessageWord (gc, idontsee, gc.m_nArg2);
       return;
     }
  if (gc.m_mortal [gc.m_nArg2])
     {
       sayMessage (gc, repulsive);
       return;
     }

  if (chance (50))
     sayMessageWord (gc, rublamp, gc.m_nArg2);
  else
     sayMessage (gc, peculiar);
}

void screamProc
  (AdvGlobalContext& gc)   // global context
//
//  Handles screaming.
//
{
  if (gc.m_nCmdWords == 2)
     {
       strupr (gc.m_szArg2);
       sayProc (gc);
       return;
     }

  if (chance (30))
     printf ("Aaaaaaaaaaaaaargh!  (I hope you're enjoying yourself)\n");
  else
     if (chance (50))
        printf ("Aiiiiiieeeeeeeeeeee!  (My, aren't we having fun)\n");
     else
        printf ("Eeeeeeeeeeeeeeeek!  (Oh boy, we have a live one here)\n");
}

void throwProc
  (AdvGlobalContext& gc)   // global context
//
//  Handler for "throw"
//
{
  // Is he making sense?
  if (gc.m_nCmdWords == 1)
     {
       gc.m_nContext = throw_it;
       sayMessageWord (gc, clarify, throw_it);
     }
  else
     if (!isObject (gc.m_nArg2))
        if (chance (50))
           sayMessage (gc, i_dont_understand);
        else
           sayMessage (gc, huh);

     // Does he have the object?
     else
        if (!near (gc.m_nArg2))
           sayMessageWord (gc, idontsee, gc.m_nArg2);

        // Can't throw mortals or non-portable nObjects
        else
           if (gc.m_mortal [gc.m_nArg2])
              sayMessage (gc, beserious);
           else
              if (!gc.m_portable [gc.m_nArg2])
                 sayMessage (gc, no_can_fix);

              // And must be holding it
              else
                 if (!carrying (gc.m_nArg2))
                    sayMessage (gc, notcarrying);
                 else

                    // Throw the object
                    switch (gc.m_nArg2)
                    {
                      case axe:
                      case sword:
                        throwWeapon (gc);
                        break;
                      case food:
                        throwFood (gc);
                        break;
                      case teeth:
                        throwTeeth (gc);
                        break;
                      case vial:
                        breakVial (gc);
                        break;
                      case oil:
                      case water:
                        dropLiquid (gc);
                        break;
                      case cage:
                        dropCage (gc);
                        break;
                      default:
                        if (gc.m_thrower [gc.m_nHere])  // handles throwing objects
                           upChuck (gc);                // at troll
                        else
                           {
                             dropIt (gc.m_nArg2);
                             sayMessage (gc, ok);
                           }
                        break;
                    }

  gc.m_bOk2Describe = false;
}

void waveProc
  (AdvGlobalContext& gc)   // global context
//
//  Handler for "wave".
//
{
  // First, the obvious situations...
  if (gc.m_nCmdWords == 1)
     if (at(window))
        {
          sayMessage (gc, waveback);
          return;
        }
     else
        {
          gc.m_nContext = wave;
          sayMessageWord (gc, clarify, wave);
          return;
        }

  // Can only wave an object that he's carrying
  if (!isObject (gc.m_nArg2))
     {
       sayMessage (gc, what);
       return;
     }
  if (!gc.m_portable [gc.m_nArg2])
     {
       sayMessage (gc, hah);
       return;
     }
  if (!near (gc.m_nArg2))
     {
       sayMessageWord (gc, idontsee, gc.m_nArg2);
       return;
     }
  if (!carrying (gc.m_nArg2))
     {
       sayMessage (gc, notcarrying);
       return;
     }

  // Special cases
  switch (gc.m_nArg2)
  {
    case rod:
      if (near (fissure))   // toggle crystal bridge
         if (gc.m_nClosure < 2)
            {
              gc.m_nState [fissure]++;
              describeObject (gc, fissure, gc.m_nState [fissure]);
              if (gc.m_nState [fissure] == 2)
                 {
                   gc.m_nState [fissure] = 0;
                   gc.m_invisible [fissure] = true;
                 }
              else
                 gc.m_invisible [fissure] = false;
            }
         else
            sayMessage (gc, nothing);
      else
         if (near (quicksand))    // harden the quicksand
            {
              sayMessage (gc, nothing_obvious);
              gc.m_nState [quicksand] = 1;
            }
         else
            if (near (wheatstone) && (gc.m_nClosure < 2))   // cycle wheatstone bridge
               {
                 gc.m_nState [wheatstone]++;
                 describeObject (gc, wheatstone, gc.m_nState [wheatstone]);
                 gc.m_nState [wheatstone]++;
                 if (gc.m_nState [wheatstone] == 4)
                    {
                      gc.m_nState [wheatstone] = 0;
                      gc.m_invisible [wheatstone] = true;
                      gc.m_noDesc [wheatstone] = true;
                    }
                 else
                    {
                      gc.m_invisible [wheatstone] = false;
                      gc.m_noDesc [wheatstone] = false;
                    }
               }
            else
               sayMessage (gc, nothing);
      break;

  case axe:
  case sword:
    throwWeapon (gc);
    break;

  default:
    sayMessage (gc, chance (50) ? nothing : ok);
  }
}

void wizardProc
  (AdvGlobalContext& gc)   // global context
//
//  Toggles wizard mode.
//
{
char  szPassword [256];   // wizard password

  if (gc.m_bWizard)
     {
       gc.m_bWizard = false;
       sayMessage (gc, ok);
       return;
     }
  else
     if ((gc.m_nCmdWords != 1) || (gc.m_nTurns > 5))
        {
          sayMessage (gc, magickword);
          return;
        }

  if (yes (gc, r_u_a_wizard))
     {
       sayMessage (gc, prove_it);
       printf ("> ");
       if (gets (szPassword) == NULL)
          printf ("\n");
       if (strcmp (szPassword, "rbmc") == 0)
          {
            sayMessage (gc, so_you_are);
            gc.m_bWizard = true;
            advDebug (gc);
          }
       else
          {
            sayMessage (gc, oh_pooh);
            gc.m_nPenalties += 10;
          }
     }
  else
     sayMessage (gc, ok);
}