Author: Keron Blackfeld
Author Website: n/a
Script Name: Lootable Creature Corpse
Description: This script, when placed in a creature's onDeath event, causes the critter's corpse to remain either indefinitely or for a specified amount of time (see below) - and it can be looted!  That's not exactly true  what it does is set the corpse to not selectable and then spawns an invisible, lootable "corpse" object under the actual body. It then moves all of the creature's inventory to that object so it "fakes" actual lootable bodies.
Instructions on Use: You can now set a delay for the corpses to hang out before they automatically fade - and you can also set them to auto fade upon the emptying of their inventories.

To do the auto fade on empties... you actually need a second script that goes in the onheatbeat of the lootable object. If you are concerned about the onHeartbeats being a problem in your module... just don't use them and just use the "Corpse Fade" delay.

There are a couple of settings you can toy with in the beginning of the script. These are:

nUseBlood - Set this to true and it will spawn a bloodspot under the corpse upon death. This will also be destroyed during the CorpseFade event.

nCorpseFade - Setting this to 0 (zero) will toggle it off. Use this to set your delay. i.e. nCorpseFade = 60 will keep the corpses around for 1 minute (real time).

nKeepEmpties - Setting this to TRUE means that Empty corpses will hang out for the delay period as well. Setting this to FALSE will trigger the auto fade when the inventory is empty. The auto fade on empty will ONLY WORK IF YOU USE THE ONHEARTBEAT SCRIPT AS WELL.

nOverrideForPlacedCorpses - I use this to make the corpses that I place in the toolset permanent. They way this works is you place any creature - then add "Dead" as a prefix to it's TAG. Now place the _kb_loot_corpse in that creature's onSpawn event. It will kill the critter upon spawning - thereby creating a lootable corpse. I call this a creature that is "Spawned Dead". When the nOverrideForPlacedCorpses is set to TRUE, the script overrides the nCorpseFade and nKeepEmpties settings for creatures who are "Spawned Dead" - those corpses will NEVER FADE. Setting this to FALSE just means that this corpse will be handled exactly as any other in your module (i.e. it will fade after the delay or when emptied - if your settings indicate such).

To use this script effectively, first you need to create your Blueprint ResRef for an INVISIBLE OBJECT with the ResRef (on the Advanced Tab) of "invis_corpse_obj" and the name "corpse". Now put the following script in it's onHeartBeat event (if you want to use the auto-fade-empties functionality):

ONE LAST NOTE: When a corpse with stuff still in its inventory fades, it leaves behind a normal loot bag with the inventory contents in it. If there are a few people out there who would prefer this NOT TO BE THE CASE, let me know here and I'll add an option to clean the inventory before the corpses fade, that way NOTHING will be left behind to litter the landscape after the corpses fade. I just haven't decided for myself if I want to get rid of the bags or not...

Comments from
site visitors:
Visitor: Comments:
Alexandra
  1. In the lootable corpse script, there are a few (imho) improvements available. First, move the corpse item generation from OnDeath to OnUserDefined, and enable the Death event in OnSpawn, that way you can remove the code you copied from OnDeath, and continue using the default OnDeath. (Not much difference I admit, but cleaner.)
  2. Next, move the empty corpse removal routine from OnHeartbeat to OnDisturbed. On a corpse littered battlefield it will make a HUGE difference in overhead.

Script 1 (OnHearbeat):

////////////////////////////////////////////////////////////////////////////////

//                                                                            //

//  _kb_ohb_lootable                                                          //

//                                                                            //

//  by Keron Blackfeld on 07/14/2002                                          //

//  email Questions and Comments to: keron@broadswordgaming.com or catch me   //

//  in Bioware's NWN Community - Builder's NWN Scripting Forum                //

//                                                                            //

////////////////////////////////////////////////////////////////////////////////

//                                                                            //

//  This is an OnHearbeat Script to go with my _kb_loot_corpse script for     //

//  LOOTABLE MONSTER/NPC CORPSES.                                             //

//                                                                            //

//  PLACE THIS SCRIPT IN THE ONHEARTBEAT EVEN OF YOUR "invis_corpse_obj"      //

//  BLUEPRINT. This script checks the inventory of OBJECT_SELF, and when it   //

//  is empty, it checks the LocalInt to see if the now empty corpse should    //

//  be Destroyed along with the Lootable Corpse Object.                       //

//                                                                            //

//  The _kb_loot_corpse script must have this line:                           //

//  int nKeepEmpties = FALSE;                                                 //

//  in order for the Empty Corpse to Destroy itself in this script.           //

//                                                                            //

////////////////////////////////////////////////////////////////////////////////

void main()

{

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

     ** Check inventory, does nothing else if **

     ** the inventory is not empty. Delayed   **

     ** Corpse Fade is handled within the     **

     ** _kb_loot_corpse script.               **

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

    object oHasInventory = GetFirstItemInInventory(OBJECT_SELF); //Check for inventory

    if (oHasInventory == OBJECT_INVALID)

    {

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

         ** Inventory is empty. Now we check the  **

         ** nKeepEmpty value.                     **

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

        object oHostCorpse = GetLocalObject(OBJECT_SELF, "oHostBody"); //Get Value set by _kb_loot_corpse at creation

        object oCorpseBlood = GetLocalObject(OBJECT_SELF, "oBloodSpot"); //Get Value set by _kb_loot_corpse at creation

        int nKeepEmpty = GetLocalInt(OBJECT_SELF, "oKeepEmpty"); //Get Value set by _kb_loot_corpse at creation

        if (!nKeepEmpty)

        {

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

             ** nKeepEmpty is FALSE. Delete empty.    **

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

            AssignCommand(oHostCorpse,SetIsDestroyable(TRUE,FALSE,FALSE)); //Set actual corpse to destroyable

            DestroyObject(oHostCorpse); //Delete the actual Creature Corpse

            DestroyObject(oCorpseBlood); //Delete the BloodSpot

            DelayCommand(1.0f,DestroyObject(OBJECT_SELF)); //Delete Lootable Object (Self)

        }

     }

}

Script 2 (OnDeath -or- OnSpawn):

////////////////////////////////////////////////////////////////////////////////

//                                                                            //

// _kb_loot_corpse                                                            //

//                                                                            //

//  by Keron Blackfeld on 07/13/2002                                          //

//  email Questions and Comments to: keron@broadswordgaming.com or catch me   //

//  in Bioware's NWN Community - Builder's NWN Scripting Forum                //

//                                                                            //

////////////////////////////////////////////////////////////////////////////////

//                                                                            //

//  strip_equiped function was borrowed from the Hard Core Ruleset, which     //

//  looks REALLY incredible by the way - Thanks guys!                         //

//                                                                            //

//  THE ONLY OTHER THING NEEDED for this script to work is a custom PLACEABLE //

//  INVISIBLE OBJECT with a Blueprint ResRef of "invis_corpse_obj". Also, set //

//  its name to "corpse" or something equally appropriate - this will be the  //

//  TEXT your players see when they put their mouse over the body.            //

//                                                                            //

//  This script can perform its functions in two ways.                        //

//                                                                            //

//  #1 PLACED IN THE onDeath EVENT: If used in place of or added to the       //

//  onDeath script of any creature, it will keep their corpse from decaying   //

//  for either a delayed period (set in this script) or until the module is   //

//  closed. It then creates an invisible corpse object under the body that    //

//  may be clicked for looting.                                               //

//                                                                            //

//  #2 PLACED IN THE onSpawn EVENT: If the creature's tag is set so that it   //

//  starts with the string 'Dead' and this script is used in the onSpawn      //

//  event, it will kill the creature at spawn, preserve the corpse, and add   //

//  an invisible, lootable corpse object (as in #1). This functionality gives //

//  you placeable, lootable corpses of all types. Please note tha by default  //

//  this script is set to override the Corpse Fade and Keep Empties on placed //

//  'Dead' creatures (or creatures that are "Spawned Dead"). This may be      //

//  changed by setting nOverrideForPlacedCorpses = TRUE; in the beginning of  //

//  the script.                                                               //

//                                                                            //

////////////////////////////////////////////////////////////////////////////////

#include "NW_I0_GENERIC"

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

 ** This script was borrowed from the Hard Core Ruleset, where they use it to **

 ** move a Dead PC's inventory to a lootable corpse object. Credit where      **

 ** credit is due, I always say. :)                                                **

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

void strip_equiped(object oDeadNPC, object oLootCorpse, object oEquip)

{

    if(GetIsObjectValid(oEquip))

    {

        AssignCommand(oLootCorpse, ActionTakeItem(oEquip, oDeadNPC));

    }

}



void main()

{

    //SET YOUR BLOOD, CORPSE FADE, KEEP EMPTY, AND SPAWNED DEAD OVERRIDE PREFERENCES HERE ///////////////////////////

    int nUseBlood = FALSE;    // Set this to TRUE if you want a Bloodspot to appear under the corpse               //

    int nCorpseFade = 60;     // Set this to 0 (ZERO) if you DO NOT want the corpses to fade                       //

    int nKeepEmpties = FALSE; //Set this to FALSE if you want EMPTY corpses to fade immediately                    //

    int nOverrideForPlacedCorpses = TRUE; //Set this to TRUE if you want the 'Spawned Corpses' you                 //

    //                                    //place to be permament. Setting it to FALSE will cause                  //

    //                                    //your Placed Dead creatures to act as the settings above dictate.       //

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    //ALTER THE FOLLOWING AT YOUR OWN RISK :)     

    object oDeadNPC = OBJECT_SELF; //Get the Dead Creature Object

    string sBaseTag = GetTag(oDeadNPC); //Get that TAG of the dead creature

    string sPrefix = GetStringLeft(sBaseTag, 4); //Look for Dead Prefix

    int nKillMe;

    if (sPrefix == "Dead") //Do Spawned Cropse

    {

        nKillMe = 1; //Set nKillMe to 1 if you need this creature to 'spawn dead'

    }

    else //Do Default On Death Functions from Bioware Script: nw_c2_default7

    {

        int nClass = GetLevelByClass(CLASS_TYPE_COMMONER);

        int nAlign = GetAlignmentGoodEvil(OBJECT_SELF);

        if(nClass > 0 && (nAlign == ALIGNMENT_GOOD || nAlign == ALIGNMENT_NEUTRAL))

        {

            object oKiller = GetLastKiller();

            AdjustAlignment(oKiller, ALIGNMENT_EVIL, 5);

        }

        SpeakString("NW_I_AM_DEAD", TALKVOLUME_SILENT_TALK);

        //Shout Attack my target, only works with the On Spawn In setup

        SpeakString("NW_ATTACK_MY_TARGET", TALKVOLUME_SILENT_TALK);

        if(GetSpawnInCondition(NW_FLAG_DEATH_EVENT))

        {

            SignalEvent(OBJECT_SELF, EventUserDefined(1007));

        }

    }



    location lCorpseLoc = GetLocation(oDeadNPC); //Set the spawnpoint for our lootable object

    //Do 'spawned corpse' if desired

    if(nKillMe)

    {

        //Set up and Deliver our Death Blow

        /*  this is only needed if you need this

            creature to SPAWN as a corpse.  */

        effect eDamage = EffectDamage(1000); //Set up for the kill

        ApplyEffectToObject (DURATION_TYPE_INSTANT, eDamage, oDeadNPC); //Deliver the killing effect

        if (nOverrideForPlacedCorpses)

        {

            nKeepEmpties = TRUE; //Set 'Spawned Dead' corpses to Keep Empties

            nCorpseFade = 0; //Disable Corpse Fade for 'Spawned Dead' corpses

        }

    }

    SetIsDestroyable(FALSE,FALSE,FALSE); //Protect our corpse from decaying

    object oCorpseBlood;

    if (nUseBlood)

    {

        oCorpseBlood = CreateObject(OBJECT_TYPE_PLACEABLE, "plc_bloodstain", lCorpseLoc, FALSE); //Spawn some blood for effect (if nUseBlood == TRUE)

    }

    object oLootCorpse = CreateObject(OBJECT_TYPE_PLACEABLE, "invis_corpse_obj", lCorpseLoc, FALSE); //Spawn our lootable object

    SetLocalObject(oLootCorpse, "oHostBody", oDeadNPC); //Set Local for deletion later if needed

    SetLocalObject(oLootCorpse, "oBloodSpot", oCorpseBlood); //Set Local for deletion later if needed

    SetLocalInt(oLootCorpse, "oKeepEmpty", nKeepEmpties); //Set Local for deletion later if needed

    //Get DEAD CREATURE'S INVENTORY

    int nAmtGold = GetGold(oDeadNPC); //Get any gold from the dead creature

    if(nAmtGold)

    {

        object oGold = CreateItemOnObject("nw_it_gold001", oLootCorpse, nAmtGold);

        AssignCommand(oLootCorpse,TakeGoldFromCreature(nAmtGold,oDeadNPC,TRUE));

    }

    //Get any loot the dead creature has equipped - thanks again to the HCR for strip-equiped

    strip_equiped(oDeadNPC, oLootCorpse, GetItemInSlot(INVENTORY_SLOT_ARMS, oDeadNPC));

    strip_equiped(oDeadNPC, oLootCorpse, GetItemInSlot(INVENTORY_SLOT_ARROWS, oDeadNPC));

    strip_equiped(oDeadNPC, oLootCorpse, GetItemInSlot(INVENTORY_SLOT_BELT, oDeadNPC));

    strip_equiped(oDeadNPC, oLootCorpse, GetItemInSlot(INVENTORY_SLOT_BOLTS, oDeadNPC));

    strip_equiped(oDeadNPC, oLootCorpse, GetItemInSlot(INVENTORY_SLOT_BOOTS, oDeadNPC));

    strip_equiped(oDeadNPC, oLootCorpse, GetItemInSlot(INVENTORY_SLOT_BULLETS, oDeadNPC));

    strip_equiped(oDeadNPC, oLootCorpse, GetItemInSlot(INVENTORY_SLOT_CHEST, oDeadNPC));

    strip_equiped(oDeadNPC, oLootCorpse, GetItemInSlot(INVENTORY_SLOT_CLOAK, oDeadNPC));

    strip_equiped(oDeadNPC, oLootCorpse, GetItemInSlot(INVENTORY_SLOT_HEAD, oDeadNPC));

    strip_equiped(oDeadNPC, oLootCorpse, GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oDeadNPC));

    strip_equiped(oDeadNPC, oLootCorpse, GetItemInSlot(INVENTORY_SLOT_LEFTRING, oDeadNPC));

    strip_equiped(oDeadNPC, oLootCorpse, GetItemInSlot(INVENTORY_SLOT_NECK, oDeadNPC));

    strip_equiped(oDeadNPC, oLootCorpse, GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oDeadNPC));

    strip_equiped(oDeadNPC, oLootCorpse, GetItemInSlot(INVENTORY_SLOT_RIGHTRING, oDeadNPC));

    //Get the remaining loot from the dead creature and move it to the lootable object

    object oLootEQ = GetFirstItemInInventory(oDeadNPC);

    while(GetIsObjectValid(oLootEQ))

    {

        AssignCommand(oLootCorpse, ActionTakeItem(oLootEQ, oDeadNPC));

        oLootEQ = GetNextItemInInventory(oDeadNPC);

    }

    //Do Corpse Fade out after specified delay (unless flagged 0)

    if (nCorpseFade > 0)

    {

        float fCorpseFade = IntToFloat(nCorpseFade);

        ActionWait(fCorpseFade);

        DelayCommand(fCorpseFade, DestroyObject(oLootCorpse));

        DelayCommand(fCorpseFade + 1.0f, SetIsDestroyable(TRUE,FALSE,FALSE));

        DelayCommand(fCorpseFade + 1.5f, DestroyObject(oDeadNPC));

    }

}