Spell Energy Flow

Moridin

Snow Leopard
Reaction score
144
Energy Flow
View attachment Spell - Energy Flow.w3x

Description:

GUI
MUI
Leakless
Lagless


Summons 3 orbs of energy around the caster. These orbs spin in a circle, growing larger and more powerful as they spin. Whenever the caster targets a unit with another spell, one of the orbs breaks away from the circle to explode near the target, damaging all units in an AOE.

Orbs gain 1 charge per 360 degrees of spin. Damage depends on Base damage, level of Energy Flow and number of charges gained by the orb.

Requirements:

Hashtables (TFT, WC 1.24(e) recommended)

Implementation:

Read the README File in the map.

Screenshots:

energyflowstill.jpg


energyflowaction.jpg

Triggers:

Trigger:
  • Init
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Hashtable - Create a hashtable
      • Set EN_Hashtable = (Last created hashtable)


Trigger:
  • EN Cast
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Energy Flow
    • Actions
      • -------- EDITABLE VALUES --------
      • Set EN_NoOfBombs = 3
      • Set EN_MaxBombCharge = 3
      • Set EN_Base_Damage = 50
      • Set EN_PerLevel_Damage = 50
      • Set EN_PerCharge_Damage = 10
      • Set EN_Splash = True
      • Set EN_AOE_Splash = 175
      • Set EN_FriendlyFire = False
      • -------- Total Bomb Damage = Base Damage + (PerLevelDamage*LevelOfAbility) + (PerChargeDamage*NoOfCharges) --------
      • -------- ------------------------------ --------
      • Trigger - Turn on EN Spin <gen>
      • Trigger - Turn on EN Activate <gen>
      • Hashtable - Save False as ((Key (Triggering unit)) - 2) of 1 in EN_Hashtable
      • Unit Group - Add (Triggering unit) to EN_casters
      • -------- Number of charges left --------
      • Hashtable - Save EN_NoOfBombs as ((Key (Triggering unit)) - 1) of 1 in EN_Hashtable
      • For each (Integer A) from 1 to EN_NoOfBombs, do (Actions)
        • Loop - Actions
          • Unit - Remove (Load (Key (Triggering unit)) of (Integer A) in EN_Hashtable) from the game
          • -------- --------------------- --------
          • Set temp_point = (Position of (Triggering unit))
          • Set temp_point_2 = (temp_point offset by 100.00 towards ((Real((Integer A))) x (360.00 / (Real(EN_NoOfBombs)))) degrees)
          • Unit - Create 1 Charge for (Triggering player) at temp_point_2 facing Default building facing degrees
          • Hashtable - Save Handle Of(Last created unit) as (Key (Triggering unit)) of (Integer A) in EN_Hashtable
          • Custom script: call RemoveLocation (udg_temp_point)
          • Custom script: call RemoveLocation (udg_temp_point_2)
          • -------- EDITABLE VALUES --------
          • -------- size and hover height --------
          • Animation - Change (Last created unit)'s size to (50.00%, 50.00%, 50.00%) of its original size
          • -------- ------------------------------ --------
          • -------- Degrees the charge has rotated --------
          • Hashtable - Save 0 as ((Key (Triggering unit)) + 1) of (Integer A) in EN_Hashtable
          • -------- Power of the charge --------
          • Hashtable - Save 0 as ((Key (Triggering unit)) + 2) of (Integer A) in EN_Hashtable
          • -------- Angle --------
          • Set EN_Current_angle[(Integer A)] = ((Real((Integer A))) x (360.00 / (Real(EN_NoOfBombs))))


Trigger:
  • EN Spin
    • Events
      • Time - Every 0.05 seconds of game time
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (EN_casters is empty) Not equal to True
        • Then - Actions
          • Unit Group - Pick every unit in EN_casters and do (Actions)
            • Loop - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Load ((Key (Picked unit)) - 1) of 1 from EN_Hashtable) Equal to 0
                • Then - Actions
                  • Unit Group - Remove (Picked unit) from EN_casters
                  • Skip remaining actions
                • Else - Actions
              • For each (Integer A) from 1 to (Load ((Key (Picked unit)) - 1) of 1 from EN_Hashtable), do (Actions)
                • Loop - Actions
                  • Set Current_unit = (Load (Key (Picked unit)) of (Integer A) in EN_Hashtable)
                  • Set EN_Current_angle[(Integer A)] = (EN_Current_angle[(Integer A)] + 12.00)
                  • Set temp_point = (Position of (Picked unit))
                  • Set temp_point_2 = (temp_point offset by 50.00 towards EN_Current_angle[(Integer A)] degrees)
                  • Unit - Move Current_unit instantly to temp_point_2
                  • Custom script: call RemoveLocation (udg_temp_point)
                  • Custom script: call RemoveLocation (udg_temp_point_2)
                  • Hashtable - Save ((Load ((Key (Picked unit)) + 1) of (Integer A) from EN_Hashtable) + 12) as ((Key (Picked unit)) + 1) of (Integer A) in EN_Hashtable
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Load ((Key (Picked unit)) + 1) of (Integer A) from EN_Hashtable) Greater than 360
                      • (Load ((Key (Picked unit)) + 2) of (Integer A) from EN_Hashtable) Less than EN_MaxBombCharge
                    • Then - Actions
                      • Hashtable - Save ((Load ((Key (Picked unit)) + 2) of (Integer A) from EN_Hashtable) + 1) as ((Key (Picked unit)) + 2) of (Integer A) in EN_Hashtable
                      • Hashtable - Save 0 as ((Key (Picked unit)) + 1) of (Integer A) in EN_Hashtable
                    • Else - Actions
                  • -------- The actions below are just effects for the different levels of charge --------
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Load ((Key (Picked unit)) + 2) of (Integer A) from EN_Hashtable) Equal to 1
                    • Then - Actions
                      • Animation - Change Current_unit's size to (70.00%, 70.00%, 70.00%) of its original size
                    • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Load ((Key (Picked unit)) + 2) of (Integer A) from EN_Hashtable) Equal to 2
                    • Then - Actions
                      • Animation - Change Current_unit's size to (90.00%, 90.00%, 90.00%) of its original size
                    • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Load ((Key (Picked unit)) + 2) of (Integer A) from EN_Hashtable) Equal to 3
                    • Then - Actions
                      • Animation - Change Current_unit's size to (110.00%, 110.00%, 110.00%) of its original size
                    • Else - Actions
        • Else - Actions
          • Trigger - Turn off EN Activate <gen>
          • Trigger - Turn off EN Blowing up <gen>
          • Trigger - Turn off (This trigger)


Trigger:
  • EN Activate
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • ((Triggering unit) is in EN_casters) Equal to True
      • (Target unit of ability being cast) Not equal to No unit
    • Actions
      • Set temp_boolean = (Load ((Key (Triggering unit)) - 2) of 1 from EN_Hashtable)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • temp_boolean Equal to False
        • Then - Actions
          • Hashtable - Save True as ((Key (Triggering unit)) - 2) of 1 in EN_Hashtable
          • Skip remaining actions
        • Else - Actions
      • Set temp_int = (Load ((Key (Triggering unit)) - 1) of 1 from EN_Hashtable)
      • Set EN_Activated_Charge = (Load (Key (Triggering unit)) of temp_int in EN_Hashtable)
      • Set EN_Activated_Charge_handle = (Load (Key (Triggering unit)) of temp_int in EN_Hashtable)
      • -------- for later use in the next trigger --------
      • Unit - Set the custom value of EN_Activated_Charge to temp_int
      • -------- Saving target --------
      • Hashtable - Save Handle Of(Target unit of ability being cast) as (Key EN_Activated_Charge_handle) of temp_int in EN_Hashtable
      • -------- Power of the charge --------
      • Hashtable - Save (Load ((Key (Triggering unit)) + 2) of temp_int from EN_Hashtable) as ((Key EN_Activated_Charge_handle) + 1) of temp_int in EN_Hashtable
      • Hashtable - Save (Level of Energy Flow for (Triggering unit)) as ((Key EN_Activated_Charge_handle) + 2) of temp_int in EN_Hashtable
      • -------- Deducting from number of charges (balls) left --------
      • Hashtable - Save (temp_int - 1) as ((Key (Triggering unit)) - 1) of 1 in EN_Hashtable
      • -------- For slide trigger --------
      • Unit Group - Add EN_Activated_Charge to EN_Bombs
      • Trigger - Turn on EN Blowing up <gen>


Trigger:
  • EN Blowing up
    • Events
      • Time - Every 0.05 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in EN_Bombs and do (Actions)
        • Loop - Actions
          • Set Current_unit = (Load (Key (Picked unit)) of (Custom value of (Picked unit)) in EN_Hashtable)
          • Set temp_point = (Position of (Picked unit))
          • Set temp_point_2 = (Position of Current_unit)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Distance between temp_point and temp_point_2) Greater than or equal to 50.00
            • Then - Actions
              • Set temp_point_3 = (temp_point offset by 50.00 towards (Angle from temp_point to temp_point_2) degrees)
              • Unit - Move (Picked unit) instantly to temp_point_3
              • Custom script: call RemoveLocation (udg_temp_point)
              • Custom script: call RemoveLocation (udg_temp_point_2)
              • Custom script: call RemoveLocation (udg_temp_point_3)
            • Else - Actions
              • Custom script: call RemoveLocation (udg_temp_point_2)
              • Set EN_Current_Damage = (EN_Base_Damage + ((EN_PerLevel_Damage x (Load ((Key (Picked unit)) + 2) of (Custom value of (Picked unit)) from EN_Hashtable)) + (EN_PerCharge_Damage x (Load ((Key (Picked unit)) + 1) of (Custom value of (Picked unit)) from EN_Hashtable))))
              • Set temp_unit = (Picked unit)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • EN_Splash Equal to True
                • Then - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • EN_FriendlyFire Equal to True
                    • Then - Actions
                      • Unit - Cause temp_unit to damage circular area after 0.00 seconds of radius (Real(EN_AOE_Splash)) at temp_point, dealing (Real(EN_Current_Damage)) damage of attack type Spells and damage type Normal
                    • Else - Actions
                      • Set temp_group = (Units within (Real(EN_AOE_Splash)) of temp_point matching (((Matching unit) belongs to an enemy of (Owner of temp_unit)) Equal to True))
                      • Unit Group - Pick every unit in temp_group and do (Actions)
                        • Loop - Actions
                          • Unit - Cause temp_unit to damage (Picked unit), dealing (Real(EN_Current_Damage)) damage of attack type Spells and damage type Normal
                      • Custom script: call DestroyGroup (udg_temp_group)
                • Else - Actions
                  • Unit - Cause (Picked unit) to damage Current_unit, dealing (Real(EN_Current_Damage)) damage of attack type Spells and damage type Normal
              • Unit - Remove temp_unit from the game
              • Special Effect - Create a special effect at temp_point using Abilities\Spells\Human\ThunderClap\ThunderClapCaster.mdl
              • Special Effect - Destroy (Last created special effect)
              • Custom script: call RemoveLocation (udg_temp_point)


Credits:

Spell Resource template map by Tinki3.
Spell concept by Dest. (Originally called Energitism)
Icon by bigapple90. Check the page here.
Model by RED BARON. Check the page here.

Additional notes:

This is the first time I'm submitting a resource :). Also this spell is somewhat old, so it's probably not as efficient as I thought it might be.
I'm not exactly sure as to clearing hashtable leaks, so if there ARE leaks that I haven't removed, give me a heads up. :D

Changelog:

26/06/10 - Fixed numerous leaks pointed out. Optimized triggers to switch off when not needed. Added Friendly_Fire editable.

07/07/10 - Optimized code a little bit more. Fixed a bug where the third charge didn't move or detonate correctly.
 

Ayanami

칼리
Reaction score
288
Just seeing through triggers quickly. Spotted some leaks, I think.

Firstly, your EN Spin trigger.

Trigger:
  • Unit - Move Current_unit instantly to ((Position of (Picked unit)) offset by 50.00 towards EN_Current_angle[(Integer A)] degrees)


Leaks. You set temp_point = (Position of (Picked unit)) yet didn't use it. But the offset leaks at well. Should be:

Trigger:
  • Actions
    • Set temp_point = (Position of (Picked unit))
    • Set temp_offset = (temp_point offset by 50.00 towards EN_Current_angle[(Integer A)] degrees)
    • Unit - Move Current_unit instantly to temp_offset
    • <Remember to remove leaks>


Now, your EN Blowing up trigger.

Trigger:
  • (Distance between (Position of (Picked unit)) and (Position of Current_unit)) Greater than or equal to 50.00


I believe this leaks.

Trigger:
  • Unit - Move (Picked unit) instantly to (temp_point offset by 50.00 towards (Angle from temp_point to temp_point_2) degrees)


Same leak as mentioned above. Offsets needs to be set as a variable and removed after using it.

Trigger:
  • Unit - Cause (Picked unit) to damage circular area after 0.00 seconds of radius (Real(EN_AOE_Splash)) at temp_point, dealing (Real(EN_Current_Damage)) damage of attack type Spells and damage type Normal


Are you trying to deal damage in an area? I suggest you set a unit group and deal damage to picked units instead. Circular area deals damage to friends and foes alike.

Well, I just read through roughly. Might have more leaks, etc.

Anyways, concept-wise, looks nice. May I suggest that you alter the skill a bit, so that point-targeted spells also trigger the orbs to explode at the targeted point?
 

Moridin

Snow Leopard
Reaction score
144
Thanks :). Yeah I need to run through this spell again and eliminate all the leaks.

I was thinking of picking units in a group and then damaging them so I can choose whether or not friendly fire is switched on (planning on making this an editable).

I was also thinking of the target point idea. Right now though, I'm still thinking of how to implement it properly....because most of the variables change depending on whether a unit or a point is targeted.

Thanks for the feedback. Will work on getting it fixed.

Edit: How do you remove offset leaks? The custom script isn't given in emjlr3's tutorial on leak removal.
 

Ayanami

칼리
Reaction score
288
Offsets are basically locations.

Trigger:
  • Custom script: RemoveLocation(udg_temp_offset)
 

Ayanami

칼리
Reaction score
288
Looks good. Except you might want to track the number of units in a unit group rather than using "Unit Group is Empty". I heard it's inefficient. Thus, you could use a integer variable to count. Set GroupInteger = GroupInteger +1 when you add a unit into the group. Then you decrease it when removed. Then you can make an integer comparison rather than "Unit Group is Empty".

Your hashtables are confusing, at least to me. I normally use Handle of a unit, similar to yours, in the parent key and stringhash for the child key.

For example:

Trigger:
  • Custom script: call SaveReal(udg_Hashtable, GetHandleId(GetTriggerUnit()), StringHash("damage"), 500.00)


But it's just all up to personal preferences. As long as your method works, it's fine :)
 

Moridin

Snow Leopard
Reaction score
144
Yeahh :p What you're doing is using a string as the second key in your hashtable. Unfortunately, because I don't know JASS or custom script (same thing technically) yet, I have to stick to integer keys. :p Which is why I have all my values stored as (Triggering unit), 1 and so on.

I've gotten used to it by now, mainly by making a mental map of a 2D array in my head that remembers where everything goes. It is confusing at a first read though, I admit :p.

Also, for the boolean "unit group is empty" innefficiency, I'd like another opinion on this. Converting it to an integer condition would add another few confusing lines of code to an already confusing to read spell. If it does indeed reduce lag, then I don't mind changing it. It should be pretty easy.

Edit: I would also like someone to comment on hashtable leaks. I'm definitely sure my hashtable leaks, but I have no idea how to solve that problem.
 

Ayanami

칼리
Reaction score
288
Wait, GUI hashtables are in the sequence of child key and parent key right? If that's so, aren't you setting all your child key to Handle Id of the caster? You're going to have a hard time flushing the values as the parent keys are all different while the child keys are all the same.
 

Moridin

Snow Leopard
Reaction score
144
StringHash("damage") = String Id (found under Handle Id)

Woops. Yeah I just saw that there right now. I really should learn how to use it then, would make hashtable a lot easier to read :p. Ty for pointing that out btw.

Wait, GUI hashtables are in the sequence of child key and parent key right? If that's so, aren't you setting all your child key to Handle Id of the caster? You're going to have a hard time flushing the values as the parent keys are all different while the child keys are all the same.
Reply With Quote

I actually don't know. This is what I was talking about in terms of leaking.

Edit: Also where do you guys get your info from on hashtables? The only tutorial I've ever seen or read on hashtables is the "Hashtables and MUI" tutorial on the hive... :S
 

hgkjfhfdsj

Active Member
Reaction score
55
This is what I was talking about in terms of leaking.
seeing that youre using child key for the caster rather than the parent, just flush the unit values (i think thats all i see)>> non-handles dont need to be flushed anyways. otherwise revamp the trigger and use string id as child.

Edit: Also where do you guys get your info from on hashtables? The only tutorial I've ever seen or read on hashtables is the "Hashtables and MUI" tutorial on the hive... :S
click me
 

Ayanami

칼리
Reaction score
288
Edit: Also where do you guys get your info from on hashtables? The only tutorial I've ever seen or read on hashtables is the "Hashtables and MUI" tutorial on the hive... :S

Well, I just happened to hear that you can use strings for keys. So I experimented and found out that StringHash("string") is the one. This site also lists all the natives for hashtable. Considering that BJ reverses the arguments for the hashtables, you ARE saving Handle Id of the caster in the child key and not the parent key. As you can see, the native function's sequence is hashtable, parent key, child key, value. So if the arguments are reversed, it becomes value, child key, parent key, hashtable. Thus, I suggest you rework the hashtable parts.
 

Moridin

Snow Leopard
Reaction score
144
Thanks for the comments. As of now, this isn't my highest priority because it works as is and I'm working on another spell, but I'll definitely optimise the hashtable when i get time.
 

Ayanami

칼리
Reaction score
288
Well, at least from now on, you know the correct positions for the child key and the parent key ;)
 

Moridin

Snow Leopard
Reaction score
144
Yeah thats true :). I've optimised my other spell's code. Also, the string keys make everything SO much easier :D.
 

Moridin

Snow Leopard
Reaction score
144
Bump. Fixed a bug where a trigger switched off too early, resulting in the third charge always failing. Optimized the code a little more.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top