// Hemophiliacs Always Bleed to Death
// By Demtrious and OldManWhistler
//
// PLEASE READ "habd_include" FOR MORE INFORMATION.
//
// OnPlayerRespawn event handler.

#include "habd_include"

// Change this value if it is causing server lag.
const float GHOST_LOOP_TIMER = 6.0f;

// ****************************************************************************

// This function acts as a player heartbeat while the player is under the
// "respawn effect".
//   oOldFollow - is the last object the player was told to follow.

void Ghost(object oOldFollow = OBJECT_INVALID)
{
    object oMod = GetModule();
    object oPC = OBJECT_SELF;
    string sID = GetPCPlayerName(oPC)+GetName(oPC);

    if (HABD_DEBUG) SpeakString("DEBUG: HABD OnGhostHB, "+GetName(oPC)+", PlotFlag:"+IntToString(GetPlotFlag(OBJECT_SELF))+", CommandableFlag:"+IntToString(GetCommandable())+", HP: "+IntToString(GetCurrentHitPoints(oPC))+", master: "+GetName(GetMaster(oPC))+", state:"+HABDGetPlayerStateName(oPC), TALKVOLUME_SHOUT);

    if (
        (GetPlotFlag(OBJECT_SELF)) &&
        (GetLocalInt(oMod, HABD_PLAYER_STATE+sID) == HABD_STATE_RESPAWNED_GHOST)
        )
    {
        // Is there someone to follow?
        object oFollow = GetLocalObject(oPC, HABD_GHOST_AUTOFOLLOW);
        HABDAssociateBusy();
        SetCommandable(TRUE);
        // Most important, schedule the next iteration of the heartbeat.
        DelayCommand(GHOST_LOOP_TIMER, Ghost(oFollow));
        if (GetIsObjectValid(oFollow))
        {
            if (oFollow != oOldFollow) FloatingTextStringOnCreature(GetName(OBJECT_SELF)+" is now following "+ GetName(oFollow), oPC, TRUE);
            if (GetArea(OBJECT_SELF) != GetArea(oFollow))
            {
                SendMessageToPC(oPC, "Jumping to "+GetName(oFollow));
                // Not in same area, jump them there
                ClearAllActions();
                ActionJumpToObject(oFollow);
            } else {
                // In same area, move them there
                ClearAllActions();
                DelayCommand(0.5, ActionForceFollowObject(oFollow, 6.0f));
            }
        }
        // Remove their ability to control themselves
        SetCommandable(FALSE);
    } else {
        // Respawn state has been removed. Restore the player to normal.
        SetCommandable(TRUE);
        SetPlotFlag(OBJECT_SELF, FALSE);
        // Set playerstate to alive.
        SetLocalInt(oMod, HABD_PLAYER_STATE+sID, HABD_STATE_PLAYER_ALIVE);
        FloatingTextStringOnCreature("OOC: You shake off the ghostly effects.", OBJECT_SELF, FALSE);
        // Restore the player's reputation with HOSTILE faction.
        SetStandardFactionReputation(STANDARD_FACTION_HOSTILE, GetLocalInt(oPC, HABD_OLD_FACTION), oPC);
        DeleteLocalInt(oPC, HABD_OLD_FACTION_SET);
        effect eEffect = GetFirstEffect(OBJECT_SELF);
        while(GetIsEffectValid(eEffect))
        {
            // They are rezzed, remove sanctuary visual effects.
            if (GetEffectType(eEffect) == EFFECT_TYPE_CONCEALMENT)
            {
                RemoveEffect(OBJECT_SELF, eEffect);
            }
            eEffect = GetNextEffect(OBJECT_SELF);
        }
        HABDAssociateNotBusy();
        AssignCommand(OBJECT_SELF, ClearAllActions());
        // Fixes the inital respawn issue with monsters not reattacking.
        object oMonster = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY,oPC, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
        DelayCommand(9.0, AssignCommand(oMonster, ActionAttack(oPC)));
    }
}

// ****************************************************************************

// OnPlayerRespawn event handler.

void main()
{
    // Check to see if the system is supposed to run this script, otherwise
    // it may be configured improperly.
    if (HABD_RESPAWN_SCRIPT != "habd_onpcrespawn")
    {
        ExecuteScript(HABD_RESPAWN_SCRIPT, OBJECT_SELF);
        return;
    }

    object oPC;
    // Catch if the script was forced to executed.
    if (GetLocalInt(OBJECT_SELF, HABD_FORCED_RESPAWN) == 1)
    {
        oPC = OBJECT_SELF;
        HABDAssociateBusy();
    } else {
        oPC = GetLastRespawnButtonPresser();
    }
    object oMod = GetModule();
    string sID = GetPCPlayerName(oPC)+GetName(oPC);

    if (HABD_DEBUG) SpeakString("DEBUG: HABD OnRespawn, "+GetName(oPC)+", HP: "+IntToString(GetCurrentHitPoints(oPC))+", master: "+GetName(GetMaster(oPC))+", state:"+HABDGetPlayerStateName(oPC), TALKVOLUME_SHOUT);

    // Set the player state to respawn.
    SetLocalInt(oMod, HABD_PLAYER_STATE+sID, HABD_STATE_RESPAWNED_GHOST); //set playerstate to DM raised.

    // Make it look like something happened.
    ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_DOOM), oPC);
    // Raise the player.
    ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectResurrection(), oPC);

    // Most important, schedule the ghost heartbeat.
    AssignCommand(oPC, DelayCommand(3.0, Ghost()));

    // If they have a master, set up the master as the autofollow.
    if (GetIsObjectValid(GetMaster(oPC))) SetLocalObject(oPC, HABD_GHOST_AUTOFOLLOW, GetMaster(oPC));
    else
    {
        // Remove any old autofollow objects.
        DeleteLocalObject(oPC, HABD_GHOST_AUTOFOLLOW);
    }

    // Apply the user defined effects.
    AssignCommand(oPC, HABDUserDefinedRespawn());

    // Check if we are re-entering this state from persistence.
    if (GetLocalInt(oPC, HABD_PERSISTANT_REAPPLY) != 1)
    {
        // Apply the respawn penalty.
        HABDApplyPenalty(oPC, HABD_RESPAWN_XP_LOSS, HABD_RESPAWN_GP_LOSS);
    } else {
        DeleteLocalInt(oPC, HABD_PERSISTANT_REAPPLY);
    }

    // Make them invulnerable
    SetPlotFlag(oPC, TRUE);

    // Make them ignored by hostiles
    if (!GetLocalInt(oPC, HABD_OLD_FACTION_SET))
    {
        SetLocalInt(oPC, HABD_OLD_FACTION, GetStandardFactionReputation(STANDARD_FACTION_HOSTILE, oPC));
        SetLocalInt(oPC, HABD_OLD_FACTION_SET, 1);
    }
    SetStandardFactionReputation(STANDARD_FACTION_HOSTILE, 100, oPC);

    // Apply effects to make them a ghost.
    // Don't set the concealment too high just incase they find a way to abuse the system.
    effect eBad = EffectConcealment(1);
    eBad = EffectLinkEffects(EffectVisualEffect(VFX_DUR_PROT_SHADOW_ARMOR), eBad);
    eBad = EffectLinkEffects(EffectVisualEffect(VFX_DUR_GHOSTLY_VISAGE), eBad);
    ApplyEffectToObject(DURATION_TYPE_PERMANENT, eBad, oPC);

    FloatingTextStringOnCreature("OOC: You are a ghost. Do not interact with the other players.", oPC, FALSE);
    SetCommandable(FALSE, oPC);
}

