// Throw.cpp : Handler for various throw actions
//

#include "stdafx.h"
#include "string.h"

#include "AdvIO.h"
#include "AdvMain.h"
#include "AdvUtil.h"
#include "Drop.h"
#include "Throw.h"

/////////////////////
// Forward references

///////////////////
// Public functions

void throwWeapon
  (AdvGlobalContext& gc)   // global context
//
//  Handles attacks with weapons (axe/sword).  We can assume that he's
//  holding the weapon in his hand.
//
{
  dropIt (gc.m_nArg2);

  // Dwarf attack
  if (near (dwarf))
     {
       long nChanceOfHittingADwarf = (gc.m_nDwarvesInRoom + 2) * 15;
       long nSurvival = (gc.m_nStrength - gc.m_nInventory)*5 + nChanceOfHittingADwarf;
       if (gc.m_nArg2 == axe)
          nSurvival += 15;

       if (chance (nSurvival))
          {
            sayMessage (gc, dwarf_poof);
            gc.m_nDwarvesInRoom--;
            gc.m_nDwarfCount--;
            if (gc.m_nDwarvesInRoom == 0)
               apport (dwarf, limbo);
          }
       else
          {
            sayMessage (gc, dwarfdodges);
            long nKnives = random (gc.m_nDwarvesInRoom + 1);  // how many knives thrown?
            if (nKnives > 0)                                  // at least one?
               {
                 if (nKnives == 1)
                    sayMessage (gc, knifethrown);
                 else
                    sayMessageValue (gc, knivesthrown, nKnives);
                 if (gc.m_special2 [dwarf])   // is he mad?
                    nSurvival -= 20;
                 if (chance (nSurvival) || gc.m_special1 [dwarf])
                    {
                      // First dwarf is a lousy shot
                      sayMessage (gc, (nKnives == 1 ? misses : knivesmiss));
                      gc.m_special1 [dwarf] = false;
                    }
                 else
                    {
                      // But you need luck on your side to escape the others!
                      sayMessage (gc, getsyou);
                      coroner (gc);
                      return;
                    }
               }
          }
     }
  else

     // No point in attacking the snake or the dragon
     if (near(snake))
        {
          sayMessage (gc, cantkillsnake);
          getIt (gc.m_nArg2);
        }
     else
        if (near(dragon))
           sayMessageWord (gc, kill_dragon, gc.m_nArg2);
        else

           // Same story with the bear
           if (near(bear))
              if (gc.m_nState [bear] == 0)
                 if ((strcmpi (gc.m_szArg1, "throw") == 0) || (strcmpi (gc.m_szArg2, "throw") == 0))
                    if ((gc.m_nArg1 == axe) || (gc.m_nArg2 == axe))
                       {
                         sayMessage (gc, axe_bear);
                         gc.m_nState [axe] = 1;
                       }
                    else
                       sayMessage (gc, sword_misses);
                 else
                    if (chance (50))
                       sayMessage (gc, bear_misses);
                    else
                       {
                         sayMessage (gc, bear_gets_you);
                         coroner (gc);
                         return;
                       }
              else
                 sayMessage (gc, bear_puzzled);
           else

              // Trolls are pretty tough, too
              if (near (troll))
                 if (chance (50))
                    sayMessage (gc, troll_data);
                 else
                    sayMessageWord (gc, el_cheapo, gc.m_nArg2);
              else

                 // Ogre attack
                 if (near (ogre))
                    if ((strcmpi (gc.m_szArg1, "swing") == 0) || (strcmpi (gc.m_szArg2, "swing") == 0))
                       {
                         sayMessageWord (gc, ogre_rebuff, gc.m_nArg2);
                         coroner (gc);
                         return;
                       }
                    else
                       if ((gc.m_nArg1 == axe) || (gc.m_nArg1 == axe))
                          {
                            sayMessageWord (gc, ogre_catch, axe);
                            coroner (gc);
                            return;
                          }
                       else
                          {
                            sayMessage (gc, ogre_killed);
                            apport (sword, limbo);
                            apport (ogre, limbo);
                            apport (ring, gc.m_nHere);
                          }
                 else

                    // Blob attack
                    if (near (blob))
                       sayMessageWord (gc, slice_blob, gc.m_nArg2);
                    else

                       // Basilisk attack
                       if (near (basilisk))
                          if (gc.m_nState [basilisk] > 1)
                             {
                               sayMessage (gc, it_is_dead);
                               getIt (gc.m_nArg2);
                             }
                          else
                             {
                               sayMessageWord (gc, axe_basilisk, gc.m_nArg2);
                               coroner (gc);
                               return;
                             }
                       else

                          // Djinn attack
                          if (near (djinn))
                             sayMessageWord (gc, rebound, gc.m_nArg2);
                          else

                             // Goblin attack
                             if (near (goblins))
                                {
                                  sayMessageWord (gc, kill_a_few, gc.m_nArg2);
                                  coroner (gc);
                                  return;
                                }
                             else

                                // There's nothing here to attack!
                                if (gc.m_thrower [gc.m_nHere])
                                   upChuck (gc);
                                else
                                   {
                                     dropIt (gc.m_nArg2);
                                     sayMessage (gc, ok);
                                   }
}

void throwFood
  (AdvGlobalContext& gc)   // global context
//
//  Handler for throwing food.
//
{
  // Troll isn't interested in food
  if (near(troll))
     sayMessage (gc, feed_troll);
  else
     if (near(dwarf))
        {
          // Feeding the dwarf makes him mad!
          sayMessage (gc, fed_dwarf);
          dropIt (food);
          gc.m_special2 [dwarf] = 1;
        }
     else
        if (near(bear))
           {
             // Feeding the bear makes him tame
             sayMessage (gc, bear_urrp);
             apport (food, limbo);
             gc.m_nState [bear] = 1;
             if (gc.m_nState [axe] == 1)
                gc.m_nState [axe] = 0;
           }
        else
           {
             // Otherwise just throw it on the ground
             dropIt (food);
             sayMessage (gc, ok);
           }
}

void throwTeeth
  (AdvGlobalContext& gc)   // global context
//
//  Handler for throwing dragon's teeth.
//
{
  if (near (goblins))
     {
       // Throwing the dragon's teeth is the only way to get rid of the goblins
       gc.m_nState [teeth] = 0;
       sayMessage (gc, warriors);
       apport (teeth, limbo);
       apport (goblins, limbo);
     }
  else
     {
       dropIt (teeth);
       sayMessage (gc, ok);
     }
}

void breakVial
  (AdvGlobalContext& gc)   // global context
//
//  Handler for breaking vial.
//
{
  // Describe a random explosion
  apport (vial, limbo);
  long nFume = random (last_fume - first_fume_1 + 1);
  sayMessage (gc, vial_bang);
  sayMessage (gc, first_fume_1 + nFume);
  sayMessage (gc, blank);

  // Throwing the vial at dwarves, goblins or the slime has its uses
  if (near (dwarf))
     {
       if (gc.m_nDwarvesInRoom == 1)
          sayMessage (gc, vial_dwarf);
       else
          sayMessage (gc, vial_dwarves);
       apport (dwarf, limbo);
     }
  if (near (goblins))
     {
       apport (goblins, limbo);
       sayMessage (gc, vial_goblins);
     }
  if (near (slime))
     {
       apport (slime, limbo);
       sayMessage (gc, vial_slime);
     }

  // Other creatures aren't harmed by the vial, but display a response
  if (near (troll))
     sayMessage (gc, vial_troll);
  if (near (bear))
     if (gc.m_nState [bear] != 0)
        sayMessage (gc, vial_bear1);
     else
        sayMessage (gc, vial_bear2);
  if (near (snake))
     sayMessage (gc, vial_snake);
  if (near (bird))
     sayMessage (gc, vial_bird);
  if (near(dragon) && (gc.m_nState [dragon] != 0))
     sayMessage (gc, vial_dragon);
  if (near (djinn))
     sayMessage (gc, vial_djinn);
  if (near(basilisk) && (gc.m_nState [basilisk] < 2))
     sayMessage (gc, vial_basilisk);
}

void upChuck
  (AdvGlobalContext& gc)   // global context
//
//  Handler for throwing things that end up elsewhere.
//
{
long  nMessage;       // message
long  nDestination;   // destination

  nMessage = 0;
  switch (gc.m_nHere)
  {
    case nslope:
      nMessage = throw_ledge;
      nDestination = pathway;
      break;
    case pit:
      nMessage = throw_pit;
      nDestination = mists;
      break;
    case eastoffissur:
    case westoffissur:
      nMessage = throw_fissure;
      nDestination = cavern;
      break;
    case wend2pit:
      nMessage = throw_pit;
      nDestination = eastpit;
      break;
    case eend2pit:
      nMessage = throw_pit;
      nDestination = westpit;
      break;
    case lownspassage:
      nMessage = throw_hole;
      nDestination = dirty;
      break;
    case window:
    case window2:
      nMessage = throw_pit;
      nDestination = mirrorcnyn;
      break;
    case brink:
      nMessage = throw_pit;
      nDestination = streampit;
      break;
    case dusty:
      nMessage = throw_hole;
      nDestination = complex;
      break;
    case mazea_16_pit:
      nMessage = throw_pit;
      nDestination = birdchamber;
      break;
    case secretnscyn:
      nMessage = throw_room;
      nDestination = slab;
      break;
    case secretnspas:
      nMessage = throw_room;
      nDestination = bedquilt;
      break;
    case secretew_tite:
      nMessage = throw_canyon;
      nDestination = nscanyonwide;
      break;
    case incline:
      nMessage = throw_room;
      nDestination = low;
      break;
    case cavern:
      nMessage = throw_whirlpool;
      nDestination = ylem;
      break;
    case misty:
      nMessage = throw_cavern;
      nDestination = cavern;
      break;
    case stalact:
      nMessage = throw_room;
      nDestination = mazea_12;
      break;
    case reservoir:
    case reservoir_n:
      nMessage = throw_reservoir;
      nDestination = ylem;
      break;
    case balcony:
      nMessage = throw_room;
      nDestination = ylem;
      break;

    case swofchasm:
    case neofchasm:
      // Troll has been hurled down chasm
      if (!near(troll))
         {
           nMessage = throw_chasm;
           nDestination = ylem;
           break;
         }
      // The troll is present
      if (!gc.m_valued [gc.m_nArg2])    // troll only wants treasure
         {
           dropIt (gc.m_nArg2);
           sayMessageWord (gc, el_cheapo, gc.m_nArg2);
           return;
         }
      // Throwing a treasure at the troll
      if (gc.m_nArg2 == eggs)     // throwing eggs at troll twice makes him angry!
         if (gc.m_special1 [troll])
            {
              describeObject (gc, troll, 6);  // The troll nimbly steps aside and grins nastily as the nest of golden eggs
              apport (eggs, ylem);            // flies past him and plumets into the chasm.  "Fool me once, shame on you!
              gc.m_nState [troll] = 0;        // Fool me twice, shame on me!" he sneers.  "I want something a touch more
              return;                         // substantial this time!".
            }
      // Troll can be bought off by throwing eggs for the first time, or
      // throwing any other treasure.
      sayMessageWord (gc, boughthimoff, gc.m_nArg2);
      gc.m_nState [troll] = 1;  // bought off
      apport (troll, limbo);
      if (at (swofchasm))
         apport (troll2, neofchasm);
      else
         apport (troll2, swofchasm);
      apport (gc.m_nArg2, limbo);
      return;

    case breathtaker:
    case faces:
    case platform:
      nMessage = throw_gorge;
      nDestination = ylem;
      break;
    case tube:
      nMessage = throw_chimney;
      nDestination = chimney;
      break;
    case tube_slide:
      nMessage = throw_tube;
      nDestination = plain_1;
      break;
    case basque_fork:
      nMessage = throw_steps;
      nDestination = on_steps;
      break;
    case on_steps:
      nMessage = throw_steps;
      nDestination = steps_exit;
      break;
    case steps_exit:
      nMessage = throw_steps;
      nDestination = storage;
      break;
    case brink_1:
    case brink_2:
    case brink_3:
      nMessage = throw_pit;
      nDestination = ylem;
      break;
    case ice:
      nMessage = throw_slide;
      nDestination = ylem;
      break;
    case shelf:
      nMessage = throw_beach;
      nDestination = beach;
      break;
  }

  // If we can't find alternate destination, drop the object here
  if (nMessage == 0)
     {
       dropIt (gc.m_nArg2);
       sayMessage (gc, ok);
       return;
     }

  // ...else drop it *there* and check for breakables, etc.
  sayMessageWord (gc, nMessage, gc.m_nArg2);
  apport (gc.m_nArg2, nDestination);
  switch (gc.m_nArg2)
  {
    case vase:
      apport (vase, ylem);
      apport (shards, nDestination);
      if (nDestination != ylem)
         sayMessage (gc, shattered_it);
      break;

    case bottle:
      apport (oil, limbo);
      apport (water, limbo);
      break;

    case oil:
    case water:
      gc.m_nState [bottle] = 1;
      apport (gc.m_nArg2, limbo);
      break;

    case cage:
      if (carrying (bird))
         apport (bird, nDestination);
      break;

    case lamp:
      if ((gc.m_nState [lamp] == 1) && (!gc.m_lit [gc.m_nHere]))
         sayMessage (gc, itisnowdark);
      break;

    case bird:
      gc.m_nState [bird] = 0;
      break;
  }
}
