• 🏆 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!

Case Statements

Status
Not open for further replies.
Level 9
Joined
Dec 6, 2007
Messages
233
After playing with C++, I've learned the glory of case statements.

Is there a world editor equivalent?

I've looked for them for a while, but with no results. I really want case statements as it would clean up a lot of large if/then/else trees
 
Level 9
Joined
Dec 6, 2007
Messages
233
Aww dang, well then how do I most efficiently write a trigger that functions like this:

  • Player Zone Reset Void
    • Events
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Owner of (Last created unit)) Equal to Player 1 (Red)
        • Then - Actions
          • Set Temp_Region = Player 1 zone <gen>
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Owner of (Last created unit)) Equal to Player 2 (Blue)
        • Then - Actions
          • Set Temp_Region = Player 2 zone <gen>
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Owner of (Last created unit)) Equal to Player 3 (Teal)
        • Then - Actions
          • Set Temp_Region = Player 3 zone <gen>
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Owner of (Last created unit)) Equal to Player 4 (Purple)
        • Then - Actions
          • Set Temp_Region = Player 4 zone <gen>
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Owner of (Last created unit)) Equal to Player 5 (Yellow)
        • Then - Actions
          • Set Temp_Region = Player 5 zone <gen>
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Owner of (Last created unit)) Equal to Player 6 (Orange)
        • Then - Actions
          • Set Temp_Region = Player 6 zone <gen>
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Owner of (Last created unit)) Equal to Player 7 (Green)
        • Then - Actions
          • Set Temp_Region = Player 7 zone <gen>
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Owner of (Last created unit)) Equal to Player 8 (Pink)
        • Then - Actions
          • Set Temp_Region = Player 8 zone <gen>
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Owner of (Last created unit)) Equal to Player 9 (Gray)
        • Then - Actions
          • Set Temp_Region = Player 9 zone <gen>
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Owner of (Last created unit)) Equal to Player 10 (Light Blue)
        • Then - Actions
          • Set Temp_Region = Player 10 zone <gen>
        • Else - Actions
      • Set Temp_Point = (Center of Temp_Region)
      • Set Temp_Handle = (Last created unit)
      • Set Temp_Unit = (Last created unit)
      • Set Temp_Group = (Units in Temp_Region)
      • For each (Integer A) from 1 to (Load Compound_TurretNumber of (Key Temp_Handle) from Compound_Hash), do (Actions)
        • Loop - Actions
          • Set Temp_Point2 = (Temp_Point offset by (Load Compound_AbsOffset[(Integer A)] of (Key Temp_Handle) from Compound_Hash) towards (Load Compound_RadOffset[(Integer A)] of (Key Temp_Handle) from Compound_Hash) degrees)
          • Unit - Create 1 Empty Slot (Rep.) for (Owner of Temp_Unit) at Temp_Point2 facing Default building facing degrees
          • Hashtable - Save (Integer A) as Slot of (Key (Last created unit)) in Auxillary_Hash
          • Custom script: call RemoveLocation(udg_Temp_Point2)
      • Custom script: call RemoveLocation(udg_Temp_Point)
      • Unit Group - Pick every unit in Temp_Group and do (Actions)
        • Loop - Actions
          • Hashtable - Clear all child hashtables of child (Key (Picked unit)) in Compound_Hash
          • Set Temp_Item = (Item carried by (Picked unit) in slot 1)
          • Item - Make Temp_Item Droppable
          • Hero - Drop Temp_Item from (Picked unit)
          • Unit - Remove (Picked unit) from the game
          • Hero - Give Temp_Item to Temp_Unit
      • Custom script: call DestroyGroup(udg_Temp_Group)
I'm referring to the first portion of the trigger that sets Temp_Region

EDIT: I suppose I could just make a variable array, preset all the values on map init, and then do Temp_Region = PlayerZone[index # of player]
soo that's a bad example, lemme find a better one

EDIT2: ok, this one will be a little hard to explain

  • Shell periodic
    • Events
      • Time - Every 0.05 seconds of game time
    • Conditions
      • (Shell_Group is empty) Equal to False
    • Actions
      • -------- Projectile motion, collision, damage, and special functions --------
      • Unit Group - Pick every unit in Shell_Group and do (Actions)
        • Loop - Actions
          • Set Projectile = (Picked unit)
          • Set Temp_Point = (Position of Projectile)
          • Set Temp_Real = 0.00
          • -------- Missile Homing --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Or - Any (Conditions) are true
                • Conditions
                  • (Unit-type of (Picked unit)) Equal to Dummy Missile
              • ((Load Missile_Target of (Key (Picked unit)) in Shell_Hash) is alive) Equal to True
            • Then - Actions
              • Set Temp_Point4 = (Position of (Load Missile_Target of (Key (Picked unit)) in Shell_Hash))
              • Set Temp_Real = (((Angle from Temp_Point to Temp_Point4) - (Facing of (Picked unit))) mod 360.00)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Or - Any (Conditions) are true
                    • Conditions
                      • Temp_Real Less than or equal to 5.00
                      • (360.00 - Temp_Real) Less than or equal to 5.00
                • Then - Actions
                  • Set Temp_Real = (Angle from Temp_Point to Temp_Point4)
                • Else - Actions
                  • Set Temp_Real = ((Facing of (Picked unit)) - (5.00 x (Sign((Temp_Real - 180.00)))))
              • Unit - Make (Picked unit) face Temp_Real over 0.00 seconds
            • Else - Actions
          • -------- Rocket Flight --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Or - Any (Conditions) are true
                • Conditions
                  • (Unit-type of (Picked unit)) Equal to Dummy Rocket
            • Then - Actions
              • Set Temp_Real = ((Facing of (Picked unit)) + (Random real number between -5.00 and 5.00))
              • Unit - Make (Picked unit) face Temp_Real over 0.00 seconds
            • Else - Actions
          • Set Temp_Point2 = (Temp_Point offset by (Load Shell_Velocity of (Key (Picked unit)) from Shell_Hash) towards (Facing of (Picked unit)) degrees)
          • Custom script: call SetUnitX(udg_Projectile, GetLocationX(udg_Temp_Point2))
          • Custom script: call SetUnitY(udg_Projectile, GetLocationY(udg_Temp_Point2))
          • -------- Missile Deploying function --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Load Deploy_Amount of (Key (Picked unit)) from Shell_Hash) Greater than or equal to 2
            • Then - Actions
              • Set Temp_Group = (Units within (Load Deploy_Distance of (Key (Picked unit)) from Shell_Hash) of Temp_Point matching ((Evaluate Shell Target Args <gen> conditions) Equal to True))
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Temp_Group is empty) Equal to False
                • Then - Actions
                  • For each (Integer A) from 1 to (Load Deploy_Amount of (Key (Picked unit)) from Shell_Hash), do (Actions)
                    • Loop - Actions
                      • Unit - Create 1 (Unit-type of (Picked unit)) for (Owner of (Picked unit)) at Temp_Point facing (((Facing of (Picked unit)) - ((Load Deploy_Spread of (Key (Picked unit)) from Shell_Hash) / 2.00)) + (((Real((Integer A))) - 1.00) x ((Load Deploy_Spread of (Key (Picked unit)) from Shell_Hash) / ((Real((Load Deploy_Amount of (Key (Picked unit)) from Shell_H degrees
                      • Unit - Add a 3.00 second Generic expiration timer to (Last created unit)
                      • Unit Group - Add (Last created unit) to Shell_Group
                      • Hashtable - Save Handle Of(Load Missile_Target of (Key (Picked unit)) in Shell_Hash) as Missile_Target of (Key (Last created unit)) in Shell_Hash
                      • Hashtable - Save (Load Shell_Velocity of (Key (Picked unit)) from Shell_Hash) as Shell_Velocity of (Key (Last created unit)) in Shell_Hash
                      • Hashtable - Save (Load Shell_ArmorDamage of (Key (Picked unit)) from Shell_Hash) as Shell_ArmorDamage of (Key (Last created unit)) in Shell_Hash
                      • Hashtable - Save (Load Shell_ShieldDamage of (Key (Picked unit)) from Shell_Hash) as Shell_ShieldDamage of (Key (Last created unit)) in Shell_Hash
                      • Hashtable - Save (Load Shell_HullDamage of (Key (Picked unit)) from Shell_Hash) as Shell_HullDamage of (Key (Last created unit)) in Shell_Hash
                  • Unit - Kill Projectile
                • Else - Actions
              • Custom script: call DestroyGroup(udg_Temp_Group)
            • Else - Actions
          • -------- Collision and damage calculation --------
          • Set Armor_Damage = (Load Shell_ArmorDamage of (Key (Picked unit)) from Shell_Hash)
          • Set Shield_Damage = (Load Shell_ShieldDamage of (Key (Picked unit)) from Shell_Hash)
          • Set Hull_Damage = (Load Shell_HullDamage of (Key (Picked unit)) from Shell_Hash)
          • Set Shell_Contact_Group = (Units within 500.00 of Temp_Point matching ((Evaluate Shell Target Args <gen> conditions) Equal to True))
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Projectile is alive) Equal to True
              • (Shell_Contact_Group is empty) Equal to False
            • Then - Actions
              • Unit Group - Pick every unit in Shell_Contact_Group and do (Actions)
                • Loop - Actions
                  • -------- Collision check --------
                  • Set Temp_Point3 = (Position of (Picked unit))
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Distance between Temp_Point2 and Temp_Point3) Less than or equal to (Load Ship_Size of (Key (Picked unit)) from armorhash)
                    • Then - Actions
                      • -------- skips damage check if the shell doesn't do anything anyways --------
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • Or - Any (Conditions) are true
                            • Conditions
                              • Armor_Damage Greater than 0
                              • Shield_Damage Greater than 0
                              • Hull_Damage Greater than 0
                        • Then - Actions
                          • -------- checks shields first --------
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • ((Picked unit) is in Shield_Protectees) Equal to True
                            • Then - Actions
                              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                • If - Conditions
                                  • (Integer((Mana of (Picked unit)))) Greater than or equal to Shield_Damage
                                • Then - Actions
                                  • Unit - Set mana of (Picked unit) to ((Mana of (Picked unit)) - (Real(Shield_Damage)))
                                • Else - Actions
                                  • Unit - Set mana of (Picked unit) to 0.00
                            • Else - Actions
                              • -------- If not shields, then checks armor --------
                              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                • If - Conditions
                                  • (Load Armor_Value of (Key (Picked unit)) from armorhash) Greater than 0
                                • Then - Actions
                                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    • If - Conditions
                                      • (Load Armor_Value of (Key (Picked unit)) from armorhash) Greater than or equal to Armor_Damage
                                    • Then - Actions
                                      • Hashtable - Save ((Load Armor_Value of (Key (Picked unit)) from armorhash) - Armor_Damage) as Armor_Value of (Key (Picked unit)) in armorhash
                                    • Else - Actions
                                      • Hashtable - Save 0 as Armor_Value of (Key (Picked unit)) in armorhash
                                • Else - Actions
                                  • -------- Then damages Health --------
                                  • Unit - Set life of (Picked unit) to ((Life of (Picked unit)) - (Real(Hull_Damage)))
                                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    • If - Conditions
                                      • (Life of (Picked unit)) Less than or equal to 0.00
                                    • Then - Actions
                                      • Set Temp_Int = (Load Experience_Gain of (Key (Picked unit)) from Auxillary_Hash)
                                      • Player - Set (Owner of Projectile) Current gold to (((Owner of Projectile) Current gold) + (Load Bounty of (Key (Picked unit)) from Auxillary_Hash))
                                      • Hero - Add Temp_Int experience to Player_Ship[(Player number of (Owner of Projectile))], Show level-up graphics
                                      • Set Temp_Group = (Units within 1000.00 of Temp_Point matching ((((Matching unit) is A Hero) Equal to True) and (((Owner of (Matching unit)) is an ally of (Owner of Projectile)) Equal to True)))
                                      • Unit Group - Pick every unit in Temp_Group and do (Actions)
                                        • Loop - Actions
                                          • Hero - Add Temp_Int experience to Player_Ship[(Player number of (Owner of (Picked unit)))], Show level-up graphics
                                      • Custom script: call DestroyGroup(udg_Temp_Group)
                                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                        • If - Conditions
                                          • ((Picked unit) is in Player_Ships) Equal to True
                                        • Then - Actions
                                          • Game - Display to (All players) the text: ((Name of (Owner of (Picked unit))) + ( was destroyed by + (Name of (Owner of Projectile))))
                                        • Else - Actions
                                    • Else - Actions
                        • Else - Actions
                      • -------- Destroys contacting shell --------
                      • Unit Group - Remove Projectile from Shell_Group
                      • Unit - Kill Projectile
                      • Set Temp_Bool = True
                    • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Temp_Bool Equal to True
                • Then - Actions
                  • -------- clears shell child hashtables if the shell contacts --------
                  • Hashtable - Clear all child hashtables of child (Key (Picked unit)) in Shell_Hash
                  • Set Temp_Bool = False
                • Else - Actions
            • Else - Actions
          • Custom script: call DestroyGroup(udg_Shell_Contact_Group)
          • Custom script: call RemoveLocation(udg_Temp_Point)
          • Custom script: call RemoveLocation(udg_Temp_Point2)
          • Custom script: call RemoveLocation(udg_Temp_Point3)
          • Custom script: call RemoveLocation(udg_Temp_Point4)
in the trigger, there are sections designated to handle different things depending on the projectile the trigger is operating on (see missile homing, rocket flight, missile deployment). As my map is further developed, the number of special handlers will increase, and the strain from this already hefty trigger will become tough to deal with. Is there a better way to write the handlers?
 

Cokemonkey11

Spell Reviewer
Level 29
Joined
May 9, 2006
Messages
3,534
The best thing you can do in wc3 is "else if".

In GUI that means you nest each additional if block in the "else - multiple actions" block of the previous if block. That's really ugly though and I recommend just doing it the inefficient way.

If you do want to do it more efficiently, just learn jass.

JASS:
if <expression> then
 //case 1
elseif <expression> then
 //case 2
endif
 
Level 2
Joined
Mar 10, 2012
Messages
10
I think it's not even necessary to use switch-case statement..how about using "for" statement?it would be far easier..and that you're familiar with C++, you should understand about using array in looping..
 
Level 9
Joined
Dec 6, 2007
Messages
233
Actually, I just figured out how to make case statements

  • Init
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set Case_Array[1] = Case1 <gen>
      • Set Case_Array[2] = Case2 <gen>
      • Set Case_Array[3] = Case3 <gen>
      • Set Case_Array[4] = Case4 <gen>
  • Trigger
    • Events
    • Conditions
    • Actions
      • Trigger - Run Case_Array[(Integer A)] (ignoring conditions)
  • Case1
    • Events
    • Conditions
    • Actions
      • Do Something
...
  • Case4
    • Events
    • Conditions
    • Actions
      • Do something else


So you are wrong, warcraft 3 does have case statements. Time to redesign half my systems!
 
Level 9
Joined
Dec 6, 2007
Messages
233
It doesn't need to be multi-threaded
The purpose of the cases is to direct the trigger flow through exactly the code it needs to run for the projectile it's operating on, and nothing more. I'm making a case for each special handler; the projectile will have an integer stored that will direct the case statement to exactly the code that the projectile needs
 
Level 9
Joined
Dec 6, 2007
Messages
233
I don't see how it's not more efficient; I'm replacing several if/then/else statements with a single "run trigger" line. Can you please explain? And I'll get around to learning Jass eventually, but for now I want to work in GUI.
 

Cokemonkey11

Spell Reviewer
Level 29
Joined
May 9, 2006
Messages
3,534
an if statement looks like this

if <conditions> (fast)
then actions (fast)

a trigger looks like this

declare triggers (fast)
create trigger (slow)
declare conditions and actions (fast)
//later
check trigger conditions (fast)
then actions (fast)

Sorry I'm in a bit of a rush to explain this but basically, even just running the conditions for a trigger takes procesing power (you're not just "running 1 trigger"). Additionally, you have to create objects (which are stored in memory) to create these triggers.

I could show you what your code above compiles to in jass (versus the if then else version) and you would understand I think.
 
Level 9
Joined
Dec 6, 2007
Messages
233
Sure, I'd appreciate that
and don't forget conditions are ignored by that code, and there's not even any conditions to declare anyways
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
If you have several different lines of code for the actions and a big list of statements it's not that bad.
You can't make it better in GUI, afaik.

EDIT : In jass, instead of use several triggers, split the "switch" in several functions which will be called by ExecuteFunc("YourFunctionName" + I2S(...) ) will be better.
And for more speedfreak power you could use several boolean functions (takes nothing returns boolean), and the trick ForceEnumPlayerCounted(1) trick, since we are not allowed to use code array, only boolexpr array in jass, but this way is really ugly and for speedfreaks.

However, if you just need to check for something and have the same actions with a different argument, you may consider to use an hashtable instead.
 
Level 9
Joined
Dec 6, 2007
Messages
233
That's precisely why i'm doing it; a lot of different lines of code. I'm going to wait on implementing it into the trigger above, but I did implement it into another trigger where it replaced about 20 if/then/else statements (there are separate sets of code for each weapon in the game, but every set gets called by the same damage detection trigger). Big efficiency boost there.

So how slow is "Trigger - Run <trigger>"? Because I use it a lot elsewhere to create voids

EDIT:
  • Basic Cannon Sale
    • Events
      • Unit - A unit Acquires an item
    • Conditions
      • (Item-type of (Item being manipulated)) Equal to Basic Cannon
      • ((Triggering unit) is in Player_Ships) Equal to True
    • Actions
      • Trigger - Run Slot Checker Void <gen> (ignoring conditions)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Temp_Bool Equal to False
        • Then - Actions
          • Game - Display to (All players matching ((Owner of (Triggering unit)) Equal to (Matching player))) the text: Out of Slots!
          • Player - Set (Owner of (Triggering unit)) Current gold to (((Owner of (Triggering unit)) Current gold) + 10)
          • Item - Remove (Item being manipulated)
          • Skip remaining actions
        • Else - Actions
      • Set Temp_Point = (Position of (Triggering unit))
      • Unit - Create 1 Basic Cannon for (Owner of (Triggering unit)) at Temp_Point facing Default building facing degrees
      • Unit - Turn collision for (Last created unit) Off
      • Hashtable - Save 1 as Handler_Case of (Key (Last created unit)) in Compound_Hash
      • Set Sale_Unit_Type = Basic Cannon (Rep.)
      • Set Sale_Value_Nonhash = 10
      • Trigger - Run Slot Dropper Void <gen> (ignoring conditions)
      • Custom script: call RemoveLocation(udg_Temp_Point)
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
ExecuteTrigger is quite expensive by itself, i'm not sure you win something with only 20 statements.
But anyway if you care about efficiency you would switch to jass, because GUI is just jass but really inefficient.

Also, i don't get your example, it seems a trigger like an other, without any "switch".
Or do you want mean that you create X triggers, one for each item rawcode instead of one with a big if/then ?

EDIT : Ok i suppose you do the checks in the trigger "Slot Checker Void".
But why not just use one trigger for each item ?
As long you don't have tons of them, and/or aren't be used heavily in short time like each 0.03 s, it will be fine.
 
Level 9
Joined
Dec 6, 2007
Messages
233
Well I mean i have a set of actions that perform a specific task, And i've left them in a seperate trigger that i just call whenever i need them, such as slot checker void and slot dropper void. it's not a switch, i just use it to make my code look nicer by moving pieces of code that are repeated in several triggers into one trigger.
 
Level 9
Joined
Dec 6, 2007
Messages
233
I do it mostly in code that doesn't run that often; some places I have to do it. So I guess my final question is what's more efficient: 10 if/then/else statements or one "Trigger - Run <trigger>"?
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
I don't know, i would say the if but i'm not sure, especially with GUI since you don't have elseif, go benchmark it if you really want to know.
I would say that in almost every cases it doesn't matter, and if you have performance issues, you would switch to jass anyway.
So just use what you prefer.

Also most of times use one hashtable can get rid of a long if/then.
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
People are obsessing about inefficiency, which I think is a shame; you'll rarely run into efficiency issues when you're coding for wc3, so it's a really bad and unconvincing argument.

I think the bigger issue is that it's just awful to put together. Sure, it may seem reasonable because other parts of GUI are equally awful to put together, but learning JASS you'll appreciate code flowing a little better and just how ugly the kind of stuff you're proposing is, not to mention associated problems with your methodology (like losing all your locals).
 
Status
Not open for further replies.
Top