//::///////////////////////////////////////////////
//:: OnPlayerRest eventscript
//:: prc_rest
//:://////////////////////////////////////////////
/*
    Hooked NPC's into this via prc_npc_rested - 06.03.2004, Ornedan
*/

#include "prc_inc_function"
#include "psi_inc_psifunc"
#include "prc_sp_func"
#include "prc_inc_domain"
#include "true_inc_trufunc"
#include "inv_inc_invfunc"
#include "inc_epicspells"
#include "prc_inc_scry"
#include "prc_inc_dragsham"
#include "prc_inc_wpnrest"
#include "inc_dynconv"
#include "prc_inc_util"
#include "shd_inc_myst"
#include "prc_inc_template"

void PrcFeats(object oPC)
{
    if(DEBUG) DoDebug("prc_rest: Evaluating PC feats for " + DebugObject2Str(oPC));

    SetLocalInt(oPC,"ONREST",1);
    object oSkin = GetPCSkin(oPC);
    DelayCommand(0.0, ScrubPCSkin(oPC, oSkin));
    DelayCommand(0.1, FeatSpecialUsePerDay(oPC));
    DelayCommand(0.2, DeletePRCLocalInts(oSkin));
    DelayCommand(0.3, DeletePRCLocalIntsT(oPC));
    DelayCommand(0.4, EvalPRCFeats(oPC));
    DelayCommand(0.4, DoWeaponsEquip(oPC));
    DelayCommand(1.0, DeleteLocalInt(oPC,"ONREST"));
}

void RestCancelled(object oPC)
{
    if(GetPRCSwitch(PRC_PNP_REST_HEALING))
    {
        int nHP = GetLocalInt(oPC, "PnP_Rest_InitialHP");
        //cancelled, dont heal anything
        //nHP += GetHitDice(oPC);
        int nCurrentHP = GetCurrentHitPoints(oPC);
        int nDamage = nCurrentHP-nHP;
        //check its a positive number
        if(nDamage > 0)
        {
            //DelayCommand(1.5, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDamage, DAMAGE_TYPE_MAGICAL, DAMAGE_POWER_PLUS_TWENTY), oPC));
            SetCurrentHitPoints(oPC, nCurrentHP - nDamage);
        }    
    }
    if(DEBUG) DoDebug("prc_rest: Rest cancelled for " + DebugObject2Str(oPC));
    DelayCommand(1.0,PrcFeats(oPC));
    // Execute scripts hooked to this event for the player triggering it
    ExecuteAllScriptsHookedToEvent(oPC, EVENT_ONPLAYERREST_CANCELLED);
}

void RestFinished(object oPC)
{
    int nGeneration = PRC_NextGeneration(GetLocalInt(oPC, PRC_Rest_Generation));
    if (DEBUG > 1) DoDebug("Rest Generation: " + IntToString(nGeneration));
    SetLocalInt(oPC, PRC_Rest_Generation, nGeneration);

    if(DEBUG) DoDebug("prc_rest: Rest finished for for " + DebugObject2Str(oPC));
    //Restore Power Points for Psionics
    ExecuteScript("prc_psi_ppoints", oPC);
    ExecuteScript("tob_evnt_recover", oPC);
    DelayCommand(0.0, BonusDomainRest(oPC));
    DelayCommand(0.0, ClearLawLocalVars(oPC));
    DelayCommand(0.0, ClearMystLocalVars(oPC));
    DelayCommand(0.0, ClearLegacyUses(oPC));
    DelayCommand(0.1, ClearInvocationLocalVars(oPC));

    // To heal up enslaved creatures...
    object oSlave = GetLocalObject(oPC, "EnslavedCreature");
    if (GetIsObjectValid(oSlave) && !GetIsDead(oSlave) && !GetIsInCombat(oSlave))
            AssignCommand(oSlave, ActionRest());
            //ForceRest(oSlave);

    if (GetIsEpicSpellcaster(oPC)) {
        FloatingTextStringOnCreature("*You feel refreshed*", oPC, FALSE);
        ReplenishSlots(oPC);
    }

    if (GetHasFeat(FEAT_SF_CODE,oPC))
        DelayCommand(0.1, RemoveSpecificProperty(GetPCSkin(oPC),ITEM_PROPERTY_BONUS_FEAT,IP_CONST_FEAT_SF_CODE));

    // begin flurry of swords array
    if (GetLevelByClass(CLASS_TYPE_ARCANE_DUELIST, oPC))
    {
        DeleteLocalInt(oPC, "FLURRY_TARGET_NUMBER");

        int i;
        for (i = 0 ; i < 10 ; i++)
        {
            string sName = "FLURRY_TARGET_" + IntToString(i);
            SetLocalObject(oPC, sName, OBJECT_INVALID);
        }
    }
    // end flurry or swords array

    //Check for leftover Diamond Dragon appendages
    if (GetLevelByClass(CLASS_TYPE_DIAMOND_DRAGON, oPC))
    {
        if(GetPersistantLocalInt(oPC, "ChannelingTail"))
        {
            SetPersistantLocalInt(oPC, "ChannelingTail", FALSE);
            SetCreatureTailType(CREATURE_TAIL_TYPE_NONE, oPC);
        }
        if(GetPersistantLocalInt(oPC, "ChannelingWings"))
        {
            SetPersistantLocalInt(oPC, "ChannelingWings", FALSE);
            SetCreatureWingType(CREATURE_WING_TYPE_NONE, oPC);
        }
    }

    if(GetPRCSwitch(PRC_PNP_REST_HEALING))
    {
        int nHP = GetLocalInt(oPC, "PnP_Rest_InitialHP");
        int nOldMax = GetLocalInt(oPC, "PnP_Rest_InitialMax");
        if(DEBUG) DoDebug("prc_rest: Finished HPs for " + DebugObject2Str(oPC)+"n/n/"+" nCurrent: "+IntToString(nHP)+" nMax: "+IntToString(nOldMax));
        //only heal HP if not undead and not a construct
        if(MyPRCGetRacialType(oPC) != RACIAL_TYPE_UNDEAD && MyPRCGetRacialType(oPC) != RACIAL_TYPE_CONSTRUCT)
            nHP = GetMaxHitPoints(oPC) - nOldMax + nHP + GetHitDice(oPC);
        int nCurrentHP = GetCurrentHitPoints(oPC);
        int nDamage = nCurrentHP-nHP;
        //check its a positive number
        if(nDamage > 0)
        {
            //DelayCommand(1.5, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDamage, DAMAGE_TYPE_MAGICAL, DAMAGE_POWER_PLUS_TWENTY), oPC));
            SetCurrentHitPoints(oPC, nCurrentHP - nDamage);
        }  
        // We've finished rest, clean up
        DeleteLocalInt(oPC, "PnP_Rest_InitialHP");
        DeleteLocalInt(oPC, "PnP_Rest_InitialMax");
    }

    int nSpellCount = GetPRCSwitch(PRC_DISABLE_SPELL_COUNT);
    int i;
    string sMessage;
    for(i=1;i<nSpellCount;i++)
    {   //WARNING! WILL DO BAD THINGS TO SPONTANEOUS CASTERS AFFECTED
        int nSpell = GetPRCSwitch(PRC_DISABLE_SPELL_+IntToString(i));
        int nMessage;
        while(PRCGetHasSpell(nSpell, oPC))
        {
            if(!nMessage)
            {
                sMessage += "You cannot use "+GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpell)))+" in this module.\n";
                nMessage = TRUE;
            }
            PRCDecrementRemainingSpellUses(oPC, nSpell);
        }
    }
    if(sMessage != "")
        FloatingTextStringOnCreature(sMessage, oPC, TRUE);

    //Clear Battle Fortitude lock
    DeleteLocalInt(oPC, "BattleFortitude");
    DeleteLocalInt(oPC, "ArmouredStealth");
    
    //Clear Spelldancing
    DeleteLocalInt(oPC, "SpelldanceFatigue");
    DeleteLocalInt(oPC, "SpelldanceExhaust");    
    DeleteLocalInt(oPC, "SpelldanceRounds");  
    
    //Clear Killoren
    DeleteLocalInt(oPC, "KillorenAncient");    
    DeleteLocalInt(oPC, "KillorenHunter"); 
    
    //Clear Earth Smite
    DeleteLocalInt(oPC, "EarthSmite"); 
    
    //Clear Fatigue
    DeleteLocalInt(oPC, "Fatigued");    
    DeleteLocalInt(oPC, "HeatstrokeCount");  
    
    // Allow Readying
    DeleteLocalInt(oPC, "ReadyManeuverCru");
    DeleteLocalInt(oPC, "ReadyManeuverSwd");
    DeleteLocalInt(oPC, "ReadyManeuverWar");
    
    // Rest Ranged Recall
    DeleteLocalInt(oPC, "RangedRecall");  
    
    // Animal Affinity
    DeleteLocalInt(oPC, "AnimalAffin"+IntToString(ABILITY_STRENGTH));
    DeleteLocalInt(oPC, "AnimalAffin"+IntToString(ABILITY_DEXTERITY));
    DeleteLocalInt(oPC, "AnimalAffin"+IntToString(ABILITY_CONSTITUTION));
    DeleteLocalInt(oPC, "AnimalAffin"+IntToString(ABILITY_WISDOM));
    DeleteLocalInt(oPC, "AnimalAffin"+IntToString(ABILITY_INTELLIGENCE));
    DeleteLocalInt(oPC, "AnimalAffin"+IntToString(ABILITY_CHARISMA));
    
    // Talon of Tiamat
    DeleteLocalInt(oPC, "TalonBreath1");
    DeleteLocalInt(oPC, "TalonBreath2");
    DeleteLocalInt(oPC, "TalonBreath3");
    DeleteLocalInt(oPC, "TalonBreath4");
    DeleteLocalInt(oPC, "TalonBreath5");

    if(GetHasFeat(FEAT_WEAPON_APTITUDE, oPC))
    {
        FloatingTextStringOnCreature(GetStringByStrRef(16837723), oPC, FALSE);
        SetLocalInt(oPC, "PRC_WEAPON_APTITUDE_APPLIED", 0);
    }

    //DelayCommand(1.0,PrcFeats(oPC));
    PrcFeats(oPC);

    //allow players to recruit a new cohort
    DeleteLocalInt(oPC, "CohortRecruited");

    //in large parties, sometimes people dont rest
    //loop over all and forcerest when necessary
    //assumes NPCs start and finish resting after the PC
    /*if(!GetIsObjectValid(GetMaster(oPC)))
    {*/
        int nType;
        for(nType = 1; nType < 6; nType++)
        {
            int i = 1;
            object oOldTest;
            object oTest = GetAssociate(nType, oPC, i);
            while(GetIsObjectValid(oTest) && oTest != oOldTest)
            {
                if(GetCurrentAction(oTest) != ACTION_REST)
                    AssignCommand(oTest, DelayCommand(0.01, PRCForceRest(oTest)));
                i++;
                oOldTest = oTest;
                oTest = GetAssociate(nType, oPC, i);
            }
        }
    //}

    // New Spellbooks
    DelayCommand(0.3, CheckNewSpellbooks(oPC));
    // PnP spellschools
    if(GetPRCSwitch(PRC_PNP_SPELL_SCHOOLS)
        && GetLevelByClass(CLASS_TYPE_WIZARD, oPC))
    {
        //need to put a check in to make sure the player
        //memorized one spell of their specialized
        //school for each spell level
        //also need to remove spells of prohibited schools
    }

    //Reset potions brewed
    DeleteLocalInt(oPC, "PRC_POTIONS_BREWED");

    //Reset scry on familiar uses
    DeleteLocalInt(oPC, "Scry_Familiar");

    //for Touch of Vitality point resetting
    ResetTouchOfVitality(oPC);

    //Lahm's finger darts - recover lost fingers
    SetPersistantLocalInt(oPC, "FINGERS_LEFT_HAND", 6);
    SetPersistantLocalInt(oPC, "FINGERS_RIGHT_HAND", 6);
    SetPersistantLocalInt(oPC, "LEFT_HAND_USELESS", FALSE);
    SetPersistantLocalInt(oPC, "RIGHT_HAND_USELESS", FALSE);

    //DelayCommand(6.0f, ExecuteScript("prc_trueappear", oPC));

    //skip time forward if applicable
    DelayCommand(0.4, AdvanceTimeForPlayer(oPC, HoursToSeconds(8)));
    
    int nRest = GetPRCSwitch(PRC_PNP_REST_LIMIT);
    if(nRest > 0 || nRest < 0)    
    {
        int nDelay = nRest * GetHitDice(oPC);
        if (nRest == -1) nDelay = 24; 
        else if (nRest == -2) nDelay = 16;     
      
        SetLocalInt(oPC, "RestTimer", TRUE);
        DelayCommand(HoursToSeconds(nDelay), DeleteLocalInt(oPC, "RestTimer"));
        DelayCommand(HoursToSeconds(nDelay), FloatingTextStringOnCreature("You may now rest again.", oPC, FALSE));
        FloatingTextStringOnCreature("You may rest again in "+IntToString(nDelay)+" hours.", oPC, FALSE);
    }    

    //ebonfowl: execute reserve feat update
    if(GetLocalInt(oPC, "ReserveFeatsRunning") == TRUE)
    {
        DelayCommand(1.0, ExecuteScript("prc_reservefeat", oPC));
    }
    
    // Execute scripts hooked to this event for the player triggering it
    ExecuteAllScriptsHookedToEvent(oPC, EVENT_ONPLAYERREST_FINISHED);
}

void RestStarted(object oPC)
{
    if(DEBUG) DoDebug("prc_rest: Rest started for " + DebugObject2Str(oPC));

    // Scrying cleanup
    if (GetIsScrying(oPC))
    {
        object oCopy = GetLocalObject(oPC, "Scry_Copy");
        DoScryEnd(oPC, oCopy);
    }
    
    int nRest = GetPRCSwitch(PRC_PNP_REST_LIMIT);
    if(nRest > 0 || nRest < 0)    
    {
        int nDelay = nRest * GetHitDice(oPC);
        if (nRest == -1) nDelay = 24; 
        else if (nRest == -2) nDelay = 16;     
        
        if(GetLocalInt(oPC, "RestTimer"))
        {
            AssignCommand(oPC, ClearAllActions());
            FloatingTextStringOnCreature("You may not rest yet. You may rest once every "+IntToString(nDelay)+" hours.", oPC, FALSE);
        }
    }
    
    // Clean up Crown of Might
    object oCrown = GetItemPossessedBy(oPC, "prc_crown_might");
    if (GetIsObjectValid(oCrown)) DestroyObject(oCrown);
    oCrown = GetItemPossessedBy(oPC, "prc_crown_prot");
    if (GetIsObjectValid(oCrown)) DestroyObject(oCrown);    

    if (GetLevelByClass(CLASS_TYPE_DRUNKEN_MASTER, oPC)){
        SetLocalInt(oPC, "DRUNKEN_MASTER_IS_IN_DRUNKEN_RAGE", 0);
        SetLocalInt(oPC, "DRUNKEN_MASTER_IS_DRUNK_LIKE_A_DEMON", 0);
    }
    /* Left here in case the multisummon trick is ever broken. In that case, use this to make Astral Constructs get unsummoned properly
    if(GetHasFeat(whatever feat determines if the PC can manifest Astral Construct here)){
        int i = 1;
        object oCheck = GetHenchman(oPC, i);
        while(oCheck != OBJECT_INVALID){
            if(GetStringLeft(GetTag(oCheck), 14) == "psi_astral_con")
                DoDespawn(oCheck);
            i++;
            oCheck = GetHenchman(oPC, i);
        }
    }
    */

    if (GetIsPC(oPC)) SetLocalInt(oPC, "PnP_Rest_InitialHP", GetCurrentHitPoints(oPC));
    SetLocalInt(oPC, "PnP_Rest_InitialMax", GetMaxHitPoints(oPC));
    if(DEBUG) DoDebug("prc_rest: HPs for " + DebugObject2Str(oPC)+"n/n/"+" nCurrent: "+IntToString(GetCurrentHitPoints(oPC))+" nMax: "+IntToString(GetMaxHitPoints(oPC)));
    // Remove Psionic Focus
    if(GetIsPsionicallyFocused(oPC))
    {
        LosePsionicFocus(oPC);
    }
    DeleteLocalInt(oPC, PRC_SPELL_CHARGE_COUNT);
    DeleteLocalInt(oPC, PRC_SPELL_CHARGE_SPELLID);
    DeleteLocalObject(oPC, PRC_SPELL_CONC_TARGET);
    if(GetLocalInt(oPC, PRC_SPELL_HOLD)) FloatingTextStringOnCreature("*Normal Casting*", oPC);
    DeleteLocalInt(oPC, PRC_SPELL_HOLD);
    DeleteLocalInt(oPC, PRC_SPELL_METAMAGIC);
    DeleteLocalManifestation(oPC, PRC_POWER_HOLD_MANIFESTATION);
    DeleteLocalMystery(oPC, "MYST_HOLD_MYST");
    // run the prereq check here
    ExecuteScript("prc_prereq", oPC);
    // Execute scripts hooked to this event for the player triggering it
    ExecuteAllScriptsHookedToEvent(oPC, EVENT_ONPLAYERREST_STARTED);
}

void main()
{
    object oPC = GetLastBeingRested();

    if(DEBUG) DoDebug("prc_rest: Running for " + DebugObject2Str(oPC));
    if(DEBUG) DoDebug("prc_rest Void Main: HPs for " + DebugObject2Str(oPC) +" nCurrent: "+IntToString(GetCurrentHitPoints(oPC)));

    // return here for DMs as they don't need all this stuff
    if(GetIsDM(oPC))
        return;

    //rest kits
    if(GetPRCSwitch(PRC_SUPPLY_BASED_REST))
        ExecuteScript("sbr_onrest", OBJECT_SELF);

    // Handle the PRCForceRest() wrapper
    if(GetLocalInt(oPC, "PRC_ForceRested"))
    {
        if(DEBUG) DoDebug("prc_rest: Handling forced rest");
        RestStarted(oPC);
        // A minor delay to break the script association and to lessen TMI chances
        DelayCommand(0.1f, RestFinished(oPC));
        // Clear the flag
        DeleteLocalInt(oPC, "PRC_ForceRested");
    }
    else
    {
        switch(MyGetLastRestEventType()){
            case REST_EVENTTYPE_REST_CANCELLED:{
                RestCancelled(oPC);
                break;
            }
            case REST_EVENTTYPE_REST_STARTED:{
                RestStarted(oPC);
                break;
            }
            case REST_EVENTTYPE_REST_FINISHED:{
                RestFinished(oPC);
                break;
            }
            case REST_EVENTTYPE_REST_INVALID:{
                break;
            }
        }
    }
}
