Skip to content

Help with a simple script

MorganZMorganZ Member Posts: 17
Hello, i'm totally new to scripting and i'm basically starting by reading someone else scripts and trying to change em and merge them to see what happens (usually bad things!)

//
// CONSTANTS
//

const string HC_RES_SKINNING_MEAT = "it_mmidmisc006";
const string HC_RES_SKINNING_MEAT2 = "it_mmidmisc007";


//
// FUNCTIONS
//

void HC_ActionButcherAnimal()
{
object oPC = OBJECT_SELF;

FloatingTextStringOnCreature("*" + GetName(oPC) + SKINNING, oPC);
CreateObject(OBJECT_TYPE_ITEM, HC_RES_SKINNING_MEAT, GetLocation(oPC));

}

This is a script which fires when a PC use an item (skinning knife) on an animal corpse. HC_RES_SKINNING_MEAT = "it_mmidmisc006" is the item he obtain from that action. I would like the PC to obtain additional items based on the creature name (or tag, or resref). Something like IF the creature is X then drop also Y. The bold part hes been added by me..

hope you can help me!

Comments

  • ForSeriousForSerious Member Posts: 466
    Yeah you can add some if statements. You would add something like this to your script:
    void HC_ActionButcherAnimal()
    {
    	object oPC = OBJECT_SELF;
    	// Define the animal object being targeted with the skinning knife.
    	object oTarget = GetSpellTargetObject();
    	FloatingTextStringOnCreature("*" + GetName(oPC) + SKINNING, oPC);
    	// Check what the tag of the animal is.
    	if(GetTag(oTarget) == "TagNameHere")
    	{
    		CreateObject(OBJECT_TYPE_ITEM, HC_RES_SKINNING_MEAT, GetLocation(oPC));
    		// You can also give item 2 here if that's more what you wanted.
    	}
    	if(GetTag(oTarget) == "TagName2Here")
    	{
    		CreateObject(OBJECT_TYPE_ITEM, HC_RES_SKINNING_MEAT2, GetLocation(oPC));
    	}
    }
    

    This should give you a start. Feel free to plaster me with questions.
  • MorganZMorganZ Member Posts: 17
    Thank you! i'm gonna try your adjustment, but i think (correct me if i'm wrong) that with such a script i would need to add every tag of every creature i want to drop something. While the previous version of the script where already dropping the item1 on every "animal" type creature. I just wanted to add some exceptions where on top of the item 1 you also get the item 2.


    void HC_ActionButcherAnimal()
    {
    object oPC = OBJECT_SELF;

    FloatingTextStringOnCreature("*" + GetName(oPC) + SKINNING, oPC);
    CreateObject(OBJECT_TYPE_ITEM, HC_RES_SKINNING_MEAT, GetLocation(oPC));

    if(GetTag(oTarget) == "TagNameHere")

    {
    CreateObject(OBJECT_TYPE_ITEM, HC_RES_SKINNING_MEAT2, GetLocation(oPC));

    }

    Would this little adjustment make it work as i imagine it should?
  • ForSeriousForSerious Member Posts: 466
    edited May 2021
    Yeah, that would do it.
    Another way to go about it would be use variables. This would be pretty easy if you're using all custom versions of animals that can be skinned.
    In the Advanced tab on the creatures properties, there is a button near the bottom where you can define them. Then in your script you can check for them using GetLocalInt() and the like.
    If not, then yes. You would have to make an exception for each animal that should drop something else too.
  • MorganZMorganZ Member Posts: 17
    Unfortunately it is not working. Must be related to the way the script i'm modifying is built. Basically when an animal is killed it leave a corpse to be skinned, but the corpse does not keep the old tag of the creature. I'm using all custom versions of animal, i'm having fun creating them with the toolset btw..thanks again for your help :)
  • ForSeriousForSerious Member Posts: 466
    edited May 2021
    Oh... right. That might complicate things. You can always turn on the "Flood lights." Add SendMessageToPC(oPC, GetTag(oTarget)); right after where you define oTarget. That will tell you just what the tag is. If it's something like BodyBag we'll need to come up with another approach, but I thought the 'Leaves Lootable Corpse' worked differently.

    Edit: I did a simple test and leaves lootable corpse does have the same tag as the creature.
    In your original post, 'SKINNING' is undefined. Would that be part of it?
  • MorganZMorganZ Member Posts: 17
    yes, i'm gonna post the entire script, at the beginning i tought my problem could be easly solved just modifying that first part but i guess it is not.
    OnActivate event script for skinning knife item.
    */
    //  ----------------------------------------------------------------------------
    /*
        26 July 2004 - Sunjammer
        - rewritten
    */
    //  ----------------------------------------------------------------------------
    #include "hc_inc_npccorpse"
    #include "hc_text_activate"
    
    
    //  ----------------------------------------------------------------------------
    //  CONSTANTS
    //  ----------------------------------------------------------------------------
    
    const string HC_RES_SKINNING_MEAT   = "it_mmidmisc006";
    
    //  ----------------------------------------------------------------------------
    //  FUNCTIONS
    //  ----------------------------------------------------------------------------
    
    void HC_ActionButcherAnimal()
    {
        object oPC = OBJECT_SELF;
    
    
        FloatingTextStringOnCreature("*" + GetName(oPC) + SKINNING, oPC);
        CreateObject(OBJECT_TYPE_ITEM, HC_RES_SKINNING_MEAT, GetLocation(oPC));
    
    
    }
    
    
    //  ----------------------------------------------------------------------------
    //  MAIN
    //  ----------------------------------------------------------------------------
    
    void main()
    {
        object oPC = OBJECT_SELF;
        object oCorpse = GetLocalObject(oPC, "OTHER");
        object oBody = GetLocalObject(oCorpse, HC_VAR_NPCCORPSE_BODY);
    
        DeleteLocalObject(oPC, "OTHER");
    
        // pre-emptive abort for invalid objects
        if(GetIsObjectValid(oCorpse) == FALSE
        || GetIsObjectValid(oBody) == FALSE)
        {
            return;
        }
    
        // the body must be an animal, must be dead and must be within 3m to be
        // successfully skinned.
    
        if(GetRacialType(oBody) != RACIAL_TYPE_ANIMAL)
        {
            SendMessageToPC(oPC, ANIMALONLY);
            return;
        }
    
        if(GetIsDead(oBody) == FALSE)
        {
            SendMessageToPC(oPC, NOTDEAD);
            return;
        }
    
        if(GetDistanceBetween(oPC, oBody) > 3.0)
        {
            SendMessageToPC(oPC, MOVECLOSER);
            return;
        }
    
        // skin the body: animate the PC, create the product and destroy the body
        AssignCommand(oPC, ActionMoveToLocation(GetLocation(oBody)));
        AssignCommand(oPC, DelayCommand(1.0, ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW, 1.0, 1.0)));
        AssignCommand(oPC, DelayCommand(2.0, HC_ActionButcherAnimal()));
        HC_NPCCorpse_CleanUp(oCorpse);
    }
    


    skinning is part of "hc_text_activate" and is just a text string that will float, inside hc_text_activate the author placed every text spoken by his script to help others with translation or if someone wants to change the phrase, smart i'd say! It contains lot of strings like this one: string SKINNING= " Skins Animal*";

    I think (from reading "hc_inc_npccorpse") that this script is not using the standard nwn cropses but is creating his own corspes thru "hc_inc_npccorpse". I've tryed to run the script with animal creatues with "leave lootable corpse" unchecked and those still generate a corpse!
  • ForSeriousForSerious Member Posts: 466
    It's looking more involved than I expected.
    Totally doable though. In this scrips I can see
    object oCorpse = GetLocalObject(oPC, "OTHER");
    object oBody = GetLocalObject(oCorpse, HC_VAR_NPCCORPSE_BODY);
    
    At this point, both those objects have been created and stored. All you have to do is find where SetLocalObject(<oPC>, HC_VAR_NPCCORPSE_BODY, <someObject>); is called. You can SetLocalInt on the line before it... it's still weird. Why is the object being stored on oPC at all? I think I would need a look at hc_inc_npccorpse to understand that.

    On my favorite server (Lala Land [Gone now]), they had a similar skinning system. Animals would leave lootable corpses. If you had a skinning knife equipped, it would play an animation and give you a pelt or whatever depending on what animal it was. After so many times, your skinning knife would get destroyed from being used up. This system you've got here seems like it's maybe trying to be like that, but I'm not seeing any advantages so far.
  • MorganZMorganZ Member Posts: 17
    edited May 2021
    Sure i can post it! it's a bit long and i didnt want to bother you too much.. i think this is because it's an old script set but is pretty cool to run things thath someone wrote 20 years ago.. i like that so much, is some kind of a tribute..
    //  ----------------------------------------------------------------------------
    //  CONSTANTS: CONFIGURATION
    //  ----------------------------------------------------------------------------
    
    // Sets an override for standard Bioware creatures (NW_*) to enable them to drop
    // items not flagged as droppable (such as weapons).  Creature items and no-drop
    // items will still not drop.
    const int HC_NPCCORPSE_DROP_IF_BIOWARE      = FALSE;
    
    // Sets limitations on the above override.
    //  *_BW_PLOT:   items will not drop if they are flagged as plot
    //  *_BW_STOLEN: items will not drop if they are flagged as stolen
    const int HC_NPCCORPSE_SKIP_IF_BW_PLOT     = FALSE;
    const int HC_NPCCORPSE_SKIP_IF_BW_STOLEN   = FALSE;
    
    // Modes available controlling how an NPC's "visible" items are handled.
    //  *_NONE: item remains on NPC even if droppable
    //  *_MOVE: item removed from NPC, appears in corpse
    //  *_COPY: item remains on NPC, a copy appears in corpse
    //  *_DROP: item removed from NPC, a copy appears on ground nearby (hands only)
    const int HC_NPCCORPSE_DROP_MODE_NONE   = 1;
    const int HC_NPCCORPSE_DROP_MODE_MOVE   = 2;
    const int HC_NPCCORPSE_DROP_MODE_COPY   = 3;
    const int HC_NPCCORPSE_DROP_MODE_DROP   = 4;
    
    // Sets the mode controlling how an NPC's "visible" items are handled. Use a
    // HC_NPCCORPSE_DROP_MODE_* constant from the list above for each *_MODE_*.
    const int HC_NPCCORPSE_DROP_MODE_FOR_CHEST  = HC_NPCCORPSE_DROP_MODE_COPY;
    const int HC_NPCCORPSE_DROP_MODE_FOR_HANDS  = HC_NPCCORPSE_DROP_MODE_COPY;
    const int HC_NPCCORPSE_DROP_MODE_FOR_HEAD   = HC_NPCCORPSE_DROP_MODE_COPY;
    
    // Modes available for the controling the clean up process.
    //  *_NEVER: clean up is never initiated
    //  *_EMPTY: clean up is initiated when corpse is emptied (checked OnClose)
    //  *_TIMED: clean up is intiated after HC_NPCCORPSE_CLEANUP_DELAY minutes
    //  *_COMBO: clean up is intiated after the earlier of EMPTY or TIMED
    const int HC_NPCCORPSE_CLEANUP_MODE_NEVER   = 1;
    const int HC_NPCCORPSE_CLEANUP_MODE_EMPTY   = 2;
    const int HC_NPCCORPSE_CLEANUP_MODE_TIMED   = 3;
    const int HC_NPCCORPSE_CLEANUP_MODE_COMBO   = 4;
    
    // Sets the mode and time (in minutes) controling the clean up process. Use a
    // HC_NPCCORPSE_CLEANUP_MODE_* constant from the list above for *_MODE.
    const int HC_NPCCORPSE_CLEANUP_MODE     = 3;
    const int HC_NPCCORPSE_CLEANUP_DELAY    = 5;
    
    // Controls if a blood pool should form under the NPC.
    const int HC_NPCCORPSE_USE_BLOOD            = TRUE;
    
    // Sets an override for animals to enable them to persist until skinned.  This
    // is mainly for use with EMPTY or COMBO modes for cleanup.  Cleanup is handled
    // in the appropriate OnActivateItem script.
    const int HC_NPCCORPSE_USE_SKINNING         = TRUE;
    
    
    //  ----------------------------------------------------------------------------
    //  CONSTANTS: SYSTEM
    //  ----------------------------------------------------------------------------
    
    // blueprints for the placeable elements
    const string HC_RES_NPCCORPSE_CORPSE        = "invis_corpse_obj";
    const string HC_RES_NPCCORPSE_BLOOD         = "plc_bloodstain";
    
    // tags for the placeable elements
    const string HC_TAG_NPCCORPSE_CORPSE        = "HC_NPCCorpse_Corpse";
    
    // name of variables to register elements with corpse
    const string HC_VAR_NPCCORPSE_BLOOD         = "HC_NPCCorpse_Blood";
    [b]const string HC_VAR_NPCCORPSE_BODY          = "HC_NPCCorpse_Body";[/b]
    
    // name of variables for various system flags
    //  *_CHECKED:  identifies checked items to prevents duplication on transfer
    //  *_CLEANUP:  creature override for clean up mode
    //  *_COPIED:   identifies coppied items for clean up on distrubed
    //  *_DROPPED:  identifies dropped items (e.g. weapons) for clean up
    //  *_PRESERVE: prevents deletion of coprse elements (on body, dual purpose)
    //  *_PREVENT:  prevents creation of corpse elements (on body)
    const string HC_VAR_NPCCORPSE_CHECKED       = HC_VAR_TRANSFER_CHECKED;
    const string HC_VAR_NPCCORPSE_CLEANUP       = "HC_NPCCorpse_CleanUp";
    const string HC_VAR_NPCCORPSE_COPIED        = "HC_NPCCorpse_Copied";
    const string HC_VAR_NPCCORPSE_DROPPED       = "HC_NPCCorpse_Dropped";
    const string HC_VAR_NPCCORPSE_PRESERVE      = "HC_NPCCorpse_Preserve";
    const string HC_VAR_NPCCORPSE_PREVENT       = "HC_NPCCorpse_Prevent";
    //const string HC_VAR_NPCCORPSE_PRESERVE      = "Dead";           // legacy
    //const string HC_VAR_NPCCORPSE_PREVENT       = "NORMALCORPSE";   // legacy
    
    
    //  ----------------------------------------------------------------------------
    //  PROTOTYPES
    //  ----------------------------------------------------------------------------
    
    // Creates the corpse components for the NPC, drops items as appropriate and
    // handles initial clean up/scheduling.
    //  - oBody:        a dead NPC/creature
    void HC_NPCCorpse_CreateCorpse(object oBody);
    
    // Destroys the corpse components.  Will not destroy the NPC if it has been
    // revived between corpse creation and clean up.
    //  - oCorpse:      a invisible corpse object
    void HC_NPCCorpse_CleanUp(object oCorpse);
    
    // Returns the clean up mode associated with the NPC.
    //  - oBody:        a dead NPC/creature
    int HC_NPCCoprse_GetCleanUpMode(object oBody);
    
    // Returns the drop mode for the "visible" item in nSlot.
    //  - nSlot:        one of the visible INVENTORY_SLOT_* constants
    int HC_NPCCorpse_GetDropMode(int nSlot);
    
    // Returns TRUE if oCreature can bleed.
    int HC_NPCCorpse_GetIsBleeder(object oCreature);
    
    // Returns TRUE if oItem is "droppable" according to system settings.
    int HC_NPCCorpse_GetIsDroppable(object oItem);
    
    // Returns TRUE if oCorpse is empty AND there are no associated dropped items
    // remaining on the ground.
    //  - oCorpse:      an invisible corpse object
    int HC_NPCCorpse_GetIsEmpty(object oCorpse);
    
    // Returns TRUE if any of the *_DROP_MODE_FOR_* settings are *_DROP_MODE_COPY.
    int HC_NPCCorpse_GetIsUsingCopyMode();
    
    // Generates a location beneath the NPC's body.
    //  - oBody:        a dead NPC/creature
    location HC_NPCCorpse_GetLocationForCorpse(object oBody);
    
    // Generates a location appropriate for an item that has dropped to the ground
    // from an NPC's hand.
    //  - oBody:        a dead NPC/creature
    //  - nSlot:        one of the INVENTORY_SLOT_*HAND constants
    location HC_NPCCorpse_GetLocationForDropped(object oBody, int nSlot);
    
    // Destroys any associated dropped items remaining on the ground.
    //  - oCorpse:      an invisible corpse object
    //  - nSlot:        one of the visible INVENTORY_SLOT_* constants
    void HC_NPCCorpse_DestroyDropped(object oCorpse, int nSlot);
    
    // Destroys all items that remain equiped on oBody.
    void HC_NPCCorpse_DestroyEquipment(object oBody);
    
    // Destroys all items in oContainers inventory.
    void HC_NPCCorpse_DestroyInventory(object oContainer);
    
    // Transfers all "droppable" equipped items oBody to oCorpse except "visible"
    // items, namely those in the *_CHEST, *_HEAD, *_LEFTHAND and *_RIGHTHAND
    // inventory slots.
    //  - oBody:        a dead NPC/creature
    //  - oCorpse:      an invisible corpse object
    void HC_NPCCorpse_DropEquipment(object oBody, object oCorpse);
    
    // Transfers all "droppable" inventory items from oBody to oCorpse.
    //  - oBody:        a dead NPC/creature
    //  - oCorpse:      an invisible corpse object
    void HC_NPCCorpse_DropInventory(object oBody, object oCorpse);
    
    // Transfers or drops all "visible", "droppable" equipted items form oBody to
    // oCorpse.  In other words those items in the *_CHEST, *_HEAD, *_LEFTHAND and
    // *_RIGHTHAND inventory slots.
    //  - oBody:        a dead NPC/creature
    //  - oCorpse:      an invisible corpse object
    //  - nSlot:        one of the visible INVENTORY_SLOT_* constants
    void HC_NPCCorpse_DropVisible(object oBody, object oCorpse, int nSlot);
    
    
    //  ----------------------------------------------------------------------------
    //  FUNCTIONS
    //  ----------------------------------------------------------------------------
    
    void HC_NPCCorpse_CreateCorpse(object oBody)
    {
        // pre-emptive abort: the body has a normal corpse override flag or or has
        // an ATS, a CNR or a legacy no-corpse tag
        string sTag = GetTag(oBody);
        if(GetLocalInt(oBody, HC_VAR_NPCCORPSE_PREVENT)
        || HC_GetIsInString(sTag, "NC_")
        || HC_GetIsInString(sTag, "ATS_")
        || HC_GetIsInString(sTag, "cnra"))
        {
            return;
        }
    
        // -------------------------------------------------------------------------
        // Part 1: Create the Components
        // -------------------------------------------------------------------------
    
        // prevent the body from decaying
        AssignCommand(oBody, SetIsDestroyable(FALSE));
    
        // create the lootable container
        location lCorpse = HC_NPCCorpse_GetLocationForCorpse(oBody);
        object oCorpse = CreateObject(OBJECT_TYPE_PLACEABLE, HC_RES_NPCCORPSE_CORPSE, lCorpse, FALSE, HC_TAG_NPCCORPSE_CORPSE);
    
        // register the body with the corpse
      [b]  SetLocalObject(oCorpse, HC_VAR_NPCCORPSE_BODY, oBody);[/b]
    
        // create a blood stain for effect if required/appropriate
        if(HC_NPCCORPSE_USE_BLOOD && HC_NPCCorpse_GetIsBleeder(oBody))
        {
            // create the blood and register it with the corpse
            object oBlood = CreateObject(OBJECT_TYPE_PLACEABLE, HC_RES_NPCCORPSE_BLOOD, GetLocation(oBody));
            SetLocalObject(oCorpse, HC_VAR_NPCCORPSE_BLOOD, oBlood);
        }
    
        // -------------------------------------------------------------------------
        // Part 2: Drop or Transfer Items
        // -------------------------------------------------------------------------
    
        // drop the gold
        HC_Transfer_MoveGold(oBody, oCorpse);
    
        // drop visible items, i.e. those affecting appearance on dynamic models
        HC_NPCCorpse_DropVisible(oBody, oCorpse, INVENTORY_SLOT_HEAD);
        HC_NPCCorpse_DropVisible(oBody, oCorpse, INVENTORY_SLOT_CHEST);
        HC_NPCCorpse_DropVisible(oBody, oCorpse, INVENTORY_SLOT_LEFTHAND);
        HC_NPCCorpse_DropVisible(oBody, oCorpse, INVENTORY_SLOT_RIGHTHAND);
    
        // drop residual equipment
        HC_NPCCorpse_DropEquipment(oBody, oCorpse);
    
        // drop all other items
        HC_NPCCorpse_DropInventory(oBody, oCorpse);
    
        // -------------------------------------------------------------------------
        // Part 3: Arrange Clean Up
        // -------------------------------------------------------------------------
    
        int nMode = HC_NPCCoprse_GetCleanUpMode(oBody);
    
        // NOTE: given the duality of applciation all three of these must be checked
    
        if(nMode == HC_NPCCORPSE_CLEANUP_MODE_COMBO
        || nMode == HC_NPCCORPSE_CLEANUP_MODE_EMPTY)
        {
            // clean up if empty, otherwise clean up via OnClose
            if(HC_NPCCorpse_GetIsEmpty(oCorpse))
            {
                HC_NPCCorpse_CleanUp(oCorpse);
            }
        }
    
        if(nMode == HC_NPCCORPSE_CLEANUP_MODE_COMBO
        || nMode == HC_NPCCORPSE_CLEANUP_MODE_TIMED)
        {
            // schedule clean up after delay (converted to seconds)
            float fDelay = IntToFloat(HC_NPCCORPSE_CLEANUP_DELAY * 60);
            DelayCommand(fDelay, HC_NPCCorpse_CleanUp(oCorpse));
        }
    
        if(nMode == HC_NPCCORPSE_CLEANUP_MODE_NEVER
        || nMode == HC_NPCCORPSE_CLEANUP_MODE_TIMED)
        {
            // prevent premature clean up via OnClose
            SetLocalInt(oBody, HC_VAR_NPCCORPSE_PRESERVE, TRUE);
        }
    }
    
    
    void HC_NPCCorpse_CleanUp(object oCorpse)
    {
        // get the elements registered with the corpse
        object oBody = GetLocalObject(oCorpse, HC_VAR_NPCCORPSE_BODY);
        object oBlood = GetLocalObject(oCorpse, HC_VAR_NPCCORPSE_BLOOD);
    
        // clean up blood
        DestroyObject(oBlood);
    
        // destroy items to prevent "remains", clean up corpse
        HC_NPCCorpse_DestroyInventory(oCorpse);
        DestroyObject(oCorpse);
    
        // destroy items dropped and not yet picked up (hands only)
        if(HC_NPCCORPSE_DROP_MODE_FOR_HANDS == HC_NPCCORPSE_DROP_MODE_DROP)
        {
            HC_NPCCorpse_DestroyDropped(oCorpse, INVENTORY_SLOT_LEFTHAND);
            HC_NPCCorpse_DestroyDropped(oCorpse, INVENTORY_SLOT_RIGHTHAND);
        }
    
        // ONLY clean up Body and retained weapons IF STILL DEAD
        if(GetIsDead(oBody))
        {
            // destroy items to prevent "remains"
            HC_NPCCorpse_DestroyEquipment(oBody);
            HC_NPCCorpse_DestroyInventory(oBody);
    
            // clean up body: no need to use DestroyObject as SetIsDestroyable will
            // cause it to fade after a short delay
            AssignCommand(oBody, SetIsDestroyable(TRUE));
        }
    }
    
    
    int HC_NPCCoprse_GetCleanUpMode(object oBody)
    {
        // assume default mode will apply
        int nRet = HC_NPCCORPSE_CLEANUP_MODE;
    
        //[b] override if it is an animal and using skinning so it can be skinned[/b]
        if(HC_NPCCORPSE_USE_SKINNING
        && GetRacialType(oBody) == RACIAL_TYPE_ANIMAL)
        {
            nRet = HC_NPCCORPSE_CLEANUP_MODE_NEVER;
        }
    
        // override if body is flagged or tagged to leave a permanent corpse
        if(GetLocalInt(oBody, HC_VAR_NPCCORPSE_PRESERVE)
        || HC_GetIsInString(GetTag(oBody), HC_VAR_NPCCORPSE_PRESERVE))
        {
            nRet = HC_NPCCORPSE_CLEANUP_MODE_NEVER;
        }
    
        // check body for creature override
        int nOverride = GetLocalInt(oBody, HC_VAR_NPCCORPSE_CLEANUP);
        if(nOverride) return nOverride;
    
        // return mode
        return nRet;
    }
    
    
    int HC_NPCCorpse_GetDropMode(int nSlot)
    {
        int nRet;
    
        // parse the inventory slot for the corresponding mode
        switch(nSlot)
        {
            case INVENTORY_SLOT_CHEST:
                nRet = HC_NPCCORPSE_DROP_MODE_FOR_CHEST;
                break;
    
            case INVENTORY_SLOT_HEAD:
                nRet = HC_NPCCORPSE_DROP_MODE_FOR_HEAD;
                break;
    
            case INVENTORY_SLOT_LEFTHAND:
            case INVENTORY_SLOT_RIGHTHAND:
                nRet = HC_NPCCORPSE_DROP_MODE_FOR_HANDS;
                break;
        }
    
        // return mode
        return nRet;
    }
    
    
    int HC_NPCCorpse_GetIsBleeder(object oCreature)
    {
        int nRace = GetRacialType(oCreature);
    
        // constructs, elementals, oozes and the undead don't bleed
        if(nRace == RACIAL_TYPE_CONSTRUCT
        || nRace == RACIAL_TYPE_ELEMENTAL
        || nRace == RACIAL_TYPE_OOZE
        || nRace == RACIAL_TYPE_UNDEAD)
        {
            // creature doesn't bleed
            return FALSE;
        }
    
        // creature bleeds
        return TRUE;
    }
    
    
    int HC_NPCCorpse_GetIsDroppable(object oItem)
    {
        string sTag;
    
        if(GetDroppableFlag(oItem) == FALSE)
        {
            // if not droppable check override ...
            if(HC_NPCCORPSE_DROP_IF_BIOWARE)
            {
                // ... and check it is a Bioware creature
                sTag = GetTag(GetItemPossessor(oItem));
                if(HC_GetIsInString(sTag, "nw_")
                || HC_GetIsInString(sTag, "x0_")
                || HC_GetIsInString(sTag, "x2_"))
                {
                    // skipping plot items?
                    if(HC_NPCCORPSE_SKIP_IF_BW_PLOT && GetPlotFlag(oItem))
                    {
                        return FALSE;
                    }
    
                    // skipping stolen items?
                    if(HC_NPCCORPSE_SKIP_IF_BW_STOLEN && GetStolenFlag(oItem))
                    {
                        return FALSE;
                    }
    
                    // always skip creature/henchmen weapons
                    // NOTE: not relevant to custom creature as creator has ability
                    // to choose if such items are droppable
                    sTag = GetTag(oItem);
                    if(HC_GetIsInString(sTag, "_it_cre")
                    || HC_GetIsInString(sTag, "_hen_")
                    || HC_GetIsInString(sTag, "_wdrow")
                    || HC_GetIsInString(sTag, "_wduer")
                    || HC_GetIsInString(sTag, "_it_rakstaff")
                    || HC_GetIsInString(sTag, "_manti_spikes")
                    || HC_GetIsInString(sTag, "_it_frzdrowbld"))
                    {
                        return FALSE;
                    }
                }
            }
            else
            {
                // not droppable and override doesn't apply
                return FALSE;
            }
        }
    
        // always skip no-drop items
        if(HC_GetIsItemNoDrop(oItem))
        {
            return FALSE;
        }
    
        // passed all checks
        return TRUE;
    }
    
    
    int HC_NPCCorpse_GetIsEmpty(object oCorpse)
    {
        // any items in corpse?
        if(GetIsObjectValid(GetFirstItemInInventory(oCorpse)))
        {
            return FALSE;
        }
    
        // if using DROP mode, any items on ground?
        int nMode = HC_NPCCorpse_GetDropMode(INVENTORY_SLOT_LEFTHAND);
    
        if(nMode == HC_NPCCORPSE_DROP_MODE_DROP)
        {
            string sItem;
            object oItem, oOwner;
    
             // if object from LEFT hand is valid it must have a possessor
            sItem = HC_VAR_NPCCORPSE_DROPPED + IntToString(INVENTORY_SLOT_LEFTHAND);
            oItem = GetLocalObject(oCorpse, sItem);
    
            if(GetIsObjectValid(oItem))
            {
                if(GetIsObjectValid(GetItemPossessor(oItem)) == FALSE)
                {
                    return FALSE;
                }
            }
    
            // if object from RIGHT hand is valid it must have a possessor
            sItem = HC_VAR_NPCCORPSE_DROPPED + IntToString(INVENTORY_SLOT_RIGHTHAND);
            oItem = GetLocalObject(oCorpse, sItem);
    
            if(GetIsObjectValid(oItem))
            {
                if(GetIsObjectValid(GetItemPossessor(oItem)) == FALSE)
                {
                    return FALSE;
                }
            }
        }
    
        // no items found
        return TRUE;
    }
    
    
    int HC_NPCCorpse_GetIsUsingCopyMode()
    {
        // check all modes and return TRUE if any are *_COPY
        if(HC_NPCCORPSE_DROP_MODE_FOR_CHEST == HC_NPCCORPSE_DROP_MODE_COPY
        || HC_NPCCORPSE_DROP_MODE_FOR_HANDS == HC_NPCCORPSE_DROP_MODE_COPY
        || HC_NPCCORPSE_DROP_MODE_FOR_HEAD == HC_NPCCORPSE_DROP_MODE_COPY)
        {
            return TRUE;
        }
        return FALSE;
    }
    
    
    location HC_NPCCorpse_GetLocationForCorpse(object oBody)
    {
        vector vBody = GetPosition(oBody);
    
        // get co-ordingates of a point just below vBody
        float fZ = vBody.z - 0.1;
    
        // return the location
        return Location(GetArea(oBody), Vector(vBody.x, vBody.y, fZ), 0.0);
    }
    
    
    location HC_NPCCorpse_GetLocationForDropped(object oBody, int nSlot)
    {
        vector vBody = GetPosition(oBody);
    
        // get the offsets appropriate to the hand the item is falling from
        float fFacing = (nSlot == INVENTORY_SLOT_LEFTHAND) ? 45.0f : -45.0f;
        float fWeapon = (nSlot == INVENTORY_SLOT_LEFTHAND) ? -20.0f : 20.0f;
    
        // add a random element to facings and direction, values are arbitray
        fFacing += GetFacing(oBody) + IntToFloat(d20());
        fWeapon += GetFacing(oBody) - IntToFloat(d20(2));
        float fDistance = 0.5f + (IntToFloat(d10())/10);
    
        // get co-ordinates of a point fDistance meters away at fFacing degrees
        float fX = vBody.x + cos(fFacing) * fDistance;
        float fY = vBody.y + sin(fFacing) * fDistance;
    
        // return the location
        return Location(GetArea(oBody), Vector(fX, fY, vBody.z), fWeapon);
    }
    
    
    void HC_NPCCorpse_DropEquipment(object oBody, object oCorpse)
    {
        location lCorpse = GetLocation(oCorpse);
    
        int n;
        for(n = 0; n < HC_NUM_PC_INVENTORY_SLOTS; n++)
        {
            object oItem = GetItemInSlot(n, oBody);
    
            // if valid and droppable and as yet unchecked
            if(GetIsObjectValid(oItem)
            && HC_NPCCorpse_GetIsDroppable(oItem)
            && GetLocalInt(oItem, HC_VAR_NPCCORPSE_CHECKED) == FALSE)
            {
                // copy item to corpse, destroy original
                CopyObject(oItem, lCorpse, oCorpse);
                DestroyObject(oItem);
            }
        }
    }
    
    
    void HC_NPCCorpse_DropVisible(object oBody, object oCorpse, int nSlot)
    {
        object oCopy;
        object oItem = GetItemInSlot(nSlot, oBody);
    
        // pre-emptive aborts: object is not valid or is not droppable
        if(GetIsObjectValid(oItem) == FALSE
        || HC_NPCCorpse_GetIsDroppable(oItem) == FALSE)
        {
            return;
        }
    
        // flag as checked to avoid duplication
        SetLocalInt(oItem, HC_VAR_NPCCORPSE_CHECKED, TRUE);
    
        // parse drop mode
        int nMode = HC_NPCCorpse_GetDropMode(nSlot);
        if(nMode == HC_NPCCORPSE_DROP_MODE_MOVE)
        {
            // copy item to corpse, destroy original
            oCopy = CopyObject(oItem, GetLocation(oCorpse), oCorpse);
            DestroyObject(oItem);
        }
        else if(nMode == HC_NPCCORPSE_DROP_MODE_COPY)
        {
            // copy item to corpse, register as copy, keep original
            oCopy = CopyObject(oItem, GetLocation(oCorpse), oCorpse);
            SetLocalInt(oCopy, HC_VAR_NPCCORPSE_COPIED, nSlot);
        }
        else if(nMode == HC_NPCCORPSE_DROP_MODE_DROP)
        {
            // copy item to ground, register with corpse, destroy original
            oCopy = CopyObject(oItem, HC_NPCCorpse_GetLocationForDropped(oBody, nSlot));
            SetLocalObject(oCorpse, HC_VAR_NPCCORPSE_DROPPED + IntToString(nSlot), oCopy);
            DestroyObject(oItem);
        }
    }
    
    
    void HC_NPCCorpse_DropInventory(object oBody, object oCorpse)
    {
        location lCorpse = GetLocation(oCorpse);
    
        // check each item
        object oItem = GetFirstItemInInventory(oBody);
        while(GetIsObjectValid(oItem))
        {
            // if droppable and as yet unchecked ...
            if(HC_NPCCorpse_GetIsDroppable(oItem)
            && GetLocalInt(oItem, HC_VAR_NPCCORPSE_CHECKED) == FALSE)
            {
                // copy item to corpse, destroy original
                CopyObject(oItem, lCorpse, oCorpse);
                DestroyObject(oItem);
            }
    
            oItem = GetNextItemInInventory(oBody);
        }
    }
    
    
    void HC_NPCCorpse_DestroyDropped(object oCorpse, int nSlot)
    {
        // get item and owner (local object released when corpse destroyed)
        object oItem = GetLocalObject(oCorpse, HC_VAR_NPCCORPSE_DROPPED + IntToString(nSlot));
        object oOwner = GetItemPossessor(oItem);
    
        // if valid or held by someone valid
        if(GetIsObjectValid(oOwner) == FALSE)
        {
            DestroyObject(oItem);
        }
    }
    
    
    void HC_NPCCorpse_DestroyEquipment(object oBody)
    {
        int n;
        for(n = 0; n < HC_NUM_PC_INVENTORY_SLOTS; n++)
        {
            // destroy any items left on the body
            object oItem = GetItemInSlot(n, oBody);
            if(GetIsObjectValid(oItem))
            {
                DestroyObject(oItem);
            }
        }
    }
    
    
    void HC_NPCCorpse_DestroyInventory(object oContainer)
    {
        // destroy each item in turn
        object oItem = GetFirstItemInInventory(oContainer);
        while(GetIsObjectValid(oItem))
        {
            DestroyObject(oItem);
            oItem = GetNextItemInInventory(oContainer);
        }
    }
    
    //void main(){}
    

    I've bolded the part where it sets corpse obody and another one about skinning (i guess that second one is just about decaying time of the corpse but i'm not that sure). I think this sistem works pretty similar to the one you described! I'm not sure what should i do when i set local int before SetLocalObject(<oPC>, HC_VAR_NPCCORPSE_BODY. I mean after that how do I change or modify the item dropped by the action "skinning"?
  • ForSeriousForSerious Member Posts: 466
    It's still a little confusing. It looks to me like it creates an invisible placeable at the location of the body, so maybe that's what you are able to target with the other script—and that's why the tag doesn't match the creature.

    So really I think the change is in the first script you shared, but seeing that big one helped me decide what's going on. (I still wonder where it calls SetLocalObject(oPc, "Other", corpse))

    Anyway, here's the script modified to take a string. You can use that as a start.
    /*
    OnActivate event script for skinning knife item.
    */
    //  ----------------------------------------------------------------------------
    /*
        26 July 2004 - Sunjammer
        - rewritten
    */
    //  ----------------------------------------------------------------------------
    #include "hc_inc_npccorpse"
    #include "hc_text_activate"
    
    
    //  ----------------------------------------------------------------------------
    //  CONSTANTS
    //  ----------------------------------------------------------------------------
    
    const string HC_RES_SKINNING_MEAT   = "it_mmidmisc006";
    const string HC_RES_SKINNING_MEAT2   = "it_mmidmisc007";
    
    //  ----------------------------------------------------------------------------
    //  FUNCTIONS
    //  ----------------------------------------------------------------------------
    
    void HC_ActionButcherAnimal(string sTag)
    {
        object oPC = OBJECT_SELF;
        FloatingTextStringOnCreature("*" + GetName(oPC) + SKINNING, oPC);
        CreateObject(OBJECT_TYPE_ITEM, HC_RES_SKINNING_MEAT, GetLocation(oPC));
        // Here's your bit you added.
        if(sTag == "TagNameHere")
        {
            CreateObject(OBJECT_TYPE_ITEM, HC_RES_SKINNING_MEAT2, GetLocation(oPC));
        }
    }
    
    
    //  ----------------------------------------------------------------------------
    //  MAIN
    //  ----------------------------------------------------------------------------
    
    void main()
    {
        object oPC = OBJECT_SELF;
        object oCorpse = GetLocalObject(oPC, "OTHER");
        object oBody = GetLocalObject(oCorpse, HC_VAR_NPCCORPSE_BODY);
    
        DeleteLocalObject(oPC, "OTHER");
    
        // pre-emptive abort for invalid objects
        if(GetIsObjectValid(oCorpse) == FALSE
        || GetIsObjectValid(oBody) == FALSE)
        {
            return;
        }
    
        // the body must be an animal, must be dead and must be within 3m to be
        // successfully skinned.
    
        if(GetRacialType(oBody) != RACIAL_TYPE_ANIMAL)
        {
            SendMessageToPC(oPC, ANIMALONLY);
            return;
        }
    
        if(GetIsDead(oBody) == FALSE)
        {
            SendMessageToPC(oPC, NOTDEAD);
            return;
        }
    
        if(GetDistanceBetween(oPC, oBody) > 3.0)
        {
            SendMessageToPC(oPC, MOVECLOSER);
            return;
        }
    
        // skin the body: animate the PC, create the product and destroy the body
        AssignCommand(oPC, ActionMoveToLocation(GetLocation(oBody)));
        AssignCommand(oPC, DelayCommand(1.0, ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW, 1.0, 1.0)));
        // If you wanted to go the variable route, you could pass in GetLocalString/int(oBody) instead.
        // Pass in the tag
        AssignCommand(oPC, DelayCommand(2.0, HC_ActionButcherAnimal(GetTag(oBody))));
        HC_NPCCorpse_CleanUp(oCorpse);
    }
    

  • MorganZMorganZ Member Posts: 17
    I'm trying your script now and it works nicely!! thank you! i'm gonna expand it with some exceptions as i planned! Thanks again.. that variable things is still too much for me i guess but i'm reading some articles about INT var to acquire a better knowledge!
Sign In or Register to comment.