// ************************************************
//      OnPlayerRest Wandering Monster Script
// ************************************************
//
// According to p. 40 of the DMG (1st Ed.), spells may be
// regained only by quiet, contemplative rest.  Ninth
// level spells are regained only after 12 hours of rest,
// so each rest period is considered to take a full 12 hours
// by default.
//
// According to p. 82 of the DMG (1st Ed.), the only non-
// magical way to regain lost hit points is from slow
// recuperation after uninterrupted DAYS of rest.  In fact,
// the rate cited is just 1 hp/day.  Therefore, there are
// no limitations placed on how often a PC may rest, but
// only 1 hp will be healed per 12-hour rest period
// (plus any CON bonuses).
//
#include "nw_i0_plot"
//
void SetStoredHitPoints(object oPlayer);
//Returns the last stored hit points for oPlayer.
int GetStoredHitPoints(object oPlayer);
//
void SetStoredHitPointsHench1(object oHench1);
//Returns the last stored hit points for 1st Henchman.
int GetStoredHitPointsHench1(object oHench1);
//
void SetStoredHitPointsHench2(object oHench2);
//Returns the last stored hit points for 2nd Henchman.
int GetStoredHitPointsHench2(object oHench2);
//
void SetStoredHitPointsFamiliar(object oFamiliar);
//Returns the last stored hit points for PC's Familiar.
int GetStoredHitPointsFamiliar(object oFamiliar);
//
//
void main()
{

    ///////////
    //Sometimes spawn monster in during rest v1.6
    ///////////
    ///////////
    //Original script by Michael Ham (mindtakerr)
    //Date Created: 6/25/03
    //Filename: monster_rest
    ///////////

    // An object to hold the last player who rested
    object oPlayer = GetLastPCRested();
    object oHench1 = GetHenchman(oPlayer, 1);
    object oHench2 = GetHenchman(oPlayer, 2);
    object oFamiliar = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPlayer);
    location lHere = GetLocation(oPlayer);
    int bPlayerIsSafe = GetLocalInt(oPlayer, "nRestIsSafe");
    int nAttackPercentage = GetLocalInt(oPlayer, "nAttackPercentage");
    int bMonsterSpawnWillSpawn = TRUE;
    int nHour = GetTimeHour();

    // Check to see whether resting has started or is over
    int nRestTurn = GetLocalInt(oPlayer, "nRestTurns");
    SetLocalInt(oPlayer, "nRestTurns", nRestTurn + 1);
    nRestTurn = GetLocalInt(oPlayer, "nRestTurns");

    // Determine if PC can actually rest
    if (GetLastRestEventType() == REST_EVENTTYPE_REST_STARTED)
     {
     // Store hit points for PC and all valid associates
     SetStoredHitPoints(oPlayer);
     if (GetIsObjectValid(oHench1)) SetStoredHitPointsHench1(oHench1);
     if (GetIsObjectValid(oHench2)) SetStoredHitPointsHench2(oHench2);
     if (GetIsObjectValid(oFamiliar)) SetStoredHitPointsFamiliar(oFamiliar);
     // Apply resting VFX to PC and all valid associates
     effect eSleep = EffectVisualEffect(VFX_IMP_SLEEP);
     ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eSleep, oPlayer, 1.5);
     if (GetIsObjectValid(oHench1)) ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eSleep, oHench1, 1.5);
     if (GetIsObjectValid(oHench2)) ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eSleep, oHench2, 1.5);
     if (GetIsObjectValid(oFamiliar)) ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eSleep, oFamiliar, 1.5);
     }

    //Determine whether the PC is in the Upper Ruins or the Dungeon Level of
    //Keep Inverness (there are no wandering monsters in the Ghost Tower)
    int nUpperRuins = GetLocalInt(oPlayer, "nUpperRuins");
    int nDungeonLevel = GetLocalInt(oPlayer, "nDungeonLevel");

    // Determine whether rest will be peaceful or not
    int nRestRoll = d100(); // Roll percentage to see if rest happens or not
    int nEnemyType = d10(); //Number of enemy monster types

    int nEnemy;
    object oEnemy;
    string sCreature;

    //Determine where the encounter will spawn (relative to the PC)
    int nDirection = d4();
    float fX;
    float fY;
    if (nDirection == 1)
     {
     fX=0.0;
     fY=5.0;
     }
    if (nDirection == 2)
     {
     fX=5.0;
     fY=0.0;
     }
    if (nDirection == 3)
     {
     fX=0.0;
     fY=-5.0;
     }
    if (nDirection == 4)
     {
     fX=-5.0;
     fY=0.0;;
     }

     vector vStart = GetPosition(oPlayer);
     vector vOffset = Vector(fX,fY);
     vector vEndvector = vStart + vOffset;
     lHere=Location(GetArea(oPlayer),vEndvector,GetFacing(oPlayer));

    if (nRestTurn == 1)
        {
        //FloatingTextStringOnCreature("In 'nRestTurn=1' Section", oPlayer);

        // Determine whether or not a monster is coming
        // UPDATE (6/20/02): Now has a local variable to test for whether or not rest can be
        //          automatically safe.
        // UPDATE (1/31/03): Now the attacked percentage is set
        //          by the area.

        if(nRestRoll >= nAttackPercentage)
            bMonsterSpawnWillSpawn = FALSE;

        if(bPlayerIsSafe == 1)
            bMonsterSpawnWillSpawn = FALSE;

        if (bMonsterSpawnWillSpawn)
            {
            //FloatingTextStringOnCreature("In 'MonsterWillSpawn' Section", oPlayer);
            // Decide which monster to spawn, based on area
            //Here are the monsters in the Upper Ruins:
            if ((nEnemyType == 1)&&(nUpperRuins == 1))
             {
             nEnemy = d4();
             sCreature = "nw_wight";
             }
            else if ((nEnemyType == 2)&&(nUpperRuins == 1))
             {
             nEnemy = d3();
             sCreature = "nw_werecat";
             }
            else if ((nEnemyType == 3)&&(nUpperRuins == 1))
             {
             nEnemy = (d4()+1);
             sCreature = "nw_btlbomb";
             }
            else if ((nEnemyType == 4)&&(nUpperRuins == 1))
             {
             nEnemy = d3();
             sCreature = "doppleganger0";
             }
            else if ((nEnemyType == 5)&&(nUpperRuins == 1))
             {
             nEnemy = d4();
             sCreature = "giantlizard";
             }
            else if ((nEnemyType == 6)&&(nUpperRuins == 1))
             {
             nEnemy = d3();
             sCreature = "giantviper";
             }
            else if ((nEnemyType == 7)&&(nUpperRuins == 1))
             {
             nEnemy = d3();
             sCreature = "nw_bearbrwn";
             }
            else if ((nEnemyType == 8)&&(nUpperRuins == 1))
             {
             nEnemy = d8();
             sCreature = "giantant";
             }
            else if ((nEnemyType == 9)&&(nUpperRuins == 1))
             {
             nEnemy = 1;
             sCreature = "giantstone";
             }
            else if ((nEnemyType == 10)&&(nUpperRuins == 1))
             {
             nEnemy = 1;
             sCreature = "horneddevil";
             }
            //And here are the monsters in the Dungeon Level:
            if ((nEnemyType == 1)&&(nDungeonLevel == 1))
             {
             nEnemy = (d6()*3);
             sCreature = "giantcentipede";
             }
            else if ((nEnemyType == 2)&&(nDungeonLevel == 1))
             {
             nEnemy = 1;
             sCreature = "x2_gelcube";
             }
            else if ((nEnemyType == 3)&&(nDungeonLevel == 1))
             {
             nEnemy = d6();
             sCreature = "giantbadger";
             }
            else if ((nEnemyType == 4)&&(nDungeonLevel == 1))
             {
             nEnemy = d8();
             sCreature = "ghoul_wander";
             }
            else if ((nEnemyType == 5)&&(nDungeonLevel == 1))
             {
             nEnemy = d3();
             sCreature = "greenslimesmall";
             }
            else if ((nEnemyType == 6)&&(nDungeonLevel == 1))
             {
             nEnemy = d3();
             sCreature = "nw_grayooze";
             }
            else if ((nEnemyType == 7)&&(nDungeonLevel == 1))
             {
             nEnemy = d2();
             sCreature = "leucrotta";
             }
            else if ((nEnemyType == 8)&&(nDungeonLevel == 1))
             {
             nEnemy = d2();
             sCreature = "rustmonster";
             }
            else if ((nEnemyType == 9)&&(nDungeonLevel == 1))
             {
             nEnemy = 1;
             sCreature = "basilisk_wander";
             }
            else if ((nEnemyType == 10)&&(nDungeonLevel == 1))
             {
             nEnemy = d2();
             sCreature = "ogremage_wander";
             }
             // Create the monster(s) at the PC's location  and spawn as many
             // monsters at that location as is dictated by nEnemy
             int i;
             for (i = 1; i < (nEnemy+1); i++)
              {
              //FloatingTextStringOnCreature("In 'nEnemy' Loop", oPlayer);
              oEnemy = CreateObject(OBJECT_TYPE_CREATURE, sCreature, lHere, FALSE);
              }
             // The PC alerts of danger
             AssignCommand(oPlayer, ActionSpeakString("You have been ambushed while attempting to rest!"));
             // Tell the enemy to attack the player
             AssignCommand(oEnemy, ActionWait(3.0));
             AssignCommand(oEnemy, ActionAttack(oPlayer));
             SetLocalInt(oPlayer, "nRestTurns", -1);
            }
        }

    else if (nRestTurn != 1)
    SetLocalInt(oPlayer, "nRestTurns", 0);

if (GetLastRestEventType() == REST_EVENTTYPE_REST_CANCELLED)
        {
        //Return the player to the hit points they started resting with.
        int currentHP  = GetStoredHitPoints(oPlayer);
        //Return the current Player hit points (after partial rest).
        int newHP = GetCurrentHitPoints(oPlayer);
        //Return the difference between current & stored hit points.
        int deltaHP = (newHP - currentHP);
        //Only apply damage if PC is not at his/her max hit points.
        if (currentHP != newHP)
         {
         effect eDam = EffectDamage(deltaHP);
         ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oPlayer);
         }
        // Apply same conditions to 1st Henchman
        if (GetIsObjectValid(oHench1))
         {
         currentHP  = GetStoredHitPointsHench1(oHench1);
         newHP = GetCurrentHitPoints(oHench1);
         deltaHP = (newHP - currentHP);
         if (currentHP != newHP)
          {
          effect eDam = EffectDamage(deltaHP);
          ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oHench1);
          }
         }
        // Apply same conditions to 2nd Henchman
        if (GetIsObjectValid(oHench2))
         {
         currentHP  = GetStoredHitPointsHench2(oHench2);
         newHP = GetCurrentHitPoints(oHench2);
         deltaHP = (newHP - currentHP);
         if (currentHP != newHP)
          {
          effect eDam = EffectDamage(deltaHP);
          ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oHench2);
          }
         }
        // Apply same conditions to PC's familiar
        if (GetIsObjectValid(oFamiliar))
         {
         currentHP  = GetStoredHitPointsFamiliar(oFamiliar);
         newHP = GetCurrentHitPoints(oFamiliar);
         deltaHP = (newHP - currentHP);
         if (currentHP != newHP)
          {
          effect eDam = EffectDamage(deltaHP);
          ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oFamiliar);
          }
         }
        //Adjust the game clock for interrupted rest
        SetTime(nHour+2,0,0,0);
        }

if (GetLastRestEventType() == REST_EVENTTYPE_REST_FINISHED)
        {
        //Return the player to the hit points they started resting with.
        int currentHP  = GetStoredHitPoints(oPlayer);
        //Return the maximum Player hit points.
        int maxHP = GetMaxHitPoints(oPlayer);
        //Return the difference between current & maximum hit points.
        int deltaHP = (maxHP - currentHP);
        //Return the overall Constitution modifier adjustment (which can
        //never be less than -1).
        int adjCON = GetAbilityModifier(ABILITY_CONSTITUTION, oPlayer);
        if (adjCON <= -1) adjCON = -1;
        //Only apply damage if PC is not at his/her max hit points
        if (currentHP != maxHP)
         {
         effect eDam = EffectDamage(deltaHP - adjCON - 1);
         ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oPlayer);
         }
        //Apply same conditions to 1st Henchman
        currentHP  = GetStoredHitPointsHench1(oHench1);
        maxHP = GetMaxHitPoints(oHench1);
        deltaHP = (maxHP - currentHP);
        adjCON = GetAbilityModifier(ABILITY_CONSTITUTION, oHench1);
        if (adjCON <= -1) adjCON = -1;
        if (currentHP != maxHP)
         {
         effect eDam = EffectDamage(deltaHP - adjCON - 1);
         ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oHench1);
         }
        //Apply same conditions to 2nd Henchman
        currentHP  = GetStoredHitPointsHench2(oHench2);
        maxHP = GetMaxHitPoints(oHench2);
        deltaHP = (maxHP - currentHP);
        adjCON = GetAbilityModifier(ABILITY_CONSTITUTION, oHench2);
        if (adjCON <= -1) adjCON = -1;
        if (currentHP != maxHP)
         {
         effect eDam = EffectDamage(deltaHP - adjCON - 1);
         ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oHench2);
         }
        //Apply same conditions to PC's familiar
        currentHP  = GetStoredHitPointsFamiliar(oFamiliar);
        maxHP = GetMaxHitPoints(oFamiliar);
        deltaHP = (maxHP - currentHP);
        adjCON = GetAbilityModifier(ABILITY_CONSTITUTION, oFamiliar);
        if (adjCON <= -1) adjCON = -1;
        if (currentHP != maxHP)
         {
         effect eDam = EffectDamage(deltaHP - adjCON - 1);
         ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oFamiliar);
         }
        //Adjust the game clock for uninterrupted rest
        SetTime(nHour+12,0,0,0);
        }
}
//
// Determine PC's hit points prior to resting.
// This function is used to determine how many
// hit points to add as a result of resting
// (as per 1st edition rules)
void SetStoredHitPoints(object oPlayer)
{
    SetLocalInt(oPlayer, "LAST_STORED_HITPOINTS", GetCurrentHitPoints(oPlayer));
}
int GetStoredHitPoints(object oPlayer)
{
    return GetLocalInt(oPlayer, "LAST_STORED_HITPOINTS");
}
// Determine 1st Henchman's hit points prior to resting.
void SetStoredHitPointsHench1(object oHench1)
{
    SetLocalInt(oHench1, "LAST_STORED_HITPOINTS_HENCH1", GetCurrentHitPoints(oHench1));
}
int GetStoredHitPointsHench1(object oHench1)
{
    return GetLocalInt(oHench1, "LAST_STORED_HITPOINTS_HENCH1");
}
// Determine 2nd Henchman's hit points prior to resting.
void SetStoredHitPointsHench2(object oHench2)
{
    SetLocalInt(oHench2, "LAST_STORED_HITPOINTS_HENCH2", GetCurrentHitPoints(oHench2));
}
int GetStoredHitPointsHench2(object oHench2)
{
    return GetLocalInt(oHench2, "LAST_STORED_HITPOINTS_HENCH2");
}
// Determine PC's hit points prior to resting.
void SetStoredHitPointsFamiliar(object oFamiliar)
{
    SetLocalInt(oFamiliar, "LAST_STORED_HITPOINTS_FAMILIAR", GetCurrentHitPoints(oFamiliar));
}
int GetStoredHitPointsFamiliar(object oFamiliar)
{
    return GetLocalInt(oFamiliar, "LAST_STORED_HITPOINTS_FAMILIAR");
}
// End Script
