• 🏆 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!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Local globals > not working

Status
Not open for further replies.
Level 12
Joined
Feb 27, 2019
Messages
399
Hello,

I have a map I am editing with editor 1.31.1. It has many GUI triggers, and I am trying to use the local globals trick (having a local with the name of a global so you can use GUI functions).

However the trigger below displays "TODO Security1" then "55".

What do I do wrong ? How do you do "if" conditions with local globals ? Custom script ?
It seems to be that because when I convert the trigger to JASS, the integer comparison is in a subfunction, so the local is not defined there...

Or did they remove this local global cheat in Warcraft 1.31 ?

  • Actions
    • Custom script: local boolean udg_TempBoolean
    • Custom script: local integer udg_TempInteger
    • Set TempInteger = (Count structures controlled by Player 9 (Gray) (Exclude incomplete structures))
    • Set TempInteger = (TempInteger + (Count structures controlled by Player 10 (Light Blue) (Exclude incomplete structures)))
    • Set TempInteger = (TempInteger + (Count structures controlled by Player 11 (Dark Green) (Exclude incomplete structures)))
    • Set TempInteger = (TempInteger + (Count structures controlled by Player 12 (Brown) (Exclude incomplete structures)))
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • TempInteger Equal to 55
      • Then - Actions
        • Do nothing
      • Else - Actions
        • Game - Display to (All players) the text: TOTO Security1
        • Game - Display to (All players) the text: (String(TempInteger))
        • Custom script: call DestroyTrigger(gg_trg_AttackStart)
Also some people said that local global variables are limited to one of each type. For example I cannot have 2x unit or 2x location this way, is it true ?
 
Last edited:
Level 7
Joined
Jan 23, 2011
Messages
350
A local variable is limited within the function where is declared. You are declaring your local variable on the "Actions" functions, but If/then/else uses a different function for its condition. So "TempInteger equal to 55" is a line in a different function from actions, so your local value can't be red.

You could use the custom script "if udg_TempInteger == 55 then"
do your then block
custom script "else"
do your else block
custom script "endif"

and that's it
 
Level 12
Joined
Feb 27, 2019
Messages
399

Thanks !

> So for conditions in "if" I should use custom scripts.

> For actions in "Pick units in unit group and do", "Pick players in force and do", "Pick items in region and do", etc...
I guess I can declare new local globals "udg_TempXXX" within the inner block, and initialize them from Blizzard getters like GetTriggerUnit(), or from real globals (not local globals I set before in the same trigger) ?

> And more important, For the people saying I can only have 1 local global of each type, is it true ??
For example in the case below :
  • StartPitch
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Game - Display to (All players) for 15.00 seconds the text: |cff5A8CDENew proje...
      • Custom script: local unit udg_TempUnit
      • Custom script: local unit udg_TempUnit1
      • Set TempUnit = Castle 0027 <gen>
      • Set TempUnit1 = Castle 0027 <gen>
      • ....
      • ....
      • ....
      • Custom script: set udg_TempUnit1 = null
      • Custom script: set udg_TempUnit = null
local variable udg_TempUnit would be set to Castle 0027.
global variable udg_TempUnit1 would be set to Castle 0027, not local udg_TempUnit1 ?
Fortunately there would be no memory nor reference leak ?
 
Level 12
Joined
Feb 27, 2019
Messages
399
At this point you might as well use JASS directly and save yourself a lot of effort.

Well the map I am editing has ~300 triggers, most of them are GUI (map named X Hero Siege). I added all those "TempPoint", "TempUnit"," TempGroup", "TempForce" to clean memory leaks from the previous developer of the map. It represents ~80-100 modified triggers in total.

So either converting all of them to JASS & edit to be able to use locals, or editing GUI to use global locals, will be a pain in the ass :D

And still nobody answered me: do local globals only work for 1 variable of each type, or more ? ^^


Edit:
I did a quick test and it seems that it works for more than 1 variable of each type (tested integer & player types:
New default map. Nothing edited

Triggers:
  • Untitled Trigger 001
    • Events
      • Time - Elapsed game time is 2.00 seconds
    • Conditions
    • Actions
      • Custom script: local integer udg_TempInteger
      • Custom script: local integer udg_TempInteger1
      • Custom script: local player udg_TempPlayer
      • Custom script: local player udg_TempPlayer1
      • Set TempInteger = 1
      • Set TempInteger1 = 2
      • Set TempPlayer = Player 1 (Red)
      • Set TempPlayer1 = Player 2 (Blue)
  • Untitled Trigger 002
    • Events
      • Time - Elapsed game time is 4.00 seconds
    • Conditions
    • Actions
      • Game - Display to (All players) the text: (TempInteger= + (String(TempInteger)))
      • Game - Display to (All players) the text: (TempInteger1= + (String(TempInteger1)))
      • Game - Display to (All players) the text: (TempPlayer= + (Name of TempPlayer))
      • Game - Display to (All players) the text: (TempPlayer1= + (Name of TempPlayer1))
Results:
"TempInteger=0
TempInteger1=0
TempPlayer=
TempPlayer1="
 
Last edited:
  • Actions
    • Custom script: local boolean udg_TempBoolean
    • Custom script: local integer udg_TempInteger
    • Set TempInteger = (Count structures controlled by Player 9 (Gray) (Exclude incomplete structures))
    • Set TempInteger = (TempInteger + (Count structures controlled by Player 10 (Light Blue) (Exclude incomplete structures)))
    • Set TempInteger = (TempInteger + (Count structures controlled by Player 11 (Dark Green) (Exclude incomplete structures)))
    • Set TempInteger = (TempInteger + (Count structures controlled by Player 12 (Brown) (Exclude incomplete structures)))
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • TempInteger Equal to 55
      • Then - Actions
        • Do nothing
      • Else - Actions
        • Game - Display to (All players) the text: TOTO Security1
        • Game - Display to (All players) the text: (String(TempInteger))
        • Custom script: call DestroyTrigger(gg_trg_AttackStart)

You might also use an other GUI variable to store the value of the local variable, before you leave the function for things like the if-statement, or PickAllUnits enumerations. Example in your code:

  • Actions
    • Custom script: local boolean udg_TempBoolean
    • Custom script: local integer udg_TempInteger
    • Set TempInteger = (Count structures controlled by Player 9 (Gray) (Exclude incomplete structures))
    • Set TempInteger = (TempInteger + (Count structures controlled by Player 10 (Light Blue) (Exclude incomplete structures)))
    • Set TempInteger = (TempInteger + (Count structures controlled by Player 11 (Dark Green) (Exclude incomplete structures)))
    • Set TempInteger = (TempInteger + (Count structures controlled by Player 12 (Brown) (Exclude incomplete structures)))
    • Set TempInteger2 = TempInteger
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • TempInteger2 Equal to 55
      • Then - Actions
        • Do nothing
      • Else - Actions
        • Game - Display to (All players) the text: TOTO Security1
        • Game - Display to (All players) the text: (String(TempInteger))
        • Custom script: call DestroyTrigger(gg_trg_AttackStart)
 

Wrda

Spell Reviewer
Level 25
Joined
Nov 18, 2012
Messages
1,870
Is it me or this just doesn't make any god damn sense?
What's the point of having shadowed globals if you're not using waits?
What are you trying to achieve?
Because to me, this is completly useless the way you're using it, in the scenario you're showing.
 
Level 12
Joined
Feb 27, 2019
Messages
399
Is it me or this just doesn't make any god damn sense?
What's the point of having shadowed globals if you're not using waits?
What are you trying to achieve?
Because to me, this is completly useless the way you're using it, in the scenario you're showing.

Sorry for the missunderstanding !

In the example of my first post I removed all the revelant code to make it simple. Indeed, these global variables are useful to me only in 2 cases:
- Use of waits because anything may happen to global variables then
- Use of actions that fire events (ex: create unit, issue order, change value of a global real, ...). Because they may execute other triggers that use the same Temp globals.
 

Wrda

Spell Reviewer
Level 25
Joined
Nov 18, 2012
Messages
1,870
- Use of actions that fire events (ex: create unit, issue order, change value of a global real, ...). Because they may execute other triggers that use the same Temp globals.
This one does nothing though. Even if you try to shadow these globals, the they will change the value any way, you can simply re-set the variables again and do your actions, when events fire, what happens is the trigger (all actions) is executed in order, but almost instant. Every trigger has their own place in the order of execution so there's no problem with just using "normal" global variables. (There's no way the triggers execution could be at same time, that would bring a lot of problems.
 

Wrda

Spell Reviewer
Level 25
Joined
Nov 18, 2012
Messages
1,870
Unfortunately it seems it does. Look what IcemanBo and Ceday told me in this topic
That's because you're using loop integer A.
Loop integer A and B are prompt to bugs like this and I remember they have been mentioned before to avoid them as much as possible. Use your own integer loop.
I just say this because I've used a lot of variables (global) before and never crossed this bug as you stated.
 
Level 12
Joined
Feb 27, 2019
Messages
399
Loop Integer A or B use global integer bj_For*LoopIndex and bj_For*LoopLast if I remember well. This is why it conflicts. All globals variable can conflict the same way.

For example if:
- trigger1, periodic, that sets the global udg_TempPoint to map center, then creates units, then create a special effect at udg_TempPoint.
- trigger2, on «unit enters map» event, uses global variable udg_TempPoint for any purpose, giving it whatever value.
In that case my special effect will show at wrong location, not at the center of the map...
 

Wrda

Spell Reviewer
Level 25
Joined
Nov 18, 2012
Messages
1,870
Loop Integer A or B use global integer bj_For*LoopIndex and bj_For*LoopLast if I remember well. This is why it conflicts. All globals variable can conflict the same way.
No, they simply don't.
For example if:
- trigger1, periodic, that sets the global udg_TempPoint to map center, then creates units, then create a special effect at udg_TempPoint.
- trigger2, on «unit enters map» event, uses global variable udg_TempPoint for any purpose, giving it whatever value.
In that case my special effect will show at wrong location, not at the center of the map...
No it won't, if you set it in one trigger and use it, and then in a another trigger set it again and use it. You're simply doing it wrong.
I've used few variables to reference and use them in several triggers and never had this problem.

Proof right below. You can easily figure out what's happening there, I don't need to explain.
 

Attachments

  • TestVariable.w3x
    25.4 KB · Views: 24
Last edited:

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,192
And still nobody answered me: do local globals only work for 1 variable of each type, or more ? ^^
No idea what you are even asking... A local variable cannot be a global variable by definition of what they are. There is no reasonable limit to both the number of global variables a script can have and the number of local variables a function can use.

What is important is that local variables only last the duration of the function call. GUI masks the duration of a function call hence my recommendation to convert the trigger to custom script and write JASS directly. This exposes function blocks.
Is it me or this just doesn't make any god damn sense?
What's the point of having shadowed globals if you're not using waits?
What are you trying to achieve?
Local variables are a fundamental concept with programming. In most languages one quickly finds one is reliant on them.
Loop integer A and B are prompt to bugs like this and I remember they have been mentioned before to avoid them as much as possible. Use your own integer loop.
I just say this because I've used a lot of variables (global) before and never crossed this bug as you stated.
Loop A and B are global variables...
 
Last edited:
Level 12
Joined
Feb 27, 2019
Messages
399
No idea what you are even asking... A local variable cannot be a global variable by definition of what they are.
The whole topic is about that dude.. You can create local variable with the same name as a global: udg_Xxxx. And in the given function block, GUI calls using the global will actually use a local version of the variable instead.

@Wrda sorry I cannot open your test map for now, I left for hollidays
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,192
You can create local variable with the same name as a global: udg_Xxxx. And in the given function block, GUI calls using the global will actually use a local version of the variable instead.
Yes that is because the name scopes prioritize local variables over global variables. A lot of languages work like that. Still fundamentally local variables and global variables work the same.
 
Level 39
Joined
Feb 27, 2007
Messages
4,994
  • Initialization
    • Events
      • Time - Elapsed game time is 0.00 seconds
    • Conditions
    • Actions
      • Visibility - Disable fog of war
      • Visibility - Disable black mask
      • Trigger - Turn on CreateUnit <gen>
      • Trigger - Run CreateUnit <gen> (checking conditions)
  • CreateUnit
    • Events
      • Time - Every 30.00 seconds of game time
    • Conditions
    • Actions
      • Game - Display to (All players) the text: ((Name of the current trigger) + trigger executed)
      • Unit - Remove (Last created unit) from the game
      • Wait 2.00 seconds
      • Set Point = (Center of (Playable map area))
      • Unit - Create 1 Footman for Player 1 (Red) at Point facing Default building facing degrees
      • Game - Display to (All players) the text: Note that OnUnitEnt...
      • Unit - Order (Last created unit) to Hold Position
      • Game - Display to (All players) the text: OnUnitIsIssuedOrder...
      • Unit - Move (Last created unit) instantly to Point
      • Camera - Pan camera for Player 1 (Red) to Point over 0.00 seconds
      • Game - Display to (All players) the text: The unit is not at ...
  • OnUnitEntersMap
    • Events
      • Unit - A unit enters (Entire map)
    • Conditions
    • Actions
      • Game - Display to (All players) the text: ((Name of the current trigger) + trigger executed)
      • Set Point = (Random point in (Playable map area))
      • Special Effect - Create a special effect at Point using Abilities\Spells\Human\ThunderClap\ThunderClapCaster.mdl
      • Special Effect - Destroy (Last created special effect)
  • OnUnitIsIssuedOrder
    • Events
      • Unit - A unit Is issued an order with no target
    • Conditions
    • Actions
      • Game - Display to (All players) the text: ((Name of the current trigger) + trigger executed)
      • Set Point = (Random point in (Playable map area))
      • Special Effect - Create a special effect at Point using Abilities\Spells\Human\ThunderClap\ThunderClapCaster.mdl
      • Special Effect - Destroy (Last created special effect)
You aren't shadowing any globals locally in that test map, Ricola.... As for why your value of Point changes: triggers that do things that cause other triggers to fire will pause while the secondarily fired trigger executes, then resume their execution once the secondary one is finished. So in your map example:
  1. Map Init, Initialization trigger runs, telling CreateUnit to run once
  2. CreateUnit trigger runs, sets a value for Point, creates a footman then is instantly paused and interrupted by:
  3. OnUnitEntersMap trigger runs because the footman was created and entered the map. This sets a new value for Point. When this trigger finishes, execution returns to:
  4. CreateUnit resumes asnd continues until just after the unit is ordered to Hold Positon, at which point the trigger is instantly paused and interrupted by:
  5. OnUnitIssuedOrder runs because an order was issued. This sets a third value for Point. When this trigger finishes, execution returns to:
  6. CreateUnit resumes and finishes, as nothing further it does will trigger any more triggers.
 
Level 12
Joined
Feb 27, 2019
Messages
399

The goal of this map was just to proove to Wrda than events pause the current trigger execution and are fired right now. That's why it doesn't use global locals.
However, if you execute the map and look at the logs:
upload_2019-8-13_13-6-58.png


It seems that the event "Unit enters map" is only fired & triggered after the end of the execution of "CreateUnit". Try it yourself ^^

It also seems that "Unit - Move instantly" fires an order, odd :eek:
 
Status
Not open for further replies.
Top