// Main0.cpp : First of 3 mainline functions
//
// Public functions:
//    coroner
//    finis
//    main0
//    phog
//
// Private functions:
//    tick

#include "stdafx.h"
#include "stdlib.h"

#include "AdvInit.h"
#include "AdvIO.h"
#include "AdvMain.h"
#include "AdvUtil.h"

/////////////////////
// Forward references
void tick
  (AdvGlobalContext& gc);

///////////////////
// Public functions

void coroner
  (AdvGlobalContext& gc)   // global context
//
//  Things to do when the adventurer has gotten himself killed.
//
{
long  nIndex;   // generic index

  gc.m_bJustDied = true;
  gc.m_bQuitting = true;
  gc.m_bNoMagic = false;                // reset magic-inhibit mode
  gc.m_bTicker = false;                 // clear once-per-move

  gc.m_nState [blob] = 0;               // reset the blob
  apport (blob, limbo);                 // and get rid off him
  apport (goblins, limbo);              // the same with the goblins

  if (gc.m_nState [basilisk] == 1)      // adjust the basilisk so that
     gc.m_nState [basilisk] = 0;        // he gets viewed from the south
  else                                  // whether he's petrified or not
     if (gc.m_nState [basilisk] == 3)
        gc.m_nState [basilisk] = 2;

  apport (fog, plain_1);                // move the fog back to its initial
  gc.m_nState [fog] = 8;                // position and make it semi-visible

  // Count up a death
  gc.m_nDeaths++;
  if (gc.m_nClosure > 1)
     {
       if (gc.m_nClosure == 2)
          sayMessage (gc, dead_and_closed);
       else
          gc.m_nDeaths--;   // don't charge for dying in repository
       finis (gc);
     }

  // Tell him about it
  nIndex = youaredead_1 + 2*(gc.m_nDeaths - 1);
  if (yes (gc, nIndex))
     {
       sayMessage (gc, nIndex + 1);
       if (gc.m_nDeaths > MAXDIE)
          finis (gc);

       // Shatter the vase and drop all objects
       if (carrying (vase))
          {
            dropIt (vase);
            apport (vase, limbo);
            getIt (shards);
          }
       for (nIndex=MINOBJECTS; (nIndex <= MAXOBJECTS); nIndex++)
           if (carrying (nIndex))
              dropIt (nIndex);
       gc.m_nInventory = 0;

       phog (gc);
       apport (oil, limbo);
       apport (water, limbo);
       gc.m_nState [lamp] = 0;
       apport (lamp, road);

       gc.m_nHere = building;
       gc.m_nPrevLoc = building;
       gc.m_bOk2Describe = true;
       gc.m_bMoved = true;

       apport (dwarf, limbo);
       gc.m_nDwarvesInRoom = 0;
       gc.m_special1 [pirate] = false;   // clear chasing mode

       if ((gc.m_nLampLife == 0) ||
           (gc.m_special1 [lamp]) ||
           (!gc.m_visited [lair]))
          {
            long nLocation = gc.m_nWhereIs [batteries];
            if ((nLocation == building) || gc.m_notInCave [nLocation])
               apport (lamp, ylem);
          }

       return;
     }
  else
     finis (gc);
}

void finis
  (AdvGlobalContext& gc)   // global context
//
//  Tell player how he did and end the show.  Adventurer ratings are:
//
//  Score       Rating
//  -----       ------
//  0 - 28      Rank amateur   (hasn't entered cave yet)
//  29 - 104    Novice         (0-5  treasures kept in building)
//  105 - 214   Experienced    (6-13 treasures kept in building)
//  215 - 344   Seasoned       (14-21 treasures kept in building)
//  345 - 419   Junior Master  (21-26 treasures kept in building)
//  420 - 463   Master Adventurer Class C
//  464 - 507   Master Adventurer Class B
//  508 - 549   Master Adventurer Class A
//  550         Grandmaster
//
{
long  nMessage;   // rating message

  // Get and display the player's score
  getScore (gc);
  sayMessageValue (gc, you_scored, gc.m_nScore);
  sayMessageValue (gc, topscore, gc.m_nMaxScore);
  sayMessageValue (gc, inmoves, gc.m_nTurns);

  // Compute his rating
  if (gc.m_nScore < 29)
     {
       nMessage = fish;
       gc.m_nScore -= 29;
     }
  else
     if (gc.m_nScore < 105)
        {
          nMessage = novice;
          gc.m_nScore -= 105;
        }
     else
        if (gc.m_nScore < 215)
           {
             nMessage = experienced;
             gc.m_nScore -= 215;
           }
        else
           if (gc.m_nScore < 345)
              {
                nMessage = seasoned;
                gc.m_nScore -= 345;
              }
           else
              if (gc.m_nScore < 420)
                 {
                   nMessage = juniormaster;
                   gc.m_nScore -= 420;
                 }
              else
                 if (gc.m_nScore < 464)
                    {
                      nMessage = master_c;
                      gc.m_nScore -= 464;
                    }
                 else
                    if (gc.m_nScore < 508)
                       {
                         nMessage = master_b;
                         gc.m_nScore -= 508;
                       }
                    else
                       if (gc.m_nScore < 550)
                          {
                            nMessage = master_a;
                            gc.m_nScore -= 550;
                          }
                       else
                          {
                            nMessage = grand;
                            gc.m_nScore = 0;
                          }

  // Display rating
  sayMessage (gc, nMessage);
  sayMessage (gc, blank);
  gc.m_nScore = -gc.m_nScore;
  if (gc.m_nScore > 0)
     if (gc.m_nScore == 1)
        sayMessage (gc, need1);
     else
        sayMessageValue (gc, need, gc.m_nScore);

  // Terminate program
  cleanupAndExit (gc);
}

void main0
  (AdvGlobalContext& gc)   // global context
//
//  First of 3 mainline functions.
//
//  This function must be executed before getting player input and is
//  independent of whether we moved or not.
//
{
  // Tick the administrative clock
  if (gc.m_bTicker)
     tick (gc);

  // Manipulate schizoid objects - these are objects that can be viewed from
  // more than one location at the same time.
  if (at (incave) || at (depression))
     apportHere (grate);
  if (at (forest) || at (forest2))
     apportHere (tree);
  if (at (arch_cor_1) || at (arch_cor_2))
     apportHere (quicksand);
  if (at (vault) || at (peelgrunt))     // added, since safe is
     apportHere (safe);                 // accessible from both
  if (at (breathtaker) || at (faces))
     apportHere (wheatstone);
  if (at (eastoffissur) || at (westoffissur))
     apportHere (fissure);
  if (at (pit) || at (mists))
     {
       apportHere (steps);
       gc.m_nState [steps] = (at (mists) ? 1 : 0);
       gc.m_invisible [steps] = carrying (gold);
     }
  if (at (deadend1) || (at (mazed_140) && (gc.m_nWhereIs [chest] == mazea_26)))
     {
       apportHere (message);
       gc.m_noDesc [message] = (gc.m_nHere == deadend1);
     }
  if (at (nearstove) || at (belowtrap))
     {
       apportHere (trapdoor);
       gc.m_noDesc [trapdoor] = (gc.m_nHere == belowtrap);
     }

  if (at (neofchasm) || at (swofchasm))
     if (near (troll))
        {
        if (near (troll2))
           apport (troll2, limbo);      // real troll takes precedence over fake troll
        }
     else
        if (gc.m_nState [chasm] == 0)
           apportHere (troll2);
}

void phog
  (AdvGlobalContext& gc)   // global context
//
//  Control the fog and the glow in the fog and describe them.
//
{
  // State 8 is invisible fog
  if (gc.m_nState [fog] < 8)
     {
       gc.m_nState [fog] = random (8);
       gc.m_invisible [fog] = false;
     }
  else
     gc.m_invisible [fog] = true;

  // Glow appears in a random spot (1 of 8 possible directions)
  gc.m_nState [glow] = random (8);

  // Lamp masks out faint glow
  if (near (lamp) && (gc.m_nState [lamp] == 1))
     {
       apport (glow, limbo);
       if (!gc.m_invisible [fog])
          {
            describeObject (gc, fog, gc.m_nState [fog]);
            gc.m_bOk2Describe = false;
          }
     }
  else
     {
       apport (glow, plain_2);

       // Need to describe when we travel from plain_3 to plain_2
       if (at (plain_2))
          {
            describeObject (gc, glow, gc.m_nState [glow]);
            gc.m_bOk2Describe = false;  // so fog is not described
          }
     }
}

void splatter
  (AdvGlobalContext& gc)   // global context
//
// This function is called everytime it's desirable to have the adventurer
// fall to a painful death.  One of a series of messages is printed, depending
// on how many times he has been killed so far.  The caller should set gc.m_nHere
// to the location that's at the bottom of whatever the adventurer has jumped
// into.  If that place isn't well defined (bottom of chasm, volcanic gorge, etc.),
// send him to ylem.
//
{
  sayMessage (gc, plummet + gc.m_nDeaths);
}

////////////////////
// Private functions

void tick
  (AdvGlobalContext& gc)   // global context
//
//  Once-per-input function.  If the blob has been awakened (see magician()),
//  change its description as it chases the adventurer.  When the blob reaches
//  state 10, it kills the poor guy.
//
{
  if (gc.m_nState [blob] != 0)
     {
       // Blob is chasing the adventurer!
       describeObject (gc, blob, gc.m_nState [blob]);

       // If blob is in the same room as us and can be referenced, he's dead!
       if (gc.m_nState [blob] == 9)
          apport (blob, gc.m_nHere);
       if (gc.m_nState [blob] == 10)
          {
            apport (blob, limbo);
            coroner (gc);
            return;
          }
       else
          sayMessage (gc, blank);
       gc.m_nState [blob]++;
     }
}
