Spawn once

Alright, so as I am slowly working through the quest list I have an issue I do not feel skilled enough to resolve or maybe I am overcomplicating things…

So basically I got an trigger set to spawn a single creature when the player is at a certain stage in the quest. What I noticed however is that whenever a pc steps into the trigger it spawns another boss…which could be problematic for lower levels.

So, I know there is th e DO_ONCE line but I wondered if there was a more efficient way to spawn one npc and have the other spawn only when the pc killed the other spawn or when the pc left the area?

I guess you could alter the boss’ OnDeath script where if it dies, it spawns another boss. Also look at the OnExit of the area and put a script there.

1 Like

Ultimately you need to have the trigger use a check to see if the PC triggered it recently or not. Regardless of whether you have the next beastie spawn OnDeath of the previous spawn or not, the trigger will fire again unless it has a limiter of some sort.
Simplest is to put a variable check at the front, if it passes, set the variable to track on the PC and then create the NPC. Then you can either remove the variable from the PC when the NPC dies or after a certain period of time.

If you use a trigger to generate your monster/NPC just put a test at the start of your trigger OnEnter script that reads a var saved on your trigger and exits the script if var is FALSE. Mod your monster OnSpawn script to write a FALSE state in the var when spawned. Mod the OnDeath script to write the var state TRUE to allow a new monster spawn. With this system you need to reenter the trigger to spawn your new monster/npc.

yes, I use a trigger. as of current I am using this script:

#include "nw_i0_generic"

void main()
{
    object oTarget;
    object oSpawn;

 // Get the creature who triggered this event.
    object oPC = GetEnteringObject();

    // Only fire for (real) PCs.
    if ( !GetIsPC(oPC)  ||  GetIsDMPossessed(oPC) )
        return;

    // Abort if the PC is not exactly at stage 2 of journal quest "FARMHAND".
    if ( GetLocalInt(oPC, "NW_JOURNAL_ENTRYMETEOR") != 3 )
        return;

    // Only fire once per PC.
    if ( GetLocalInt(oPC, "DO_ONCE__" + GetTag(OBJECT_SELF)) )
        return;
    SetLocalInt(oPC, "DO_ONCE__" + GetTag(OBJECT_SELF), TRUE);

    // Spawn "zep_goblinsha001".
    oTarget = GetWaypointByTag("WP_GOB_SHAMAN");
    oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "zep_goblinsha001", GetLocation(oTarget));
    AssignCommand(oSpawn, DetermineCombatRound(oPC));
}

So am fairly limited in my own skills so any help would be great :slight_smile:

For myself, I would be more explicit with the DO_ONCE check, but I think what you have there should work

if(GetLocalInt(oPC, "DO_ONCE_"+GetTag(OBJECT_SELF)==TRUE)
    return;

I tested your script and it works fine - the critter only spawned the one time. But I forget - did you want it to spawn again after the first critter is dead - just not while the critter is alive?

Maybe you could do the script like this, I don’t know:

#include "nw_i0_generic"

void main()
{
    object oTarget;
    object oSpawn;

 // Get the creature who triggered this event.
    object oPC = GetEnteringObject();

    // Only fire for (real) PCs.
    if ( !GetIsPC(oPC)  ||  GetIsDMPossessed(oPC) )
        return;
		
    // Abort if the PC is not exactly at stage 2 of journal quest "FARMHAND".
    if ( GetLocalInt(oPC, "NW_JOURNAL_ENTRYMETEOR") != 3 )
        return;

    // Only fire once per PC.
 if ( GetLocalInt(oPC, "DO_ONCE__" + GetTag(OBJECT_SELF)) )
        return;
    SetLocalInt(oPC, "DO_ONCE__" + GetTag(OBJECT_SELF), TRUE);
	
	if(GetGlobalInt("MonsterSpawned")) return;
	
	SetGlobalInt("MonsterSpawned",1);

    // Spawn "zep_goblinsha001".
    oTarget = GetWaypointByTag("WP_GOB_SHAMAN");
    oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "zep_goblinsha001", GetLocation(oTarget));
    AssignCommand(oSpawn, DetermineCombatRound(oPC));
}

And then on the OnDeath of the boss/monster, and the OnExit of the area, you put this in the code:

SetGlobalInt("MonsterSpawned",0);

If you want to explicitly spawn a new monster when leaving the area, just put this code you had before on the OnExit maybe:

 // Spawn "zep_goblinsha001".
    oTarget = GetWaypointByTag("WP_GOB_SHAMAN");
    oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "zep_goblinsha001", GetLocation(oTarget));
    AssignCommand(oSpawn, DetermineCombatRound(oPC));

I’m a little confused as to exactly how you want this to be done, but maybe you’ve got the gist of it now with the answers from everyone here.

The “== TRUE” is redundant. The other way is fine and shorter.

1 Like

@Dragonqueeny

What you have should work, and only generate a monster when the int DO_ONCE__xxxx var is FALSE. Maybe there is some other problem. For purpose of testing, i will change the fabricated var name (“DO_ONCE__”+GetTag(OBJECT_SELF) for a simple one like only “GOBSHA” and try saving the Var on the trigger in place of the PC (replace oPC by OBJECT_SELF inside all GetLocalInt() and SetLocalInt()). If you want to push things before testing, you can write manually the var “GOBSHA” to the trigger and give it the FALSE (0) or TRUE (1) value using the “Variables” option in the “Advanced” page of the trigger Properties (choose int type).

This format works all the upto spawning, I normall add a journal advance in death so there is no issue with respawning. Though when there is a guy with me and also stands on the trigger it will alsp spawn the boss.

We got killed by 2 fiery chickens last time which was supposed to be just 1.

Hope that makes any sense xD

Ah, so assuming the guy is another player, it fires for both because they are both PCs.

//add this maybe
if(GetLocalObject(OBJECT_SELF, "Spawn")!=OBJECT_INVALID) return;//spawn is still there
oTarget = GetWaypointByTag("WP_GOB_SHAMAN");
oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "zep_goblinsha001", GetLocation(oTarget));
SetLocalObject(OBJECT_SELF, "Spawned", oSpawn)

So we check if the previous spawn is still there. If it is, abort the script. If not we create the spawn and set it as a local object on the trigger. This way you can tell if the spawned critter is still alive or not.

Over the years, I’ve found NWNscript can be dumb sometimes - or maybe I am projecting. It could be coincidence but sometimes when scripts that should work fail for me, I put in some of the things that appear redundant and all of the sudden the script starts working for me. But you are right - the one I tested did not have the extraneous ==TRUE. ; )

So sorry for the delay! But the script you have given me us giving me errors when I try to test it T_T

It is a partial script to be added into your own - what kind of errors?

11-7-2020 19:26:33: Error. ‘test_pony_spawn’ did not compile.
test_pony_spawn.nss(8): ERROR: NO SEMICOLON AFTER EXPRESSION

So I am adding new ones, which will be a long list…

void main()
{
//add this maybe
if(GetLocalObject(OBJECT_SELF, "Spawn")!=OBJECT_INVALID) return;//spawn is still there
oTarget = GetWaypointByTag("WP_PONY");
oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "zep_pony_001", GetLocation(oTarget));
SetLocalObject(OBJECT_SELF, "Spawned", oSpawn)
}

This compiled and includes the beginning of the script you posted earlier…

#include "nw_i0_generic"

void main()
{
    object oTarget;
    object oSpawn;

 // Get the creature who triggered this event.
    object oPC = GetEnteringObject();

    // Only fire for (real) PCs.
    if ( !GetIsPC(oPC)  ||  GetIsDMPossessed(oPC) )
        return;

    // Abort if the PC is not exactly at stage 2 of journal quest "FARMHAND".
    if ( GetLocalInt(oPC, "NW_JOURNAL_ENTRYMETEOR") != 3 )
        return;
//add this maybe
if(GetLocalObject(OBJECT_SELF, "Spawn")!=OBJECT_INVALID) return;//spawn is still there
oTarget = GetWaypointByTag("WP_GOB_SHAMAN");
oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "zep_goblinsha001", GetLocation(oTarget));
SetLocalObject(OBJECT_SELF, "Spawned", oSpawn);
}