• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

[Trigger] Telegraph to [Triggering Player] upon level-up

Status
Not open for further replies.
Level 65
Joined
Dec 23, 2013
Messages
1,408
Howdy folks

I'm working on a system which puts up a private announcement to a player when their hero levels up
"Rank 2 - Skirmisher"
"Rank 3 - Sergeant"
"Rank 4 - Lieutenant"
etc
There's 10 players on 2 sides, and I'd like to make it so if a hero levels up, he gets a private telegraph of text on his screen, telling him his new Rank

Right now this is what I've got:

Events
Unit - A unit Gains a level
Conditions
((Triggering unit) is A Hero) Equal to True
(Owner of (Triggering unit)) Equal to Player 1 (Red)
(Owner of (Triggering unit)) Equal to Player 2 (Blue)
Etc for all 24 players
Actions
Cinematic - Send transmission to (_______) From Coldfells Sergeant named: Recruiter Aval: Play no sound and display "Blablablabla, Rank 2" Modify duration: Add 0.00 seconds and Wait.

I only just today started to do this, and don't know a thing about vJASS except that - It exists, and scripters like it
 
Level 65
Joined
Dec 23, 2013
Messages
1,408
I found part of it!

I can now display the text to (Player group((Triggering player)))
After this script plays, I've told it to turn off (Rank 1) and turn on the next one (Hero levels up, display Rank 2 to triggering player)
This is great, because as I level it shows the ranks properly from 1-15

But it no longer shows for players who didn't hit level 2+

Do I need to build rank 1-15 scripts for all 20 players?
 
Level 39
Joined
Feb 27, 2007
Messages
5,037
I would highly suggest that you learn how to use array variables to massively simplify things like this.
  • Events
    • Time - Elapsed game-time is 0.50 seconds
  • Conditions
  • Actions
    • Set RankMessageBase = "Congratulations soldier, you've reached a new rank. You're now a " //note the space at the end
    • Set RankMessage[2] = "Skirmisher (Rank 2)!" //don't need it for [1] since a unit can never 'level up' to level 1
    • Set RankMessage[3] = "Sergeant (Rank 3)!"
    • Set RankMessage[4] = "Lieutenant (Rank 4)!"
    • -------- ... --------
    • Set RankMessage[15] = "President (of everything)!"
  • Events
    • Unit - A unit gains a level
  • Conditions
    • ((Owner of (Triggering Unit)) controller) Equal to User
    • (Level of (Triggering Unit)) less than 16 //not necessary but this would be useful if units can level up beyond rank 15 and you don't want a message to display each time
  • Actions
    • Player Group - Add (Owner of (Triggering Unit)) to RankForce
    • Cinematic - Send transmission to RankForce From Coldfells Sergeant named: Recruiter Aval: Play no sound and display (RankMessageBase + RankMessage[(Level of (Triggering Unit))]) Modify duration: Add 0.00 seconds and Wait.
    • Player Group - Remove all players from RankForce
For an explanation of why you should use a player group variable here: Things That Leak
 
Level 65
Joined
Dec 23, 2013
Messages
1,408
Man, I'm struggling hard to recreate "(RankMessageBase + RankMessage[(Level of (Triggering Unit))])" and I can't seem to put []'s on the Variables like you have

Questions:
1 - How do I add on the +RankMessage bit to the Transmission with the Level?

2 - How do I make these only trigger for allies of player Red? (AI army)


Does this look right?
Noname.png
 
Level 39
Joined
Feb 27, 2007
Messages
5,037
I can't seem to put []'s on the Variables like you have
You’re just pulling the right text from the string array based on the level of the unit.
The existence of brackets always means its an array index, so the variable in question is an array. RankMessage[2] stores the message for rank 2, RankMessage[3] stores the message for rank 3, and so on. Rather than hardcoding reading a specifc index of the array (like using [15] would be) instead we are using the level of the unit as the index to get the correct message for that level: RankMessage[Level-of-unit].
1 - How do I add on the +RankMessage bit to the Transmission with the Level?
"Concatenate strings" allows you to splice two strings (or string variables) together into a longer string. GUI shows that as the + operation between strings.
2 - How do I make these only trigger for allies of player Red? (AI army)
  • Conditions
    • ((Triggering Unit) belongs to an ally of Player 1 (Red)) equal to True
Does this look right?
  • Don't screenshot, do this: How To Post Your Trigger.
  • If units can level up past 15 this will continue showing rank up messages for each level beyond that even though there are no fully defined rank messages. To avoid this use the condition: (Level of (Triggering Unit)) less than 16
  • Triggering Player in this instance is the same as Owner of (Triggering Unit) so will work properly here as well as in most scenarios, but it doesn't always produce the same player. Under the hood many events are called "Player unit events" and it works for those but not for other generic/specific unit events.
  • The transmission should be sent to RankForce, not to All Players.
  • RankForce needs to be cleared of players after the transmission is sent.
 
Level 65
Joined
Dec 23, 2013
Messages
1,408
My bad

I didn't know the strings were Arrays, too
I checked the Array box and gave them their numbers (1-15) but when I went back to look at them, they were all 1s again.
Hitting [Enter] didn't seem to change anything when I put it back in, and unchecking Array defaulted it back to 1 as well.
How do I make the Array number stick?

2nd question, under Conditions - how do I set it the Equal-to section to [User] I can't find that anywhere

  • Evil Rank Up
    • Events
      • Unit - A unit Gains a level
    • Conditions
      • (Owner of (Triggering unit)) Equal to (Picked player)
      • ((Triggering unit) belongs to an ally of Player 1 (Red).) Equal to True
    • Actions
      • Player Group - Add (Owner of (Triggering unit)) to RankForce
      • Game - Display to RankForce the text: (EvilRankMessageBase + EvilRank_Scout[1])
      • Player Group - Remove all players from RankForce.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,592
Question 1:
We'd have to see how you're setting the Arrays in your trigger but it sounds like you're misunderstanding something important. Hopefully these pictures can help clear things up.

All you have to do is create a String variable like you would create any kind of variable, except check the Array box as well:

Ex 3.png


Then you Set this variable like you would any other variable, except since it's an Array you have access to these [brackets] which allow you to store a lot more data than a normal variable. The number in these [brackets] is known as the index and you can only store one value per [index].

Here you can see me assigning different text values to each [index] of my String variable:
Ex 2.png


Question 2:
Here's the Condition for checking the Controller of a Player. A Player is either a User, Computer, Rescuable, Passive, or Hostile:
Ex 1.png


Question 3:
Your trigger is currently displaying whatever value you gave EvilRank_Scout[1] and doesn't take into consideration the Hero's level anywhere:
  • Evil Rank Up
    • Events
      • Unit - A unit Gains a level
    • Conditions
      • (Owner of (Triggering unit)) Equal to (Picked player)
      • ((Triggering unit) belongs to an ally of Player 1 (Red).) Equal to True
    • Actions
      • Player Group - Add (Owner of (Triggering unit)) to RankForce
      • Game - Display to RankForce the text: (EvilRankMessageBase + EvilRank_Scout[1])
      • Player Group - Remove all players from RankForce.
It also has an unnecessary Condition that wouldn't work anyway (I'm guessing you forgot to delete this?):
  • (Owner of (Triggering unit)) Equal to (Picked player)
What you need to do is plug in the Level of the Hero inside of the [index] of EvilRank_Scout[]:
  • Evil Rank Up
    • Events
      • Unit - A unit Gains a level
    • Conditions
      • ((Owner of (Triggering unit)) controller) Equal to User
      • ((Triggering unit) belongs to an ally of Player 1 (Red).) Equal to True
    • Actions
      • Player Group - Add (Owner of (Triggering unit)) to RankForce
      • Game - Display to RankForce the text: (EvilRankMessageBase + EvilRank_Scout[(Hero level of (Triggering unit))])
      • Player Group - Remove all players from RankForce.
So if the Hero is Level 1 then the Text Message will display whatever value you gave EvilRank_Scout[1].
If the Hero is Level 2 then it'll display whatever value you gave EvilRank_Scout[2]. This pattern will continue for as long as possible.

This type of design allows you to make more generic triggers/variables instead of having to specify everything. You can turn 100 variables into 1 variable (array) and 100 triggers into 1 trigger by simply storing your data in arrays and making clever use of their [indexes]. Remember, a lot of things in Warcraft 3 use Integers which can be used as the [indexes] in your arrays. For example: Hero level, Ability level, Player number, Hero attributes, the list goes on.

This also allows you to get data at random. For example, this displays a random EvilRank_Scout message assuming you had [15] of them:
  • Game - Display to RankForce the text: (EvilRankMessageBase + EvilRank_Scout[(Random integer number between 1 and 15)])
Quite useful for adding randomness to your map, like spawning random enemies or creating random items.
 
Last edited:
Level 65
Joined
Dec 23, 2013
Messages
1,408
Oh!
I didn't do the Set Variable part - I couldn't find it in the GUI
I found "Set VariableSet [variable name]" which didn't match, so I wasn't sure

Just did that now for all 15 ranks;
1 - Footman / Tracker
2 - Esquire / Scout
3 - Guardsman / Skirmisher
4 - Man-at-Arms / Fighter
5 - Sergeant of the Guard / Soldier
6 - Sergeant-at-Arms / Sentry
7 - Master Guardsman / Chief Guard
8 - Master-at-Arms / Chief Warrior
9 - High Warden / Taskmaster
10 - Lieutenant / Lieutenant
11 - Commander / Commander
12 - Third Marshall / Chieftain
13 - Second Marshall / High Chieftain
14 - First Marshall / Overlord
15 - Captain-General / Tyrant

Question 1:
How do I plug in a Hero Level to the script?
I double-click the action to edit it, and all I can see is:
Display to RankForce the text: (EvilRankMessageBase + EvilRank2[2])

Question 2:
How in the world do I replicate this? -> ((Owner of (Triggering Unit)) controller) Equal to User
With your help I was able to find the Owner of Triggering Unit = to User, but I have no idea how to get the Controller part on there
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,592
Anything that's underlined and/or colored blue can be opened and edited even further.

So you want to click the Text field, then you can select the [index] of EvilRank2, then you can either type your own integer Value, choose from a list of your integer Variables to use as the Value, or select from a list of Functions which will get you an integer Value (if able).

In this case you want to use the Hero - Hero Level function:

ex 4.png
 
Last edited:
Level 65
Joined
Dec 23, 2013
Messages
1,408
@Uncle Eyy, that did it!
For some reason, mine didn't have an Index field until I switched it over to Explicitly Timed, like yours

I'm still a little lost on how this'll read through the ranks per level-up, is this right?

  • Evil Rank Up
    • Events
      • Unit - A unit Gains a level
    • Conditions
      • ((Triggering unit) belongs to an ally of Player 1 (Red).) Equal to True
    • Actions
      • Player Group - Add (Owner of (Triggering unit)) to RankForce
      • Game - Display to (All players) for 10.00 seconds the text: (EvilRankMessageBase + EvilRank2[(Hero level of (Triggering unit))])
      • Player Group - Remove all players from RankForce.
 
Level 39
Joined
Feb 27, 2007
Messages
5,037
For some reason, mine didn't have an Index field until I switched it over to Explicitly Timed, like yours
You changed the variable from normal to array while it was already in use in that line, which GUI does not deal too well with (it didn’t update).

If the message isn’t right then either the variable you are trying to read was never set or the index you’re using is the wrong index. The index looks right so wherever you are defining EvilRank2[] it’s being done incorrectly.
 
Level 65
Joined
Dec 23, 2013
Messages
1,408
I think I found the issue - all of the values of EvilRank1(2-3-4-5, etc) have defaulted back to 1 again.

By messing around pressing the up/down arrows, hitting Enter a lot and clearing /resetting the Initial Value (rank name) I am inconsistently getting the number to update and stay changed

How do I easily change this and have it stick?


n.png
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,592
It looks like you're messing around with the variable's Initial Value. You're supposed to define the Variable's values in a "setup" trigger like this:
  • Events
    • Map initialization
  • Conditions
  • Actions
    • Set Variable EvilRank2[1] = Rank 1
    • Set Variable EvilRank2[2] = Rank 2
    • Set Variable EvilRank2[3] = Rank 3
    • Set Variable EvilRank2[4] = Rank 4
    • etc...
Initial Value is used for default values, which can come in handy in some cases but aren't necessary here as far as I can tell.

Also, there's a bug when trying to change the properties of a Variable outside of the Variable editor. Sometimes the changes don't stick, so I recommend ALWAYS editing your Variables inside of the Variable Editor (Control + B). And to clarify, I mean the pop-up window where you can adjust their Name/Type/Array/Size/Initial Value.
 
Last edited:
Level 65
Joined
Dec 23, 2013
Messages
1,408
Dude, you're a lifesaver

I had no clue Ctrl + B existed :D

  • Rank Setup
    • Events
      • Time - Elapsed game time is 0.50 seconds
    • Conditions
    • Actions
      • Set VariableSet EvilRank1[1] = Tracker
      • Set VariableSet EvilRank2[2] = Scout
      • Set VariableSet EvilRank3[3] = Skirmisher
      • Set VariableSet EvilRank4[4] = Skirmisher
      • Set VariableSet EvilRank5[5] = Soldier
      • Set VariableSet EvilRank6[6] = Sentry
      • Set VariableSet EvilRank7[7] = Chief Guard
      • Set VariableSet EvilRank8[8] = Chief Warrior
      • Set VariableSet EvilRank9[9] = Taskmaster
      • Set VariableSet EvilRank10[10] = Lieutenant
      • Set VariableSet EvilRank11[11] = Commander
      • Set VariableSet EvilRank12[12] = Chieftain
      • Set VariableSet EvilRank13[13] = High Chieftain
      • Set VariableSet EvilRank14[14] = Overlord
      • Set VariableSet EvilRank15[15] = Tyrant
      • -------- -------------------------- --------
      • Set VariableSet GoodRank1[1] = Footman
      • Set VariableSet GoodRank2[2] = Esquire
      • Set VariableSet GoodRank3[3] = Guardsman
      • Set VariableSet GoodRank4[4] = Man-at-Arms
      • Set VariableSet GoodRank5[5] = Sergeant of the Guard
      • Set VariableSet GoodRank6[6] = Sergeant-at-Arms
      • Set VariableSet GoodRank7[7] = Master Guardsman
      • Set VariableSet GoodRank8[8] = Master-at-Arms
      • Set VariableSet GoodRank9[9] = High Warden
      • Set VariableSet GoodRank10[10] = Lieutenant
      • Set VariableSet GoodRank11[11] = Commander
      • Set VariableSet GoodRank12[12] = Third Marshall
      • Set VariableSet GoodRank13[13] = Second Marshall
      • Set VariableSet GoodRank14[14] = First Marshall
      • Set VariableSet GoodRank15[15] = Captain-General
I thought I did it right; this is what I've got right now
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,592
So the problem is that you're using Arrays almost as if they are still just standard Variables.

Instead of creating 15 separate String variables with one variable for each rank, you should be creating 1 String array variable with 15 [indexes] and one [index] for each rank:
  • Events
    • Map initialization
  • Conditions
  • Actions
    • Set Variable EvilRank[1] = Tracker
    • Set Variable EvilRank[2] = Scout
    • Set Variable EvilRank[3] = Skirmisher
    • etc...
See how these are all the same variable and it's their [index] that changes. Now you may ask, why is that important?

Because now we can easily reference this variable in our Level Up trigger without running into the issue of having 15 different variables to choose from:
  • Game - Display to RankForce for 10.00 seconds the text: (EvilRankMessageBase + EvilRank[(Hero level of (Triggering unit))])
The [index] is what changes, not the variable itself.

You can think of an Array like a grocery list, I find that analogy helps. You wouldn't give each grocery item on your grocery list it's own sheet of paper, right? Instead, you'd write each grocery item down on the same sheet of paper as that's far more convenient.

So the paper is the Array and the groceries on it are the different [index] values.
GroceryItem[1] = Milk
GroceryItem[2] = Eggs
GroceryItem[3] = Chicken

Also, and this isn't too important to worry about yet, but a single array variable can only hold up to [32,768] different values. In other words, it's [index] cannot exceed 32,768. It's [index] also cannot be negative.

Lastly, you should use the Map initialization Event, not Elapsed Time is 0.50 seconds. You want these variables to be Set as early as possible since you plan on referencing them in your other triggers. If a Hero were to level up before 0.50 seconds had passed then none of the Strings would work since they hadn't been Set yet. Not to call out Pyro though, 0.50 seconds works fine as an example and there's some reasons why you may want to use it instead.
 
Last edited:
Level 39
Joined
Feb 27, 2007
Messages
5,037
@HerrDave
Unless you changed it, the last trigger you showed was displaying the message to (All players) instead of to RankForce.

The Elapsed Game Time event is a trick to avoid crashing the map init thread (and to avoid being boned by one that does crash). Everything with that event gets chunked together into a big ol' function, so if you have a boatload of map init triggers it is possible (though still ultimately unlikely) to crash the Map Init thread.

In most maps the first 1s is usually lagged out as someone loads in anyway, right? (it used to be, back in my day)
 
Status
Not open for further replies.
Top