// Drop.cpp : Handler for dropping various objects
//

#include "stdafx.h"
#include "string.h"

#include "AdvIO.h"
#include "AdvMain.h"
#include "AdvUtil.h"
#include "DoVerb.h"
#include "Drop.h"

/////////////////////
// Forward references
void dropBear (AdvGlobalContext& gc);
void dropBird (AdvGlobalContext& gc);
void dropBottle (AdvGlobalContext& gc);
void dropCage (AdvGlobalContext& gc);
void dropCoins (AdvGlobalContext& gc);
void freeDjinn (AdvGlobalContext& gc);
void dropGold (AdvGlobalContext& gc);
void dropFlask (AdvGlobalContext& gc);
void dropLiquid (AdvGlobalContext& gc);
void dropVase (AdvGlobalContext& gc);
void dropVial (AdvGlobalContext& gc);

///////////////////
// Public functions

void dropProc
  (AdvGlobalContext& gc)   // global context
//
//  Handles dropping various objects.
//
{
long    nObject;      // object index
long    nSavedArg2;   // save value of 2nd arg
long    nTried;       // # objects we tried to drop

  nSavedArg2 = gc.m_nArg2;

  if (gc.m_nCmdWords == 1)
     if (gc.m_nInventory == 0)
        {
          // Complain if not carrying anything
          sayMessage (gc, armsareempty);
          return;
        }
     else
        if (gc.m_nInventory == 1)
           {
             // If carrying one object, figure out what it is
             for (nObject=MINOBJECTS; (nObject <= MAXOBJECTS); nObject++)
                 if (carrying (nObject))
                    {
                      gc.m_nArg2 = nObject;
                      printf ("(%s)\n", gc.m_objects [nObject].pszInventory);
                      break;
                    }
           }
        else
           {
             // If carrying > 1 object, ask him to be specific
             sayMessageWord (gc, clarify, drop);
             gc.m_nContext = drop;
             return;
           }

  // Has to be an object!
  if ((gc.m_nArg2 != all) && !isObject (gc.m_nArg2))
     {
       sayMessage (gc, what);
       return;
     }

  // If he dropped everything or all treasures ...
  if ((nSavedArg2 == all) || (nSavedArg2 == treasure))
     {
       nTried = 0;
       for (nObject=MINOBJECTS; (nObject <= MAXOBJECTS); nObject++)
           if (carrying (nObject))
              if (nSavedArg2 == all ||
                  ((nSavedArg2 == treasure) && gc.m_valued [nObject]))
                 {
                   // Try to drop each one
                   nTried++;
                   gc.m_nArg2 = nObject;
                   printf ("(%s)\n", gc.m_objects [nObject].pszInventory);
                   dropProc (gc);
                   if (gc.m_bJustDied)    // vial
                      return;
                 }

       // Complain if nothing could be dropped
       if (nTried == 0)
          if (nSavedArg2 == all)
             sayMessage (gc, armsareempty);
          else
             sayMessage (gc, notcarrying);
       return;
     }

  // Has to be something he could carry
  if (!gc.m_portable [gc.m_nArg2])
     {
       sayMessage (gc, hah);
       return;
     }
  if (!carrying (gc.m_nArg2))
     {
       sayMessage (gc, notcarrying);
       return;
     }

  // Handle specific drops
  switch (gc.m_nArg2)
  {
    case bear:
      dropBear (gc);
      return;
    case bird:
      dropBird (gc);
      return;
    case bottle:
      dropBottle (gc);
      return;
    case cage:
      dropCage (gc);
      return;
    case coins:
      dropCoins (gc);
      return;
    case djinn:
      freeDjinn (gc);
      return;
    case flask:
      dropFlask (gc);
      return;
    case gold:
      dropGold (gc);
      return;
    case oil:
    case water:
      dropLiquid (gc);
      return;
    case vase:
      dropVase (gc);
      return;
    case vial:
      dropVial (gc);
      return;
  }

  // Default drop
  dropIt (gc.m_nArg2);
  sayMessage (gc, dropped);
  return;
}

////////////////////
// Private functions

void dropBear
  (AdvGlobalContext& gc)   // global context
//
//  Handles releasing the bear.
//
{
  dropIt (bear);
  if (near (troll))
     {
       gc.m_nState [troll] = 4;   // scared troll?
       sayMessage (gc, bear_troll);
       apport (troll, limbo);
       apport (troll2, swofchasm);
     }
  else
     sayMessage (gc, ok);
}

void dropBird
  (AdvGlobalContext& gc)   // global context
//
//  Handles freeing the bird.
//
{
  dropIt (bird);
  gc.m_nState [bird] = 0;

  // The bird drives the snake away
  if (near (snake))
     {
       sayMessage (gc, bird_snake);
       apport (snake, limbo);
       gc.m_hintable [mtking] = false;
       return;
     }

  // But not the dragon!
  if (near(dragon) && (gc.m_nState [dragon] == 0))
     {
       sayMessage (gc, bird_dragon);
       apport (bird, limbo);
       return;
     }

  // Default drop
  sayMessage (gc, dropped);
}

void dropBottle
  (AdvGlobalContext& gc)   // global context
//
//  Handles dropping the bottle.
//
{
  dropIt (bottle);
  apport (oil, limbo);
  apport (water, limbo);
  sayMessage (gc, dropped);
}

void dropCage
  (AdvGlobalContext& gc)   // global context
//
//  Handles dropping the cage.
//
{
  // Dropping the cage also drops the bird, if caged
  dropIt (cage);
  if (carrying (bird))
     dropIt (bird);
  sayMessage (gc, dropped);
}

void dropCoins
  (AdvGlobalContext& gc)   // global context
//
//  Handles dropping coins (into the vending machine).
//
{
  dropIt (coins);
  if (at (mazed_140))
     {
       apport (coins, limbo);
       apport (batteries, gc.m_nHere);
       describeObject (gc, batteries, gc.m_nState [batteries]);
       return;
     }
  sayMessage (gc, dropped);
}

void freeDjinn
  (AdvGlobalContext& gc)   // global context
//
//  Frees the djinn.
//
{
  sayMessage (gc, djinn_advice);
  apport (djinn, limbo);
  gc.m_special1 [djinn] = true;
}

void dropGold
  (AdvGlobalContext& gc)   // global context
//
//  Handles dropping the nugget of gold.
//
{
	dropIt (gold);
	sayMessage (gc, dropped);
	gc.m_invisible [steps] = false;
}

void dropFlask
  (AdvGlobalContext& gc)   // global context
//
//  Handles dropping the flask.
//
{
	dropIt (flask);
	sayMessage (gc, dropped);
}

void dropLiquid
  (AdvGlobalContext& gc)   // global context
//
//  Handler for pouring liquid.
//
{
  apport (gc.m_nArg2, limbo);
  gc.m_nState [bottle] = 1;
  if (near(dwarf) && (gc.m_nArg2 == throw_it))
     {
       if (gc.m_nDwarvesInRoom == 1)
          sayMessageWord (gc, doused_dwarf, gc.m_nArg2);
       else
          sayMessageWord (gc, doused_dwarves, gc.m_nArg2);
       gc.m_special2 [dwarf] = true;    // drenched dwarf - angry!
     }
  else
     sayMessage (gc, pourwater);
}

void dropVase
  (AdvGlobalContext& gc)   // global context
//
//  Handles dropping the vase.
//
{
  dropIt (vase);
  if (at(soft))
     sayMessage (gc, dropped);
  else
     if (carrying(pillow) || !near(pillow))
        {
          gc.m_nState [vase] = 2;   // kept vase on ground - broke!
          describeObject (gc, vase, 2);
          apport (vase, limbo);
          apport (shards, gc.m_nHere);
        }
     else
        {
          gc.m_nState [vase] = 1;   // kept vase on pillow - safe!
          describeObject (gc, vase, 1);
          gc.m_nState [vase] = 0;
        }
}

void dropVial
  (AdvGlobalContext& gc)   // global context
//
//  Handles dropping the vial.
//
{
  if (chance(10))
     {
       sayMessage (gc, vial_explodes);
       apport (vial, limbo);
       coroner (gc);
     }
  else
     {
       sayMessage (gc, dropped);
       dropIt (vial);
     }
}
