Script question - creatures with the same tag

I have placed a script with a function, that I thought would work, on the OnDeath of creatures with the same tag. When all the creatures are dead something is suppose to happen. Before, I have used a similar custom function for creatures with different tags, and that has always worked. For some reason this doesn’t. I must have missed something:

int CheckIfCreaturesWithTagAreAllDead(string EnemyTag)
{
    object oPC = GetFirstPC();
   
    object oNPC = GetNearestObjectByTag(EnemyTag,oPC);
	
	while(GetIsObjectValid(oNPC))
    {
        if(!GetIsDead(oNPC)) 
		{
			return FALSE;
        }
        
        oNPC = GetNearestObjectByTag(EnemyTag,oPC);
    }
	return TRUE;
}
1 Like

Hmmm, when testing again, it also seems that the computer has to work quite hard when this script is run. So maybe this function is bad for the game somehow making it work hard. Maybe I’ll just have to go back to the way I’ve always done things before, by using a general trigger and my own custom scripts, spawning in a few monsters, each with a different tag, as I know that works. But it’s quite a bit more work doing it like that all the time, that’s why I in this case wanted to use an Encounter Trigger so see if that would work, which I used a lot more in the past (but then there was just an encounter with not much else going on).

Well, now that I think of it, I can actually use the encounter trigger anyway, even if I spawn in - say - 5 different creatures (or the same creature but with 5 different tags like spider1, spider2 and so on…).

I have no idea, how the commands in NWN2 will work, but probably they’re quite similar as in NWN1.

This is how I would solve the problem:

object oNPC = GetFirstObjectInArea(area);
while(GetIsObjectValid(oNPC))
{
if GetTag (oNPC == “TheTag”)
if (!GetIsDead(oNPC)) return FALSE;
oNPC = GetNextObjectInArea(area);
}

Your “GetNearestObjectByTag” within the loop will probably return always the same creature.

3 Likes

Hmm, yes, you may have a point there.

And, as you say, NWN1 and NWN2 scripting is very similar most of the times.

I have moved on to doing this like I did the other encounters I have with checking for dead NPCs though. If I attempt this kind of thing again, I’ll go back and check your script. Thanks!

FYI, encounter triggers have a unique OnExhausted event. This event fires when all of the creatures spawned from the encounter trigger are dead. It may prove to be useful in your situation.

2 Likes

Thanks travus! That’s really good to know.

Now, I have some other problem with this, and it’s REALLY weird. I don’t have a clue as to what’s going on. Like I said in my previous post, I went and “solved” this situation by doing it the way I did before, with a custom script spawning each and every creature. Every creature has a different tag but…well, they are called l_dogwolf1, l_dogwolf2 and so on…So I used the function I had used successfully before, but now when not all of them are dead, the game thinks all of them are dead. So, I went back to a previous discussion and used your, slightly different script for this, and tried it, and it the game STILL does things it should do when only all are dead, instead when almost each and everyone of them dies. The function looks like this:

int CheckIfCreaturesWithTagAreAllDead(object oPC, string EnemyTag)
{
    int n = 1;
    object oNPC = GetNearestObjectByTag(EnemyTag + IntToString(n), oPC);
	
	while(GetIsObjectValid(oNPC))
    {
        if(!GetIsDead(oNPC)) return FALSE;
        n++;
        oNPC = GetNearestObjectByTag(EnemyTag + IntToString(n), oPC);
    }
	
	return TRUE;
}

What I did, that maybe somehow interfers with this is: I copied the first blueprint that had l_dogwolf1 on Tag, Resource and Resref and gave the new blueprint l_dogwolf2 on Tag, Resource and Resref but…I mean, the script checks for the tags so…I don’t know what to do right now! This is so frustrating! :woozy_face: :weary: :confounded: :crazy_face:

Ok, I’m not making myself clear I think:

What I want: When all die, something should happen.
What happens in game: When 2 wolves (instead of all of them, they are 6) die the “something” that should happen, happens.

So why does the game run the script before all are dead?

I’m wondering if this loop is somehow wrong (but why did it work before then!). I mean, if the game checks if the l_dogwolf1 is dead, then maybe it returns TRUE even if the others are alive? But…the while loop isn’t finished by then so…urrgghh…

EDIT: Could it have something to do with me copying the c_dogwolf blueprint? Something I haven’t thought about there perhaps?

Use ginc_group functions.

Put your objects in a group and set a script for when all the members of the group have died.

1 Like

GetNearestObjectByTag() takes an iterator …

int CheckIfCreaturesWithTagAreAllDead(string EnemyTag)
{
    object oPC = GetFirstPC();

    int i = 1;
    object oNPC = GetNearestObjectByTag(EnemyTag, oPC, i);
    while (GetIsObjectValid(oNPC))
    {
        if (!GetIsDead(oNPC)) 
            return FALSE;

        oNPC = GetNearestObjectByTag(EnemyTag, oPC, ++i);
    }
    return TRUE;
}

The engine was working hard because it was finding the same creature over and over and over. the loop didn’t end until the engine emitted a TMI (too many instructions) error to itself.

1 Like

Tried your script, @kevL_s . It’s the same as before, I’m afraid. Everytime I kill a wolf the something that’s to happen when all are dead, happens each time instead. I must be doing something weird somehow.

I’ll try with @Shallina 's suggestion. I think I have an old script for my very first module where it was made that way, I believe. I’ll look that up and see if I can modify that script perhaps.

I still don’t get what is happening though, as my own, travus’ and kevL_s’ way should work since it has worked in this very same module before. It must be something I’m doing wrong with all this…

Mmm, yeah, that makes sense.

personally i like Mmat’s thing

object oNPC = GetFirstObjectInArea(area);
while (GetIsObjectValid(oNPC))
{
    if (GetObjectType(oNPC) == OBJECT_TYPE_CREATURE
        && GetTag(oNPC) == "TheTag"
        && !GetIsDead(oNPC))
    {
        return FALSE;
    }
    oNPC = GetNextObjectInArea(area);
}
return TRUE;
1 Like

Yeah, it is another way of doing it. Maybe one could modify that with adding numbers…

Don’t know if this is correct:

int CheckIfCreaturesWithTagAreAllDead(string EnemyTag)
{
	object oArea = GetObjectByTag("Island"); 
	object oNPC = GetFirstObjectInArea(oArea);
	int n = 1;
	
	while (GetIsObjectValid(oNPC))
	{
    	if (GetObjectType(oNPC) == OBJECT_TYPE_CREATURE
        && GetTag(oNPC) == EnemyTag + IntToString(n)
        && !GetIsDead(oNPC))
    	{
        	return FALSE;
    	}
		n++;
    	oNPC = GetNextObjectInArea(oArea);
	}
	
	return TRUE;
}

Tried it, and the exact same thing happens as before. I don’t get it.

uhm, if you want to go with numbered tags id do something like this

const int iMax = 5; // or whatever the max count of creatures is or input max count as an argument

int i = 1;
while (i <= iMax)
{
    object o = GetNearestObjectByTag(EnemyTag + IntToString(i++), oPC);
    if (GetIsObjectValid(o)
        && GetObjectType(o) == OBJECT_TYPE_CREATURE
        && !GetIsDead(o))
    {
        return FALSE;
    }
}
return TRUE;
2 Likes

that doesn’t strike me as safe if corpses are decaying … if, say, corpse #3 decays that will break the loop early … or something, it just doesn’t strike me as robust atm

[edit] ah, the problem with looping over objects-in-the-area is that you’d have to check all numbered-tags against each object found.

pseudo-code:

o = FirstObjectInArea()
while (GetIsObjectValid(o))
{
    int i = 1;
    while (i <= iMax)
    {
        if (loop over each possible tag etc.)
            return FALSE;
    }
}

note the loop within a loop …

1 Like

Hmmm, I had no idea about that. Interesting…maybe that’s why this doesn’t work when it should.

I tried a really convoluted way of doing it and then it worked, but I really don’t want my script to look like this: :grinning_face_with_smiling_eyes:

void main()
{

	
	object oPC = GetFirstPC();
	
	object oWolf1 = GetObjectByTag("l_wolf1");
	object oWolf2 = GetObjectByTag("l_wolf2");
	object oWolf3 = GetObjectByTag("l_wolf3");
	object oWolf4 = GetObjectByTag("l_wolf4");
	object oWolf5 = GetObjectByTag("l_wolf5");
	object oWolf6 = GetObjectByTag("l_wolf6");
	
		
		if (GetIsDead(oWolf1) && GetIsDead(oWolf2) && GetIsDead(oWolf3) 
		&& GetIsDead(oWolf4) && GetIsDead(oWolf5) && GetIsDead(oWolf6)) 
		{
		
		   AddJournalQuestEntry("q_wolf",1,oPC);
		
		}
		
		
}

If nothing else works, I will fall back on this, I suppose.

EDIT: The thing is, when I did my new wolves to try out (I mean, I’m trying everything at this point), I look at their blueprints now and all of them have decay set to FALSE.

1 Like

give me a minute to refactor that into a loop, and see what happens …

I’m trying your latest version now @kevL_s and see what happens first (your int iMax thing).

Maybe this?

const int nMax = 6;

int CheckIfCreaturesWithTagAreAllDead(object oPC, string CreatureTag, int NumberOfCreatures)
{
    int n;
	object oCreature;
	
	for (n = 1; n <= NumberOfCreatures; n++) 
	{
		oCreature = GetNearestObjectByTag(CreatureTag + IntToString(n), oPC);	
		if (!GetIsDead(oCreature)) return FALSE;
    }
	
	return TRUE;
}

void main()
{
	object oPC = GetFirstPC(FALSE);
	string sTag = "l_dogwolf";
	
	if (CheckIfCreaturesWithTagAreAllDead(oPC, sTag, nMax))
	{
		SendMessageToPC(oPC, "All are dead");
	}
	
	ExecuteScript("nw_c2_default7", OBJECT_SELF);	
}

Thanks for another thing to try, @travus !

And I still haven’t been able to conjure up @Shallina 's suggestion yet.

However, now that I tried your script @kevL_s, it worked :

// Place on the OnDeath event of each wolf.

const int iMax = 6; // or whatever the max count of creatures is or input max count as an argument

int CheckIfCreaturesWithTagAreAllDead(string EnemyTag)
{

	object oPC = GetFirstPC();
	int i = 1;
	
	while (i <= iMax)
	{
    	object oEnemy = GetNearestObjectByTag(EnemyTag + IntToString(i++), oPC);
		
    	if (GetIsObjectValid(oEnemy)
        && GetObjectType(oEnemy) == OBJECT_TYPE_CREATURE
        && !GetIsDead(oEnemy))
    	{
        	return FALSE;
    	}
	}
	return TRUE;
}

void main()
{

object oPC = GetFirstPC();
	
		if(CheckIfCreaturesWithTagAreAllDead("l_wolf"))
		{
		
		   AddJournalQuestEntry("q_wolf",1,oPC);
		
		}
				
}

So what in the name of all that is…sacred, or something…was it that made the other versions not working? It’s so odd…