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

Mesmerizing Skull v1.3f

  • Like
Reactions: DoctorReza
SPELL DESCRIPTION
Summons a skull that drift through the targeted point on the ground and drags any enemy unit within AOE of the skull and deals damage. When the skull is dead, it will release a wave of skulls to seek out target in an AOE and stuns the units (2 seconds stun for all level).

Level 1 - 7 Seconds Duration | 50/s Skull Speed | 25/s Dragged Unit Speed | 5 Damage Per Second | 300 AOE | 50 Stun Damage

Level 2 - 8 Seconds Duration | 99/s Skull Speed | 50/s Dragged Unit Speed | 10 Damage Per Second | 400 AOE | 100 Stun Damage

Level 3 - 9 Seconds Duration | 150/s Skull Speed | 75/s Dragged Unit Speed | 15 Damage Per Second | 500 AOE | 150 Stun Damage

Level 4 - 10 Seconds Duration | 198/s Skull Speed | 99/s Dragged Unit Speed | 20 Damage Per Second | 600 AOE | 200 Stun Damage
TRIGGERS
FAQ is in the Trigger Comment on Setup Trigger
  • MS Setup
    • Events
      • Time - Elapsed game time is 0.00 seconds
    • Conditions
    • Actions
      • -------- Creating a hashtable --------
      • Hashtable - Create a hashtable
      • -------- Setting the last created hashtable in a variable (for easier referrence) --------
      • Set HashtableMS = (Last created hashtable)
      • -------- This is the base duration for the skull's lifespan --------
      • Set BaseDuration = 6
      • -------- The "multiplication" power of the duration formula --------
      • Set DurationPowerValue = 1
      • -------- The "multiplication" power of AOE formula --------
      • Set PowerAOE = 100.00
      • -------- Base speed of the skull --------
      • Set BaseTimeSkullSpeed = 1.50
      • -------- Base speed of the dragged unit --------
      • Set BaseTimeMesmerizedSpeed = 0.75
      • -------- Base AOE of the effect --------
      • Set BaseAOE = 200.00
      • -------- Base damage done to the dragged unit per second --------
      • Set BaseDamage = 5.00
      • Set MesmerizingSkull = Mesmerizing Skull
      • Set SkullUnitType = Mesmering Skull Dummy
      • Set DummyUnitType = Death Dummy Stunner
  • MS Cast
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to MesmerizingSkull
    • Actions
      • Set Caster = (Triggering unit)
      • Set AbilityLevel = (Level of Mesmerizing Skull for Caster)
      • -------- Setting up caster's location --------
      • Set CasterLoc = (Position of Caster)
      • -------- Setting up target location --------
      • Set TargetLoc = (Target point of ability being cast)
      • -------- By combining both variable of CasterLoc and TargetLoc, we got Angle which is used for moving the skull towards a correct angle --------
      • Set Angle = (Angle from CasterLoc to TargetLoc)
      • -------- The duration of the skull's lifespan --------
      • Set Duration = (BaseDuration + (AbilityLevel x DurationPowerValue))
      • -------- The skull speed during his lifespan --------
      • Set SkullSpeed = (BaseTimeSkullSpeed x (Real(AbilityLevel)))
      • -------- Dragged unit's speed --------
      • Set MesmerizedSpeed = (BaseTimeMesmerizedSpeed x (Real(AbilityLevel)))
      • -------- AOE of the effect around the skull --------
      • Set AOE = (BaseAOE + ((Real(AbilityLevel)) x PowerAOE))
      • -------- Damage done to the dragged unit per second --------
      • Set Damage = (BaseDamage x (Real(AbilityLevel)))
      • Set StunLevel = AbilityLevel
      • -------- Now, create the skull --------
      • Unit - Create 1 SkullUnitType for (Triggering player) at CasterLoc facing Angle degrees
      • Set Skull = (Last created unit)
      • Custom script: set udg_HandleID = GetHandleId(udg_Skull)
      • -------- Add its lifespan --------
      • Unit - Add a (Real(Duration)) second Generic expiration timer to Skull
      • -------- Save all valueable data into a hashtable (for later usage) --------
      • Hashtable - Save Angle as (Key Angle) of HandleID in HashtableMS
      • Hashtable - Save SkullSpeed as (Key SkullSpeed) of HandleID in HashtableMS
      • Hashtable - Save MesmerizedSpeed as (Key MesmerizedSpeed) of HandleID in HashtableMS
      • Hashtable - Save AOE as (Key AOE) of HandleID in HashtableMS
      • Hashtable - Save Damage as (Key Damage) of HandleID in HashtableMS
      • Hashtable - Save StunLevel as (Key StunLevel) of HandleID in HashtableMS
      • -------- Add the last created unit (Skull) to a Unit Group for the spell effect --------
      • Unit Group - Add (Last created unit) to SkullGroup
      • -------- Turn both Loop Trigger (for 0.03 second per loop) and Damage Trigger (for 1.00 second per loop) --------
      • Trigger - Turn on MS Loop <gen>
      • Trigger - Turn on MS Damage <gen>
      • Trigger - Turn on Stun AOE <gen>
      • -------- Cleaning leaks of CasterLoc and TargetLoc --------
      • Custom script: call RemoveLocation(udg_CasterLoc)
      • Custom script: call RemoveLocation(udg_TargetLoc)
  • MS Loop
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • -------- This trigger is to move (the skull) and drag (the victim) --------
      • Unit Group - Pick every unit in SkullGroup and do (Actions)
        • Loop - Actions
          • Set Skull = (Picked unit)
          • Custom script: set udg_HandleID = GetHandleId(udg_Skull)
          • -------- I put IF/THEN/ELSE Action here is because if the skull is alive, do the effect of the spell, else, remove the skull from the unit group and ends the spell effect for the skull --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Skull is alive) Equal to True
            • Then - Actions
              • -------- Load all the saved data from the hashtable (earlier we saved the data from the "Cast" Trigger) --------
              • Set SkullSpeed = (Load (Key SkullSpeed) of HandleID from HashtableMS)
              • Set MesmerizedSpeed = (Load (Key MesmerizedSpeed) of HandleID from HashtableMS)
              • Set AOE = (Load (Key AOE) of HandleID from HashtableMS)
              • Set Angle = (Load (Key Angle) of HandleID from HashtableMS)
              • -------- Setting up new variable for the picked unit --------
              • -------- Setting up location of the picked unit (for both referrence and clean leaks) --------
              • Set SkullLoc = (Position of Skull)
              • -------- Determines where would the skull move for the next 0.03 second --------
              • Set SkullMoveLoc = (SkullLoc offset by SkullSpeed towards Angle degrees)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • ((Playable map area) contains SkullMoveLoc) Equal to True
                • Then - Actions
                  • -------- After setting its path, move the skull to the designated location --------
                  • Custom script: call SetUnitX(udg_Skull, GetLocationX(udg_SkullMoveLoc))
                  • Custom script: call SetUnitY(udg_Skull, GetLocationY(udg_SkullMoveLoc))
                • Else - Actions
                  • Unit - Kill Skull
              • -------- Once the skull moves, it picks up any enemy unit around the AOE and drag along with it --------
              • Custom script: set bj_wantDestroyGroup = true
              • Unit Group - Pick every unit in (Units within AOE of SkullMoveLoc matching ((((Matching unit) is alive) Equal to True) and (((Matching unit) belongs to an enemy of (Owner of Skull)) Equal to True))) and do (Actions)
                • Loop - Actions
                  • -------- Setting up new variable for the picked unit --------
                  • Set AffectedUnit = (Picked unit)
                  • -------- Setting up location of the picked unit (for both referrence and clean leaks) --------
                  • Set AffectedUnitLoc = (Position of AffectedUnit)
                  • -------- Determines where would the dragged unit move for the next 0.03 second --------
                  • Set AffectedUnitMove = (AffectedUnitLoc offset by MesmerizedSpeed towards (Angle from AffectedUnitLoc to SkullLoc) degrees)
                  • -------- Drags the unit to follow along with the skull --------
                  • Unit - Move AffectedUnit instantly to AffectedUnitMove
                  • -------- Clean leaks ! --------
                  • Custom script: call RemoveLocation(udg_AffectedUnitLoc)
                  • Custom script: call RemoveLocation(udg_AffectedUnitMove)
              • -------- Clean leaks ! --------
              • Custom script: call RemoveLocation(udg_SkullLoc)
              • Custom script: call RemoveLocation(udg_SkullMoveLoc)
            • Else - Actions
              • -------- Now, if the skull is dead, remove it from the Unit Group --------
              • Unit - Remove Skull from the game
              • -------- Clean the child hashtable of the skull --------
              • Hashtable - Clear all child hashtables of child HandleID in HashtableMS
              • Unit Group - Remove Skull from SkullGroup
              • -------- This is for trigger efficiency. If the game detects 0 unit in that Unit Group, turn off this trigger (meaning, no longer checks for 0.03 second per check and game could be less-laggy :D) --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (SkullGroup is empty) Equal to True
                • Then - Actions
                  • Trigger - Turn off (This trigger)
                  • Trigger - Turn off Stun AOE <gen>
                  • Trigger - Turn off MS Damage <gen>
                • Else - Actions
  • MS Damage
    • Events
      • Time - Every 1.00 seconds of game time
    • Conditions
    • Actions
      • -------- This trigger is to damage the dragged unit once per 1 second --------
      • Unit Group - Pick every unit in SkullGroup and do (Actions)
        • Loop - Actions
          • Set Skull = (Picked unit)
          • Custom script: set udg_HandleID = GetHandleId(udg_Skull)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Skull is alive) Equal to True
            • Then - Actions
              • -------- Load all the saved data from the hashtable (earlier we saved the data from the "Cast" Trigger) --------
              • Set AOE = (Load (Key AOE) of HandleID from HashtableMS)
              • Set Damage = (Load (Key Damage) of HandleID from HashtableMS)
              • -------- Setting up new variable for the picked unit --------
              • -------- Setting up location of the picked unit (for both referrence and clean leaks) --------
              • Set SkullLoc = (Position of Skull)
              • -------- Damage the dragged unit once per second around XXX(variable setup) AOE --------
              • Custom script: set bj_wantDestroyGroup = true
              • Unit Group - Pick every unit in (Units within AOE of SkullLoc matching ((((Matching unit) is alive) Equal to True) and (((Matching unit) belongs to an enemy of (Owner of Skull)) Equal to True))) and do (Actions)
                • Loop - Actions
                  • -------- This SFX marks that the unit is damaged by the spell --------
                  • Special Effect - Create a special effect attached to the overhead of (Picked unit) using Abilities\Spells\Undead\Possession\PossessionTarget.mdl
                  • -------- Clean leaks ! --------
                  • Special Effect - Destroy (Last created special effect)
                  • Unit - Cause Skull to damage (Picked unit), dealing Damage damage of attack type Spells and damage type Normal
              • -------- Clean leaks ! --------
              • Custom script: call RemoveLocation(udg_SkullLoc)
              • Custom script: call RemoveLocation(udg_SkullMoveLoc)
            • Else - Actions
              • -------- Now, if the skull is dead, remove it from the Unit Group --------
              • Unit - Remove Skull from the game
              • -------- Clean the child hashtable of the skull --------
              • Hashtable - Clear all child hashtables of child HandleID in HashtableMS
              • Unit Group - Remove Skull from SkullGroup
              • -------- This is for trigger efficiency. If the game detects 0 unit in that Unit Group, turn off this trigger (meaning, no longer checks for 0.03 second per check and game could be less-laggy :D) --------
  • Stun AOE
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Mesmering Skull Dummy
    • Actions
      • Set Skull = (Triggering unit)
      • Custom script: set udg_HandleID = GetHandleId(udg_Skull)
      • -------- This trigger is for the dummy unit to stun victim in an AOE after the skull is dead --------
      • -------- As usual, load the data from the hashtable --------
      • Set AOE = (Load (Key AOE) of HandleID from HashtableMS)
      • Set StunLevel = (Load (Key StunLevel) of HandleID from HashtableMS)
      • -------- Setting up a location for the skull's location --------
      • Set DyingLoc = (Position of (Triggering unit))
      • -------- Playing some eye-candy SFX on the location --------
      • Special Effect - Create a special effect at DyingLoc using Abilities\Spells\Undead\AnimateDead\AnimateDeadTarget.mdl
      • -------- Cleaning Leaks ! --------
      • Special Effect - Destroy (Last created special effect)
      • -------- Pick the units in the AOE and stun `em ! --------
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units within AOE of DyingLoc matching ((((Matching unit) is alive) Equal to True) and (((Matching unit) belongs to an enemy of (Triggering player)) Equal to True))) and do (Actions)
        • Loop - Actions
          • -------- Simple basic actions for Many Dummy Units *ToDoSomeAction* on Many Picked Units --------
          • Unit - Create 1 DummyUnitType for (Triggering player) at DyingLoc facing Default building facing degrees
          • Set Dummy = (Last created unit)
          • Unit - Add a 0.50 second Generic expiration timer to Dummy
          • -------- Each level varies the stun damage --------
          • Unit - Set level of Dummy Stun for Dummy to StunLevel
          • Unit - Order Dummy to Human Mountain King - Storm Bolt (Picked unit)
      • -------- Cleaning leaks on both location and hashtable --------
      • Custom script: call RemoveLocation(udg_DyingLoc)
      • Hashtable - Clear all child hashtables of child HandleID in HashtableMS
CHANGELOGS
v1.0
- Initial Release

v1.1
- Fixed tooltips on Skull and Dragged speed
- Add new writings on Trigger Comment in Setup trigger (STANDARD SETTINGS) to see the actual speed

v1.2
- Visibility has been ported to another trigger (doesn't related to the spell)
- Ability is set to a global variable
- Calling of functions has been reduced (many function call had been turned to global variable)
- Some tooltips changes
- Uses Integer to refer each unit's Handle ID
- Extra SFX had been removed (due to efficiency)
- Dummy now is "Can't raise, does not decay"
- Uses SetUnitX/Y for skull movement
- The spell now has a 0.5 seconds of channeling (to cope up with today's AoS-styled hero where we can instant cancel our spell)

v1.3f
- Key handle has been changed to custom script (calling less function)
- Trigger is turned off properly now

Keywords:
defskull, mesmerizing, skull, point, target, stun, float, drift, scary, haunt, drag.
Contents

Mesmerizing Skull v1.3f (Map)

Reviews
Approved Suggested changes Use the variable MesmerizingSkull hereSet AbilityLevel = (Level of Mesmerizing Skull for Caster) You should remove the skull from the game after you remove if from the group, not before Remove structures built and...

Moderator

M

Moderator

Reviewed by Maker, Mesmerizing Skull v1.3f, 16th Jul 2012

Approved

Suggested changes
  • Use the variable MesmerizingSkull here
    • Set AbilityLevel = (Level of Mesmerizing Skull for Caster)
  • You should remove the skull from the game
    after you remove if from the group, not before
  • Remove structures built and upgrades used from dummies
  • If a point that a unit is supposed to be moved to is not pathable,
    then the unit moves a bit awkwardly

Maker, Mesmerizing Skull v1.2, 16th Sep 2011

Remember to remove the skulls from SkullGroup in the triggers.
Add importing instructions.

You could set the dummies and the dummy ability into variables.
 
Level 37
Joined
Mar 6, 2006
Messages
9,240
Why are these in the setup trigger, they're not part of the ability?
  • Visibility - Disable fog of war
  • Visibility - Disable black mask
You could set the ability into a variable in the setup trigger, so one does not need to tamper with it in the Cast trigger when adding the ability into a map.
You're setting the level of ability into a variable after you've use <level of ability> function four times. Set the variable before you need the other <level of ability> thingies, and use the variable.
In learn tooltip, drift -> drifts.
Change the learned ability's tooltip position.
Improve the ability's learned tooltip text, remove the Level 2 from the extended description.
You have unnecessary variables. You have seven point variables for example, but you only need three. Too many real variables also.
You could use
  • Custom script: udg_integer = GetHandleId(bj_lastCreatedUnit)
to get the handle of the last created unit.
Then use the handle like this:
  • Hashtable - Save Angle as (Key Angle) of integer in HashtableMS
Saves two function calls per save action.
In MS_loop, do this before the <Is unit dead> check:
  • Set Skull = (Picked unit)
Then get the handle with
  • Custom script: udg_integer = GetHandleId(udg_Skull)
Load data with the id like this:
  • Set SkullSpeed = (Load (Key SkullSpeed) of integer from HashtableMS)
You're creating too many effects on the dragged units, one for each per 0.03 seconds.
From what I have heard, you should make the unit explode on death and apply a expiration timer instead of removing it from the game. This prevents a leak.
The dummy does not need to decay (object editor). It disappears more quickly if it doesn't decay.
You forgot
  • Unit Group - Remove (Picked unit) from SkullGroup
so the triggers won't turn off.
It might not be a good idea to remove the unit from the game before clearing the hashtable.
You don't need the actions take take place if the unit is dead in both triggers. You can remove them from the one with 1 second interval. Turn off both triggers in the trigger with 0.03 second interval. Actually you should do all the clearing things in the dying trigger. Remove from group, turn off triggers, clear child hashtable.
The unit dies trigger should be turned on/off.
Increase the follow through time so the caster has more time to do the cast animation.


Overall the spell is good, MUI and leakless :)
 
Level 15
Joined
Jul 6, 2009
Messages
889
Level 1 - 7 Seconds Duration | 50/s Skull Speed | 25/s Dragged Unit Speed | 5 Damage Per Second | 300 AOE | 50 Stun Damage

Level 2 - 8 Seconds Duration | 99/s Skull Speed | 50/s Dragged Unit Speed | 10 Damage Per Second | 400 AOE | 100 Stun Damage

Level 1 - 9 Seconds Duration | 150/s Skull Speed | 75/s Dragged Unit Speed | 15 Damage Per Second | 500 AOE | 150 Stun Damage

Level 1 - 10 Seconds Duration | 198/s Skull Speed | 99/s Dragged Unit Speed | 20 Damage Per Second | 600 AOE | 200 Stun Damage

I think you mean Level 3/4 :p
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
(Level of Mesmerizing Skull for (Triggering unit))

That should be saved into an integer variable so you don't have to reference it a million times.

So should (Key (Last created unit))

This cuts down on excessive function calls and makes overall execution spee in-game a bit faster. See the tutorial in my sig about the "(Parenthesis)" hint.
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
- dude, you can pretty much put everything in only one loop, including the 'dies'...
- Stun AOE and MS damage can be done inside the MS Loop, if you wanna damage it 'per second' just cheat the damage to this...
sample: Set Damage = (BaseDamage x (Real(AbilityLevel))) x 0.03
- you realy dont need the expiration for the dummies coz you have the duration
- I did not read the rest, sorry...anyway greate spell!
 
Level 3
Joined
Dec 26, 2009
Messages
4
hmmm.... wtf? i get two compileerrors
in this: call UnitDamageTargetBJ( udg_Skull, GetEnumUnit(), udg_Damage, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL )
and this line: set udg_Damage = LoadRealBJ(StringHashBJ("Damage"), udg_HandleID, udg_HashtableMS)
it says: index not found
its all in "MS DAmage"
 
You only need one loop, if you add an "atificial wait" into the loop you can generate something only happening every 1 second within a 0.03 second loop.

All you need is a variable for a current wait, basically:

  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • CurrentWait(Index) = 20 then
    • Then - Actions
      • CurrentWait(Index) = 0
      • (Actions)
    • Else - Actions
      • CurrentWait(Index) = CurrentWait(Index) + 1
I've used that method for ages to avoid creating additional looping triggers.

(the value of 20 = 1 second in a 0.03 loop trigger)
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
StringHash("?") are slow, use normal integers...

sample, this;
  • (Load (Key SkullSpeed) of HandleID from HashtableMS)
is converted to this;
LoadRealBJ(StringHashBJ("SkullSpeed"), udg_HandleID, udg_HashtableMS)

thus better is this;
  • (Load 1 of HandleID from HashtableMS)
and be converted to this;
LoadRealBJ(1, udg_HandleID, udg_HashtableMS)

or best, use its native form in custom script;
  • Custom script: set udg_MesmerizedSpeed = LoadReal(udg_HashtableMS, udg_HandleID, 1)
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
But by converting from StringHash to IntegerHash, makes it less readable ?

Oh, I see, when we make it in native form (JASS-styled) we can actually set our global variable from IntegerHash to a readable variable like you did in the last function.
 
Top