Aller au contenu

Photo

Creatures to die with master, randomly.


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

#1
andysks

andysks
  • Members
  • 1 650 messages

Hi all. Title doesn't say exactly what I want because I didn't know how to express myself. But here it goes.

I have a situation of an epic battle. The number of creatures will be quite big.

Some big ones, and some minions. Say... death knights and normal skeletons or something.

 

What I want, is whenever one of the big ones dies in combat, a random number of the small ones to perish with him. With some scream and vfx of course but that I can do. What I can't, is the math of picking random number of creatures by... tag? Nearest? No idea.

 

If I wanted to get it a bit further, maybe I would prefer this to be the only way of beating this battle. Maybe the small minions keep spawning every X seconds, until all the big ones die.

 

Possible?

 

Thanks a lot.

Andy.



#2
MERP_UK

MERP_UK
  • Members
  • 96 messages

Sounds like a cool idea. Definitely doable, though I'm not entirely sure of how. Looping through object tags and making stuff happen isn't something i've quite got the hang of yet.

 

In terms of the random number of minion deaths, would a die roll suffice? You could actually size the die to roll on the relative CR of the "big guy" who falls. E.g; Balor = kill d6 minions, Balor Lord = Kill 2d6 minions, or whatever suits your needs. The result gives you your number. As for how you then cycle through the minions, im not so sure, but i'd be as interested as you are in the solution.

 

It's a great idea, keep at it. Hope you get the complete answer you need.

Kevin



#3
Tchos

Tchos
  • Members
  • 5 054 messages

Completely doable, including your preferred scenario.  Many different potential approaches.  The group functions might be a good way to do it.  I'd use a controller for each summoner, personally.



#4
andysks

andysks
  • Members
  • 1 650 messages

Tchos, I thought the same right after I posted the initial thread.

 

I don't know about randomness, but what if a certain number of minions exist in a group, then when the big guy dies the group gets destroyed. I've done such a thing in the past, and I know it is doable. I just don't know how to implement randomness to make it a bit more interesting... I guess.

 

I thought, what if 10 minions are under 1 summoner, but only 5 of them are in a group. Then when he dies the grouped(5) will die leaving the rest 5. It's like a fake random effect I guess.

 

Kevin, looping is my doom too. I just can't understand how it's done :).



#5
4760

4760
  • Members
  • 1 207 messages

Still using a loop, but not involving any groups:

- each boss has a unique name

- each boss's minion has a number appended to the boss name (so if the boss is "c_deathknight_a", he'll be followed by "c_deathknight_a01", "c_deathknight_a02", etc...)

- when the boss dies, his OnDeath event chooses a random number of minions to kill at the same time, and starting from 01 to the end, a loop kills all surviving minions until the number is reached (or all minions following this boss are killed).

 

The loop in this case will be like:

	int nInt=1;
	string sInt;
	string sBoss = "c_deathknight_a";
	int nNumber = Random(8); //between 0 and 7 killed when sBoss dies
        object oMinion;
        int nTotal=12; //assuming 12 minions are following the boss
        while (nInt<nNumber)
        {
             sInt = IntToString(nInt);
             oMinion = GetObjectByTag(sBoss+sInt);
             if (GetCurrentHitPoints(oMinion) > 0)
             {
                   DestroyObject(oMinion);
                   nInt++;
             }
             else nTotal--;
             // are there any minions left?
             if nTotal <= nNumber break; //no, exit the loop
         }

 

A better script would get nNumber, nTotal and sBoss values from variables attached to the boss (using GetLocalInt and GetLocalString).


  • MERP_UK et andysks aiment ceci

#6
andysks

andysks
  • Members
  • 1 650 messages

See, this is something I could never do. But it's a good script as a template as well so that I refer to it if I need such things in the future. One thing. Can we make it so that the random number, say for the 0-7 minions you have there is at least 4 or something? That is, 4-7 will die. Because if by a chance 0 die, then there are simply too many to handle. The whole idea was for the player to realize that if the boss dies, it is the way to go, because his minions follow.



#7
4760

4760
  • Members
  • 1 207 messages

Sure, change 

int nNumber = Random(8);

to

int nNumber = Random(4) + 4; // at least 4, maximum 7 [random(n) will return an integer value between 0 and n-1

Regarding the variables: in the creature's properties, add variables nVariableKilled (integer), nMinKilled (integer), nTotal (integer) and sBoss (string) and replace in the previous script

	string sBoss = GetLocalString(OBJECT_SELF, "sBoss");
	int nNumber = Random(GetLocalInt(OBJECT_SELF, "nVariableKilled")) + GetLocalInt(OBJECT_SELF, "nMinKilled"));
        int nTotal = GetLocalInt(OBJECT_SELF, "nTotal");

For your example, nVariableKilled will be 4 and nMinKilled will be 4.


  • MERP_UK aime ceci

#8
andysks

andysks
  • Members
  • 1 650 messages

Alright... it didn't work and I don't know why. Let's see, this is how the script looks right now.

/***************************
Experimental script
Return of the Exile
Andy
15.01.2015
///////////////////////////
When we fight the generals in the Plane of Knowledge, there will be an absurd number of undeads around. Around 60 in totals.
But when one of the generals dies, a random number of these minions will go with him.
***************************/
//Script by 4760 :)

void main()
{
	    int nInt=1;
	    string sInt;
	    string sBoss = GetLocalString(OBJECT_SELF, "sBoss");
	    int nNumber = Random(GetLocalInt(OBJECT_SELF, "nVariableKilled") + GetLocalInt(OBJECT_SELF, "nMinKilled"));
            object oMinion;
            int nTotal = GetLocalInt(OBJECT_SELF, "nTotal");
        while (nInt<nNumber)
        {
             sInt = IntToString(nInt);
             oMinion = GetObjectByTag(sBoss+sInt);
             if (GetCurrentHitPoints(oMinion) > 0)
             {
		   effect eExplosion = EffectNWN2SpecialEffectFile( "fx_kos_power_spell");
	           ApplyEffectToObject(DURATION_TYPE_INSTANT, eExplosion, OBJECT_SELF);
		   object oSound = GetNearestObjectByTag("so_pl_gen_death");
		   SoundObjectPlay(oSound);
                   DestroyObject(oMinion);
                   nInt++;
             }
             else nTotal--;
             // are there any minions left?
             if (nTotal <= nNumber)	  break; //no, exit the loop
			  
       }
}		 

This runs on the OnDeath. The generals are created from convo using ga_create_object and the minions spawn from encounter, also from the convo just before the fight starts. When I kill one of them, nothing happens. Any ideas?

 

Edit: Added some debugs in between the main actions, that is where the minions get destroyed etc. They didn't fire. I use SendMessageToPC, and I didn't see anything on my chat window. That means that the script doesn't fire at all? But why?



#9
4760

4760
  • Members
  • 1 207 messages

I can confirm that the code works (except that in your case the number of minions following the general in death will be between 0 and nVariableKilled+nMinKilled-1, since you pass nVariableKilled+nMinKilled to the Random() function:

int nNumber = Random(GetLocalInt(OBJECT_SELF, "nVariableKilled") + GetLocalInt(OBJECT_SELF, "nMinKilled"));

You need to move the second closing parenthesis after nVariableKilled, as follows:

int nNumber = Random(GetLocalInt(OBJECT_SELF, "nVariableKilled")) + GetLocalInt(OBJECT_SELF, "nMinKilled");

That way, the number of minions to destroy will be between nMinKilled and nMinKilled+nVariableKilled-1, since Random() will return a number between 0 and nVariableKilled-1, which will be added to nMinKilled.

 

 

Here's the code I tried (same as yours, the only difference with yours being the correction above and the addition of some SendMessageToPC statement to show what happens):

/*****************************
Experimental script
Return of the Exile
Andy
15.01.2015
////////////////////////////
When we fight the generals in the Plane of Knowledge, there will be an absurd number of undeads around. Around 60 in totals.
But when one of the generals dies, a random number of these minions will go with him.
***************************/
//Script by 4760 :)

void main()
{
	int nInt=1;
	string sInt;
	SendMessageToPC(GetFirstPC(), GetName(OBJECT_SELF));
	string sBoss = GetLocalString(OBJECT_SELF, "sBoss");
	int nNumber = Random(GetLocalInt(OBJECT_SELF, "nVariableKilled")) + GetLocalInt(OBJECT_SELF, "nMinKilled");
	object oMinion;
	int nTotal = GetLocalInt(OBJECT_SELF, "nTotal");
	SendMessageToPC(GetFirstPC(), sBoss+" killed, " + IntToString(nNumber) + " out of " + IntToString(nTotal) + " die with him!");
	effect eExplosion = EffectNWN2SpecialEffectFile( "fx_kos_power_spell");
	ApplyEffectToObject(DURATION_TYPE_INSTANT, eExplosion, OBJECT_SELF);
	while (nInt<=nNumber)
	{
		sInt = IntToString(nInt);
		oMinion = GetObjectByTag(sBoss+sInt);
		if (GetCurrentHitPoints(oMinion) > 0)
		{
			object oSound = GetNearestObjectByTag("so_pl_gen_death");
			SoundObjectPlay(oSound);
			DestroyObject(oMinion);
			SendMessageToPC(GetFirstPC(), "Killed so far: " + IntToString(nInt));
			nInt++;
		}
		else nTotal--;
		// are there any minions left?
		if (nTotal <= nNumber)	  break; //no, exit the loop
       }
}		 

Ah, there's another difference: I moved the special effect out of the loop so it's only executed once, and not each time a minion dies.

 

 

And here are the results:

901-1-1421421452.jpg

 

901-2-1421421452.jpg

 

 

So the problem (if not only coming from the Random() function) probably comes from the variables. Here's a quick tutorial on how to do it (you may not need it, but it could be useful to others anyway):

 

1) In the creature's properties, at the very last line, click on the ... button at the end:

901-1-1421421473.png

 

2) This will open a window similar to the one below:

901-3-1421421452.png

 

3) Click on the "Add" button to get the window below:

901-4-1421421452.png

In the "Name" field, put the variable name (in our case, sBoss, nVariableKilled, nMinKilled or nTotal)

For sBoss, put the name of the general in the ValueString field. For the other three variables, as they're integer, put the values in the ValueInt field:

901-5-1421421452.png

 

4) In the end, you should get this:

901-2-1421421473.png

 

If that's what you did, the next thing to check is if the tags of the general's minions match the pattern sBoss+number. In the example above, the general's tag being "c_rat", the twelve minions should have tags between "c_rat1" and "c_rat12".


  • MERP_UK aime ceci

#10
andysks

andysks
  • Members
  • 1 650 messages

Alright. Things get clearer.

 

The script works of course, when I corrected the things you said. All debugs run fine.

 

Only problem, the creatures don't get destroyed. Tags are all there so I don't know why they're not. Debug even says:

 

killed so far: 5

killed so far: 6

killed so far: 7

etc.

But the creatures don't go away, they stay to fight. What do you think can cause such a thing?

 

Could it be because they spawn via encounter?

I could make them scripthidden and then show them... if you think it could play a role :).



#11
4760

4760
  • Members
  • 1 207 messages

:unsure: A mistake in the loop...

 

Try this instead:

/***************************
Experimental script
Return of the Exile
Andy
15.01.2015
///////////////////////////
When we fight the generals in the Plane of Knowledge, there will be an absurd number of undeads around. Around 60 in totals.
But when one of the generals dies, a random number of these minions will go with him.
***************************/
//Script by 4760 :)

void main()
{
	int nInt=1;
	int nKilled=0;
	string sInt;
	SendMessageToPC(GetFirstPC(), GetName(OBJECT_SELF));
	string sBoss = GetLocalString(OBJECT_SELF, "sBoss");
	int nNumber = Random(GetLocalInt(OBJECT_SELF, "nVariableKilled")) + GetLocalInt(OBJECT_SELF, "nMinKilled");
	object oMinion;
	SendMessageToPC(GetFirstPC(), sBoss+" killed, " + IntToString(nNumber) + " die with him!");
	effect eExplosion = EffectNWN2SpecialEffectFile( "fx_kos_power_spell");
	ApplyEffectToObject(DURATION_TYPE_INSTANT, eExplosion, OBJECT_SELF);
	while (nKilled<nNumber)
	{
		sInt = IntToString(nInt);
		oMinion = GetObjectByTag(sBoss+sInt);
		SendMessageToPC(GetFirstPC(), sBoss+sInt + " ?");
		if (GetCurrentHitPoints(oMinion) > 0)
		{
			object oSound = GetNearestObjectByTag("so_pl_gen_death");
			SoundObjectPlay(oSound);
			SendMessageToPC(GetFirstPC(), "Killing " + GetTag(oMinion));
			DestroyObject(oMinion);
			nKilled++;
			SendMessageToPC(GetFirstPC(), "Killed so far: " + IntToString(nKilled) + " (" + sBoss+sInt + ")" );
		}
		nInt++;
	}
}

For your information, the mistake was that nInt (the counter of minions killed) was used both for the number of minions killed and the tag index, so as soon as one of the minions was found dead already, the script ended.

I now put nKilled as the counter of minions killed and nInt as the index number.

 

Note that this version doesn't need to know how many minions follow the general (no more need for a nTotal variable).



#12
andysks

andysks
  • Members
  • 1 650 messages

Same thing happens. I even added an effect on every minion that dies, in order to know which is which, a small fire now appears under the minion who is supposed to die.

So, as before, effect appears, debug says we killed so many, but they still hang around.

Could it be because they are too many or something?

We are talking about 6 generals, each one of them having 9 minions. This is 54 minion tags plus the 6 of the generals... 60 tags to keep track in one fight. I mean, all I can think of is this. A general dies, the script fires and searches to loop for tags but it find too many in the area. i don't know. This is what my simple scripting mind makes out of it :D.

Numbers can go down of course. This was the maximum.



#13
4760

4760
  • Members
  • 1 207 messages

OBJECT_SELF refers to the dying general, and sBoss to the tag his minions all share.

As long as the sBoss variable for the six generals is unique, the script will know whose minions to kill.

 

The latest script tells you the tag of the minion currently being checked ("sBoss + sInt") followed by a question mark, and if he's still alive it will also confirm he's been killed ("Killing " + GetTag(oMinion)).

 

So, are the tags of the minions based on the sBoss variable value?

 

For example, if three of the six generals have their respective "sBoss" variable set to "general1_", "generalA" and "general_chief", their minions will have their tags following the pattern "general1_1" to "general1_9", "generalA1" to "generalA9" and "general_chief1" to "general_chief9".

 

Is it the case in your module?

Assuming it is, what does the console say (before the "Killed so far" information, there should be a tag followed by a ?, and if the tag is valid and the creature it corresponds to is alive, it should also show "Killing " followed by the tag in question)?



#14
andysks

andysks
  • Members
  • 1 650 messages

Late reply, I wasn't home for a while. Here is the blueprint list.

 

blueprints_zpsea436957.jpg

 

And here are the variables.

 

variables_zps41fb6ea0.jpg

 

About the ?, I will test soon and report because I can't remember what the chat says on that occasion.

Thanks for the continuous help :).

 

Edit: After the test results

Chat window says:

 

c_pl_general_a1 ?

Killing c_pl_general_a1

Killed so far c_pl_general_a1

 

Then it goes on, to say the same until it reaches 6,7,8 whatever. And the creatures stay there.

Starting to wonder if it's something completely irrelevant that blocks them from getting destroyed? Because from the debugs the script runs flawlessly. Up until the end. It's just that the creatures don't get destroyed.



#15
4760

4760
  • Members
  • 1 207 messages

Here's a script providing more details:

/***************************
Experimental script
Return of the Exile
Andy
15.01.2015
///////////////////////////
When we fight the generals in the Plane of Knowledge, there will be an absurd number of undeads around. Around 60 in totals.
But when one of the generals dies, a random number of these minions will go with him.
***************************/
//Script by 4760 :)

void main()
{
	int nInt=1; // tag index
	int nKilled=0; // counter for minions killed so far
	object oGeneral = OBJECT_SELF;
	string sInt;
	SendMessageToPC(GetFirstPC(), GetName(oGeneral));
	string sBoss = GetLocalString(oGeneral, "sBoss");
	// how many minions will follow the general to the grave (random number between nMinKilled and nMinKilled+nVariableKilled-1)
	int nNumber = Random(GetLocalInt(oGeneral, "nVariableKilled")) + GetLocalInt(oGeneral, "nMinKilled");
	int nTotal = GetLocalInt(oGeneral, "nTotal"); // total number of minions following the general, used to exit the loop if there are less survivors than nNumber
	object oMinion;
	SendMessageToPC(GetFirstPC(), sBoss+" killed, " + IntToString(nNumber) + " die with him!");
	effect eExplosion = EffectNWN2SpecialEffectFile( "fx_kos_power_spell");
	ApplyEffectToObject(DURATION_TYPE_INSTANT, eExplosion, oGeneral);
	while (nKilled<nNumber)
	{
		sInt = IntToString(nInt);
		oMinion = GetObjectByTag(sBoss+sInt);
		SendMessageToPC(GetFirstPC(), "Is " + sBoss+sInt + " alive?");
		// if currently selected minion is alive, kill him
		if (GetCurrentHitPoints(oMinion) > 0)
		{
			object oSound = GetNearestObjectByTag("so_pl_gen_death");
			SoundObjectPlay(oSound);
			SendMessageToPC(GetFirstPC(), "Yes, killing " + GetTag(oMinion));
			DestroyObject(oMinion);
			nKilled++;
			SendMessageToPC(GetFirstPC(), "Killed so far: " + IntToString(nKilled) + " (" + sBoss+sInt + ")" );
		}
		else SendMessageToPC(GetFirstPC(), "No, next one");
		// select next minion (increase tag index)
		nInt++;
		// if all minions are dead, exit!
		if (nInt > nTotal) 
		{
			SendMessageToPC(GetFirstPC(), "All minions dead...");
			break;
		}
	}
}		 

I retested with two generals (one with sBoss = c_rat, the other one with sBoss = c_pl_general_d), and I got the expected results.

 

Looking at the tags and variables, everything looks good, so let's hope all the SendMessageToPC() statements will tell us what's going on!



#16
andysks

andysks
  • Members
  • 1 650 messages

Actually... Success B)

I don't know why, but it was the DestroyObject that was bugging the system. Everything was pointing that direction.

So I changed it with this.

effect eRealDeath = EffectDeath(TRUE, FALSE, TRUE, TRUE);
ApplyEffectToObject(DURATION_TYPE_INSTANT, eRealDeath, oMinion);

After that I got what#s expected. Minor things left, like the sound not playing as I noticed... but in general sounds tend to bug me when I call them from scripts. But this is something I can fix on my own, or even leave out. Thanks a lot for the help.

Curiocity question. Why would the effect work but the DestroyObject not?



#17
4760

4760
  • Members
  • 1 207 messages

I don't know.

Did you try the latest version of the script I posted? I'd be interested in knowing what the console reports, especially when the script reaches the lines before and after DestroyObject(oMinion):

 

            SendMessageToPC(GetFirstPC(), "Yes, killing " + GetTag(oMinion));
            SendMessageToPC(GetFirstPC(), "Killed so far: " + IntToString(nKilled) + " (" + sBoss+sInt + ")" );



#18
andysks

andysks
  • Members
  • 1 650 messages

Hi, sorry for the late reply, but since it worked I got caught up perfecting the scene. I will test it at some point to see why it's failing, with the debugs and DestroyObject. In the near future and I will let you know :).