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

Spells & Systems Mini-Contest #20

Status
Not open for further replies.
Level 18
Joined
Jan 21, 2006
Messages
2,552
There's a function in JASS that increments an ability-level by 1 but other than that there is no function that increments a value by 1.

JASS:
function inc takes integer i returns nothing
    set i = i + 1
endfunction

Alright I think I am going to do Tornado from Age of Mythology. Thanks to TDR and Deolrin for help with ideas. I hope it turns out well. This is the spell:


The video really shows what it does. First it kills the unit by dealing damage over time (I think) and then once the unit is dead it can be sucked up into the Tornado. There is really only one model that I can really see working with this, and that is TornadoElemental.mdl.

Don't mind the Pig in the title, that's just because he shows off how it works with a bunch of pigs that get sucked up.
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
Nope, you have to make one. I have no idea how much the speed gain is when using array lookups instead of arithmetics, but I know that JASS is worse at the latter.

Edit: I need to get home soon, so I can debug the shit out of that evil piece of code.
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
Uploading another WIP now. I managed to fix the bug.

I mistook METEOR_IMPACT_EFFECT for METEOR_IMPACT_EFFECT_2, so it wasn't the regular effect thing which fucked up, it was my timed effect library. It wasn't anything wrong in my library though, it was just that the effect hated to be attached to a unit, and it really hated to be scaled to twice the size. Once I turned it into a regular effect it worked, but now it's smaller xD

Edit: Here we go
 
Level 22
Joined
Nov 14, 2008
Messages
3,256
Even if the meteors are instant, the smoke behind them should go away a bit slower. I mean from the top effect to the ground effect it takes less than 0.2 seconds to go away. You should increase that interval, will look a bit better due to the impale dust effect. It's just my opinion though.
 
Bah, this bugs
  • Equilibrium Strike
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Equilibrium Strike
    • Actions
      • -------- --- --------
      • -------- Setting the spell constants --------
      • -------- --- --------
      • Set ES_Caster = (Triggering unit)
      • Set ES_Target = (Target unit of ability being cast)
      • Set ES_Ability_Level = (Level of (Ability being cast) for ES_Caster)
      • Set ES_Owner = (Owner of ES_Caster)
      • -------- --- --------
      • -------- Setting the spell values --------
      • -------- --- --------
      • Set ES_Base_Damage = 60.00
      • Set ES_Level_Damage = 40.00
      • Set ES_Atribute_Factor = 0.30
      • Set ES_Atribute_Damage = (Agility of ES_Caster (Include bonuses))
      • Set ES_Caster_Life = ((Life of ES_Caster) / (Max life of ES_Caster))
      • Set ES_Target_Life = ((Life of ES_Target) / (Max life of ES_Target))
      • -------- --- --------
      • -------- Setting the dummy abilities --------
      • -------- --- --------
      • Set ES_Dummy_Ability_Slow = Equilibrium Strike(dummy slow)
      • Set ES_Dummy_Ability_Stun = Equilibrium Strike(dummy stun)
      • -------- --- --------
      • -------- Setting the spell values/locations for special effects --------
      • -------- --- --------
      • Set ES_Spell_Loc = (Position of ES_Target)
      • Set ES_Spell_Loc_2 = (Position of ES_Caster)
      • Set ES_Facing_Angle = (Angle from ES_Spell_Loc to ES_Spell_Loc_2)
      • Set ES_SFX_Offset = 200.00
      • Set ES_SFX_Angle = 50.00
      • Set ES_SFX_Duration = 1.00
      • Set ES_SFX_Loc = (ES_Spell_Loc_2 offset by ES_SFX_Offset towards (ES_Facing_Angle + ES_SFX_Angle) degrees)
      • Set ES_SFX_Loc_2 = (ES_Spell_Loc_2 offset by ES_SFX_Offset towards (ES_Facing_Angle - ES_SFX_Angle) degrees)
      • -------- --- --------
      • -------- Calculating the damage --------
      • -------- --- --------
      • Set ES_Damage_Calculation = (ES_Base_Damage + ((Real(ES_Ability_Level)) x ES_Level_Damage))
      • Set ES_Atribute_Damage_Calculation = ((Real(ES_Ability_Level)) x (ES_Atribute_Factor x (Real(ES_Atribute_Damage))))
      • -------- --- --------
      • Set ES_Total_Damage = (ES_Atribute_Damage_Calculation + ES_Damage_Calculation)
      • -------- --- --------
      • -------- Creating some nice special effects --------
      • -------- --- --------
      • Special Effect - Create a special effect attached to the weapon of ES_Caster using Abilities\Spells\Orc\Shockwave\ShockwaveMissile.mdl
      • Special Effect - Destroy (Last created special effect)
      • Special Effect - Create a special effect attached to the origin of ES_Target using Abilities\Spells\Other\Stampede\StampedeMissileDeath.mdl
      • Special Effect - Destroy (Last created special effect)
      • Special Effect - Create a special effect attached to the origin of ES_Target using Abilities\Spells\Orc\Disenchant\DisenchantSpecialArt.mdl
      • Special Effect - Destroy (Last created special effect)
      • -------- --- --------
      • -------- Starting a loop, which runs all the moving special effects --------
      • -------- --- --------
      • For each (Integer A) from 1 to 25, do (Actions)
        • Loop - Actions
          • -------- --- --------
          • -------- This loop runs two special effects at the same time, but by different angle, so don't get confused by two colums of almost same actions --------
          • -------- --- --------
          • -------- --- --------
          • -------- Calculating the values which are calculated trough every loop --------
          • -------- --- --------
          • Set ES_SFX_Value = ((Real((Integer A))) x 13.00)
          • Set ES_SFX_Value_1 = (100.00 - ((Real((Integer A))) x 2.50))
          • Set ES_SFX_Value_2 = ((Real((Integer A))) x 8.00)
          • Set ES_SFX_Value_3 = ((Real((Integer A))) x 3.00)
          • Set ES_SFX_Offset_Calculation = (ES_SFX_Offset - ES_SFX_Value)
          • -------- --- --------
          • -------- Getting a location for special effect --------
          • -------- --- --------
          • Set ES_SFX_Loc_3 = (ES_SFX_Loc offset by ES_SFX_Offset_Calculation towards (ES_Facing_Angle + ES_SFX_Angle) degrees)
          • -------- --- --------
          • -------- Creating the dummy as a special effect, setting its values experation timer/flying height/vertex coloring/ animation --------
          • -------- --- --------
          • Unit - Create 1 Dummy_SFX for ES_Owner at ES_SFX_Loc_3 facing ES_Facing_Angle degrees
          • Unit - Add a ES_SFX_Duration second Generic expiration timer to (Last created unit)
          • Unit - Order (Last created unit) to Move To ES_Spell_Loc
          • Animation - Change (Last created unit) flying height to ((Current flying height of (Last created unit)) - ES_SFX_Value_2) at 0.00
          • Animation - Play (Last created unit)'s birth animation
          • Animation - Change (Last created unit)'s size to (ES_SFX_Value_1%, ES_SFX_Value_1%, ES_SFX_Value_1%) of its original size
          • Animation - Change (Last created unit)'s vertex coloring to (100.00%, 100.00%, 100.00%) with ES_SFX_Value_3% transparency
          • -------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------
          • -------- --- --------
          • -------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------
          • -------- Getting a location for special effect --------
          • -------- --- --------
          • Set ES_SFX_Loc_4 = (ES_SFX_Loc_2 offset by ES_SFX_Offset_Calculation towards (ES_Facing_Angle - ES_SFX_Angle) degrees)
          • -------- --- --------
          • -------- Creating the dummy as a special effect, setting its values experation timer/flying height/vertex coloring/ animation --------
          • -------- --- --------
          • Unit - Create 1 Dummy_SFX for ES_Owner at ES_SFX_Loc_4 facing ES_Facing_Angle degrees
          • Unit - Add a ES_SFX_Duration second Generic expiration timer to (Last created unit)
          • Unit - Order (Last created unit) to Move To ES_Spell_Loc
          • Animation - Change (Last created unit) flying height to ((Current flying height of (Last created unit)) - ES_SFX_Value_2) at 0.00
          • Animation - Play (Last created unit)'s birth animation
          • Animation - Change (Last created unit)'s size to (ES_SFX_Value_1%, ES_SFX_Value_1%, ES_SFX_Value_1%) of its original size
          • Animation - Change (Last created unit)'s vertex coloring to (100.00%, 100.00%, 100.00%) with ES_SFX_Value_3% transparency
          • -------- --- --------
          • -------- Clearing the used locations / removing leaks --------
          • -------- --- --------
          • Custom script: call RemoveLocation(udg_ES_SFX_Loc_3)
          • Custom script: call RemoveLocation(udg_ES_SFX_Loc_4)
      • -------- --- --------
      • -------- Creating a nice floaring text that wil dispay the damage done, also setting its lifespan/color/velectory.. --------
      • -------- --- --------
      • Floating Text - Create floating text that reads ((String((Integer(ES_Total_Damage)))) + !) above ES_Target with Z offset 0.00, using font size 10.00, color (100.00%, 5.00%, 0.00%), and 0.00% transparency
      • Floating Text - Change (Last created floating text): Disable permanence
      • Floating Text - Set the velocity of (Last created floating text) to 64.00 towards 90.00 degrees
      • Floating Text - Change the fading age of (Last created floating text) to 0.75 seconds
      • Floating Text - Change the lifespan of (Last created floating text) to 2.00 seconds
      • -------- --- --------
      • -------- Creating a dummy that will Slow/Stun the target --------
      • -------- --- --------
      • Unit - Create 1 Dummy for ES_Owner at ES_Spell_Loc facing Default building facing degrees
      • Unit - Add a 0.75 second Generic expiration timer to (Last created unit)
      • Unit - Make (Last created unit) face ES_Target over 0.00 seconds
      • -------- --- --------
      • -------- This checks which life is higher target's or caster's --------
      • -------- --- --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ES_Caster_Life Greater than or equal to ES_Target_Life
        • Then - Actions
          • -------- --- --------
          • -------- Now if caster's life is higher than target's then dummy is ordered to castslow --------
          • -------- --- --------
          • Unit - Add ES_Dummy_Ability_Slow to (Last created unit)
          • Unit - Set level of ES_Dummy_Ability_Slow for (Last created unit) to ES_Ability_Level
          • Unit - Order (Last created unit) to Human Sorceress - Slow ES_Target
        • Else - Actions
          • -------- --- --------
          • -------- But if caster's life is lower than target's than dummy is ordered to cast storm bolt (stun) --------
          • -------- --- --------
          • Unit - Add Equilibrium Strike(dummy stun) to (Last created unit)
          • Unit - Set level of ES_Dummy_Ability_Stun for (Last created unit) to ES_Ability_Level
          • Unit - Order (Last created unit) to Human Mountain King - Storm Bolt ES_Target
      • -------- --- --------
      • -------- Damaging the target --------
      • -------- --- --------
      • Unit - Cause ES_Caster to damage ES_Target, dealing ES_Total_Damage damage of attack type Spells and damage type Unknown
      • -------- --- --------
      • -------- Clearing the used locations / removing leaks --------
      • -------- --- --------
      • Custom script: call RemoveLocation(udg_ES_Spell_Loc)
      • Custom script: call RemoveLocation(udg_ES_Spell_Loc_2)
      • Custom script: call RemoveLocation(udg_ES_SFX_Loc)
      • Custom script: call RemoveLocation(udg_ES_SFX_Loc_2)
If i use flat life comparison, then it works, but as I attend to use percentage or any other method for life comparison it starts to bug... if unit has lover % of life than caster, then it is ok, dummy casts slow, the problem appears on units with higher percentage of life when dummy should cast stun, but it casts slow instead. So what I'm saying dummy casts slow on every spell cast...

I'm in no mood for thinking, but there is something wrong with calculation eg. caster has full life lets say 1000 (which is 1000/1000 = 1) target has 4500 (so lets say 4500/5000 = .9) this is already wrong...

meh, I can't even think straight... goodnight.
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
Even if the meteors are instant, the smoke behind them should go away a bit slower. I mean from the top effect to the ground effect it takes less than 0.2 seconds to go away. You should increase that interval, will look a bit better due to the impale dust effect. It's just my opinion though.
Yeah, the smoke should stay for a while longer.
Well, there's nothing I can do with the smoke itself, but I guess I could increase the interval at which the meteors hit the ground to compensate.

The big flash is overpoweing and you can't see any actual meteors falling...
That's how the actual spell is. Look at the video in this post (Starts at 0:30).
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
You had it right. If the value of:

Caster Health / Caster Health Max

Is less than the value of:

Target Health / Target Health Max

Then the caster has less health (in percentage) than the target.

So, if the caster has 500/1000 then the percentage is 50%, or 0.5. If the target has 200/300, then the percentage is 66.6%, or 0.666. Since 0.5 < 0.666, the caster would have less percentage than the target.
 
Level 16
Joined
Jun 24, 2009
Messages
1,409
Final

Well, I think I'm done.
starfall.gif
Channels a soul orb to damage the first units in a line. If no enemy unit hit and the orb raches it's max distance, it disappears. The orb passes through magic immune units and buildings.


Thanks to Vengeancekael for the video

  • Init
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Visibility - Disable fog of war
      • Visibility - Disable black mask
      • Set SBMax = 2
      • -------- Configurables on each level --------
      • -------- Level 1 --------
      • Set Distance[1] = 1250.00
      • -------- Level 2 --------
      • Set Distance[2] = 1500.00
      • -------- Level 3 --------
      • Set Distance[3] = 1750.00
  • Soul Blast
    • Events
      • Unit - A unit Begins channeling an ability
    • Conditions
      • (Ability being cast) Equal to Soul Blast
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • SBHas[SBLastRecycled] Equal to True
        • Then - Actions
          • Set SBMax = (SBMax + 1)
          • Set SBLastRecycled = SBMax
          • Set SBIndex = SBLastRecycled
          • Set SBLastRecycled = SBRecycledList[SBLastRecycled]
        • Else - Actions
          • Set SBIndex = SBLastRecycled
          • Set SBLastRecycled = SBRecycledList[SBLastRecycled]
      • Set SBCaster[SBIndex] = (Triggering unit)
      • Set SBCasterPoint[SBIndex] = (Position of SBCaster[SBIndex])
      • Set SBTargetPoint[SBIndex] = (Target point of ability being cast)
      • Set SBDistance[SBIndex] = 50.00
      • Set SBLevel[SBIndex] = (Level of Soul Blast for SBCaster[SBIndex])
      • Set SBMaxDistance[SBIndex] = Distance[SBLevel[SBIndex]]
      • Set SBAngle[SBIndex] = (Angle from SBCasterPoint[SBIndex] to SBTargetPoint[SBIndex])
      • Set SBTempPoint = (SBCasterPoint[SBIndex] offset by 50.00 towards SBAngle[SBIndex] degrees)
      • Custom script: set udg_SBDummyGroup[udg_SBIndex] = CreateGroup()
      • Unit - Create 1 Missile Body 1 for (Triggering player) at SBCasterPoint[SBIndex] facing SBAngle[SBIndex] degrees
      • Unit Group - Add (Last created unit) to SBDummyGroup[SBIndex]
      • Animation - Change (Last created unit)'s animation speed to 5.00% of its original speed
      • Unit - Create 1 Missile Body 2 for (Triggering player) at SBCasterPoint[SBIndex] facing SBAngle[SBIndex] degrees
      • Unit Group - Add (Last created unit) to SBDummyGroup[SBIndex]
      • Unit - Create 1 Missile Head for (Triggering player) at SBTempPoint facing SBAngle[SBIndex] degrees
      • Unit Group - Add (Last created unit) to SBDummyGroup[SBIndex]
      • Custom script: set udg_SBChannelGroup[udg_SBIndex] = CreateGroup()
      • For each (Integer A) from 1 to 2, do (Actions)
        • Loop - Actions
          • Set SBScale[SBIndex] = (100.00 x (Real((Integer A))))
          • Unit - Create 1 Channel Effect for (Triggering player) at SBCasterPoint[SBIndex] facing SBAngle[SBIndex] degrees
          • Animation - Change (Picked unit)'s size to (SBScale[SBIndex]%, SBScale[SBIndex]%, SBScale[SBIndex]%) of its original size
          • Unit Group - Add (Last created unit) to SBChannelGroup[SBIndex]
      • Set SBHas[SBIndex] = True
      • Set SBCount = (SBCount + 1)
      • Set SBTimer[SBIndex] = 3.00
      • Set SBEffect[SBIndex] = False
      • Custom script: call RemoveLocation (udg_SBTempPoint)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Soul Blast Loop <gen> is on) Equal to False
        • Then - Actions
          • Trigger - Turn on Soul Blast Loop <gen>
          • Trigger - Turn on Wave Effect <gen>
        • Else - Actions
  • Soul Blast Halt
    • Events
      • Unit - A unit Stops casting an ability
      • Unit - A unit Finishes casting an ability
    • Conditions
      • (Ability being cast) Equal to Soul Blast
    • Actions
      • For each (Integer A) from 0 to SBMax, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • SBCaster[(Integer A)] Equal to (Triggering unit)
            • Then - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • SBTimer[(Integer A)] Greater than 0.00
                • Then - Actions
                  • Unit Group - Pick every unit in SBDummyGroup[(Integer A)] and do (Unit - Kill (Picked unit))
                  • Unit Group - Pick every unit in SBChannelGroup[(Integer A)] and do (Unit - Remove (Picked unit) from the game)
                  • Custom script: call DestroyGroup (udg_SBChannelGroup[GetForLoopIndexA()])
                  • Custom script: call DestroyGroup (udg_SBDummyGroup[GetForLoopIndexA()])
                  • Set SBTimer[(Integer A)] = 0.00
                  • Custom script: call RemoveLocation (udg_SBTargetPoint[GetForLoopIndexA()])
                  • Custom script: call RemoveLocation (udg_SBCasterPoint[GetForLoopIndexA()])
                  • Set SBHas[(Integer A)] = False
                  • Set SBRecycledList[(Integer A)] = SBLastRecycled
                  • Set SBLastRecycled = (Integer A)
                  • Set SBEffect[(Integer A)] = False
                  • Set SBCount = (SBCount - 1)
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • SBCount Equal to 0
                    • Then - Actions
                      • Trigger - Turn off Wave Effect <gen>
                      • Trigger - Turn off Soul Blast Loop <gen>
                    • Else - Actions
                • Else - Actions
            • Else - Actions
  • Soul Blast Loop
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • For each (Integer SBInteger) from 0 to SBMax, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • SBHas[SBInteger] Equal to True
            • Then - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • SBTimer[SBInteger] Greater than 0.00
                • Then - Actions
                  • Set SBTimer[SBInteger] = (SBTimer[SBInteger] - 0.03)
                  • Set SBScale[SBInteger] = (SBScale[SBInteger] - 10.00)
                  • Set r = SBScale[SBInteger]
                  • Unit Group - Pick every unit in SBChannelGroup[SBInteger] and do (Actions)
                    • Loop - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • r Less than 110.00
                        • Then - Actions
                          • Set r = 200.00
                        • Else - Actions
                          • Set r = (r - 100.00)
                      • Animation - Change (Picked unit)'s size to (r%, r%, r%) of its original size
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Number of units in SBChannelGroup[SBInteger]) Not equal to 0
                    • Then - Actions
                      • Unit Group - Pick every unit in SBChannelGroup[SBInteger] and do (Unit - Remove (Picked unit) from the game)
                    • Else - Actions
                  • Set SBEffect[SBInteger] = True
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • SBDistance[SBInteger] Less than SBMaxDistance[SBInteger]
                    • Then - Actions
                      • Set SBDistance[SBInteger] = (SBDistance[SBInteger] + 40.00)
                      • Set SBTempPoint = (SBCasterPoint[SBInteger] offset by SBDistance[SBInteger] towards SBAngle[SBInteger] degrees)
                      • Unit Group - Pick every unit in SBDummyGroup[SBInteger] and do (Actions)
                        • Loop - Actions
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • (Unit-type of (Picked unit)) Equal to Missile Head
                            • Then - Actions
                              • Set SBTempPoint2 = (SBCasterPoint[SBInteger] offset by (SBDistance[SBInteger] + 40.00) towards SBAngle[SBInteger] degrees)
                              • Unit - Move (Picked unit) instantly to SBTempPoint2
                              • Custom script: call RemoveLocation (udg_SBTempPoint2)
                            • Else - Actions
                              • Unit - Move (Picked unit) instantly to SBTempPoint
                      • Set SBTempGroup = (Units within 100.00 of SBTempPoint matching ((((Matching unit) is A structure) Equal to False) and ((((Matching unit) is Magic Immune) Equal to False) and ((((Matching unit) is alive) Equal to True) and (((Matching unit) belongs to an enemy of (Owner of SBCa
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (SBTempGroup is empty) Equal to True
                        • Then - Actions
                        • Else - Actions
                          • Custom script: call RemoveLocation (udg_SBTargetPoint[udg_SBInteger])
                          • Custom script: call RemoveLocation (udg_SBCasterPoint[udg_SBInteger])
                          • Custom script: set bj_wantDestroyGroup = true
                          • Unit Group - Pick every unit in SBDummyGroup[SBInteger] and do (Unit - Kill (Picked unit))
                          • Unit Group - Pick every unit in SBChannelGroup[SBInteger] and do (Unit - Remove (Picked unit) from the game)
                          • Custom script: call DestroyGroup (udg_SBDummyGroup[udg_SBInteger])
                          • Custom script: call DestroyGroup (udg_SBChannelGroup[udg_SBInteger])
                          • Set SBEffect[SBIndex] = False
                          • Unit Group - Pick every unit in (Units within 250.00 of SBTempPoint matching ((((Matching unit) is A structure) Equal to False) and ((((Matching unit) is Magic Immune) Equal to False) and ((((Matching unit) is alive) Equal to True) and (((Matching unit) belongs to an enemy of (Owner of SBCa and do (Actions)
                            • Loop - Actions
                              • Unit - Cause SBCaster[SBInteger] to damage (Picked unit), dealing (100.00 x (Real(SBLevel[SBInteger]))) damage of attack type Spells and damage type Magic
                          • Unit - Create 1 Blast Effect for (Owner of SBCaster[SBInteger]) at SBTempPoint facing Default building facing degrees
                          • Unit - Add a 0.10 second Generic expiration timer to (Last created unit)
                          • Set SBHas[SBInteger] = False
                          • Set SBCount = (SBCount - 1)
                          • Set SBRecycledList[SBInteger] = SBLastRecycled
                          • Set SBLastRecycled = SBInteger
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • SBCount Equal to 0
                            • Then - Actions
                              • Trigger - Turn off (This trigger)
                              • Trigger - Turn off Wave Effect <gen>
                            • Else - Actions
                      • Custom script: call DestroyGroup (udg_SBTempGroup)
                      • Custom script: call RemoveLocation (udg_SBTempPoint)
                    • Else - Actions
                      • Set SBHas[SBInteger] = False
                      • Custom script: set bj_wantDestroyGroup = true
                      • Set SBEffect[SBIndex] = False
                      • Unit Group - Pick every unit in SBDummyGroup[SBInteger] and do (Unit - Kill (Picked unit))
                      • Unit Group - Pick every unit in SBChannelGroup[SBInteger] and do (Unit - Remove (Picked unit) from the game)
                      • Custom script: call DestroyGroup (udg_SBDummyGroup[udg_SBInteger])
                      • Custom script: call DestroyGroup (udg_SBChannelGroup[udg_SBInteger])
                      • Custom script: call RemoveLocation (udg_SBTargetPoint[udg_SBInteger])
                      • Custom script: call RemoveLocation (udg_SBCasterPoint[udg_SBInteger])
                      • Set SBCount = (SBCount - 1)
                      • Set SBRecycledList[SBInteger] = SBLastRecycled
                      • Set SBLastRecycled = SBInteger
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • SBCount Equal to 0
                        • Then - Actions
                          • Trigger - Turn off (This trigger)
                          • Trigger - Turn off Wave Effect <gen>
                        • Else - Actions
            • Else - Actions
  • Wave Effect
    • Events
      • Time - Every 0.05 seconds of game time
    • Conditions
    • Actions
      • For each (Integer B) from 0 to SBMax, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • SBHas[(Integer B)] Equal to True
            • Then - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • SBEffect[(Integer B)] Equal to True
                • Then - Actions
                  • Unit Group - Pick every unit in SBDummyGroup[(Integer B)] and do (Actions)
                    • Loop - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • ((Picked unit) is alive) Equal to True
                          • (Unit-type of (Picked unit)) Equal to Missile Head
                        • Then - Actions
                          • Set SBTempPoint = (Position of (Picked unit))
                          • Unit - Create 1 Wave Effect for (Owner of (Picked unit)) at SBTempPoint facing (Facing of (Picked unit)) degrees
                          • Animation - Change (Last created unit)'s animation speed to 150.00% of its original speed
                          • Unit - Add a 1.00 second Generic expiration timer to (Last created unit)
                          • Custom script: call RemoveLocation (udg_SBTempPoint)
                        • Else - Actions
                • Else - Actions
                  • Unit - Create 1 Blast Effect for (Owner of SBCaster[(Integer B)]) at SBCasterPoint[(Integer B)] facing Default building facing degrees
                  • Unit - Add a 0.10 second Generic expiration timer to (Last created unit)
                  • Animation - Change (Last created unit)'s animation speed to 200.00% of its original speed
            • Else - Actions
View attachment Soul Blast.w3x
 
Last edited:
Level 17
Joined
Jan 21, 2010
Messages
2,111
Don't worry my friend, the intro of the contest would make you feel better
Introduction

The Spells & Systems Contest is more of a fun code learning environment than a contest, due to its low requirements, its short time limit, and its small prize. Each spell must adhere to the theme listed below, and to win, it should be executed well and take the main judging points into consideration.
 
You had it right. If the value of:

Caster Health / Caster Health Max

Is less than the value of:

Target Health / Target Health Max

Then the caster has less health (in percentage) than the target.

So, if the caster has 500/1000 then the percentage is 50%, or 0.5. If the target has 200/300, then the percentage is 66.6%, or 0.666. Since 0.5 < 0.666, the caster would have less percentage than the target.

Got any ideas how to make it more balanced, by not just using flat life?
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Got any ideas how to make it more balanced, by not just using flat life?

Well the spell is supposed to slow/stun based on whether or not the target's health percentage is lower than that of the caster, isn't it? Not much option you have lol.

If you want you could give the caster a little leniency, like if the caster's health percentage is greater than the target's or within 5% of it:

CHealthPerc = 0.57
THealthPerc = 0.6

CHealthPerc + (Leniency) < THealthPerc
0.57 + 0.05 = 0.62

0.62 > 0.6


If that makes sense to you...
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
TDR, that looks really good now; where did you get the light flashing effect from?

Does anybody own Age of Mythology? There aren't any particularly good videos of the effect it has; from what I can tell it deals damage to enemies in an area and sucks them into the wind if they die as a result.

What happens when two tornadoes come in contact with each other? What happens to the units that are being blown around by the tornado? What happens to air units (if there are air units) when they are affected by the tornado?

Okay, got some issues. When I hurl the units together by the effects of the tornado I keep them from dying so that the dead units don't look bad. This runs into some UI problems. When units are being thrown around in the tornado winds and you're holding ALT it shows all of their tags above their head and the result is kind of annoying.

If I use dead units it will remove the HUD when they die, and recently I've played with animations and animation time scales and it seems I can achieve a good effect even on dead units. The problem is now the decay. I want units to decay, but the time it takes the unit to die is a problem.

If I set the death time to something like 60 seconds (which is quite long) then I can play with the unit's animation before it "officially" dies after the death-time. This makes the HUD improvements that are necessary and makes units who are being thrown around by the tornado look a little more realistic. The problem is that this requires object-editor changes for units, and also dead units (not just tornado-killed) will lay on the ground for quite some time after they are not needed.

I could play around with the time to make this minimal, but I want to know whether or not this approach is within the rules of the spell contest.
 
Last edited:
Level 49
Joined
Apr 18, 2008
Messages
8,421
Okay, TRD, I got the exact stuff now.
Meteor Storm does not damage allies and your own units; It does, however, knock them off flying, albeit more lightly than enemy units.
Meteor Storm also has cool 'godpower music' playing while it's being cast. :D

Berb said:
Does anybody own Age of Mythology? There aren't any particularly good videos of the effect it has; from what I can tell it deals damage to enemies in an area and sucks them into the wind if they die as a result.

What happens when two tornadoes come in contact with each other? What happens to the units that are being blown around by the tornado? What happens to air units (if there are air units) when they are affected by the tornado?

2 tornadoes can't meet because you can't cast 2 godpowers in the same area at the same time.
Flying units are probably the same.
Units are being dealt damage over time, and if they die, their corpses get sucked into the tornado.
If the Tornado meets a building, random debris will appear inside it, but the debris is not actually pieces of the building model itself.
If the tornado reaches water, it becomes blue\white and all water-y. That's irrelevant, though, I guess. :D

I'll get a video of the Tornado godpower tomorrow, on the same 'playground' as my meteor storm video. I just re-installed Age of Mythology and realized that I didn't remove my save files; Yipee! :D
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
TDR, that looks really good now; where did you get the light flashing effect from?
TRD* :D
I got it from a rocket, actually. It's quite funny ^^
This is the effect "Abilities\\Weapons\\RocketMissile\\RocketMissile.mdl" and it's scaled to 16 times its own size.
I destroy it as it's spawned, like call DestroyEffect(AddSpecialEffectTarget(<derp>)) (Target because it's attached to a dummy unit so I could scale it).

Okay, TRD, I got the exact stuff now.
Meteor Storm does not damage allies and your own units; It does, however, knock them off flying, albeit more lightly than enemy units.
Meteor Storm also has cool 'godpower music' playing while it's being cast. :D
Okey, I'll implement that tomorrow. Not sure if I'll find fitting "godpower music" though without importing anything.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Lucky you. I tried to scale/play with the effects for my Tornado spell but it didn't work out as nicely. When I scale the Tornado certain things stay the same size, which is really annoying.

By the way I leave on the 13th for Europe so I pretty much only have today and tomorrow to finish up my spell. If I can't get answers then I'll do what I think is appropriate, and if that isn't good enough then so be it.

I guess I'll post a WIP of the code. The visual isn't that impressive yet.

This is the primary library. It is created to execute most of the effects from the spell.

JASS:
library TornadoObject requires SafetyQueue, TimerUtils, Group
struct tornadoobject
//******************
//* Tornado Object
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯ 
//*
//*
//* ########################################################################################################
//* Config:
//*     @ TORNADO_ID                    - the unit ID of the tornado visual unit.
//*
//*     @ TORNADO_VISUAL_COUNT          - the amount of tornado visuals created upon construction.
//*     @ TORNADO_DEBRIS_COUNT          - the amount of tornado debris visuals created upon construction.
//*
//*     @ DAMAGE_FREQUENCY              - the frequency enemies are damaged within the 'outerRadius'.
//*     @ MOTION_UPDATE_FREQUENCY       - the frequency at which motion is updated amongst tornado objects.
//*
//*     @ TORNADO_OFFSET_LIMIT          - the tornado visuals will be offset by a maximum of this value.
//*     @ TORNADO_SCALE_MINIMUM         - the smallest scale-size a tornado may have.
//*     @ TORNADO_SCALE_MAXIMUM         - the largest scale-size a tornado may have.
//*
//*     @ DAMAGE_PER_SECOND             - the damage dealt to enemies within a second.
//* ----   
    public static constant integer      TORNADO_ID                  = 'hsor'

    public static constant integer      TORNADO_VISUAL_COUNT        = 3
    public static constant integer      TORNADO_DEBRIS_COUNT        = 4
    
    public static constant real         DAMAGE_FREQUENCY            = 0.1
    public static constant real         MOTION_UPDATE_FREQUENCY     = 0.033
    
    public static constant real         TORNADO_OFFSET_LIMIT        = 30.00
    public static constant real         TORNADO_SCALE_MINIMUM       = 1.4
    public static constant real         TORNADO_SCALE_MAXIMUM       = 1.7
    
    public static real array            DAMAGE_PER_SECOND  
//*
//*
//* ########################################################################################################
//*
//*
//* Members:
//*     
//* ----
    private unit                    originCaster        = null
    private player                  casterPlayer        = null
    private integer                 level

    private unit array              visualDummy         [thistype.TORNADO_VISUAL_COUNT]
    private tornadodebris array     debrisDummy         [thistype.TORNADO_DEBRIS_COUNT]
    private extgroup                effectGroup
    
    private real                    x      
    private real                    y
    private real                    outerRadius
    private real                    innerRadius
    
    private timer                   damageTimer         = null
    private timer                   motionTimer         = null
//*
//*    
//* Method: onDestroyGroupEnum ()
//*     Iterates through the group 'effectGroup' to reset some of the states that may have been altered
//*     during the spell such as invulnerability and pause-state.
//*
//*     Uses the 'enumTempObject' member defined below to carry data to another function.
//* ----
    private static method onDestroyGroupEnum takes nothing returns nothing
        local unit en = GetEnumUnit()
        call SetUnitFlyHeight(en, 0, 20000)
        call SetUnitTimeScale(en, 1)
        call PauseUnitSafe(en, false)
        call SetUnitInvulnerableSafe(en, false)
        call UnitDamageTarget(enumTempObject.originCaster, en, GetWidgetLife(en)*2, false, false, /*
                */ ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
        set en = null
    endmethod   
//*
//*
//* Destructor:
//*
//* ----
    method onDestroy takes nothing returns nothing
        local integer i = 0
        loop    // destroy tornado visuals
            exitwhen i == TORNADO_VISUAL_COUNT
            call KillUnit(visualDummy[i])
            set i = i + 1
        endloop
        set i = 0
        loop    // destroy tornado debris visuals
            exitwhen i == TORNADO_DEBRIS_COUNT
            call debrisDummy[i].destroy()
            set i = i + 1
        endloop
        set enumTempObject = this
        call ForGroup(effectGroup.g, function thistype.onDestroyGroupEnum)
        call effectGroup.destroy()
        call ReleaseTimer(damageTimer)
        call ReleaseTimer(motionTimer)
    endmethod
//*
//* 
//* Method: createTornadoVisual ()
//*     Creates a tornado unit for visual effect at an offset location to the given coordinates.
//* ----
    private static      real        tempDist
    private static      real        tempAngl
    private static      real        tempX
    private static      real        tempY
    private static      unit        tempReturn
    
    static method createTornadoVisual takes real x, real y, real scale returns unit
        set tempDist = GetRandomReal(0, TORNADO_OFFSET_LIMIT)
        set tempAngl = GetRandomReal(0, 2*bj_PI)
        set tempX = x + tempDist * Cos(tempAngl)
        set tempY = y + tempDist * Sin(tempAngl)
        set tempReturn = CreateUnit(Player(12), TORNADO_ID, tempX, tempY, GetRandomReal(0, 360))
        call SetUnitX(tempReturn, tempX)
        call SetUnitY(tempReturn, tempY)
        call SetUnitScale(tempReturn, scale, scale, scale)
        call SetUnitTimeScale(tempReturn, 0.4)
        call extunit[tempReturn].applyFader(255, 255, 200, 0, 255, 5.0)
        return tempReturn
    endmethod
//*
//*
//* Constructor:
//*     Creates a tornado-object given coordinates and values for inner/outer radius, respectively.
//* ----
    static method create takes unit caster, integer lvl, real x, real y, real radius1, real radius2 returns thistype
        local thistype t = allocate()
        local integer i
        set t.x = x
        set t.y = y
        set t.originCaster = caster
        set t.casterPlayer = GetOwningPlayer(caster)
        set t.level = lvl
        set t.effectGroup = extgroup.create()
        if radius1 > radius2 then
            set t.innerRadius = radius2
            set t.outerRadius = radius1
        else
            set t.innerRadius = radius1
            set t.outerRadius = radius2
        endif
        set i = 0
        loop
            exitwhen i == TORNADO_VISUAL_COUNT
            set t.visualDummy[i] = createTornadoVisual(x, y, /*
                    */ GetRandomReal(TORNADO_SCALE_MINIMUM, TORNADO_SCALE_MAXIMUM))
            set i = i + 1
        endloop
        set t.damageTimer = NewTimer()
        call SetTimerData(t.damageTimer, t)
        call TimerStart(t.damageTimer, DAMAGE_FREQUENCY, true, function thistype.onDamageInterval)
        set t.motionTimer = NewTimer()
        call SetTimerData(t.motionTimer, t)
        call TimerStart(t.motionTimer, MOTION_UPDATE_FREQUENCY, true, function thistype.onMotionInterval)
        return t
    endmethod
//*
//*
//* Method: onMotionIterate ()
//*     Iterates through the group's contents and updates. There are a lot of execution trees here,
//*     so to clarify what this is doing... 
//*
//*     "onMotionInterval" is executed after the tornado has been created on a periodic interval. The
//*     timer "motionTimer" is responsible for this. On each execution of "onMotionInterval", the 
//*     members of the group "effectGroup" are iterated through.
//* ----
    private static method onMotionIterate takes nothing returns nothing
        local unit en = GetEnumUnit() 
        local real newX
        local real newY
        local real angl = Atan2(enumTempObject.y - GetUnitY(en), enumTempObject.x - GetUnitX(en))
        local real rnd = GetRandomReal(-bj_PI/16, bj_PI/16)
        
        if IsUnitInRangeXY(en, enumTempObject.x, enumTempObject.y, enumTempObject.innerRadius) then
            set newX = GetUnitX(en) + 11 * Cos(angl+bj_PI/2+rnd)
            set newY = GetUnitY(en) + 11 * Sin(angl+bj_PI/2+rnd)
            call SetUnitFlyHeight(en, GetUnitFlyHeight(en)+1, 0)
        else
            set newX = GetUnitX(en) + 10 * Cos(angl)
            set newY = GetUnitY(en) + 10 * Sin(angl)
            set newX = newX + 11 * Cos(angl+bj_PI/2)
            set newY = newY + 11 * Sin(angl+bj_PI/2)
        endif
        
        call SetUnitX(en, newX)
        call SetUnitY(en, newY)
        set en = null
    endmethod
//*
//*
//* Method: onMotionInterval ()
//*     This method uses the 'enumTempObject' which is defined below under 'onDamageInterval ()'.
//* ----
    private static method onMotionInterval takes nothing returns nothing
        set enumTempObject = GetTimerData(GetExpiredTimer())
        call ForGroup(enumTempObject.effectGroup.g, function thistype.onMotionIterate)
    endmethod
//*
//*
//* Method: onDamageFilter ()
//*     This will damage nearby enemies to the tornado. The interval method is defined below which is
//*     executed on a periodic basis, though similar to "onMotionInterval" it simply allocates the 
//*     iterative work-load to this method.
//* ----
    private static method onDamageFilter takes nothing returns boolean
        local boolean isValid = true
        local unit filt = GetFilterUnit()
        local thistype temp = enumTempObject
        if not IsUnitInGroup(filt, temp.effectGroup.g) then
            if not IsUnitEnemy(filt, temp.casterPlayer) or /*
                    */ IsUnitType(filt, UNIT_TYPE_MAGIC_IMMUNE) then
                set isValid = false
            endif
            if isValid then
                if (DAMAGE_PER_SECOND[temp.level] * DAMAGE_FREQUENCY) >= GetWidgetLife(filt) then
                    if not (GetWidgetLife(filt) < 0.405) then
                        call SetUnitInvulnerableSafe(filt, true)
                        call PauseUnitSafe(filt, true)
                        call SelectUnit(filt, false)
                        call SetUnitTimeScale(filt, 6)
                        call UnitAddAbility(filt, 'Amrf')
                        call UnitRemoveAbility(filt, 'Amrf')
                        call GroupAddUnit(temp.effectGroup.g, filt)
                    endif
                else
                    call UnitDamageTarget(temp.originCaster, filt, /*
                            */ DAMAGE_PER_SECOND[temp.level] * DAMAGE_FREQUENCY, /*
                            */ false, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
                endif
            endif
        endif
        set filt = null
        return false
    endmethod
//*
//*
//* Method: onDamageInterval ()
//*     On each damage interval nearby enemies are enumerated and dealt damage.
//* ----
    private static group            enumGroup           = CreateGroup()
    private static boolexpr         enumFilter          = null
    private static thistype         enumTempObject      

    private static method onDamageInterval takes nothing returns nothing
        set enumTempObject = GetTimerData(GetExpiredTimer())
        call GroupEnumUnitsInRange(enumGroup, enumTempObject.x, enumTempObject.y, /*
                */ enumTempObject.outerRadius, enumFilter)
    endmethod
//*
//* 
//* Initialization:
//*
//* ----
    private static method onInit takes nothing returns nothing
        set enumFilter = Filter(function thistype.onDamageFilter)
        
        set DAMAGE_PER_SECOND[0]    = 250.00
        set DAMAGE_PER_SECOND[1]    = 350.00
    endmethod
//*
//*
//**********************************************************************************************************
endstruct
endlibrary

The following are secondary libraries that are used.

JASS:
scope Tornado
struct tornado extends spell
//******************
//* Tornado
//* ¯¯¯¯¯¯¯
//* The spell-effect should be found in the "onSpellEffect" method.
//*
//*
//* ########################################################################################################
//* Config 
//*     @ ABIL_ID               - the raw-code ability ID for the spell.
//*     @ DURATION              - the duration that the tornado will last until destruction.
//* ----
    public static constant integer      ABIL_ID         = 'A000'
    public static constant real         DURATION        = 25.00
//*
//*
//* ########################################################################################################
//*
//*
//* Method: onSpellExpire ()
//*     Executes after the spell has been cast and the duration has expired. This will simply destroy
//*     the tornado object which was created on spell effect.
//* ----
    private static method onSpellExpire takes nothing returns nothing
        call tornadoobject(GetTimerData(GetExpiredTimer())).destroy()
        call ReleaseTimer(GetExpiredTimer())
    endmethod
//*
//*
//* Method: onSpellEffect ()
//*     Executes spell actions. User-interfaced method.
//* ----
    method onSpellEffect takes nothing returns nothing
        local timer t = NewTimer()
        local tornadoobject obj = tornadoobject.create(GetTriggerUnit(), /* 
                */ GetUnitAbilityLevel(GetTriggerUnit(), ABIL_ID), GetSpellTargetX(), GetSpellTargetY(), 80, 800)
        
        call SetTimerData(t, obj)
        call TimerStart(t, DURATION, false, function thistype.onSpellExpire)
    
        set t = null 
    endmethod
//*
//*
//* Initialization:
//*     Initialize 'tornado' spell struct.
//* ----
    private static method onInit takes nothing returns nothing
        call thistype.create(ABIL_ID)
    endmethod
//*
//*
//**********************************************************************************************************
endstruct
endscope

JASS:
library Unit requires AutoIndex,                            /*
                        */ optional UnitTargetModule,       /* 
                        */ optional UnitDamageModule,       /*
                        */ optional UnitFaderModule
                
struct extunit extends extunitinterface
//******************
//* Extended Unit
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯
//* The extended unit struct is implemented with AutoIndex because it is truly one of the easiest to
//* interface with for casual purposes, or at least to my standards.
//*
//* Modules can be implemented (as they are below) that add functionality in terms of API methods and
//* interface methods which make the unit struct very easy to work with.
//*
//*
//* Optional Modules:
//*     @ UnitDamageModule          - provides registration of unit structs in a damage-detection engine.
//*     @ UnitTargetModule          - provides an API for gathering unit targeting information.
//*     @ UnitFaderModule           - provides an API for fading a unit in alpha color.
//* ----
    implement optional  UnitDamageModule
    implement optional  UnitTargetModule
    implement optional  UnitFaderModule
//*
//*
//* Implemented Modules:
//*     @ AutoCreate                - provides automatic creation of 'extunit' structs for new units.
//*     @ AutoDestroy               - provides automatic recycling of 'extunit' structs when the 
//*                                 associated unit is removed from the game.
//* ----
    implement   AutoCreate
    implement   AutoDestroy
//*
//*
//**********************************************************************************************************
endstruct
endlibrary

JASS:
library UnitFader
module UnitFaderModule
//******************
//* Unit Fader Module
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//* Provides an API to the 'extunit' struct to fade a unit from a set starting alpha to a set final alpha. The 
//* unit-fader comes with a method to determine whether or not a unit is being faded, but additional calls to
//* the unit-fader will simply over-ride each other.
//*
//*
//* Timer Members:
//*     Variable members associated with the timed updates of the fader.
//* ----
    private static timer            fadeTimer           = CreateTimer() 
    private static constant real    fadeTimeout         = 0.1
//*
//* 
//* Stack Members:
//*     Variable members that maintain a stack of units that are being told to fade.
//* ----
    private static thistype array   fadeStack
    private static integer          fadeStackSize       = 0
    private integer                 fadeStackIndex     
    private boolean                 fadeStackIn         = false
//*                                                                 
//*
//* Fade Data Members:
//*     Data associated with the fade components and coloring components of the unit.
//* ----
    private integer                 fadeVertexRed
    private integer                 fadeVertexBlue
    private integer                 fadeVertexGreen
    private integer                 fadeVertexAlpha
    private integer                 fadeVertexAlphaStep
    private integer                 fadeVertexAlphaFinal
    private real                    fadeTimeLeft
//*
//*
//* Method: removeFader ()
//*     Removes the unit-fader from the stack. By the time 'removeFader()' is called the unit's final
//*     alpha should be the same value given upon application.
//* ----
    method removeFader takes nothing returns nothing
        set fadeStackSize = fadeStackSize - 1
        set fadeStack[fadeStackIndex] = fadeStack[fadeStackSize]
        set fadeStack[fadeStackIndex].fadeStackIndex = fadeStackIndex
        if fadeStackSize == 0 then
            call PauseTimer(fadeTimer)
        endif
    endmethod
//*
//* Method: fadeRefresh ()
//*     Updates the stack with appropriate fade levels.
//* ----
    private static method fadeRefresh takes nothing returns nothing
        local integer i = fadeStackSize - 1
        local thistype d
        loop
            exitwhen i < 0
            set d = fadeStack[i]
            if d != 0 then
                set d.fadeTimeLeft = d.fadeTimeLeft - fadeTimeout
                if d.fadeTimeLeft <= 0.00 then
                    set d.fadeVertexAlpha = d.fadeVertexAlphaFinal
                    call SetUnitVertexColor(d.me, d.fadeVertexRed, d.fadeVertexGreen, /*
                            */ d.fadeVertexBlue, d.fadeVertexAlpha)
                    // The unit-fader is complete and can be removed from the stack.
                    call d.removeFader()
                else
                    set d.fadeVertexAlpha = R2I(d.fadeVertexAlpha + d.fadeVertexAlphaStep * fadeTimeout)
                    call SetUnitVertexColor(d.me, d.fadeVertexRed, d.fadeVertexGreen, /*
                            */ d.fadeVertexBlue, d.fadeVertexAlpha)
                endif
            endif
            set i = i - 1
        endloop
    endmethod
//*
//*
//* Method: applyFader ()
//*     Applies the fader to a unit, adding the unit object to the stack so it can be updated.
//* ----
    method applyFader takes integer red, integer grn, integer blu, /*
            */ integer alpha1, integer alpha2, real duration returns nothing
        if fadeStackSize == 0 then
            // The fade-stack is empty.
            call TimerStart(fadeTimer, fadeTimeout, true, function thistype.fadeRefresh)
        endif
        if not fadeStackIn then
            set fadeStack[fadeStackSize] = this
            set fadeStackIndex = fadeStackSize
            set fadeStackSize = fadeStackSize + 1
        endif
        call SetUnitVertexColor(me, red, grn, blu, alpha1)
        
        set fadeVertexRed = red
        set fadeVertexBlue = blu
        set fadeVertexGreen = grn
        set fadeVertexAlpha = alpha1
        set fadeVertexAlphaStep = R2I((alpha2 - alpha1) / duration)
        set fadeVertexAlphaFinal = alpha2
        set fadeTimeLeft = duration
    endmethod
//*
//*
//*
//**********************************************************************************************************
endmodule
endlibrary

JASS:
library Spell requires SpellInterface, SpellSetupModule
struct spell extends spellinterface
//******************
//* Spell
//* ¯¯¯¯¯
//* Allows a fairly convenient interface for referencing spell-related data. Once a spell has been
//* created it is given an ID. This ID can be used to reference the spell struct.
//*
//* When you are comfortable to customize your spell, simply extend the 'spell' struct and define your
//* own actions for "onSpellEffect", or one of the other interface events.
//*
//* Each spell event must have the parameters for the caster of the spell, a target of some type, and
//* the level of the spell when it was cast. The target types are:
//*     - Unit Target
//*     - Point Target
//*     - No Target
//*
//* If "0" is given as the target then it will know there is no target. If an object of type 
//* "spelltargetunit" is given then it is a unit-target (target will have .targetUnit() method) or
//* if "spelltargetarea" is given then it is a point-target.
//* 
//*
//* Spell Members:
//*     @ id            - the raw-code or integer ID of the spell.
//* ----
    public integer              id
//*
//*
//* System Members:
//*     @ table         - the hash table used to cross-reference spells and spell IDs.
//* ----
    private static hashtable    table       = InitHashtable()
//*
//*
//* Operators:
//*     These are used to make interfacing with the spell struct a little more convenient.
//* ----
    static method operator [] takes integer id returns thistype
        if HaveSavedInteger(table, id, 0) then
            return LoadInteger(table, id, 0)
        endif
        return 0
    endmethod
//*
//* Method: verify ()
//*     Verifies whether or not a specific integer ID is already being used by a spell. The integer-ID
//*     of the spell should be able to transform to the spell struct that stores it.
//* ----
    private static method verify takes integer id returns boolean
        return not HaveSavedInteger(table, id, 0)
    endmethod
//*
//*
//* Method: register ()
//*     Registers a spell ID to the spell struct system so that the ID cannot be shared. This also
//*     allows the reference of spell structs directly from the spell IDs.
//* ----
    private static method register takes integer id, thistype sp returns nothing
        call SaveInteger(table, id, 0, sp)
    endmethod
//*
//*
//* Destructor:
//*     Destroys a spell struct, unregistering its ID.
//* ----
    method onDestroy takes nothing returns nothing
        call RemoveSavedInteger(table, id, 0)
    endmethod
//*
//* Constructor:
//*     Creates a spell struct with an ID. The spell is cross-referenced with the spell ID and can
//*     be obtained from the spell ID with the syntax "spell[ ID ]". Spells may not share IDs.
//* ----
    static method create takes integer id returns thistype
        local thistype sp = 0
        if verify(id) then
            set sp = allocate()
            set sp.id = id
            call register(id, sp)
        endif
        return sp
    endmethod
//*
//* 
//* Implemented Modules:
//*     @ SpellSetupModule      - provides a setup for the spell struct that registers events to several
//*                             triggers so that they can be extended to the user interface.
//* ----
    implement   SpellSetupModule
//*
//*
//**********************************************************************************************************
endstruct
endlibrary

So far the lifting of the units is (as it shows in the code) really poorly done. It's just something I typed up quick now because I'm on my way out, and I wanted to be sure there were no unexpected troubles I would have by incorporating fly-height.

Lol, oh and I use this stupid little group thing because I was too lazy to download GroupUtils:

JASS:
library Group 
struct extgroup
    public group g
    
    method onDestroy takes nothing returns nothing
        call GroupClear(g)
    endmethod
    
    static method create takes nothing returns thistype
        local thistype s = allocate()
        if (s.g == null) then
            set s.g = CreateGroup()
        endif
        return s
    endmethod
endstruct
endlibrary
 
Last edited:
Level 17
Joined
Jan 21, 2010
Messages
2,111
Test the map adiktuz, and you will notice why it's multi colored..
Hehe~
Btw, i can't see the vids from my hp, i'll see them if i had time to watch them in my pc..
Hehe~
Btw, thanks vengeancekael!
Oh, and adiktuz, i try to make one of those ghost, and it's look nice...
Tehehe~
 
Level 17
Joined
Jan 21, 2010
Messages
2,111
Oh..
Okay, i'll think about that too, thanks for feed back!
Edit: wait, the spell already have that balance
fire deal str+0,75*str
So, the damage is base off by the attribute, and then its get stronger by adding 75% from the str, so currently, it deal 175% str damage (forget in which level)
 
Level 7
Joined
Dec 19, 2009
Messages
249
There's my final submission (maybe)

Purgatory
Whoever cast this spell will use his great fire skills to create a cylinder of flames which will gradually become larger until a certain point and then, an explosion will trigger at the center which will burn all enemies inside the prism.
Level #1: 3 x Int + 50 damage, 300 AOE.
Level #2: 5 x Int + 100 damage, 400 AOE.
Level #3: 7 x Int + 150 damage, 500 AOE.



  • Purgatory Constant
    • Events(On)
      • Time - Elapsed game time is 0.01 seconds
    • Conditions
    • Actions
      • Set PgFHUp = 80.00
      • Set PgLateralSpeed = 5.00
      • Set PgSpiralAngle = 20.00
      • Set PgSizeCylinder = 150.00
      • Set PgSizeExplosion = 300.00
      • Set PgSpeed = 0.10
      • Set PgSpell = Purgatory

  • Purgatory Init(On)
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Purgatory
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • PgB Equal to 0
        • Then - Actions
          • Trigger - Turn on Purgatory Periodic <gen>
        • Else - Actions
      • Set PgB = (PgB + 1)
      • Set PgA = (PgA + 1)
      • Set PgCaster[PgA] = (Triggering unit)
      • Set PgLevel = (Level of PgSpell for PgCaster[PgA])
      • Set PgIntDmgPart = ((1.00 + (2.00 x (Real(PgLevel)))) x (Real((Intelligence of PgCaster[PgA] (Include bonuses)))))
      • Set PgBonusDmgPart = (50.00 x (Real(PgLevel)))
      • Set PgDamage[PgA] = (PgIntDmgPart + PgBonusDmgPart)
      • Set PgTargetPoint[PgA] = (Target point of ability being cast)
      • Set PgOwner[PgA] = (Owner of PgCaster[PgA])
      • Set PgMaxAOE[PgA] = (200.00 + (100.00 x (Real(PgLevel))))
      • Set PgCurrentAOE[PgA] = 100.00
      • Set PgAngleLeft1 = 360.00
      • Set PgAngleRight1 = 0.00
      • Set PgAngleLeft2 = 450.00
      • Set PgAngleRight2 = 90.00
      • Set PgAngleLeft3 = 540.00
      • Set PgAngleRight3 = 180.00
      • Set PgAngleLeft4 = 630.00
      • Set PgAngleRight4 = 270.00
      • Set PgFlyingHeight = 0.00
      • For each (Integer A) from 1 to 10, do (Actions)
        • Loop - Actions
          • -------- ------------------------------------------------------------------------------------------------------------------------------------------------------------ --------
          • Set PgSpiralPointL1 = (PgTargetPoint[PgA] offset by PgCurrentAOE[PgA] towards PgAngleLeft1 degrees)
          • Set PgSpiralPointL2 = (PgTargetPoint[PgA] offset by PgCurrentAOE[PgA] towards PgAngleLeft2 degrees)
          • Set PgSpiralPointL3 = (PgTargetPoint[PgA] offset by PgCurrentAOE[PgA] towards PgAngleLeft3 degrees)
          • Set PgSpiralPointL4 = (PgTargetPoint[PgA] offset by PgCurrentAOE[PgA] towards PgAngleLeft4 degrees)
          • -------- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --------
          • Unit - Create 1 PurgDummy[Cylindre] for PgOwner[PgA] at PgSpiralPointL1 facing 0.00 degrees
          • Set PgCylinderDummy[PgA] = (Last created unit)
          • Unit - Set the custom value of PgCylinderDummy[PgA] to (Integer(PgAngleLeft1))
          • Animation - Change PgCylinderDummy[PgA]'s size to (PgSizeCylinder%, PgSizeCylinder%, (2.00 x PgSizeCylinder)%) of its original size
          • Animation - Change PgCylinderDummy[PgA] flying height to PgFlyingHeight at 0.00
          • Unit Group - Add PgCylinderDummy[PgA] to PgDummyGroup[PgA]
          • -------- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --------
          • Unit - Create 1 PurgDummy[Cylindre] for PgOwner[PgA] at PgSpiralPointL2 facing 0.00 degrees
          • Set PgCylinderDummy[PgA] = (Last created unit)
          • Unit - Set the custom value of PgCylinderDummy[PgA] to (Integer(PgAngleLeft2))
          • Animation - Change PgCylinderDummy[PgA]'s size to (PgSizeCylinder%, PgSizeCylinder%, (2.00 x PgSizeCylinder)%) of its original size
          • Animation - Change PgCylinderDummy[PgA] flying height to PgFlyingHeight at 0.00
          • Unit Group - Add PgCylinderDummy[PgA] to PgDummyGroup[PgA]
          • -------- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --------
          • Unit - Create 1 PurgDummy[Cylindre] for PgOwner[PgA] at PgSpiralPointL3 facing 0.00 degrees
          • Set PgCylinderDummy[PgA] = (Last created unit)
          • Unit - Set the custom value of PgCylinderDummy[PgA] to (Integer(PgAngleLeft3))
          • Animation - Change PgCylinderDummy[PgA]'s size to (PgSizeCylinder%, PgSizeCylinder%, (2.00 x PgSizeCylinder)%) of its original size
          • Animation - Change PgCylinderDummy[PgA] flying height to PgFlyingHeight at 0.00
          • Unit Group - Add PgCylinderDummy[PgA] to PgDummyGroup[PgA]
          • -------- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --------
          • Unit - Create 1 PurgDummy[Cylindre] for PgOwner[PgA] at PgSpiralPointL4 facing 0.00 degrees
          • Set PgCylinderDummy[PgA] = (Last created unit)
          • Unit - Set the custom value of PgCylinderDummy[PgA] to (Integer(PgAngleLeft4))
          • Animation - Change PgCylinderDummy[PgA]'s size to (PgSizeCylinder%, PgSizeCylinder%, (2.00 x PgSizeCylinder)%) of its original size
          • Animation - Change PgCylinderDummy[PgA] flying height to PgFlyingHeight at 0.00
          • Unit Group - Add PgCylinderDummy[PgA] to PgDummyGroup[PgA]
          • Set PgAngleLeft1 = (PgAngleLeft1 - PgSpiralAngle)
          • Set PgAngleLeft2 = (PgAngleLeft2 - PgSpiralAngle)
          • Set PgAngleLeft3 = (PgAngleLeft3 - PgSpiralAngle)
          • Set PgAngleLeft4 = (PgAngleLeft4 - PgSpiralAngle)
          • -------- ------------------------------------------------------------------------------------------------------------------------------------------------------------ --------
          • Set PgSpiralPointR1 = (PgTargetPoint[PgA] offset by PgCurrentAOE[PgA] towards PgAngleRight1 degrees)
          • Set PgSpiralPointR2 = (PgTargetPoint[PgA] offset by PgCurrentAOE[PgA] towards PgAngleRight2 degrees)
          • Set PgSpiralPointR3 = (PgTargetPoint[PgA] offset by PgCurrentAOE[PgA] towards PgAngleRight3 degrees)
          • Set PgSpiralPointR4 = (PgTargetPoint[PgA] offset by PgCurrentAOE[PgA] towards PgAngleRight4 degrees)
          • -------- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --------
          • Unit - Create 1 PurgDummy[Cylindre] for PgOwner[PgA] at PgSpiralPointR1 facing 0.00 degrees
          • Set PgCylinderDummy[PgA] = (Last created unit)
          • Unit - Set the custom value of PgCylinderDummy[PgA] to (Integer(PgAngleRight1))
          • Animation - Change PgCylinderDummy[PgA]'s size to (PgSizeCylinder%, PgSizeCylinder%, (2.00 x PgSizeCylinder)%) of its original size
          • Animation - Change PgCylinderDummy[PgA] flying height to PgFlyingHeight at 0.00
          • Unit Group - Add PgCylinderDummy[PgA] to PgDummyGroup[PgA]
          • -------- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --------
          • Unit - Create 1 PurgDummy[Cylindre] for PgOwner[PgA] at PgSpiralPointR2 facing 0.00 degrees
          • Set PgCylinderDummy[PgA] = (Last created unit)
          • Unit - Set the custom value of PgCylinderDummy[PgA] to (Integer(PgAngleRight2))
          • Animation - Change PgCylinderDummy[PgA]'s size to (PgSizeCylinder%, PgSizeCylinder%, (2.00 x PgSizeCylinder)%) of its original size
          • Animation - Change PgCylinderDummy[PgA] flying height to PgFlyingHeight at 0.00
          • Unit Group - Add PgCylinderDummy[PgA] to PgDummyGroup[PgA]
          • -------- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --------
          • Unit - Create 1 PurgDummy[Cylindre] for PgOwner[PgA] at PgSpiralPointR3 facing 0.00 degrees
          • Set PgCylinderDummy[PgA] = (Last created unit)
          • Unit - Set the custom value of PgCylinderDummy[PgA] to (Integer(PgAngleRight3))
          • Animation - Change PgCylinderDummy[PgA]'s size to (PgSizeCylinder%, PgSizeCylinder%, (2.00 x PgSizeCylinder)%) of its original size
          • Animation - Change PgCylinderDummy[PgA] flying height to PgFlyingHeight at 0.00
          • Unit Group - Add PgCylinderDummy[PgA] to PgDummyGroup[PgA]
          • -------- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --------
          • Unit - Create 1 PurgDummy[Cylindre] for PgOwner[PgA] at PgSpiralPointR4 facing 0.00 degrees
          • Set PgCylinderDummy[PgA] = (Last created unit)
          • Unit - Set the custom value of PgCylinderDummy[PgA] to (Integer(PgAngleRight4))
          • Animation - Change PgCylinderDummy[PgA]'s size to (PgSizeCylinder%, PgSizeCylinder%, (2.00 x PgSizeCylinder)%) of its original size
          • Animation - Change PgCylinderDummy[PgA] flying height to PgFlyingHeight at 0.00
          • Unit Group - Add PgCylinderDummy[PgA] to PgDummyGroup[PgA]
          • Set PgAngleRight1 = (PgAngleRight1 + PgSpiralAngle)
          • Set PgAngleRight2 = (PgAngleRight2 + PgSpiralAngle)
          • Set PgAngleRight3 = (PgAngleRight3 + PgSpiralAngle)
          • Set PgAngleRight4 = (PgAngleRight4 + PgSpiralAngle)
          • -------- ------------------------------------------------------------------------------------------------------------------------------------------------------------ --------
          • Set PgFlyingHeight = (PgFlyingHeight + PgFHUp)
          • Custom script: call RemoveLocation(udg_PgSpiralPointL1)
          • Custom script: call RemoveLocation(udg_PgSpiralPointL2)
          • Custom script: call RemoveLocation(udg_PgSpiralPointL3)
          • Custom script: call RemoveLocation(udg_PgSpiralPointL4)
          • Custom script: call RemoveLocation(udg_PgSpiralPointR1)
          • Custom script: call RemoveLocation(udg_PgSpiralPointR2)
          • Custom script: call RemoveLocation(udg_PgSpiralPointR3)
          • Custom script: call RemoveLocation(udg_PgSpiralPointR4)

  • Purgatory Periodic(Off)
    • Events
      • Time - Every 0.04 seconds of game time
    • Conditions
    • Actions
      • For each (Integer Pg) from 1 to PgA, do (Actions)
        • Loop - Actions
          • Unit Group - Pick every unit in PgDummyGroup[Pg] and do (Actions)
            • Loop - Actions
              • Set PgCylinderDummy[Pg] = (Picked unit)
              • Set PgMovingAngle[Pg] = ((Real((Custom value of PgCylinderDummy[Pg]))) + PgLateralSpeed)
              • Set PgMovePoint[Pg] = (PgTargetPoint[Pg] offset by PgCurrentAOE[Pg] towards PgMovingAngle[Pg] degrees)
              • Unit - Move PgCylinderDummy[Pg] instantly to PgMovePoint[Pg]
              • Set PgCurrentAOE[Pg] = (PgCurrentAOE[Pg] + PgSpeed)
              • Unit - Set the custom value of PgCylinderDummy[Pg] to (Integer(PgMovingAngle[Pg]))
              • Custom script: call RemoveLocation(udg_PgMovePoint[udg_Pg])
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • PgCurrentAOE[Pg] Greater than or equal to PgMaxAOE[Pg]
                • Then - Actions
                  • Unit Group - Add all units of PgDummyGroup[Pg] to PgDummyGroup2[Pg]
                  • Custom script: call DestroyGroup(udg_PgDummyGroup[udg_Pg])
                • Else - Actions
          • Unit Group - Pick every unit in PgDummyGroup2[Pg] and do (Actions)
            • Loop - Actions
              • Set PgCylinderDummy[Pg] = (Picked unit)
              • Set PgMovingAngle[Pg] = ((Real((Custom value of PgCylinderDummy[Pg]))) + PgLateralSpeed)
              • Set PgMovePoint[Pg] = (PgTargetPoint[Pg] offset by PgCurrentAOE[Pg] towards PgMovingAngle[Pg] degrees)
              • Unit - Move PgCylinderDummy[Pg] instantly to PgMovePoint[Pg]
              • Set PgCurrentAOE[Pg] = (PgCurrentAOE[Pg] - PgSpeed)
              • Unit - Set the custom value of PgCylinderDummy[Pg] to (Integer(PgMovingAngle[Pg]))
              • Custom script: call RemoveLocation(udg_PgMovePoint[udg_Pg])
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • PgCurrentAOE[Pg] Less than or equal to 50.00
                • Then - Actions
                  • Unit - Kill PgCylinderDummy[Pg]
                  • Unit - Create 1 PurgDummy[Final Explosion] for PgOwner[Pg] at PgTargetPoint[Pg] facing 0.00 degrees
                  • Set PgExplosionDummy[Pg] = (Last created unit)
                  • Set PgExplosionPoint[Pg] = (Position of PgExplosionDummy[Pg])
                  • Unit - Add a 2.00 second Generic expiration timer to PgExplosionDummy[Pg]
                  • Animation - Change PgExplosionDummy[Pg]'s size to (PgSizeExplosion%, PgSizeExplosion%, (2.00 x PgSizeExplosion)%) of its original size
                  • Set PgTargetGroup = (Units within PgMaxAOE[Pg] of PgExplosionPoint[Pg])
                  • Unit Group - Pick every unit in PgTargetGroup and do (Actions)
                    • Loop - Actions
                      • Set PgTarget = (Picked unit)
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (PgTarget is A structure) Equal to False
                          • (PgTarget is Magic Immune) Equal to False
                          • (PgTarget belongs to an enemy of PgOwner[Pg]) Equal to True
                        • Then - Actions
                          • Unit - Cause PgCaster[Pg] to damage PgTarget, dealing PgDamage[Pg] damage of attack type Spells and damage type Normal
                        • Else - Actions
                  • Custom script: call RemoveLocation(udg_PgExplosionPoint[udg_Pg])
                  • Custom script: call DestroyGroup(udg_PgTargetGroup)
                  • Custom script: call RemoveLocation(udg_PgTargetPoint[udg_Pg])
                  • Unit Group - Remove PgCylinderDummy[Pg] from PgDummyGroup2[Pg]
                  • Set PgB = (PgB - 1)
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • PgB Equal to 0
                      • (PgDummyGroup[Pg] is empty) Equal to True
                      • (PgDummyGroup2[Pg] is empty) Equal to True
                    • Then - Actions
                      • Set PgA = 0
                      • Trigger - Turn off Purgatory Periodic <gen>
                    • Else - Actions
                • Else - Actions




I Hope you enjoyed to test my spell.
Feel free to give comments or suggestion.

View attachment Purgatory spell contest.w3x
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Eh; I've got to get to bed and go to the airport in the morning so it doesn't look like I'll have time to finalize things. I felt like I had more time. Good luck to all the contestants, wish me luck in Europe.
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
Just a few days left now :D

Btw, to those who are submitting their final submissions: Please post a video or a description of the spell you're copying together with your spell, so the Judge has something to compare to. This is after all, a copy pasta contest.

@Berb, have fun in Europe!
 
Status
Not open for further replies.
Top