NPC not equipping gear with ActionEquipItem

In NWN:EE, I have a script intended to spawn an NPC, spawn some items in its inventory, and force it to equip the items. The last part is giving me a headache. I suspect it’s something dumb, but I am not sure what. I have a wrapper for this because I thought maybe the NPC wasn’t commandable due to various things that happen right after a spawn. But, it doesn’t help.

Below is the part that checks whether the NPC is commandable and tries to add ActionEquipItem to the NPC’s queue.

void EquipItemWhenCommandable(object oCreature, object oItem, int nSlot, float fdelay = 2.0f)
    {
    if ( GetIsDead(oCreature) )         // oCreature is beyond caring about gear
        return;
    if ( GetCommandable(oCreature) )    // queue isn't locked
        AssignCommand(oCreature, ActionEquipItem(oItem, nSlot));
    else                                // queue is locked, wait and try again
        DelayCommand(fdelay, EquipItemWhenCommandable(oCreature, oItem, nSlot, fdelay));
    }

Note that the above is called from the script that spawns oCreature and oItem and it is called with a delay. E.g.
DelayCommand(2.0f, EquipItemWhenCommandable(oCreature, oItem, nSlot));

BTW, I have run this with some debugging PrintStrings and I can say that

  • oCreature's action queue is not locked.
  • If I use the in-game script console, running AssignCommand(oCreature, ActionEquipItem(oItem, nSlot)); does not work (after assigning the variables properly) on the NPC just as he is. But, if I go into DM mode and possess the NPC and run the same script command, it works fine.

Anyway, I’d love to know why this isn’t doing what I thought it would.

if the item has class/alignment/race restriction, NPC must meet those or have high ranks of UMD

The item has no restrictions (standard Helm of Brilliance) and it was identified. No ILR enabled.

Try assigning ClearAllActions() before ActionEquipItem().

I was worried that ClearAllActions() could mess up OnSpawn scripts, patrol / walkpath scripting, or other things that might have been on the NPC’s queue. Is that not an issue?

Is there some way to suspend whatever the NPC currently has in its queue and push my equip action to the top and then resume queue processing?

From the downloadable version of the NwN Lexicon 1.69 -

ClearAllActions(int)

Clears currently queued actions from the calling object.

void ClearAllActions(int nClearCombatState = FALSE);

Parameters

nClearCombatState

Stop all current actions, combat optional. (Default: FALSE)

Description

Clears all current and queued actions from the calling object. Note that unless TRUE is passed for nClearCombatState, any current fighting involving the caller of ClearAllActions will continue.

Remarks

Commonly used to stop and immediately redirect the current actions of a PC or NPC.

Only existing Action functions will be cleared by this call.* This includes ActionDoCommand(). It also doesn’t clear any DelayCommand() functions or actions.

Anything that can have actions assigned to it (even just ActionDoCommand()) can have those actions cleared.

Functions are instant - and are not actions.

Version

1.64 onwards

Example

// Example of a PC triggered earthquake for use in the OnEnter event of a generic trigger.
void main()
{
    object oPC = GetEnteringObject();
    object oTrigger = OBJECT_SELF;
    object oArea = GetArea(oTrigger);

    // Stop here if the triggering object is not a PC.
    if(!GetIsPC(oPC))
    {   return;   }

    // Triggering object was a PC, cycle through all objects in area and apply the earthquake effect if appropriate.
    object oTarget = GetFirstObjectInArea(oArea);
    while(GetIsObjectValid(oTarget))
    {
        // We are looking for creatures. Don't apply the effect to doors, placeables, items, etc.
        if(GetObjectType(oTarget) == OBJECT_TYPE_CREATURE)
        {
            // Stop anything the target creature may be doing (TRUE = including combat).
            AssignCommand(oTarget, ClearAllActions(TRUE));

            // Apply the earthquake effects to the target creature.
            ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_SCREEN_SHAKE), oTarget);
            AssignCommand(oTarget, ActionPlayAnimation(ANIMATION_LOOPING_DEAD_BACK, 1.0, 3.0));
        }
        // Get next possible target in area
        oTarget = GetNextObjectInArea(oArea);
    }
}

TR

The script is unnecessarily complicated. For example,

  object oNPC  = CreateObject(OBJECT_TYPE_CREATURE, "king_henry", GetLocation(oPC));
  object oItem = CreateItemOnObject("crowbar", oNPC);
  AssignCommand(oNPC, ActionEquipItem(oItem, INVENTORY_SLOT_RIGHTHAND));

works every time.

Presumably you’ve checked that the items are created in the creature’s inventory?

If so, failure to equip could be

  • ClearAllActions() issued by some other script just after the equip commands
  • Wrong slot specified for the item
  • Item not equippable by that creature (which you can test in the toolset by adding the items to inventory temporarily, then equipping them on the paper doll)
  • Attempting to equip armour during combat

Like guys said here - no. You want a creature to do something now, you purge its action queue with CAA and push the action into it. It is also how you make it stop doing what it is doing right now, i.e. to break looping animations or master following.

If the creature has logic for some low-priority tasks such as patrol routes, it’s not your problem. They are normally handled in OnHeartbeat, so it will resume them the next time it is found to be idle.

Also all creatures are spawned not dead and commandable. Discounting external factors (i.e. combat or fear-causing enemy nearby or cutscene scripts), your OnSpawn would need to instakill them or make them uncommandable in the first place.

Well, this did the trick, at least in the test cases I have run. I am still concerned that the OnSpawn script for some critters is going to populate their queue and ClearAllActions() is going to cause trouble there. But, until I see that happening, this will work. When it happens, I can work out some sort of delay scheme that hopefully doesn’t cause trouble.

Thanks to everyone who helped me with this. :-)

BTW, I had added the check for creature commandability in the pre-ClearAllActions() version when some unknown factor (which is still unknown, BTW) was causing the equip action to be ignored. I can clear some of that out now that I know that it isn’t needed.