// Get.cpp : Handler for getting various objects
//

#include "stdafx.h"
#include "string.h"

#include "AdvIO.h"
#include "AdvMain.h"
#include "AdvUtil.h"
#include "DoVerb.h"
#include "Get.h"

/////////////////////
// Forward references
void getAndSetState (AdvGlobalContext& gc, long nObject);
void getAll (AdvGlobalContext& gc);
void getAxe (AdvGlobalContext& gc);
void getBear (AdvGlobalContext& gc);
void getBird (AdvGlobalContext& gc);
void getBottle (AdvGlobalContext& gc);
void getCage (AdvGlobalContext& gc);
void getCarpet (AdvGlobalContext& gc);
void getChain (AdvGlobalContext& gc);
void getFlask (AdvGlobalContext& gc);
void getGold (AdvGlobalContext& gc);
void getKnife (AdvGlobalContext& gc);
void getOil (AdvGlobalContext& gc);
void getPlant (AdvGlobalContext& gc);
void getRug (AdvGlobalContext& gc);
void getSceptre (AdvGlobalContext& gc);
void getScroll (AdvGlobalContext& gc);
void getSculpture (AdvGlobalContext& gc);
void getSword (AdvGlobalContext& gc);
void getTree (AdvGlobalContext& gc);
void getTurtle (AdvGlobalContext& gc);
void getWater (AdvGlobalContext& gc);

///////////////////
// Public functions

void getProc
  (AdvGlobalContext& gc)   // global context
//
//  Handles picking up various objects.
//
{
  // First, take care of the obvious no-nos
  if (!gc.m_lit [gc.m_nHere])
     if ((gc.m_nState [lamp] == 0) || !near(lamp))
        if (gc.m_nHere != dark)
           {
             sayMessage (gc, cant_see_anything);
             return;
           }

  if (gc.m_nCmdWords == 1)
     {
       // Find out what he wants to pick up
       long nObjectToGet = -1;    // -1 means none, -2 means more than one object
       for (long nObject=MINOBJECTS; (nObject <= MAXOBJECTS); nObject++)
           if ((gc.m_nWhereIs [nObject] == gc.m_nHere) && gc.m_portable [nObject])
              if (nObjectToGet == -1)
                 nObjectToGet = nObject;
              else
                 {
                   nObjectToGet = -2;
                   break;
                 }

       // If there's only thing he can pick up here, assume it's the one he wants
       if ((nObjectToGet >= 0) && !gc.m_invisible [nObjectToGet])
          {
            gc.m_nArg2 = nObjectToGet;
            printf ("(%s)\n", gc.m_objects [gc.m_nArg2].pszInventory);
          }
       else
          {
            // Otherwise ask him what he wants to get
            sayMessageWord (gc, clarify, obtain);
            gc.m_nContext = obtain;
            return;
          }
     }

  // It had better be an object!
  if ((gc.m_nArg2 != all) && !isObject (gc.m_nArg2))
     {
       sayMessage (gc, what);
       return;
     }

	// Can't pick up anything in the fog
	if ((gc.m_nWhereIs [fog] == gc.m_nHere) &&
      (gc.m_nState [fog] < 8) &&
      !gc.m_invisible [fog] &&
      (gc.m_nWhereIs [glow] != gc.m_nHere))
	   {
	     if ((gc.m_nArg2 == fog) || (gc.m_nArg2 == glow))
	        sillyProc (gc);
	     else
	        if (gc.m_nArg2 == all)
	           sayMessage (gc, foggy2);
	        else
	           sayMessageWord (gc, foggy, gc.m_nArg2);
	     return;
	   }

	// Special case: "get all"
	if ((gc.m_nArg2 == all) || (gc.m_nArg2 == treasure))
	   {
	     getAll (gc);
	     return;
	   }

  // Already carrying it?
  if (carrying (gc.m_nArg2) && (gc.m_nArg2 != bear))
     {
       sayMessage (gc, youhaveit);
       return;
     }

  // Attempting to get a normal object that's not here?
  if ((gc.m_nArg2 != knife) && (gc.m_nArg2 != oil) && (gc.m_nArg2 != water) &&
      (gc.m_nArg2 != plant) && (gc.m_nArg2 != fissure))
     if (gc.m_invisible [gc.m_nArg2] || !near (gc.m_nArg2))
        {
          sayMessageWord (gc, idontsee, gc.m_nArg2);
          return;
        }

  // Attempting to get something he can't carry
  if (!gc.m_portable [gc.m_nArg2] &&
      (gc.m_nArg2 != tree) &&
      (gc.m_nArg2 != plant))
     {
       sayMessage (gc, hah);
       return;
     }

  // Is he loaded?
  if (gc.m_nInventory == gc.m_nStrength)
     if (!gc.m_weightless [gc.m_nArg2])
        if ((gc.m_nArg2 != tree) && (gc.m_nArg2 != plant))
           {
             sayMessage (gc, armsarefull);
             return;
           }

  // Next, check for specific gets
  switch (gc.m_nArg2)
  {
    case bag:
    case beads:
    case crown:
    case mushroom:
    case yacht:
      getAndSetState (gc, gc.m_nArg2);
      return;

    case axe:
      getAxe (gc);
      return;
    case bear:
      getBear (gc);
      return;
    case bird:
      getBird (gc);
      return;
    case bottle:
      getBottle (gc);
      return;
    case cage:
      getCage (gc);
      return;
    case carpet:
      getCarpet (gc);
      return;
    case chain:
      getChain (gc);
      return;
    case flask:
      getFlask (gc);
      return;
    case gold:
      getGold (gc);
      return;
    case knife:
      getKnife (gc);
      return;
    case oil:
      getOil (gc);
      return;
    case plant:
      getPlant (gc);
      return;
    case rug:
      getRug (gc);
      return;
    case sceptre:
      getSceptre (gc);
      return;
    case scroll:
      getScroll (gc);
      return;
    case sculpture:
      getSculpture (gc);
      return;
    case sword:
      getSword (gc);
      return;
    case tree:
      getTree (gc);
      return;
    case turtle:
      getTurtle (gc);
      return;
    case water:
      getWater (gc);
      return;
  }

  // Generic get
  getIt (gc.m_nArg2);
  sayMessage (gc, taken);
}

////////////////////
// Private functions

void getAndSetState
  (AdvGlobalContext&  gc,         // global context
   long               nObject)    // object
//
//  Gets object and updates its state.
//
{
	if (gc.m_nState [nObject] == 0)
	   gc.m_nState [nObject] = 1;
	getIt (nObject);
	sayMessage (gc, taken);
}

void getAll
  (AdvGlobalContext& gc)   // global context
//
//  Handles picking up all objects in the room.
//
{
long    nObject;      // object index
long    nSavedArg2;   // save value of 2nd arg
long    nTried;       // # objects we tried to pick up

  nSavedArg2 = gc.m_nArg2;

  // First attempt to grab all the treasures
  nTried = 0;
  for (nObject=MINTREASURES; (nObject <= MAXTREASURES); nObject++)
      if (!carrying (nObject) &&
          (gc.m_nWhereIs [nObject] == gc.m_nHere) &&
          gc.m_portable [nObject] &&
          !gc.m_invisible [nObject])
         {
           // Compute inventory count
           gc.m_nInventory = 0;
           for (long nObject2=MINOBJECTS; (nObject2 <= MAXOBJECTS); nObject2++)
               if (carrying (nObject2) && !gc.m_weightless [nObject2])
                  gc.m_nInventory++;

           // Is he overloaded?
           if ((gc.m_nInventory == gc.m_nStrength) && !gc.m_weightless [gc.m_nArg2])
              {
                sayMessage (gc, armsarefull);
                return;
              }
           else
              {
                // Display the object we're trying to pick up
                printf ("(%s)\n", gc.m_objects [nObject].pszInventory);
                gc.m_nArg2 = nObject;
                nTried++;
                getProc (gc);  // pick up the object
              }
         }

  // Is that all he wants?
  if (nSavedArg2 == treasure)
     {
       if (nTried == 0)
          sayMessageWord (gc, idontsee, treasure);
       return;
     }

  // Next, get the sundry items
  for (nObject=MINSUNDRIES; (nObject <= MAXSUNDRIES); nObject++)
      if (!carrying (nObject)                     &&
          gc.m_portable [nObject]                 &&
          (gc.m_nWhereIs [nObject] == gc.m_nHere)	&&
          !gc.m_invisible [nObject]               &&
          !gc.m_noDesc [nObject]                  &&
          ((nObject != knife) && (nObject != oil) && (nObject != water) &&
           (nObject != plant) && (nObject!=fissure)))
         {
           // Compute inventory count
           gc.m_nInventory = 0;
           for (long nObject2=MINOBJECTS; (nObject2 <= MAXOBJECTS); nObject2++)
               if (carrying (nObject2) && !gc.m_weightless [nObject2])
                  gc.m_nInventory++;

           // Is he overloaded?
           if ((gc.m_nInventory == gc.m_nStrength) && !gc.m_weightless [gc.m_nArg2])
              {
                sayMessage (gc, armsarefull);
                return;
              }
           else
              {
                // Display the object we're trying to pick up
                printf ("(%s)\n", gc.m_objects [nObject].pszInventory);
                gc.m_nArg2 = nObject;
                nTried++;
                getProc (gc);  // pick up the object
              }
         }

  // Go for the bird if you're carrying the cage and (a) the bird is already in
  // it or (b) it's not in it and you're not toting the rod.
  if (near (bird) && !carrying (bird) && carrying (cage) &&
      ((gc.m_nState [bird] == 1) || !carrying(rod)))
     {
       nTried++;
       getIt (bird);
       gc.m_nState [bird] = 1;
       printf ("(%s)\n", gc.m_objects [bird].pszInventory);
       sayMessage (gc, taken);
     }

  // Could we pick up anything?
  if (nTried == 0)
     sayMessage (gc, nothing2get);
}

void getAxe
  (AdvGlobalContext& gc)   // global context
//
//  Handles getting the dwarf's axe.
//
{
	if (gc.m_nState [axe] == 0)
	   {
	     getIt (axe);
	     sayMessage (gc, taken);
	     return;
	   }
	sayMessageWord (gc, cantgetaxe, axe);
}

void getBear
  (AdvGlobalContext& gc)   // global context
//
//  Handles getting the bear.
//
{
  if (carrying (bear))
     sayMessage (gc, i_c_a_bear);
  else
     if (at (bearhere))
        if (gc.m_nState [bear] == 2)
           {
             getIt (bear);
             sayMessage (gc, taken);
           }
        else
           sayMessage (gc, bear_is_chained);
     else
        {
          getIt (bear);
          sayMessage (gc, taken);
        }
}

void getBird
  (AdvGlobalContext& gc)   // global context
//
//  Handles getting the bird.
//
{
  if (gc.m_nState [bird] == 1)
     {
       getIt (cage);
       getIt (bird);
       sayMessage (gc, taken);
     }
  else
     if (carrying(cage))
        if (carrying(rod))
           sayMessage (gc, birdisscared);
        else
           {
             gc.m_hintable [birdchamber] = false;
             getIt (bird);
             gc.m_nState [bird] = 1;
             sayMessage (gc, taken);
           }
     else
        sayMessage (gc, needcage);
}

void getBottle
  (AdvGlobalContext& gc)   // global context
//
//  Handles getting the bottle and its contents, if any.
//
{
  getIt (bottle);
  if (gc.m_nState [bottle] == 0)
     getIt (water);
  else
     if (gc.m_nState [bottle] == 2)
        getIt (oil);
  sayMessage (gc, taken);
}

void getCage
  (AdvGlobalContext& gc)   // global context
//
//  Handles getting the cage.
//
{
  getIt (cage);
  if (near (bird))
     if (gc.m_nState [bird] == 1)
        getIt (bird);
  sayMessage (gc, taken);
}

void getCarpet
  (AdvGlobalContext& gc)   // global context
//
//  Handles picking up the carpet.
//
{
  sayMessage (gc, pile);
}

void getChain
  (AdvGlobalContext& gc)   // global context
//
//  Handles getting the golden chain.
//
{
  if (at (bearhere))
     if (gc.m_nState [chain] == 0)
        {
          getIt (chain);
          sayMessage (gc, taken);
        }
     else
        sayMessage (gc, chain_locked);
  else
     {
       getIt (chain);
       sayMessage (gc, taken);
     }
}

void getFlask
  (AdvGlobalContext& gc)   // global context
//
//  Handles picking up the flask.
//
{
  if (gc.m_nState [flask] == 1)
     gc.m_nState [flask] = 0;
	getIt (flask);
  sayMessage (gc, taken);
}

void getGold
  (AdvGlobalContext& gc)   // global context
//
//  Handles picking up the nugget of gold.
//
{
	getIt (gold);
	sayMessage (gc, taken);
}

void getKnife
  (AdvGlobalContext& gc)   // global context
//
//  Handles picking up the dwarves' knives.
//
{
  if (gc.m_notInCave [gc.m_nHere] || !gc.m_seen [axe])
      sayMessageWord (gc, idontsee, knife);
  else
      sayMessage (gc, no_knives);
}

void getOil
  (AdvGlobalContext& gc)   // global context
//
//  Handles picking up the oil.
//
{
  if (!at (eastpit))
     {
       sayMessageWord (gc, idontsee, gc.m_nArg2);
       return;
     }

  if (carrying (bottle))
     if (gc.m_nState [bottle] == 1)
        {
          gc.m_nState [bottle] = 2;
          getIt (oil);
          sayMessage (gc, bottle_oil);
        }
     else
        sayMessage (gc, bottlewasfull);
  else
     sayMessage (gc, nowaytocarry);
}

void getPlant
  (AdvGlobalContext& gc)   // global context
//
//  Handles picking up the plant.
//
{
  if (at (westpit))
     sayMessage (gc, get_plant);
  else
     sayMessageWord (gc, idontsee, plant);
}

void getRug
  (AdvGlobalContext& gc)   // global context
//
//  Handles getting the rug.
//
{
  if (at(secretnscyn) && (gc.m_nState [dragon] == 0))
     {
       sayMessage (gc, dragon_rug);
       return;
     }
  getIt (rug);
  sayMessage (gc, taken);
}

void getSceptre
  (AdvGlobalContext& gc)   // global context
//
//  Handles getting the sceptre.
//
{
  getIt (sceptre);
  if (gc.m_nState [sceptre] == 0)
     {
       // Get sceptre from skeleton, who utters a random password
       gc.m_nState [sceptre] = 1;
       gc.m_nPassword = random (5);
       switch (gc.m_nPassword)
       {
         case 0: gc.m_nPassword = blerbi; break;
         case 1: gc.m_nPassword = klaetu; break;
         case 2: gc.m_nPassword = knerl;  break;
         case 3: gc.m_nPassword = snoeze; break;
         case 4: gc.m_nPassword = zorton; break;
       }
       if (gc.m_nState [safe] == 0)
          sayMessageWord (gc, whisper, gc.m_nPassword);
       else
          sayMessage (gc, blew_safe);
       apport (skeleton, limbo);
     }
  else
     sayMessage (gc, taken);
}

void getScroll
  (AdvGlobalContext& gc)   // global context
//
//  Handles picking up the scroll.
//
{
  if (gc.m_nState [scroll] == 1)    // burned
     sayMessage (gc, scroll_is_burned);
  else
     {
       gc.m_nState [scroll] = 2;    // out of stove
       getIt (scroll);
       sayMessage (gc, taken);
     }
}

void getSculpture
  (AdvGlobalContext& gc)   // global context
//
//  Handles picking up the sculpture.
//
{
	if ((gc.m_nState [sculpture] % 2) == 0)
     gc.m_nState [sculpture]++;
	getIt (sculpture);
	sayMessage (gc, taken);
}

void getSword
  (AdvGlobalContext& gc)   // global context
//
//  Handles getting the sword.
//
{
  if (gc.m_nState [sword] == 0)
     if (gc.m_nState [mushroom] == 2)
        {
          getIt (sword);
          gc.m_nState [sword] = 1;
          sayMessage (gc, got_the_sword);
        }
     else
        sayMessage (gc, sword_is_stuck);
  else
     {
       getIt (sword);
       sayMessage (gc, taken);
     }
}

void getTree
  (AdvGlobalContext& gc)   // global context
//
//  Handles getting the trees.
//
{
  if (at(forest) || at(forest2))
     sayMessage (gc, inforest);
  else
     sayMessageWord (gc, idontsee, tree);
}

void getTurtle
  (AdvGlobalContext& gc)   // global context
//
//  Handles getting the turtle.
//
{
  sayMessage (gc, heavy_turtle);
}

void getWater
  (AdvGlobalContext& gc)   // global context
//
//  Handles getting water.
//
{
  // Maybe he meant get the (bottle of) water...
  if (near(bottle) && (gc.m_nState [bottle] == 0))
     {
       getBottle (gc);
       return;
     }

  // Complain if he's not not at a watering hole
  if (!gc.m_waterHere [gc.m_nHere])
     {
       sayMessageWord (gc, idontsee, water);
       return;
     }

  // Otherwise, try to get the water (in the bottle)
  if (carrying(bottle))
     if (gc.m_nState [bottle] == 1)
        {
          gc.m_nState [bottle] = 0;
          getIt (water);
          sayMessage (gc, bottle_h2o);
        }
     else
        sayMessage (gc, bottlewasfull);
  else
     sayMessage (gc, nowaytocarry);
}
