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.
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?
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);
}
}
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)
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.
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.