How to respawn Henchman after death

I’d be grateful for a little help on the topic of henchman if anyone has time ( and if they know anything about it so much the better :grinning: )

Some of you may know, I’m working with kids in a Games Design class using NWN:EE this year and its going pretty well so far. however, since I only came across NWN in January of this year and the class is pretty decent it has been a little like the blind leading the much more capable . . .

At the moment I’m looking to introduce them to how to create a henchman in their modules.

I’ve had a look at the Module Builder’s Henchman Kit but it seems pretty elaborate and, besides, I use a Mac and it keeps crashing (!). So, at the moment I’m going with the simple approach of creating the henchman, loading the “set_xp2_henchman.ini” scripts and constructing a conversation with a Script Generator script to hire them. Works perfectly and tbh, its as much as they need.

However, I just can’t seem to figure out how to respawn the henchman in a place of my choosing. I’ve been pluttering around trying to add henchie tags to the PC death temple Waypoint, trying to alter their OnDeath script ( without having a clue what I’m doing), using a SG script to respawn but trying to change PC to the Henchman’s tag but it strikes me there has to be an easier way - or, more accurately, one that actually works, short of equipping my PC with a job lot of Rods of Resurrection.

Any help would be appreciated. I’ve done quite a bit of ferreting about here and elsewhere and can’t seem to find the answer to this.

I assume this is what you are looking for. So here’s a resurrection MWE - put it as any creature’s OnDeath handler. You can tailor it to your custom hench AI.

// raises OBJECT_SELF after death at location of object with tag "RESPAWN"

#include "nw_i0_plot"

// function made after RespawnHenchman from x0_i0_henchman
void RespawnHenchman(location lSpot, object oTarget=OBJECT_SELF)
{
    // resurrect
    DelayCommand(0.1, ApplyEffectToObject(DURATION_TYPE_PERMANENT,
        EffectResurrection(), oTarget));

    // heal
    DelayCommand(0.2, ApplyEffectToObject(DURATION_TYPE_PERMANENT,
        EffectHeal(GetMaxHitPoints(oTarget)), oTarget));

    // jump
    DelayCommand(0.3, AssignCommand(oTarget,
        JumpToLocation(lSpot)));

    // remove negative effects
    DelayCommand(0.4, RemoveEffects(oTarget));

    // make destroyable again (NOT REQUIRED)
    DelayCommand(0.5, AssignCommand(oTarget,
        SetIsDestroyable(TRUE, TRUE, TRUE)));
}

void main()
{
    // make sure the object sticks around when dead
    SetIsDestroyable(FALSE, TRUE, TRUE);

    ActionSpeakString("I AM DEAD");
    ActionWait(2.5); // dead object cannot perform this action!
    ActionSpeakString("I'LL RAISE SOON");

    // resurrect at target location after 5 seconds
    DelayCommand(5.0, RespawnHenchman(
        GetLocation(GetObjectByTag("RESPAWN")), OBJECT_SELF));
}

Some boring details:

  • Dead creatures cannot perform a lot of Actions. For example ActionSpeakString works, but ActionWait does not.
  • Dead creatures cannot JumpToLocation/Object - they need to be raised first.
  • There is a working set of functions in x0_i0_henchman but they aren’t generic - this code is.
1 Like

@NWShacker, thanks for this. I’m not at home at the moment but will try this later tonight.

Works perfectly. Thanks.

I spoke a little too soon., @NWShacker. The script does resurrect the NPC but he seems to be respawning at the point where he died rather than at the Waypoint with the tag “Respawn” that I created for him.

I’m guessing I’ve done something wrong but can’t think what.

EDIT. Yup, user error. Lower / Upper case always my downfall in scripting !!!

Sorted and thanks again.

no, i think there’s a small glitch in nwshacker’s script :

DelayCommand(0.3, JumpToLocation(lSpot));

this works fine as long as the routine is called w/o a 2nd parameter, because then oTarget resolves to OBJECT_SELF, so all of the functions work on the same object. however, if called w/an explicit 2nd argument, the other function calls target the parameterised object, but the above call still targets OBJECT_SELF – which may not be the henchman. instead of that, you may want to try sth like :

DelayCommand(0.3, AssignCommand(oTarget, JumpToLocation(lSpot)));

since you’ve only just revived the henchie, there should be no need to ClearAllActions() beforehand, but if you modify the routine to do other things, keep in mind that [1] JumpToLocation(lSpot) should normally add the jump in at the head of the queue while ActionJumpToLocation(lSpot) adds it to the end, and [2] you may need to clear all actions first.

1 Like

Altered as suggested. Thanks, Xorbaxian.

Yeah, the AssignCommand was missing. Silly mistake. It worked in the scope of this script but would be wrong in a library. Which leads to the fact, that the original BioWare script has the same error - undiscovered until today (?) since only henchies were calling that subroutine.

Thanks for your input - I fixed the script.

1 Like

what ?!   an error in an actual bioware script ?!
inconthievable!!
;p

Or inefficient things like this…

// x2_s0_restother
effect eBad = GetFirstEffect(oTarget);
while(GetIsEffectValid(eBad))
{
    if (GetEffectType(eBad) == EFFECT_TYPE_ABILITY_DECREASE ||
        GetEffectType(eBad) == EFFECT_TYPE_AC_DECREASE ||
        GetEffectType(eBad) == EFFECT_TYPE_ATTACK_DECREASE ||
        GetEffectType(eBad) == EFFECT_TYPE_DAMAGE_DECREASE ||
        GetEffectType(eBad) == EFFECT_TYPE_DAMAGE_IMMUNITY_DECREASE ||
        GetEffectType(eBad) == EFFECT_TYPE_SAVING_THROW_DECREASE ||
        GetEffectType(eBad) == EFFECT_TYPE_SPELL_RESISTANCE_DECREASE ||
        GetEffectType(eBad) == EFFECT_TYPE_SKILL_DECREASE ||
        GetEffectType(eBad) == EFFECT_TYPE_BLINDNESS ||
        GetEffectType(eBad) == EFFECT_TYPE_DEAF ||
        GetEffectType(eBad) == EFFECT_TYPE_PARALYZE ||
        GetEffectType(eBad) == EFFECT_TYPE_NEGATIVELEVEL)
        {
            //Remove effect if it is negative.
            RemoveEffect(oTarget, eBad);
        }
    eBad = GetNextEffect(oTarget);
}

Which, you’ll eventually notice, is also missing STUNNED and I think a couple of others too. :slight_smile: