// HCR v3.2.0 -
//::////////////////////////////////////////////////////////////////////////////
//:: FileName:  HC_On_Play_Death
//::////////////////////////////////////////////////////////////////////////////
/*
     This script sets the PlayerState to DEAD once they hit -10 hitpoits and
    displays one GUI if they have a deity, and another if they do not. Respawn
    button prays for ressurection on the one, and does nothing on other.

    REZPENALTY code by: Jamos and Majoru
*/
//::////////////////////////////////////////////////////////////////////////////
#include "CRR_Subrace_HC_i"
#include "HC_Inc_DCorpse"
#include "HC_Inc_Death"
#include "HC_Inc_DropBag"
#include "HC_Inc_Gods"
#include "HC_Inc_On_Death"
#include "HC_Inc_RezPen"
#include "HC_Inc_TimeCheck"
#include "HC_Inc_Transfer"
//::////////////////////////////////////////////////////////////////////////////
void main()
{
    // Check User code.
    if (!preEvent())
        return;

    // Prevent re-death while already in fugue. Thanks Sir Elric.
    object oPlayer = GetLastPlayerDied();
    if (HCR_CheckDeathPlane(oPlayer))
        return;

    // Check Subrace System Death.
    if (GetLocalInt(oMod, "SUBRACES") && !crr_SubraceHCRdeath(oPlayer))
        return;

    // If using the Deity system, check to see if they have a god, and if that
    // god is listening. (5% chance by default, only once per character)
    if (GetLocalInt(oMod, "GODSYSTEM") && RessCheck(oPlayer))
        return;

    // Player is dead and the code should continue processing at this point.
    object oKiller = GetLastAttacker(oPlayer);
    string sName   = GetName(oPlayer);
    string sPCName = GetPCPlayerName(oPlayer);
    string sID     = GetPlayerID(oPlayer);
    int nCurState  = GPS(oPlayer);

    // Set/Check last death time.
    int nSSB = SecondsSinceBegin();
    if ((GetLocalInt(oMod, "LASTDIED" + sID) + 60) > nSSB)
        SendMessageToAllDMs("** WARNING **" + sPCName + " might be trying to avoid death.");
    else
        SetLocalInt(oMod, "LASTDIED" + sID, nSSB);

    // Check if the player was PK'd and PK Tracker is used.
    if (GetLocalInt(oMod, "PKTRACKER") > 0)
    {
        // Loop through the masters looking for the player that owns the NPC's.
        // Note DM's should not be considered for this purpose.
        int nCount;
        string sPKName = GetPCPlayerName(oKiller);
        object oMaster = GetMaster(oKiller);
        while (GetIsObjectValid(oMaster))
        {
            if (GetIsPC(oMaster) &&
               !GetIsDM(oMaster) &&
               !GetIsDMPossessed(oMaster))
            {
                sPKName = GetPCPlayerName(oMaster);
                oKiller = oMaster;
                break;
            }
            oMaster = GetMaster(oMaster);
        }

        // If we have a valid PC Name and the killer is not a member of the
        // players faction, then increment the PK count.
        if (sPKName != "" && !GetFactionEqual(oPlayer, oKiller))
        {
            nCount = GetPersistentInt(oMod, "PKCOUNT" + sPKName);
            SetPersistentInt(oMod, "PKCOUNT" + sPKName, nCount + 1);
        }
    }

    // Check if Tell on PK is used.
    if (GetLocalInt(oMod, "TELLONPK") && GetIsPC(oKiller))
        SendMessageToAllDMs("**(PK): " + sName + " was PK'd by " + GetName(oKiller));

    // Set the death location.
    location lPlayer = GetLocation(oPlayer);
    location lDiedHere;
    if (GetLocalInt(oPlayer, "LOGINDEATH"))
    {
        // For graveyard and relogin.
        object oGraveYard = GetObjectByTag("GraveYard");
        if (GetLocalInt(oPlayer, "GRAVEYARD"))
        {
            DeleteLocalInt(oPlayer, "GRAVEYARD");
            lDiedHere = GetLocation(oGraveYard);
        }
        else
        {
            // Set location to previously saved death loc. If for any reason
            // that area is now invalid or was deleted/removed from the DB use
            // the graveyard as the death location.
            lDiedHere = GetPersistentLocation(oMod, "DIED_HERE" + sID);
            if (!GetIsObjectValid(GetAreaFromLocation(lDiedHere)))
                lDiedHere = GetLocation(oGraveYard);
        }

        // Look for a corpse already at the death location.
        object oObject = GetNearestObjectToLocation(OBJECT_TYPE_PLACEABLE, lDiedHere);
        if (GetTag(oObject) == "DeathCorpse" &&
            GetDistanceBetweenLocations(lDiedHere, GetLocation(oObject)) < 0.4)
        {
            // Add random float for drop location when logging in dead. This is
            // to help prevent too many corpses from stacking directly on top of
            // each other at the graveyard.
            float fRan = (IntToFloat(d20()) / 10.0);
            if (d2() == 1)
                fRan *= -1.0;
            vector vAdj = Vector(0.4 + fRan, 0.4 + fRan, 0.0);
            vector vPos = (GetPositionFromLocation(lDiedHere) + vAdj);
            lDiedHere = Location(GetArea(oObject), vPos, GetFacing(oPlayer));
        }
    }
    else
    {
        // Just died. Use current location as the death location.
        lDiedHere = lPlayer;
    }

    // Save the Death Location to the DB.
    SetPersistentLocation(oMod, "DIED_HERE" + sID, lDiedHere);

    // Remove all Henchmen from service.
    int nNth = 1;
    object oHench = GetHenchman(oPlayer, nNth);
    while (GetIsObjectValid(oHench))
    {
        RemoveHenchman(oPlayer, oHench);
        nNth++;
    }

    // If we are using the loot system, strip all items from the dead man.
    object oDeathCorpse;
    int nDEATHSYSTEM = GetLocalInt(oMod, "DEATHSYSTEM");
    int nLOOTSYSTEM = GetLocalInt(oMod, "LOOTSYSTEM");
    int nLIMBO = GetLocalInt(oMod, "LIMBO");
    if (nDEATHSYSTEM)
    {
        // Change the player state.
        int nState = GPS(oPlayer);
        SPS(oPlayer, PWS_PLAYER_STATE_DEAD);

        // Drop corpses held on death.
        ExecuteScript("hc_drop_corpse", oPlayer);

        object oDB;
        if (nLOOTSYSTEM)
        {
            // If no Drop Bag exists, make one.
            oDB = GetLocalObject(oMod, "DropBag" + sID);
            location lDB = GetLocation(oDB);
            if (!GetIsObjectValid(oDB) ||
                GetDistanceBetweenLocations(lPlayer, lDB) > 3.0 ||
                GetArea(oDB) != GetArea(oPlayer))
            {
                oDB = DropBag(lDiedHere, oPlayer);
                SetLocalObject(oDB, "Owner", oPlayer);
                SetLocalString(oDB, "Name", sName);
                SetLocalString(oDB, "Key", sPCName);
                SetLocalString(oDB, "Pkey", sID);
                SetLocalObject(oMod, "DropBag" + sID, oDB);
            }

            // Tansfer Equipment. Only if equipped items are suppossed to be
            // transferred.
            if (!GetLocalInt(oMod, "INVSTRIP"))
            {
                int nSlot;
                for (nSlot = 0; nSlot < 14; nSlot++)
                {
                    object oSlot = GetItemInSlot(nSlot, oPlayer);
                    if (oSlot != OBJECT_INVALID)
                    {
                        HCR_StripEquipped(oPlayer, oDB, oSlot);
                    }
                }
            }

            // Check to make sure the player wasnt already dying. If the player
            // was dying and Dying Strip is used then inventory is already being
            // transferred. If not dying or that system is off then transfer.
            if (nState != PWS_PLAYER_STATE_DYING ||
               !GetLocalInt(oMod, "DYINGSTRIP"))
            {
                // Transfer Inventory.
                hcTakeObjects(oPlayer, oDB);

                // Transfer Gold
                int nAmtGold = GetGold(oPlayer);
                if (nAmtGold > 0)
                {
                    object oBag = CreateItemOnObject("bagofgold", oDB);
                    if (oBag != OBJECT_INVALID)
                    {
                        SetLocalInt(oBag, "AmtGold", nAmtGold);
                        AssignCommand(oBag, TakeGoldFromCreature(nAmtGold, oPlayer, TRUE));
                    }
                }
            }
        }

        // Create the Death Corpse.
        oDeathCorpse = CreateObject(OBJECT_TYPE_PLACEABLE, "DC", lDiedHere);
        if (oDeathCorpse != OBJECT_INVALID)
        {
            SetLocalObject(oMod, "DeathCorpse" + sID, oDeathCorpse);
            SetLocalObject(oDeathCorpse, "Owner", oPlayer);
            SetLocalString(oDeathCorpse, "Name", sName);
            SetLocalString(oDeathCorpse, "Key", sPCName);
            SetLocalString(oDeathCorpse, "Pkey", sID);
        }

        // Create the "copied" corpse.
        // Note: Using delay to avoid creating copy when the player is not dead.
        DelayCommand(8.0, CreateCorpse(oPlayer));

        // Create a Player Corpse Token (PCT).
        object oDeadMan = GetLocalObject(oMod, "PlayerCorpse" + sID);
        if (GetIsObjectValid(oDeadMan))
            SetLocalInt(oPlayer, "REDEATH", 0);
        else
            oDeadMan = CreateItemOnObject("PlayerCorpse", oDeathCorpse);

        // Set/Update the locals on the PCT, Death Corpse and Player.
        SetLocalObject(oMod, "PlayerCorpse" + sID, oDeadMan);
        SetLocalObject(oPlayer, "PlayerToken", oDeadMan);
        SetLocalObject(oDeadMan, "Owner", oPlayer);
        SetLocalObject(oDeathCorpse, "PlayerCorpse", oDeadMan);
        SetLocalObject(oDeadMan, "DeathCorpse", oDeathCorpse);
        SetLocalString(oDeadMan, "Name", sName);
        SetLocalString(oDeadMan, "Key", sPCName);
        SetLocalString(oDeadMan, "PKey", sID);
        SetLocalString(oDeadMan, "Deity", GetDeity(oPlayer));
        SetLocalInt(oDeadMan, "Alignment", GetAlignmentGoodEvil(oPlayer));


        // If using lIMBO, give feedback, set the moving local and start the
        // transfer to the Death Plane. Otherwise just pop up the GUI with the
        // respawn button disabled.
        if (nLIMBO)
        {
            SendMessageToPC(oPlayer, "You have died and your spirit was sent to the Death Plane. You may exit or wait for help.");
            SetLocalInt(oPlayer, "MOVING", TRUE);
            object oLimbo = GetObjectByTag("FugueMarker");
            HCR_SendToDeathPlane(oPlayer, oLimbo, sID);
        }
        else
        {
            DelayCommand(2.5, PopUpDeathGUIPanel(oPlayer, FALSE, TRUE, 0, "You may exit or wait for help."));
        }
    }
    else
    {
        // Check/Set Rez Penalty for respawn.
        if (GetLocalInt(oMod, "REZPENALTY") )
            SetPersistentInt(oMod, "REZPEN" + sID, 1);

        // Not using Death System, let them respawn normally.
        DelayCommand(2.5, PopUpDeathGUIPanel(oPlayer, TRUE, TRUE, 0, "You may exit or respawn."));
    }

    // Reset last recovery check time, last rest time and log in death values.
    DeletePersistentInt(oMod, "LastRecCheck" + sID);
    DeletePersistentInt(oMod, "LastRest" + sID);
    DeleteLocalInt(oPlayer, "LOGINDEATH");

    postEvent();
}
//::////////////////////////////////////////////////////////////////////////////
