// OpenClose.cpp : Handler for opening/closing objects
//
#include "stdafx.h"
#include "string.h"

#include "AdvIO.h"
#include "AdvMain.h"
#include "AdvUtil.h"
#include "Throw.h"

///////////////////
// Public functions

void openProc
  (AdvGlobalContext& gc)   // global context
//
//  Handles opening and unlocking objects.
//
{
  // First, the obvious cases ...
  if (gc.m_nCmdWords == 1)
     {
       gc.m_nContext = unlock;
       sayMessageWord (gc, clarify, unlock);
       return;
     }
  if (!isObject (gc.m_nArg2))
     {
       sayMessage (gc, what);
       return;
     }
  if ((gc.m_nArg2 != door) && (!near (gc.m_nArg2) || gc.m_invisible [gc.m_nArg2]))
     {
       sayMessageWord (gc, idontsee, gc.m_nArg2);
       return;
     }
  if (gc.m_mortal [gc.m_nArg2] && (gc.m_nArg2 != clam))
     {
       sayMessage (gc, repulsive);
       return;
     }

  // Next, the special cases ...
  switch (gc.m_nArg2)
  {
    case door:
      if (at (immensenspass))
         {
           sayMessage (gc, nolock);
           break;
         }
      else
         if (!(at(nearstove) || at(belowtrap)))
            {
              sayMessageWord (gc, idontsee, gc.m_nArg2);
              return;
            }
         else
            ;   // fall thru to trapdoor case

    case trapdoor:
      if (!near(trapdoor) || gc.m_invisible [trapdoor])
         sayMessageWord (gc, idontsee, gc.m_nArg2);
      else
         if (gc.m_nState [trapdoor] == 0)       // shut
            if (at(nearstove))
               {
                 sayMessage (gc, ok);
                 gc.m_nState [trapdoor] = 1;    // open
               }
            else
               sayMessage (gc, trapshut);       // can't open from below!
         else
            sayMessage (gc, already_open);
      break;

    case stove:
      if (gc.m_special1 [stove])    // open
         sayMessageWord (gc, already_open, stove);
      else
         {
           if (gc.m_nState [scroll] < 2)    // inside stove
              gc.m_invisible [scroll] = 0;
           describeObject (gc, stove, gc.m_special2 [stove] ? 6 : 5);
           gc.m_special1 [stove] = true;
         }
      break;

    case grate:
      if (near(keys))
         if ((gc.m_nClosure > 1) || gc.m_bNoMagic)
            {
              sayMessage (gc, grate_stuck);
              if (gc.m_nClosure > 1)
                 {
                   gc.m_bPanicked = true;
                   if (!gc.m_special1 [grate])
                      {
                        gc.m_special1 [grate] = true;
                        sayMessage (gc, grate_closed);
                      }
                 }
            }
         else
            {
              gc.m_nState [grate] = 1;
              sayMessage (gc, grateunlocked);
              gc.m_hintable [depression] = false;
            }
      else
         sayMessage (gc, needkeys);
      break;

    case chain:
      if (near(keys))
         if (gc.m_nState [chain] == 0)
            sayMessage (gc, chain_unlocked);
         else
            if (gc.m_nState [chain] == 1)
               if (gc.m_nState [bear] == 0)
                  sayMessage (gc, bear_chain);
               else
                  {
                    sayMessage (gc, chain_unlocked);
                    gc.m_nState [chain] = 0;
                    gc.m_nState [bear] = 2;
                  }
            else
               {
                 sayMessage (gc, chain_unlocked);
                 gc.m_nState [chain] = 0;
               }
      else
         sayMessage (gc, needkeys);
      break;

    case keys:
      sayMessage (gc, unlockkeys);
      break;

    case safe:
      if (gc.m_nState [safe] == 0)
         sayMessage (gc, no_keyhole);
      else
         if (gc.m_nState [safe] == 1)
            sayMessageWord (gc, already_open, safe);
         else
            sayMessage (gc, it_is_melted);
      break;

    case clam:
      if (carrying(clam))
         sayMessage (gc, droptheclam);
      else
         if (carrying(trident))
            {
              apport (clam, limbo);
              apport (oyster, gc.m_nHere);
              apport (pearl, culdesac);
              sayMessage (gc, clam_opened);
            }
         else
            sayMessage (gc, need_trident);
      break;

    case oyster:
      if (carrying(oyster))
         sayMessage (gc, droptheoyster);
      else
         if (carrying(trident))
            sayMessage (gc, oyster_opened);
         else
            sayMessage (gc, need_tridnt2);
      break;

    case vial:
      breakVial (gc);
      break;

    case flask:
      if (gc.m_nState [flask] < 2)
         {
           if (gc.m_nWhereIs [flask] == pentagram)
              {
                apport (djinn, pentagram);
                sayMessage (gc, polite_djinn);
              }
           else
              sayMessage (gc, rude_djinn);
           gc.m_nState [flask] = 2;
         }
      else
         sayMessageWord (gc, already_open, gc.m_nArg2);
      break;

    case _pentagram:
      if (at(pentagram))
         if (near(djinn))
            {
              sayMessage (gc, djinn_advice);
              apport (djinn, limbo);
              gc.m_special1 [djinn] = true;
            }
         else
            sayMessage (gc, empty_penta);
      else
         sayMessageWord (gc, idontsee, _pentagram);
      break;

    default:
      if (gc.m_openable [gc.m_nArg2])
         {
           printf ("GLITCH! openProc (%d)\n", gc.m_nArg2);
           printf ("Please submit a bug report to ravib@ravib.com.  Thanks!\n");
         }
      else
         sayMessage (gc, cantlockit);
      break;
  }
}

void closeProc
  (AdvGlobalContext& gc)   // global context
//
//  Handles closing and locking objects.
//
{
  // First, the obvious ...
  if (gc.m_nCmdWords == 1)
     {
       gc.m_nContext = lock;
       sayMessageWord (gc, clarify, lock);
       return;
     }
  if (!isObject (gc.m_nArg2))
     {
       sayMessage (gc, what);
       return;
     }
  if ((gc.m_nArg2 != door) && (gc.m_invisible [gc.m_nArg2] || !near (gc.m_nArg2)))
     {
       sayMessageWord (gc, idontsee, gc.m_nArg2);
       return;
     }
  if (gc.m_mortal [gc.m_nArg2])
     {
       sayMessage (gc, repulsive);
       return;
     }

  // Next, the special cases ...
  switch (gc.m_nArg2)
  {
    case door:
      if (at (immensenspass))
         {
           sayMessage (gc, nolock);
           break;
         }
      else
         if (!(at(nearstove) || at(belowtrap)))
            {
              sayMessageWord (gc, idontsee, gc.m_nArg2);
              return;
            }
         else
            ;   // fall thru to case trapdoor
    case trapdoor:
      if (!near (trapdoor) || gc.m_invisible [trapdoor])
         sayMessageWord (gc, idontsee, trapdoor);
      else
         if (gc.m_nState [trapdoor] == 0)   // already shut!
            sayMessageWord (gc, already_shut, trapdoor);
         else
            {
              gc.m_nState [trapdoor] = 0;
              sayMessage (gc, ok);
            }
      break;

    case stove:
      if (!gc.m_special1 [stove])   // closed
         sayMessageWord (gc, already_shut, stove);
      else
         {
           if (gc.m_nState [scroll] < 2)    // inside stove
              gc.m_invisible[scroll] = true;
           gc.m_special1 [stove] = false;   // now closed
           sayMessage (gc, ok);
         }
      break;

    case _pentagram:
      sayMessage (gc, hah);
      break;

    case grate:
      gc.m_nState [grate] = 0;
      sayMessage (gc, gratelocked);
      break;

    case chain:
      if (at(bearhere))
         {
           if (gc.m_nState [chain] == 0)
              if (near(bear))
                 {
                   dropIt (bear);
                   gc.m_nState [bear] = 1;
                   gc.m_nState [chain] = 1;
                 }
              else
                 gc.m_nState [chain] = 2;

           sayMessage (gc, lock_chain);
           if (carrying(chain))
              dropIt (chain);
         }
      else
         sayMessage (gc, cant_lock_chain);
      break;

    case flask:
      if (gc.m_nState [flask] == 0)
         sayMessageWord (gc, already_shut, flask);
      else
         sayMessageWord (gc, dunno_hao, lock);
      break;

    case safe:
      if (gc.m_nState [safe] == 1)
         {
           sayMessage (gc, safe_shut);
           gc.m_nState [safe] = 0;
         }
      else
         sayMessageWord (gc, already_shut, safe);
      break;

    default:
      if (gc.m_openable [gc.m_nArg2])
         {
           printf ("GLITCH! closeProc (%d)\n", gc.m_nArg2);
           printf ("Please submit a bug report to ravib@ravib.com.  Thanks!\n");
         }
      else
         sayMessage (gc, cantlockit);
      break;
  }
}
