Aller au contenu

Photo

Help with a henchman respawn script?


  • Veuillez vous connecter pour répondre
17 réponses à ce sujet

#1
Mr. Versipellis

Mr. Versipellis
  • Members
  • 206 messages
 I hate to beg but I've been puzzling over this for a good few days and I simply can't get it to work as I would like it to. This script is placed OnDeath for a certain henchman, tagged "erno". What I would like it to do is to have him sit there for thirty-odd seconds, then respawn, restore his health, say a random phrase taken from a list of four strings and then add himself back to the party. The script I have at the moment looks like this:

#include "nw_i0_generic"
#include "nw_i0_plot"
void main()
{
{
    object oMe = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, GetMaster());
    if (oMe == OBJECT_SELF
        // * this is to prevent 'double hits' from stopping
        // * the henchmen from moving to the temple of tyr
        // * I.e., henchmen dies 'twice', once after leaving  your party
        || GetLocalInt(OBJECT_SELF, "NW_L_HEN_I_DIED") == TRUE)
       {       SetPlotFlag(oMe, TRUE);
       SetAssociateState(NW_ASC_IS_BUSY, TRUE);
       SetIsDestroyable(FALSE, TRUE, TRUE);
       SetLocalInt(OBJECT_SELF, "NW_L_HEN_I_DIED", TRUE);
        ClearAllActions();
        DelayCommand(0.5, ActionDoCommand(SetCommandable(TRUE)));
        DelayCommand(5.0, ActionDoCommand(SetAssociateState(NW_ASC_IS_BUSY, FALSE)));

        DelayCommand(5.1, SetPlotFlag(oMe, FALSE));

        SetCommandable(FALSE);       }}
  string sRevive;

  {    int iRandom = d4();
    switch(iRandom)
    {      case 1:
        sRevive = "1";
        break;
      case 2:
        sRevive = "2";
        break;
      case 3:
        sRevive = "3";
        break;
      case 4:
        sRevive = "4";
      break;
    }
  }
    SetLocalObject(OBJECT_SELF,"NW_L_FORMERMASTER", GetMaster());
    DelayCommand(0.1, RemoveEffects(OBJECT_SELF));
    DelayCommand(30.2, ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectResurrection(), OBJECT_SELF));
    DelayCommand(30.3, ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectHeal(GetMaxHitPoints(OBJECT_SELF)), OBJECT_SELF));
    DelayCommand(31.0, AssignCommand(OBJECT_SELF, ActionSpeakString(sRevive)));
    DelayCommand(35.1, SetIsDestroyable(TRUE, TRUE, TRUE));
    DelayCommand(35.1, SpeakString(sRevive));
    SetLocalInt(GetMaster(OBJECT_SELF), GetResRef(OBJECT_SELF) + "_dead", 1);

  object oMaster = GetLocalObject(OBJECT_SELF,"NW_L_FORMERMASTER");
  PrintString("Trying to join " + GetName(oMaster));
  PrintString("Distance " + FloatToString(GetDistanceBetween(oMaster, OBJECT_SELF)));

  if(
      (!(oMaster == OBJECT_INVALID)) &&
      (GetHenchman(oMaster) == OBJECT_INVALID) &&
      (GetDistanceBetween(oMaster, OBJECT_SELF) < 30.0) )  {
    PrintString("Joining");
    ClearAllActions();
    SetAssociateState(NW_ASC_IS_BUSY, FALSE);
    SetAssociateListenPatterns();
    SetLocalInt(OBJECT_SELF, "NW_COM_MODE_COMBAT", ASSOCIATE_COMMAND_ATTACKNEAREST);
    SetLocalInt(OBJECT_SELF, "NW_COM_MODE_MOVEMENT", ASSOCIATE_COMMAND_FOLLOWMASTER);
    SetAssociateState(NW_ASC_IS_BUSY, FALSE);
    AddHenchman(oMaster);
    SetLocalObject(OBJECT_SELF, "Master", GetPCSpeaker());
   }}

 

It is succesfully resurrecting him and stripping him of effects after the set time, but then he always says the fourth line and does not add himself back to the party. What am I doing wrong here?

Edit: Formatting

Modifié par Mr. Versipellis, 03 juillet 2012 - 03:28 .


#2
GhostOfGod

GhostOfGod
  • Members
  • 863 messages
Well you did have a few extra curly brackets in there I took out. I edited it a bit mor for readability.


#include "nw_i0_generic"
#include "nw_i0_plot"
void main()
{
    object oMe = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, GetMaster());
    if (oMe == OBJECT_SELF
        // * this is to prevent 'double hits' from stopping
        // * the henchmen from moving to the temple of tyr
        // * I.e., henchmen dies 'twice', once after leaving  your party
        || GetLocalInt(OBJECT_SELF, "NW_L_HEN_I_DIED") == TRUE)
    {
        SetPlotFlag(oMe, TRUE);
        SetAssociateState(NW_ASC_IS_BUSY, TRUE);
        SetIsDestroyable(FALSE, TRUE, TRUE);
        SetLocalInt(OBJECT_SELF, "NW_L_HEN_I_DIED", TRUE);
        ClearAllActions();
        DelayCommand(0.5, ActionDoCommand(SetCommandable(TRUE)));
        DelayCommand(5.0, ActionDoCommand(SetAssociateState(NW_ASC_IS_BUSY, FALSE)));
        DelayCommand(5.1, SetPlotFlag(oMe, FALSE));
        SetCommandable(FALSE);
    }

    string sRevive;
    int iRandom = d4();
    switch(iRandom)
    {
        case 1: sRevive = "1"; break;
        case 2: sRevive = "2"; break;
        case 3: sRevive = "3"; break;
        case 4: sRevive = "4"; break;
    }

    SetLocalObject(OBJECT_SELF,"NW_L_FORMERMASTER", GetMaster());
    DelayCommand(0.1, RemoveEffects(OBJECT_SELF));
    DelayCommand(30.2, ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectResurrection(), OBJECT_SELF));
    DelayCommand(30.3, ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectHeal(GetMaxHitPoints(OBJECT_SELF)), OBJECT_SELF));
    DelayCommand(31.0, AssignCommand(OBJECT_SELF, ActionSpeakString(sRevive)));
    DelayCommand(35.1, SetIsDestroyable(TRUE, TRUE, TRUE));
    DelayCommand(35.1, SpeakString(sRevive));
    SetLocalInt(GetMaster(OBJECT_SELF), GetResRef(OBJECT_SELF) + "_dead", 1);

    object oMaster = GetLocalObject(OBJECT_SELF,"NW_L_FORMERMASTER");
    PrintString("Trying to join " + GetName(oMaster));
    PrintString("Distance " + FloatToString(GetDistanceBetween(oMaster, OBJECT_SELF)));

    if((!(oMaster == OBJECT_INVALID)) &&
       (GetHenchman(oMaster) == OBJECT_INVALID) &&
       (GetDistanceBetween(oMaster, OBJECT_SELF) < 30.0))
    {
        PrintString("Joining");
        ClearAllActions();
        SetAssociateState(NW_ASC_IS_BUSY, FALSE);
        SetAssociateListenPatterns();
        SetLocalInt(OBJECT_SELF, "NW_COM_MODE_COMBAT", ASSOCIATE_COMMAND_ATTACKNEAREST);
        SetLocalInt(OBJECT_SELF, "NW_COM_MODE_MOVEMENT", ASSOCIATE_COMMAND_FOLLOWMASTER);
        SetAssociateState(NW_ASC_IS_BUSY, FALSE);
        AddHenchman(oMaster);
        SetLocalObject(OBJECT_SELF, "Master", GetPCSpeaker());
    }
}


There are a couple other things that make this confusing to read and hard to figure out what you want to check exactly. Like this:

(!(oMaster == OBJECT_INVALID))

Would just be the same as this:

oMaster != OBJECT_INVALID

So this section the way you have it:

if((!(oMaster == OBJECT_INVALID)) &&

       (GetHenchman(oMaster) == OBJECT_INVALID) &&

       (GetDistanceBetween(oMaster, OBJECT_SELF) < 30.0))

Would be the same as:

if (oMaster != OBJECT_INVALID &&

    GetHenchman(oMaster) == OBJECT_INVALID &&

    GetDistanceBetween(oMaster, OBJECT_SELF) < 30.0)

#3
Mr. Versipellis

Mr. Versipellis
  • Members
  • 206 messages

GhostOfGod wrote...

Well you did have a few extra curly brackets in there I took out. I edited it a bit mor for readability.


#include "nw_i0_generic"
#include "nw_i0_plot"
void main()
{
    object oMe = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, GetMaster());
    if (oMe == OBJECT_SELF
        // * this is to prevent 'double hits' from stopping
        // * the henchmen from moving to the temple of tyr
        // * I.e., henchmen dies 'twice', once after leaving  your party
        || GetLocalInt(OBJECT_SELF, "NW_L_HEN_I_DIED") == TRUE)
    {
        SetPlotFlag(oMe, TRUE);
        SetAssociateState(NW_ASC_IS_BUSY, TRUE);
        SetIsDestroyable(FALSE, TRUE, TRUE);
        SetLocalInt(OBJECT_SELF, "NW_L_HEN_I_DIED", TRUE);
        ClearAllActions();
        DelayCommand(0.5, ActionDoCommand(SetCommandable(TRUE)));
        DelayCommand(5.0, ActionDoCommand(SetAssociateState(NW_ASC_IS_BUSY, FALSE)));
        DelayCommand(5.1, SetPlotFlag(oMe, FALSE));
        SetCommandable(FALSE);
    }

    string sRevive;
    int iRandom = d4();
    switch(iRandom)
    {
        case 1: sRevive = "1"; break;
        case 2: sRevive = "2"; break;
        case 3: sRevive = "3"; break;
        case 4: sRevive = "4"; break;
    }

    SetLocalObject(OBJECT_SELF,"NW_L_FORMERMASTER", GetMaster());
    DelayCommand(0.1, RemoveEffects(OBJECT_SELF));
    DelayCommand(30.2, ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectResurrection(), OBJECT_SELF));
    DelayCommand(30.3, ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectHeal(GetMaxHitPoints(OBJECT_SELF)), OBJECT_SELF));
    DelayCommand(31.0, AssignCommand(OBJECT_SELF, ActionSpeakString(sRevive)));
    DelayCommand(35.1, SetIsDestroyable(TRUE, TRUE, TRUE));
    DelayCommand(35.1, SpeakString(sRevive));
    SetLocalInt(GetMaster(OBJECT_SELF), GetResRef(OBJECT_SELF) + "_dead", 1);

    object oMaster = GetLocalObject(OBJECT_SELF,"NW_L_FORMERMASTER");
    PrintString("Trying to join " + GetName(oMaster));
    PrintString("Distance " + FloatToString(GetDistanceBetween(oMaster, OBJECT_SELF)));

    if((!(oMaster == OBJECT_INVALID)) &&
       (GetHenchman(oMaster) == OBJECT_INVALID) &&
       (GetDistanceBetween(oMaster, OBJECT_SELF) < 30.0))
    {
        PrintString("Joining");
        ClearAllActions();
        SetAssociateState(NW_ASC_IS_BUSY, FALSE);
        SetAssociateListenPatterns();
        SetLocalInt(OBJECT_SELF, "NW_COM_MODE_COMBAT", ASSOCIATE_COMMAND_ATTACKNEAREST);
        SetLocalInt(OBJECT_SELF, "NW_COM_MODE_MOVEMENT", ASSOCIATE_COMMAND_FOLLOWMASTER);
        SetAssociateState(NW_ASC_IS_BUSY, FALSE);
        AddHenchman(oMaster);
        SetLocalObject(OBJECT_SELF, "Master", GetPCSpeaker());
    }
}


There are a couple other things that make this confusing to read and hard to figure out what you want to check exactly. Like this:

(!(oMaster == OBJECT_INVALID))

Would just be the same as this:

oMaster != OBJECT_INVALID

So this section the way you have it:

if((!(oMaster == OBJECT_INVALID)) &&

       (GetHenchman(oMaster) == OBJECT_INVALID) &&

       (GetDistanceBetween(oMaster, OBJECT_SELF) < 30.0))

Would be the same as:

if (oMaster != OBJECT_INVALID &&

    GetHenchman(oMaster) == OBJECT_INVALID &&

    GetDistanceBetween(oMaster, OBJECT_SELF) < 30.0)




Thanks for that - I really do need to be more careful with my programming! Does this give you any clue of what the problem with the actual code is?

#4
Failed.Bard

Failed.Bard
  • Members
  • 774 messages

ClearAllActions();
DelayCommand(0.5, ActionDoCommand(SetCommandable(TRUE)));
DelayCommand(5.0, ActionDoCommand(SetAssociateState(NW_ASC_IS_BUSY, FALSE)));
DelayCommand(5.1, SetPlotFlag(oMe, FALSE));
SetCommandable(FALSE);

Can a dead PC/NPC quoue actions? Also, with the delays on them, even if they can, then they'd be assigned after the NPC has been set to non-commandable anyways.

#5
Mr. Versipellis

Mr. Versipellis
  • Members
  • 206 messages

Failed.Bard wrote...

ClearAllActions();
DelayCommand(0.5, ActionDoCommand(SetCommandable(TRUE)));
DelayCommand(5.0, ActionDoCommand(SetAssociateState(NW_ASC_IS_BUSY, FALSE)));
DelayCommand(5.1, SetPlotFlag(oMe, FALSE));
SetCommandable(FALSE);

Can a dead PC/NPC quoue actions? Also, with the delays on them, even if they can, then they'd be assigned after the NPC has been set to non-commandable anyways.

I believe that I've seen other people do it in the same way, but my memory may well be at fault. Do you know of another, more effective way to delay actions like these? That would make sense, considering that the only actions that aren't running are the "DoCommand" ones.

#6
GhostOfGod

GhostOfGod
  • Members
  • 863 messages
You could assign commands to the 'area' of the dead henchmen.

Also something else I noticed on your last line:

SetLocalObject(OBJECT_SELF, "Master", GetPCSpeaker());

If this is an OnDeath script I'm not sure what object, if any, will be returned using the GetPCSpeaker function. That is usually meant for conversations. So this might be causing a problem as well.

Modifié par GhostOfGod, 04 juillet 2012 - 01:05 .


#7
Mr. Versipellis

Mr. Versipellis
  • Members
  • 206 messages

GhostOfGod wrote...

You could assign commands to the 'area' of the dead henchmen.

And how would I go about doing that? Would that solve the problem? As it stands, I'm using a slightly tweaked script that does everything except add the henchman back to the party; instead, the player has to speak to them, which is a bit of a problem since they can easily be forgotten, which affects the story.

#8
GhostOfGod

GhostOfGod
  • Members
  • 863 messages
Are you seeing your PrintString "Joining"?

Modifié par GhostOfGod, 04 juillet 2012 - 07:02 .


#9
Mr. Versipellis

Mr. Versipellis
  • Members
  • 206 messages

GhostOfGod wrote...

Are you seeing your PrintString "Joining"?

No - that's exactly the reason I stuck it in there; I figured that as soon as I saw that, the rest of the code must be working since it's all in one block. If you like, I could put together an ERF with the script and henchman in question in it?

#10
GhostOfGod

GhostOfGod
  • Members
  • 863 messages
Ok then you are not getting past your "if". So lets break this down:

if (oMaster != OBJECT_INVALID &&

    GetHenchman(oMaster) == OBJECT_INVALID &&

    GetDistanceBetween(oMaster, OBJECT_SELF) < 30.0)


What this is saying is;

If oMaster exists (which is an object that has been set on the henchman) AND oMaster does NOT have any henchmen AND the distance to oMaster is less than 30.0, then do stuff.

So one of these things is not happening. It is most likely this line:

object oMaster = GetLocalObject(OBJECT_SELF,"NW_L_FORMERMASTER");

Somewhere in some other script there should be a SetLocalObject line that makes sure this gets set.

You could add a couple lines under the above mentioned line that will let you know if oMaster exists.
Something kinda like so:

object oMaster = GetLocalObject(OBJECT_SELF,"NW_L_FORMERMASTER");
if (!GetIsObjectValid(oMaster))
{
    SendMessageToPC(GetFirstPC(), "oMaster not found");
}

Hopefully this will at least get you pointed in the right direction.

Modifié par GhostOfGod, 04 juillet 2012 - 10:55 .


#11
meaglyn

meaglyn
  • Members
  • 811 messages
I think the logic of that "if" looks iffy (so to speak :)

As GhostofGod said it's based on the master which is set earlier in the script from this:

SetLocalObject(OBJECT_SELF,"NW_L_FORMERMASTER", GetMaster());

and then retrieved with this:

object oMaster = GetLocalObject(OBJECT_SELF,"NW_L_FORMERMASTER");

So if you take out the variable what the if is saying is

if (GetMaster() != OBJECT_INVALID
&& GetHenchmen(GetMaster()) == OBJECT_INVALID)
&& GetDistanceBetween(oMaster, OBJECT_SELF) < 30.0)

It seems to me that if GetMaster() returns a valid object then a GetHenchman() call on that
master really must also be returning a valid object. So this second clause will never be true.

I don't know when in the death process a henchman gets removed from the his/her master.

As GhostofGod said it could also be the master is INVALID already. It won't be from the
object oMaster = GetLocalObject(OBJECT_SELF,"NW_L_FORMERMASTER") line
but from the actual GetMaster() call.

#12
Mr. Versipellis

Mr. Versipellis
  • Members
  • 206 messages
Thanks guys, I got it sorted. I basically had to "trim the fat" out of the script and make sure that all the "if" conditions were doing what they were supposed to - I must admit, I took parts of this script from an ERF template so I didn't really know what I was doing. I really do appreciate the help!
Just one question, though: how do you think this design will work in terms of gameplay? The script is working without a hitch, but would you like the henchman system to work this way if you were playing the module? And can you forsee any problems with the design? I'm going for a Dragon Age/Neverwinter Nights 2 system, but I'm not quite sure how that'll work out in the Aurora engine.

#13
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
Can you post your current version of the script.

#14
Mr. Versipellis

Mr. Versipellis
  • Members
  • 206 messages

Lightfoot8 wrote...

Can you post your current version of the script.


#include "nw_i0_generic"
#include "nw_i0_plot"
void main()

{

//Define the former master
object oMaster = GetNearestPC();
//Define the henchman
object oMe = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, GetMaster());

//Set the HCH erno_dead variable, just in case the script goes wrong.
//This means that you see a special bit of dialogue when you speak to the hench post-death, but only if something goes wrong, i.e. the PC moves areas
SetLocalInt(GetMaster(OBJECT_SELF), GetResRef(OBJECT_SELF) + "erno_dead", 1);



//Double-hit thing to stop the body from getting destroyed or anything
if (oMe == OBJECT_SELF
|| GetLocalInt(OBJECT_SELF, "NW_L_HEN_I_DIED") == TRUE)
    {
        SetPlotFlag(oMe, TRUE);
        SetAssociateState(NW_ASC_IS_BUSY, TRUE);
        SetIsDestroyable(FALSE, TRUE, TRUE);
        SetLocalInt(OBJECT_SELF, "NW_L_HEN_I_DIED", TRUE);
        ClearAllActions();
        DelayCommand(0.5, ActionDoCommand(SetCommandable(TRUE)));
        DelayCommand(5.0, ActionDoCommand(SetAssociateState(NW_ASC_IS_BUSY, FALSE)));
        DelayCommand(5.1, SetPlotFlag(oMe, FALSE));
        SetCommandable(FALSE);
    }
//Choose a random dialogue string
string sRevive;
int iRandom = d4();
switch(iRandom)
    {
    case 1: sRevive = "Better luck next time, eh?"; break;
    case 2: sRevive = "Thank all the Gods that we pulled through that..."; break;
    case 3: sRevive = "That was... unpleasant, to say the least."; break;
    case 4: sRevive = "Oh my... how long was I out for?"; break;
    case 5: sRevive = "Well, there's one for the journal."; break;
    case 6: sRevive = "Argh, I can barely feel my legs!"; break;
    case 7: sRevive = "That was strangely invigorating!"; break;
    case 8: sRevive = "For the love of all things holy, let's be more careful next time!"; break;
    }

//Resurrect and remove effects, then add back the henchman
DelayCommand(0.1, RemoveEffects(OBJECT_SELF));
DelayCommand(30.0, ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectResurrection(), OBJECT_SELF));
DelayCommand(30.25, ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectHeal(GetMaxHitPoints(OBJECT_SELF)), OBJECT_SELF));
DelayCommand(30.75, SetIsDestroyable(TRUE, TRUE, TRUE));
DelayCommand(31.0, SpeakString(sRevive));
DelayCommand(31.5, AddHenchman(oMaster, oMe));

//Re-set the variable to get rid of annoying dialogueif the henchie has successfully re-joined
DelayCommand(32.0, SetLocalInt(GetMaster(OBJECT_SELF), GetResRef(OBJECT_SELF) + "erno_dead", 0));

//Set up the proper conditions for henchman as defined by the X2 script
SetAssociateState(NW_ASC_IS_BUSY, FALSE);
SetAssociateListenPatterns();
SetLocalInt(OBJECT_SELF, "NW_COM_MODE_COMBAT", ASSOCIATE_COMMAND_ATTACKNEAREST);
SetLocalInt(OBJECT_SELF, "NW_COM_MODE_MOVEMENT", ASSOCIATE_COMMAND_FOLLOWMASTER);
SetAssociateState(NW_ASC_IS_BUSY, FALSE);
SetLocalObject(OBJECT_SELF, "Master", GetNearestPC());

}

 

Modifié par Mr. Versipellis, 06 juillet 2012 - 09:38 .


#15
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages

Mr. Versipellis wrote...

http://pastebin.com/CpmY4F7R#


Your script still looks problematic to me.  The problems start with how you are defining oMaster and oMe at the begining of the script ( lines 6-9 ).  Both of them as written have a chance of returning the wrong object.  oMaster should be defined as a local that is set up at the time the henchman is added to the party.   oMe should be simply OBJECT_SELF


for oMaster you can use the wrapper function set up in X0_I0_HENCHMAN.

ie
object oMaster = GetLastMaster();
object oMe = OBJECT_SELF;

At that point if oMaster does not return the correct object, make sure that you have the SetLastMaster function in the script that adds the henchman to the party.


line 13:  SetLocalInt(GetMaster(OBJECT_SELF), GetResRef(OBJECT_SELF) + "erno_dead", 1);
Makes no since to me as being  set up on the master instead of the henchman.  We even have the problem here that if the henchman has already been removed from the party GetMaster is going to return an invalid object.  assuming that the other scripts are done correctly for the var being set on the PC, just use oMaster instead of GetMaster() ie:

 SetLocalInt(oMaster, GetResRef(OBJECT_SELF) + "erno_dead", 1);


lines: 17 through 30: 
This section does nothing close to the comments say it is doing.   None of the actions have a chance to fire, the Henchman being dead will not even que up actions.  even if the action que was active, The ActionDoCommands would get added to the que, however  the Action que is already locked when they fire and try to add the actions they contain to the action que.    ActionDoCommand is normally used to add commands to the Action que in this maner, NOT OTHER ACTIONS.

The SetDestroyable function in this section is way to late.  If the Henchman is not already set to be non destroyable, it will do no good to try and set it now. the henchman is already well on his way to being destroyed.   This is another function that you will want to make sure is set when the henchman is added to the party. 

To get this section to do what it looks like it is tring to do simply changing it to 

 
if (GetDidDie()) return;
else SetDidDie();

GetDidDie and SetDidDie are wrapper functions around the NW_L_HEN_I_DIED var in  X0_I0_HENCHMAN. 


Line 33: 
Change it to a d8 since you have added more options.

Line 48 & 49: should be  DURATION_TYPE_INSTANT

Line55:  should only be ran if a valid connection to oMaster has been made This means that lines 46 - 63 should be removed to there own functoin for better control.   this will also allow us to make checks to see if combat is still going on before raising the henchman. 


With the above adjustments you end up with something like this. 

#include "nw_i0_generic"
#include "nw_i0_plot"
#include "X0_I0_HENCHMAN"

void ResHenchman(object oPC,string sLiner = "", object oHenchman =OBJECT_SELF)
{
   if ( GetIsInCombat (oPC) || !GetIsObjectValid(oPC))
   {
     DelayCommand(30.0,ResHenchman(oPC,sLiner,oHenchman));
     return;
   }


  ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectResurrection(), oHenchman);
  ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectHeal(GetMaxHitPoints(oHenchman)), oHenchman);
  //DelayCommand(30.75, SetIsDestroyable(TRUE, TRUE, TRUE));
  DelayCommand(1.0, SpeakString(sLiner));
  SetDidDie(FALSE);

  if (GetArea(oPC) == GetArea(oHenchman))
  {
    DelayCommand(1.5, AddHenchman(oPC, oHenchman));

    //Re-set the variable to get rid of annoying dialogueif the henchie has successfully re-joined
    DeleteLocalInt(oPC, GetResRef(oHenchman) + "erno_dead");

    //Set up the proper conditions for henchman as defined by the X2 script
    SetAssociateState(NW_ASC_IS_BUSY, FALSE,oHenchman);
    //SetAssociateListenPatterns();
    SetLocalInt(oHenchman, "NW_COM_MODE_COMBAT", ASSOCIATE_COMMAND_ATTACKNEAREST);
    SetLocalInt(oHenchman, "NW_COM_MODE_MOVEMENT", ASSOCIATE_COMMAND_FOLLOWMASTER);
    SetAssociateState(NW_ASC_IS_BUSY, FALSE,oHenchman);
  }
}
void main()
{
  //Define the former master
  object oMaster=GetLastMaster();
  //Define the henchman
  object oMe =OBJECT_SELF;

  //Set the HCH erno_dead variable, just in case the script goes wrong.
  //This means that you see a special bit of dialogue when you speak to the hench post-death, but only if something goes wrong, i.e. the PC moves areas
  SetLocalInt(oMaster, GetResRef(OBJECT_SELF) + "erno_dead", 1);


  //Double-hit thing to stop the body from getting destroyed or anything
  if (GetDidDie()) return;
  else SetDidDie();

  //Choose a random dialogue string
  string sRevive;
  int iRandom = d8();
  switch(iRandom)
  {
    case 1: sRevive = "Better luck next time, eh?"; break;
    case 2: sRevive = "Thank all the Gods that we pulled through that..."; break;
    case 3: sRevive = "That was... unpleasant, to say the least."; break;
    case 4: sRevive = "Oh my... how long was I out for?"; break;
    case 5: sRevive = "Well, there's one for the journal."; break;
    case 6: sRevive = "Argh, I can barely feel my legs!"; break;
    case 7: sRevive = "That was strangely invigorating!"; break;
    case 8: sRevive = "For the love of all things holy, let's be more careful next time!"; break;
  }
 
//Resurrect and remove effects, then add back the henchman
  DelayCommand(0.1, RemoveEffects(OBJECT_SELF));
  DelayCommand( 30.0,ResHenchman(oMaster,sRevive) );
}
 

  
 
EDIT:  Forgot to reset his death flag.   Done.

Modifié par Lightfoot8, 08 juillet 2012 - 01:43 .


#16
Mr. Versipellis

Mr. Versipellis
  • Members
  • 206 messages

Lightfoot8 wrote...

Mr. Versipellis wrote...

http://pastebin.com/CpmY4F7R#


Your script still looks problematic to me.  The problems start with how you are defining oMaster and oMe at the begining of the script ( lines 6-9 ).  Both of them as written have a chance of returning the wrong object.  oMaster should be defined as a local that is set up at the time the henchman is added to the party.   oMe should be simply OBJECT_SELF


for oMaster you can use the wrapper function set up in X0_I0_HENCHMAN.

ie
object oMaster = GetLastMaster();
object oMe = OBJECT_SELF;

At that point if oMaster does not return the correct object, make sure that you have the SetLastMaster function in the script that adds the henchman to the party.


line 13:  SetLocalInt(GetMaster(OBJECT_SELF), GetResRef(OBJECT_SELF) + "erno_dead", 1);
Makes no since to me as being  set up on the master instead of the henchman.  We even have the problem here that if the henchman has already been removed from the party GetMaster is going to return an invalid object.  assuming that the other scripts are done correctly for the var being set on the PC, just use oMaster instead of GetMaster() ie:

 SetLocalInt(oMaster, GetResRef(OBJECT_SELF) + "erno_dead", 1);


lines: 17 through 30: 
This section does nothing close to the comments say it is doing.   None of the actions have a chance to fire, the Henchman being dead will not even que up actions.  even if the action que was active, The ActionDoCommands would get added to the que, however  the Action que is already locked when they fire and try to add the actions they contain to the action que.    ActionDoCommand is normally used to add commands to the Action que in this maner, NOT OTHER ACTIONS.

The SetDestroyable function in this section is way to late.  If the Henchman is not already set to be non destroyable, it will do no good to try and set it now. the henchman is already well on his way to being destroyed.   This is another function that you will want to make sure is set when the henchman is added to the party. 

To get this section to do what it looks like it is tring to do simply changing it to 

 
if (GetDidDie()) return;
else SetDidDie();

GetDidDie and SetDidDie are wrapper functions around the NW_L_HEN_I_DIED var in  X0_I0_HENCHMAN. 


Line 33: 
Change it to a d8 since you have added more options.

Line 48 & 49: should be  DURATION_TYPE_INSTANT

Line55:  should only be ran if a valid connection to oMaster has been made This means that lines 46 - 63 should be removed to there own functoin for better control.   this will also allow us to make checks to see if combat is still going on before raising the henchman. 


With the above adjustments you end up with something like this. 

#include "nw_i0_generic"
#include "nw_i0_plot"
#include "X0_I0_HENCHMAN"

void ResHenchman(object oPC,string sLiner = "", object oHenchman =OBJECT_SELF)
{
   if ( GetIsInCombat (oPC) || !GetIsObjectValid(oPC))
   {
     DelayCommand(30.0,ResHenchman(oPC,sLiner,oHenchman));
     return;
   }


  ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectResurrection(), oHenchman);
  ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectHeal(GetMaxHitPoints(oHenchman)), oHenchman);
  //DelayCommand(30.75, SetIsDestroyable(TRUE, TRUE, TRUE));
  DelayCommand(1.0, SpeakString(sLiner));
  SetDidDie(FALSE);

  if (GetArea(oPC) == GetArea(oHenchman))
  {
    DelayCommand(1.5, AddHenchman(oPC, oHenchman));

    //Re-set the variable to get rid of annoying dialogueif the henchie has successfully re-joined
    DeleteLocalInt(oPC, GetResRef(oHenchman) + "erno_dead");

    //Set up the proper conditions for henchman as defined by the X2 script
    SetAssociateState(NW_ASC_IS_BUSY, FALSE,oHenchman);
    //SetAssociateListenPatterns();
    SetLocalInt(oHenchman, "NW_COM_MODE_COMBAT", ASSOCIATE_COMMAND_ATTACKNEAREST);
    SetLocalInt(oHenchman, "NW_COM_MODE_MOVEMENT", ASSOCIATE_COMMAND_FOLLOWMASTER);
    SetAssociateState(NW_ASC_IS_BUSY, FALSE,oHenchman);
  }
}
void main()
{
  //Define the former master
  object oMaster=GetLastMaster();
  //Define the henchman
  object oMe =OBJECT_SELF;

  //Set the HCH erno_dead variable, just in case the script goes wrong.
  //This means that you see a special bit of dialogue when you speak to the hench post-death, but only if something goes wrong, i.e. the PC moves areas
  SetLocalInt(oMaster, GetResRef(OBJECT_SELF) + "erno_dead", 1);


  //Double-hit thing to stop the body from getting destroyed or anything
  if (GetDidDie()) return;
  else SetDidDie();

  //Choose a random dialogue string
  string sRevive;
  int iRandom = d8();
  switch(iRandom)
  {
    case 1: sRevive = "Better luck next time, eh?"; break;
    case 2: sRevive = "Thank all the Gods that we pulled through that..."; break;
    case 3: sRevive = "That was... unpleasant, to say the least."; break;
    case 4: sRevive = "Oh my... how long was I out for?"; break;
    case 5: sRevive = "Well, there's one for the journal."; break;
    case 6: sRevive = "Argh, I can barely feel my legs!"; break;
    case 7: sRevive = "That was strangely invigorating!"; break;
    case 8: sRevive = "For the love of all things holy, let's be more careful next time!"; break;
  }
 
//Resurrect and remove effects, then add back the henchman
  DelayCommand(0.1, RemoveEffects(OBJECT_SELF));
  DelayCommand( 30.0,ResHenchman(oMaster,sRevive) );
}
 

  
 
EDIT:  Forgot to reset his death flag.   Done.

Thanks much. I think this is all set up and working perfectly, I've run through a few dungeons and I haven't encountered any issues yet. You've been so helpful with this script - I'll be sure to credit you in the module documentation!

#17
Mr. Versipellis

Mr. Versipellis
  • Members
  • 206 messages
Hey, I hate to resurrect an old thread but I've noticed that this script only ever seems to work once - that is to say, the first time the NPC dies, they are resurrected as dictated by the script, but after that, their corpse just lies there on the floor.
The current version is here, designed for an NPC tagged "Erno" and copied ad verbatim from the module:
http://pastebin.com/Cd4YjCbe
Any clue what might be causing this?

#18
Mr. Versipellis

Mr. Versipellis
  • Members
  • 206 messages
Bump?