Aller au contenu

Photo

Making an on enter trigger script more reliable - help needed please


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

#1
Clyordes

Clyordes
  • Members
  • 300 messages
Hi folks,
Lilac Soul user Clyordes here again.
I've got a script that works - sometimes.  What's supposed to happen, is when a character (anyone in the party) enters a trigger, it checks for the value of a variable "sussurus_alive". 
If its anything other than '2', nothing happens.
If its '2', a bit of floaty text about coffin lids moving appears, and a group of undead spawn at various waypoints.
The script should only fire the undead spawn once - the coffins only have enough room for one skeleton each!

The variable depends on whether a creature called the sussurus is alive or not, and changes to '2' via its ondeath script.  This seems to be working OK, as the same script generates a bit of floaty text, which shows fine - so I'm assuming the variable is changing too.

For some reason though, the on_enter trigger script works sometimes, but not others. 
What seems to be important in making the trigger fire is that the person who killed the sussurus is the one you're controlling when entering the trigger - which may make complete sense to someone who understands scripting better than me, but I can't see what I need to change to make it work regardless of who kills the suss & who you're controlling when you enter the trigger.

This is the script I have - please take a look & see if you can let me know what will work whoever enters the trigger:

//Put this script OnEnter
#include "nw_i0_generic"
void main()
{

object oPC = GetEnteringObject();

if (!GetIsPC(oPC)) return;

if (GetLocalInt(oPC, "sussurus_alive")== 2)
   {
   FloatingTextStringOnCreature("You hear the worrying noise of sarcophagus lids being opened...", oPC);

   oTarget = GetWaypointByTag("i1");

   lTarget = GetLocation(oTarget);

   oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_dagger", lTarget);

   oTarget = oSpawn;

   SetIsTemporaryEnemy(oPC, oTarget);

   AssignCommand(oTarget, ActionAttack(oPC));

   AssignCommand(oTarget, DetermineCombatRound(oPC));

   oTarget = GetWaypointByTag("i2");

   lTarget = GetLocation(oTarget);

   oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_dagger", lTarget);

   oTarget = oSpawn;

   SetIsTemporaryEnemy(oPC, oTarget);

   AssignCommand(oTarget, ActionAttack(oPC));

   AssignCommand(oTarget, DetermineCombatRound(oPC));

   oTarget = GetWaypointByTag("i3");

   lTarget = GetLocation(oTarget);

   oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_club", lTarget);

   oTarget = oSpawn;

   SetIsTemporaryEnemy(oPC, oTarget);

   AssignCommand(oTarget, ActionAttack(oPC));

   AssignCommand(oTarget, DetermineCombatRound(oPC));

   oTarget = GetWaypointByTag("i4");

   lTarget = GetLocation(oTarget);

   oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_club", lTarget);

   oTarget = oSpawn;

   SetIsTemporaryEnemy(oPC, oTarget);

   AssignCommand(oTarget, ActionAttack(oPC));

   AssignCommand(oTarget, DetermineCombatRound(oPC));

   oTarget = GetWaypointByTag("i5");

   lTarget = GetLocation(oTarget);

   oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_dagger", lTarget);

   oTarget = oSpawn;

   SetIsTemporaryEnemy(oPC, oTarget);

   AssignCommand(oTarget, ActionAttack(oPC));

   AssignCommand(oTarget, DetermineCombatRound(oPC));

   oTarget = GetWaypointByTag("i6");

   lTarget = GetLocation(oTarget);

   oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_dagger", lTarget);

   oTarget = oSpawn;

   SetIsTemporaryEnemy(oPC, oTarget);

   AssignCommand(oTarget, ActionAttack(oPC));

   AssignCommand(oTarget, DetermineCombatRound(oPC));

   oTarget = GetWaypointByTag("i7");

   lTarget = GetLocation(oTarget);

   oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_dagger", lTarget);

   oTarget = oSpawn;

   SetIsTemporaryEnemy(oPC, oTarget);

   AssignCommand(oTarget, ActionAttack(oPC));

   AssignCommand(oTarget, DetermineCombatRound(oPC));

   oTarget = GetWaypointByTag("i8");

   lTarget = GetLocation(oTarget);

   oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_club", lTarget);

   oTarget = oSpawn;

   SetIsTemporaryEnemy(oPC, oTarget);

   AssignCommand(oTarget, ActionAttack(oPC));

   AssignCommand(oTarget, DetermineCombatRound(oPC));

   oTarget = GetObjectByTag("trigger_south_south");

   DestroyObject(oTarget, 0.0);

   }
else
   {
   }

}


Thanks folks, Cly.  :)

#2
Shallina

Shallina
  • Members
  • 1 011 messages
object oPC = GetEnteringObject();

if (!GetIsPC(oPC)) return;

if (GetLocalInt(oPC, "sussurus_alive")== 2)

all is there.

You check your value in oPC wich is the object entering the trigger, if it's a party member and not the one you stored the value in, you'll nevers find it. You need to check the object in wich you stored the value and not the object entering the trigger.

#3
_Knightmare_

_Knightmare_
  • Members
  • 643 messages
Yup, my guess is that your error is in the ondeath script that is setting the variable in the first place. Try setting it as a global variable and then retrieving that global variable to test it in the script you posted. I assume you currently set the variable on the one who killed the creature. If so, then this script will only work when that same PC enters the trigger.

#4
Lugaid of the Red Stripes

Lugaid of the Red Stripes
  • Members
  • 955 messages
For plot-related variables like this, I would use the journal if it all possible, and then update the journal so that it doesn't fire again. I don't like destroying plot-critical elements, because then it's harder to fix things in-game if something goes wrong.

Also, spawning creatures right as they attack can lead to hiccups. I like to spawn them ahead of time (like when the player enters the area) and set them to script-hidden. Then you just un-hide them at the right moment.

#5
Kaldor Silverwand

Kaldor Silverwand
  • Members
  • 1 585 messages
For use cases like this I use global variables. I have a generic ondeath script I use that can do a number of things including setting a global, updating a journal, dropping an item, etc. based on variables set on the creature.

#6
Dann-J

Dann-J
  • Members
  • 3 161 messages
Why not just use the GetIsDead() function to checked whether ol' windy has bitten the dust?

#7
Kaldor Silverwand

Kaldor Silverwand
  • Members
  • 1 585 messages
Does GetIsDead work once the creature is destroyed?

#8
Shallina

Shallina
  • Members
  • 1 011 messages
GetISDEAd work if the creature hasn't be created as well. So it's not always a good solution.

#9
Morbane

Morbane
  • Members
  • 1 883 messages
global variable - then it is not important who killed sussurus

#10
Morbane

Morbane
  • Members
  • 1 883 messages
//Put this script OnEnter
#include "nw_i0_generic"
void main()
{

object oPC = GetEnteringObject();

if (!GetIsPC(oPC)) return;

if (GetGlobalInt("sussurus_alive")== 2)
{
FloatingTextStringOnCreature("You hear the worrying noise of sarcophagus lids being opened...", oPC);

location lTarget = GetLocation(GetWaypointByTag("i1"));

CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_dagger", lTarget);

lTarget = GetLocation(GetWaypointByTag("i2"));

CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_dagger", lTarget);

lTarget = GetLocation(GetWaypointByTag("i3"));

CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_club", lTarget);

lTarget = GetLocation(GetWaypointByTag("i4"));

CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_club", lTarget);

lTarget = GetLocation(GetWaypointByTag("i5"));

CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_dagger", lTarget);

lTarget = GetLocation(GetWaypointByTag("i6"));

CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_dagger", lTarget);

lTarget = GetLocation(GetWaypointByTag("i7"));

CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_dagger", lTarget);

lTarget = GetLocation(GetWaypointByTag("i8"));

CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_club", lTarget);

DestroyObject(GetObjectByTag("trigger_south_south"), 0.0);

}

}

#11
Morbane

Morbane
  • Members
  • 1 883 messages
the script above compiles and is a bit simpler - dont worry your skeleton WILL attack as long as they are HOSTILE Faction

#12
Clyordes

Clyordes
  • Members
  • 300 messages
Awesome ideas folks - as always I'm right impressed - will test them as soon as my wife gets engrossed in a reality TV show :-)

Cly.

#13
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages
Hi,

Use Global Ints or attach the Local Int to the object in question and compare it there instead of on the PC. Which one you decide to use depends on whether the resource is around to attach a local int to ... all of the time. e.g. Even if you use just one of the coffins where the skeletons are due to come out, add, remove and check variables from that object only. (Don't forget to make it plot if you do though, so the object carrying the ints is not lost.)

If there is no object to use with local ints and/or you have not used many globals, then global ints are very convenient instead. The only reason I might use a local int on an object rather than a variable is simply because I have (irrational) visions of loadsof global variables hanging around a module taking up resources, even when a player is nowhere near an area where they may be used. Having the ints local on nearby objects (if possible) feels more "modular" to me, that is all. ;)

BTW, Sussurus - "The Lichway" perchance? ;)

Lance.

#14
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages
REMOVED DOUBLE POST - The forum really has slowed its updating lately.

Modifié par Lance Botelle, 04 décembre 2011 - 06:21 .


#15
Dann-J

Dann-J
  • Members
  • 3 161 messages

Kaldor Silverwand wrote...

Does GetIsDead work once the creature is destroyed?


That's pretty much the point of the function. If the creature is alive (or undead) and well, even if it's script-hidden, it returns FALSE. If it doesn't exist (was never spawned, or has been killed), if returns TRUE.

Provided the sussurus is a creature that was placed somewhere using the toolset (rather than spawned in), and it has a unique tag,  then the function should always work as expected.

Why use the round-about route of setting a variable in an OnDeath script, then rely on that variable to tell you if the creature is dead, when GetIsDead() will tell you directly? All you'd be doing is creating more ways for things to go wrong.

Modifié par DannJ, 04 décembre 2011 - 10:30 .


#16
Kaldor Silverwand

Kaldor Silverwand
  • Members
  • 1 585 messages

DannJ wrote...

Kaldor Silverwand wrote...

Does GetIsDead work once the creature is destroyed?


That's pretty much the point of the function. If the creature is alive (or undead) and well, even if it's script-hidden, it returns FALSE. If it doesn't exist (was never spawned, or has been killed), if returns TRUE.

Provided the sussurus is a creature that was placed somewhere using the toolset (rather than spawned in), and it has a unique tag,  then the function should always work as expected.

Why use the round-about route of setting a variable in an OnDeath script, then rely on that variable to tell you if the creature is dead, when GetIsDead() will tell you directly? All you'd be doing is creating more ways for things to go wrong.


Seems like a strange function. It isn't really checking if something is dead since something that never existed will return true. Sounds like it is basically just a wrapper for an object existence check. In this case I suspect it is limited to searching areas in the current module, so if the check is being done in a different module than the creature is/was in then it may return a false positive.

Regards

Modifié par Kaldor Silverwand, 04 décembre 2011 - 10:57 .


#17
Dann-J

Dann-J
  • Members
  • 3 161 messages
Yes - it's more of an anti-GetIsAlive() function.

And I agree, having multiple modules might complicate things. But then that also complicates a lot of other script checks. However, you could always loop through all modules and their areas to search for the object that you plug into the function - although that would pretty much make the function itself redundant.

In the case of multiple modules, a simple global variable would be the better option.

#18
Clyordes

Clyordes
  • Members
  • 300 messages
Hi Lance,
The variable that changes when the Sussurus is killed is a local variable set in the 'local variables' section of the area properties - not global (although I wondered if it should be) & not on an object - did I do wrong?

As for the trigger script just checking if old windy britches is still in teh game using the GetIsDead function - that may be the obvious solution (well - another one :-)).

Finally - Sussurus - Yep - its the Lichway - do you remember it from way back too?

Cly.

#19
Clyordes

Clyordes
  • Members
  • 300 messages
Hang on - scrub that - the variable WAS local, but I changed it to global so it would have an effect in different areas.

#20
Clyordes

Clyordes
  • Members
  • 300 messages
Hi folks,

Had a short play earlier on using the script that Morbane kindly provided.  For some (probably obvious) reason, its still not triggering my nice spawning undead unless its the main PC who walks into the trigger - other companions can walk in & out without anything happening.

I was going to try the GetIsDead function, but although I can use it fine in conversations (what with the handy 'insert variables in these clearly marked boxes approahc used in convos), I'm just sitting staring at the blank script editor with a big dumb look on my face - so can anyone give me a clue what goes where in this function to make it work with the script I have above?

Apologies if that's a big ask. :unsure:

Cly.

#21
_Knightmare_

_Knightmare_
  • Members
  • 643 messages
Does the float string fire off and the creatures are just not spawning or does the float string not show up either as if nothing in the script is working? I have a couple ideas based off your response there.

#22
bealzebub

bealzebub
  • Members
  • 352 messages
couldn't you just remove the check?
if (!GetIsPC(oPC)) return;
just make sure no wandering monsters are near.

#23
_Knightmare_

_Knightmare_
  • Members
  • 643 messages

bealzebub wrote...

couldn't you just remove the check?
if (!GetIsPC(oPC)) return;
just make sure no wandering monsters are near.


Could just change it to

if(!GetIsRosterMember(oPC)) return;

#24
Clyordes

Clyordes
  • Members
  • 300 messages
Hi folks,

Just run a couple of tests with the following script:

location lTarget;
object oSpawn;
object oTarget;
/* Script generated by
Lilac Soul's NWN Script Generator, v. 2.3

For download info, please visit:
http://nwvault.ign.c...&id=4683&id=625 */

//Put this script OnEnter
#include "nw_i0_generic"
void main()
{

object oPC = GetEnteringObject();

//if (!GetIsPC(oPC)) return;
if(!GetIsRosterMember(oPC)) return;

if (GetLocalInt(oPC, "sussurus_alive")== 2)
{
FloatingTextStringOnCreature("You hear the worrying grating of stone on stone...", oPC);



oTarget = GetWaypointByTag("i1");

lTarget = GetLocation(oTarget);

oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_dagger", lTarget);

oTarget = oSpawn;

SetIsTemporaryEnemy(oPC, oTarget);

AssignCommand(oTarget, ActionAttack(oPC));

AssignCommand(oTarget, DetermineCombatRound(oPC));

oTarget = GetWaypointByTag("i2");

lTarget = GetLocation(oTarget);

oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_dagger", lTarget);

oTarget = oSpawn;

SetIsTemporaryEnemy(oPC, oTarget);

AssignCommand(oTarget, ActionAttack(oPC));

AssignCommand(oTarget, DetermineCombatRound(oPC));

oTarget = GetWaypointByTag("i3");

lTarget = GetLocation(oTarget);

oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_club", lTarget);

oTarget = oSpawn;

SetIsTemporaryEnemy(oPC, oTarget);

AssignCommand(oTarget, ActionAttack(oPC));

AssignCommand(oTarget, DetermineCombatRound(oPC));

oTarget = GetWaypointByTag("i4");

lTarget = GetLocation(oTarget);

oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_club", lTarget);

oTarget = oSpawn;

SetIsTemporaryEnemy(oPC, oTarget);

AssignCommand(oTarget, ActionAttack(oPC));

AssignCommand(oTarget, DetermineCombatRound(oPC));

oTarget = GetWaypointByTag("i5");

lTarget = GetLocation(oTarget);

oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_dagger", lTarget);

oTarget = oSpawn;

SetIsTemporaryEnemy(oPC, oTarget);

AssignCommand(oTarget, ActionAttack(oPC));

AssignCommand(oTarget, DetermineCombatRound(oPC));

oTarget = GetWaypointByTag("i6");

lTarget = GetLocation(oTarget);

oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_dagger", lTarget);

oTarget = oSpawn;

SetIsTemporaryEnemy(oPC, oTarget);

AssignCommand(oTarget, ActionAttack(oPC));

AssignCommand(oTarget, DetermineCombatRound(oPC));

oTarget = GetWaypointByTag("i7");

lTarget = GetLocation(oTarget);

oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_dagger", lTarget);

oTarget = oSpawn;

SetIsTemporaryEnemy(oPC, oTarget);

AssignCommand(oTarget, ActionAttack(oPC));

AssignCommand(oTarget, DetermineCombatRound(oPC));

oTarget = GetWaypointByTag("i8");

lTarget = GetLocation(oTarget);

oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_club", lTarget);

oTarget = oSpawn;

SetIsTemporaryEnemy(oPC, oTarget);

AssignCommand(oTarget, ActionAttack(oPC));

AssignCommand(oTarget, DetermineCombatRound(oPC));

oTarget = GetObjectByTag("trigger_south_south");

DestroyObject(oTarget, 0.0);

}
else
{
}

}

As before, the trigger only fires properly if you're controlling the main PC when entering the trigger. If controlling any other member of the party, even if the main PC is following & walks through the trigger - nothing happens.

Hopefully you can see from the script what I've changed, but if you have any other questions, please shout up. I'm sure there's an easy answer, but with my poor script knowledge, I can't see it.

Knightmare - the floating text string isn't showing - so I'm guessing that unless you're controlling the main PC, the entire script isn't firing.

I guess for most players, this won't even be an issue, as they'll be in control of their main PC for most of the time, but for anyone (like me) who likes to send a scout off ahead, or control different party members at different times, this is something I'd definitely like to fix.

Cly.

#25
_Knightmare_

_Knightmare_
  • Members
  • 643 messages
Use the following as the OnDeath script for the creature you want to later check for death (sussurus):

void main()
{
// Set Global Int
SetGlobalInt ("sussurus_alive", 2);

// Execute default OnDeath script
ExecuteScript("nw_c2_default7", OBJECT_SELF);
}

Then try the following for the trigger OnEnter script:

//Put this script OnEnter
#include "nw_i0_generic"
void main()
{
object oPC = GetEnteringObject();
if (!GetIsRosterMember(oPC)) return;
if (GetGlobalInt("sussurus_alive")== 2)
 {
 // Set Global Int to 3 so that this does not fire off multiple times when multiple party members walk through at same time
 SetGlobalInt("sussurus_alive", 3);
 FloatingTextStringOnCreature("You hear the worrying noise of sarcophagus lids being opened...", oPC);
 location lTarget;
 string sRand;
 int nRand;
 // Spawn in creatures
 for (nRand = 1; nRand < 9; nRand++)
  {
  sRand = IntToString(nRand);
  lTarget = GetLocation(GetNearestObjectByTag("i" + sRand, oPC));
  if ((nRand == 3) || (nRand == 4) || (nRand == 8))
   {
   CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_club", lTarget);  
   }
  else
   {
   CreateObject(OBJECT_TYPE_CREATURE, "lichway_skele_dagger", lTarget);
   }
  }
 DestroyObject(GetNearestObjectByTag("trigger_south_south", oPC), 0.0);
 }
}

The stuff in the "for" loop is just a shortcut method instead of listing every different creature out. If the creature blueprints are of the Hostile faction, you should not have to force them into combat.

Above codes compile but not tested.