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

Swirling Death v1.5

Swirling death occurs at the target's coordinates. Explosions move towards the target in a circle until they reach it, then it will move outwards. Blue explosions deal physical damage, green explosions deal magical. The center of explosion deals greater damage. Lasts 6 seconds. Note: Can target friendly units, primary target doesn't take damage and the target is silenced.

Siwrling Death Configuration:

  • Swirling Death Config
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- The ability itself. --------
      • Set Cnfg_SD_Ability = Swirling |cffff0000D|reath
      • -------- The speed of the explosion circle. --------
      • Set Cnfg_SD_TurnRate = 10.00
      • -------- The speed explosions move closer to the target, or away from the target. --------
      • Set Cnfg_SD_CloserDistance = 5.00
      • -------- Explosion starting range (from the caster). --------
      • Set Cnfg_SD_OffsetRealStart = 500.00
      • -------- Spell duration (configure it in object editor as well). --------
      • Set Cnfg_SD_Duration[1] = 6.00
      • Set Cnfg_SD_Duration[2] = 7.00
      • Set Cnfg_SD_Duration[3] = 8.00
      • -------- Magical damage explosion special effect. --------
      • Set Cnfg_SD_SE1 = Abilities\Spells\Undead\DeathCoil\DeathCoilSpecialArt.mdl
      • -------- Physical damage explosion special effect. --------
      • Set Cnfg_SD_SE2 = Abilities\Spells\NightElf\Blink\BlinkCaster.mdl
      • -------- Magical damage explosion damage. --------
      • Set Cnfg_SD_Damage1[1] = 10.00
      • Set Cnfg_SD_Damage1[2] = 15.00
      • Set Cnfg_SD_Damage1[3] = 20.00
      • -------- Physical damage explosion damage. --------
      • Set Cnfg_SD_Damage2[1] = 15.00
      • Set Cnfg_SD_Damage2[2] = 20.00
      • Set Cnfg_SD_Damage2[3] = 25.00
      • -------- Magical explosion AoE --------
      • Set Cnfg_SD_AoE1[1] = 150.00
      • Set Cnfg_SD_AoE1[2] = 160.00
      • Set Cnfg_SD_AoE1[3] = 170.00
      • -------- Physical explosion AoE --------
      • Set Cnfg_SD_AoE2[1] = 150.00
      • Set Cnfg_SD_AoE2[2] = 160.00
      • Set Cnfg_SD_AoE2[3] = 170.00
      • -------- Attack and Damage Types (Default attack type is magical and physical). --------
      • Set Cnfg_SD_DamageType1 = Normal
      • Set Cnfg_SD_DamageType2 = Normal
      • Set Cnfg_SD_AttackType1 = Spells
      • Set Cnfg_SD_AttackType2 = Hero


Swirling Death Starting Variables:

  • Swirling Death
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Cnfg_SD_Ability
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • SD_MaxIndex Equal to 0
        • Then - Actions
          • Trigger - Turn on Swirling Death loop <gen>
        • Else - Actions
      • Set SD_MaxIndex = (SD_MaxIndex + 1)
      • Set SD_TempPlayer[SD_MaxIndex] = (Triggering player)
      • Set SD_Target[SD_MaxIndex] = (Target unit of ability being cast)
      • Set SD_Caster[SD_MaxIndex] = (Triggering unit)
      • Set SD_ExplBoolean[SD_MaxIndex] = False
      • Set SD_StartOffsetReal[SD_MaxIndex] = Cnfg_SD_OffsetRealStart
      • Set SD_AbilityLevel[SD_MaxIndex] = (Level of Swirling |cffff0000D|reath for SD_Caster[SD_MaxIndex])
      • Set SD_Duration[SD_MaxIndex] = Cnfg_SD_Duration[SD_AbilityLevel[SD_MaxIndex]]


Swirling Death Loop:

  • Swirling Death loop
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • For each (Integer SD_TempIndex) from 1 to SD_MaxIndex, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • SD_Duration[SD_TempIndex] Greater than or equal to 0.00
              • (SD_Caster[SD_TempIndex] is alive) Equal to True
              • (SD_Target[SD_TempIndex] is alive) Equal to True
            • Then - Actions
              • Custom script: set udg_SD_ExplBoolean[udg_SD_TempIndex] = not udg_SD_ExplBoolean[udg_SD_TempIndex]
              • Set SD_Duration[SD_TempIndex] = (SD_Duration[SD_TempIndex] - 0.03)
              • Set SD_Degree[SD_TempIndex] = (SD_Degree[SD_TempIndex] - Cnfg_SD_TurnRate)
              • Set SD_StartOffsetReal[SD_TempIndex] = (SD_StartOffsetReal[SD_TempIndex] - Cnfg_SD_CloserDistance)
              • Set SD_TempPoint2 = (Position of SD_Target[SD_TempIndex])
              • Set SD_TempPoint = (SD_TempPoint2 offset by SD_StartOffsetReal[SD_TempIndex] towards SD_Degree[SD_TempIndex] degrees)
              • Custom script: call RemoveLocation(udg_SD_TempPoint2)
              • -------- If you want only 1 type of explosion, remove all the stuff from the Else block which is in the following If Then Else statement. --------
              • -------- If you want 1 type of explosion to happen at the same rate as if it would be with 2 types of explosions, remove anything that is associated with the variable SD_ExplBoolean. --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • SD_ExplBoolean[SD_TempIndex] Equal to False
                • Then - Actions
                  • Set SD_TempGroup = (Units within Cnfg_SD_AoE1[SD_AbilityLevel[SD_TempIndex]] of SD_TempPoint)
                  • Unit Group - Pick every unit in SD_TempGroup and do (Actions)
                    • Loop - Actions
                      • Set SD_PickedUnits = (Picked unit)
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (SD_PickedUnits belongs to an enemy of SD_TempPlayer[SD_TempIndex]) Equal to True
                          • SD_PickedUnits Not equal to SD_Target[SD_TempIndex]
                        • Then - Actions
                          • Unit - Cause SD_Caster[SD_TempIndex] to damage SD_PickedUnits, dealing Cnfg_SD_Damage1[SD_AbilityLevel[SD_TempIndex]] damage of attack type Cnfg_SD_AttackType1 and damage type Cnfg_SD_DamageType1
                        • Else - Actions
                  • Special Effect - Create a special effect at SD_TempPoint using Cnfg_SD_SE1
                  • Special Effect - Destroy (Last created special effect)
                • Else - Actions
                  • Set SD_TempGroup = (Units within Cnfg_SD_AoE2[SD_AbilityLevel[SD_TempIndex]] of SD_TempPoint)
                  • Unit Group - Pick every unit in SD_TempGroup and do (Actions)
                    • Loop - Actions
                      • Set SD_PickedUnits = (Picked unit)
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (SD_PickedUnits belongs to an enemy of SD_TempPlayer[SD_TempIndex]) Equal to True
                          • SD_PickedUnits Not equal to SD_Target[SD_TempIndex]
                        • Then - Actions
                          • Unit - Cause SD_Caster[SD_TempIndex] to damage SD_PickedUnits, dealing Cnfg_SD_Damage2[SD_AbilityLevel[SD_TempIndex]] damage of attack type Cnfg_SD_AttackType2 and damage type Cnfg_SD_DamageType2
                        • Else - Actions
                  • Special Effect - Create a special effect at SD_TempPoint using Cnfg_SD_SE2
                  • Special Effect - Destroy (Last created special effect)
              • Custom script: call DestroyGroup(udg_SD_TempGroup)
              • Custom script: call RemoveLocation(udg_SD_TempPoint)
            • Else - Actions
              • Set SD_ExplBoolean[SD_TempIndex] = SD_ExplBoolean[SD_MaxIndex]
              • Set SD_Duration[SD_TempIndex] = SD_Duration[SD_MaxIndex]
              • Set SD_Degree[SD_TempIndex] = SD_Degree[SD_MaxIndex]
              • Set SD_StartOffsetReal[SD_TempIndex] = SD_StartOffsetReal[SD_MaxIndex]
              • Set SD_AbilityLevel[SD_TempIndex] = SD_AbilityLevel[SD_MaxIndex]
              • Set SD_Target[SD_TempIndex] = SD_Target[SD_MaxIndex]
              • Set SD_Target[SD_MaxIndex] = No unit
              • Set SD_Caster[SD_TempIndex] = SD_Caster[SD_MaxIndex]
              • Set SD_Caster[SD_MaxIndex] = No unit
              • Set SD_TempPlayer[SD_TempIndex] = SD_TempPlayer[SD_MaxIndex]
              • Set SD_MaxIndex = (SD_MaxIndex - 1)
              • Set SD_TempIndex = (SD_TempIndex - 1)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • SD_MaxIndex Equal to 0
                • Then - Actions
                  • Trigger - Turn off (This trigger)
                • Else - Actions


Primary spell is based on melee Soul Fire ability, to instantly silence the opponent, and give them a buff. The spell itself is pretty simple. The spell is written entirely by me and it's pretty easily configurable to different looking effects, different formations, speed etc. It's MUI.

Commend/Despise me in the comments below, looking forward to receiving feedback.

v1.1 - Added level support, fixed leaks, replaced random integer with a boolean array.
v1.2 - Fixed most things that the reviewers pointed out (thanks) couldn't do some stuff, so I just left it at that, may come back later.
v1.3 - Update mostly consists of the stuff that IcemanBo pointed out (thanks). Such as moving the other If Then Else block to the firsts Else statement, stopping the spell when the caster dies, deindexing ability level variable, making some import instructions and using the variable SD_PickedUnits when checking conditions whether to damage or not.
v1.4 - Minor update containing more detailed import instructions and nulling the spell when the target is dead.
v1.5 - Minor update containing a small damage flaw.


Feedback is always highly appreciated.

Keywords:
GUI, MUI, AoE, Swirly, 2nd spell in hive, simple.
Contents

Swirling Death v1.05 (Map)

Reviews
Swirling Death v1.4 | Reviewed by BPower | 01.08.2015 Code[/COLOR]] The spell is MUI, leakless and working. There is a small mistake in your code ( See below ) I sure Damage2 should be Damage1. Unit - Cause SD_Caster[SD_TempIndex] to...

Moderator

M

Moderator


Swirling Death v1.4 | Reviewed by BPower | 01.08.2015

[COLOR="gray"

[COLOR="gray"

[COLOR="gray"

[COLOR="gray"

Code[/COLOR]]
126248-albums6177-picture66521.png
  • The spell is MUI, leakless and working.
  • There is a small mistake in your code ( See below )
126248-albums6177-picture66523.png
  • I sure Damage2 should be Damage1.

    • Unit - Cause SD_Caster[SD_TempIndex] to damage SD_PickedUnits, dealing Cnfg_SD_Damage2[SD_AbilityLevel[SD_TempIndex]] damage of attack type Cnfg_SD_AttackType1 and damage type Cnfg_SD_DamageType1
Objects[/COLOR]]
126248-albums6177-picture66523.png
  • Objects are ok. Nothing to complain here.
Effects[/COLOR]]
126248-albums6177-picture66521.png
  • Effects are ok, however you spam them quite a lot.
126248-albums6177-picture66523.png
  • @Map makers: Always be aware that effect spamming could be a reason for
    unwanted fps drops, especially in multiplayer seasons. Be careful!
Rating[/COLOR]]
CODEOBJECTSEFFECTSRATINGSTATUS
3/5
4/5
2.5/5
3.1/5
APPROVED
 
You only have to create one more integer[array] variable to support levels.
Then you have to change from some non-array variables to array variables. For Damage, AOE, Duration...

Init will look like this:

Set Damage[1] = 10
Set Damage[2] = 20
Set Damage[3] = 30
(user can change it for each level)

When you index you save the level of ability in your new variable:
Set AbilityLevel[index] = Level of (YourAbiliry for (YourUnit))

And in loop, when you do damage, you use it:
Unit - Cause Damage[AbilityLevel[index]] to unit.

So now the damage depends on the level.
 
Level 11
Joined
Jul 25, 2014
Messages
490
You only have to create one more integer[array] variable to support levels.
Then you have to change from some non-array variables to array variables. For Damage, AOE, Duration...

Init will look like this:

Set Damage[1] = 10
Set Damage[2] = 20
Set Damage[3] = 30
(user can change it for each level)

When you index you save the level of ability in your new variable:
Set AbilityLevel[index] = Level of (YourAbiliry for (YourUnit))

And in loop, when you do damage, you use it:
Unit - Cause Damage[AbilityLevel[index]] to unit.

So now the damage depends on the level.

@Iceman
As I said, I don't quite know how to implement level support. Could you make a simple trigger spell that does, and post it in a reply? Because I tried your method, and I can't seem to get it right. If not, I guess I'll just fix leaks and stuff, and save level implemention for my next spell upload.
 
Level 29
Joined
Oct 24, 2012
Messages
6,543
Please use hidden tags when posting trigger.

Also this leaks a location.
  • Set SD_TempPoint = ((Position of SD_Target[SD_TempIndex]) offset by SD_StartOffsetLoc[SD_TempIndex] towards SD_Degree[SD_TempIndex] degrees)
After you de-index you need to decrease the looping integer ( SD_TempIndex ) otherwise one index never runs each time another index is removed.

Spells should be able to have multiple levels. Yours currently only has one.
 
Level 13
Joined
Jul 16, 2012
Messages
679
You have need to change something....

In your Trigger Loop..
  • Unit Group - Pick every unit in SD_TempGroup and do (Actions)
    • Loop - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Picked unit) belongs to an enemy of SD_TempPlayer[SD_TempIndex]) Equal to True
          • (Picked unit) Not equal to SD_Target[SD_TempIndex]
      • Then - Actions
        • Set SD_PickedUnits = (Picked unit)
        • Unit - Cause SD_Caster[SD_TempIndex] to damage SD_PickedUnits, dealing Cnfg_SD_Damage2[SD_AbilityLevel[SD_TempIndex]] damage of attack type Cnfg_SD_AttackType1 and damage type Normal
        • Set SD_PickedUnits = No unit
  • Custom script: call DestroyGroup(udg_SD_TempGroup)
->>>
  • Unit Group - Pick every unit in SD_TempGroup and do (Actions)
    • Loop - Actions
      • Set SD_PickedUnits = (Picked unit)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((SD_PickedUnits) belongs to an enemy of SD_TempPlayer[SD_TempIndex]) Equal to True
          • (SD_PickedUnits) Not equal to SD_Target[SD_TempIndex]
      • Then - Actions
        • Unit - Cause SD_Caster[SD_TempIndex] to damage SD_PickedUnits, dealing Cnfg_SD_Damage2[SD_AbilityLevel[SD_TempIndex]] damage of attack type Cnfg_SD_AttackType1 and damage type Normal
        • Set SD_PickedUnits = No unit
  • Custom script: call DestroyGroup(udg_SD_TempGroup)
 
Swirling Death v1.1 - Review by IcemanBo & edo494

Date: November 6th, 2014

Concept:

Swirling Death silences the target, surrounds it with a circular movement, until it reaches it's position, and creates explosions all over it's way.
Afterwards it vanishs the same way back, in a circular/surrounding movement.

In terms of the surrounding circulation, inwards and outwards, and the different explosions on it's way (physical- and magical damage explosions),
it is a good and interesting spell concept.

Code:
  • In cast trigger:
    • Set SD_AbilityLevel[SD_MaxIndex] = (Level of Swirling Death for (Triggering unit))
    ->
    • Set SD_AbilityLevel[SD_MaxIndex] = (Level of Swirling Death for (SD_Caster[SD_MaxIndex]))
  • I personaly think it's better to try to stick in one way of coding. For example, in GUI, to use as less custom scripts as possible.
    It's not that important, but you can remove this custom script line:
    • Custom script: set udg_SD_ExplBoolean[udg_SD_TempIndex] = not udg_SD_ExplBoolean[udg_SD_TempIndex]
    ^And instead, you just could set it to true/false in the matching If/Then/Else block via normal GUI action.
  • Immediatly store "PickedUnit" into the variable, so you already can use it for the checks in conditions.
  • Damage type should be configurable.
  • There is comment in loop:
    "^And instead, you just could set it to true/false in the matching If/Then/Else block via normal GUI action."
    That's corrent. But you should mention one thing. If user removes the boolean variable, there won't be a switching anymore between these two group enumerations and no witching between physical/magical damage. It follows that only one kind of enumeration and damaging will be executed, and so it will be executed twice as often as before. (-> double phiscal, or double magical damage will be dealt)
  • Second unit enumeration can be moved in "Else - Actions" part of first If/Then/Else, to avoid a second check for the boolean value.
  • In deindex part you have forgotten to switch the boolean variable with MaxIndex.

    • Set SD_PickedUnits = No Unit
    ^Nulling this global unit variable is not really needed, as you for sure will use it again.
  • Variable name "SD_StartOffsetLoc[]" could make someone think it's a location, but not a real.

Coding is alright. Aside of these minor mentioned things, it's fine.

Visuals:

  • Icon for learning and spell icon itself differs. This doesn't really make sense. You should equal them.
  • Learning tooltip does not privide any spell describing information. You should improve it.
  • Explosions look good, and it's movement is fairly smooth.

Spell tooltip. You don't have to describe technical aspects in detail:
For example, you don't have to note that you also can target allies. (it's set in object data anyways)
"Occurs at target's cooridinates" is also obviously, if you target a unit with a spell.

Also, you could highlight the name of the ability, as well as the hotkey.


Conclusion:

Swirling death has some nice special effects, that are fitting to the explosions. Also the circular movement towards the target looks good in game.
You definitly should work on spell's tooltip, even it doesn't seem really important.
In coding there is nothing expensive/impressing. It's a simple spell, but useful.


Rating: 3/5 and vote for approval. (after fixes)

 
  • Deindex if the caster gets removed from game. The spell won't make any effect anymore, because caster can't damage anymore.
    You can check if a unit is removed if one's UnitType equals "NoUnitType".
  • You forgot about "AbilityLevel[]" in your deindex part.
  • Refer to the variable instead of using "Picked Unit" more often.
  • No need to check the boolean[index] for true and for false in loop. You can move the whole physical damage block into the 'Else' of the first 'If - statement'.
  • Make some decent import instructions.

You're on a good way, but I still await an update for approval. :csmile:
 
When target is dead/removed you should deindex. It might be tolerated for target's death, but it's not acceptable for unit being removed.
Better just cover both cases, and don't bother with these details no more. Just handle it as you do alredy for caster.

The speed in config doesn't match the actual wc3 movement speed. It's /0.03 in your case. Might be noted.

In import instructions:
4. Copy the variables if possible. If not, make them via Variable Editor.
^You should explain the usual method to use when copying triggers. It's just best for GUI.

Just for future. Try to keep variable names simple and intuitive. For example:
  • Set Cnfg_SD_CloserDistance = 5.00
User can't really imagine immediatly what you mean with this name, it could be simple "SD_Offset", or "SD_Speed".
And in config the additional "Cnfg_" is not necessarily needed. Here atleast you still have the "SD_" one included, so it's okay, but you also can remove the "Cnfg_" actually.
Hope you see what I mean. When reading a lot of code you start to get nitpicking when it comes to things like readability and good names. :D
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,183
edit: nvm.

I got a somewhat debatable suggestion.

Right now you do:
if boolean == false then
unit group stuff
else
slightly difference unit group stuff

However you can do:
Unitgroup
if boolean == false
actions

This will make the code a little shorter since you only need to store the unit group variable at one location in the code. However it will be more inefficient since you check for the boolean once per unit.
 
Last edited:
Top