• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Rolling Cutter v1.8 GUI/MUI

The blademaster throws his sword to deal aoe damage. My third MUI spell xD might be influenced by valkemiere's destructo disk.

Credits to blink for the Wind Model and xyzier_24 for Blademaster Missile



Spell Description:
Point Target, Area of Effect Damage
The Blademaster throws his weapon and hopes for the best. After a period of time or after dealing enough damage, it will return to him somehow and cuts everyone in its path.
------------------------------------------------------------
Level 1: Deals 35 Damage per hit. Lasts for 10 seconds or Damage Threshold reaches 1200.
Level 2: Deals 40 Damage per hit. Lasts for 12 seconds or Damage Threshold reaches 2400.
Level 3: Deals 45 Damage per hit. Lasts for 14 seconds or Damage Threshold reaches 3600.
The blade can linger when hitting multiple enemies, dealing huge damage.


Shadow Hunter is used for example
292528-7ffcd0be0db8ab78560cb05014a50b3d.gif


292529-d86d633c2450876ad4e3bff1cd574d80.gif




  • RoCu INI config
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- ------------------------------ --------
      • -------- Remember to assign the correct ability here (Rolling Cutter) --------
      • Set RoCu_AbilityID = Rolling Cutter
      • -------- ------------------------------ --------
      • -------- Set to false if no longer testing --------
      • Set Debug_Mode = True
      • -------- ------------------------------ --------
      • -------- 21 is optimal for Blademaster and Shadow Hunter. Adjust according to your hero. 1 = 0.03seconds so 21 is 0.63 seconds --------
      • Set RoCu_Casting_Time = 21
      • -------- ------------------------------ --------
      • -------- Will the blade destroy trees in range --------
      • Set RoCu_DestroyTree = True
      • -------- --------------------------------------------------------- --------
      • -------- Duration = How many seconds the blade spins before returning to the caster. --------
      • Set RoCu_Duration[1] = 10
      • Set RoCu_Duration[2] = 12
      • Set RoCu_Duration[3] = 14
      • -------- ------------------------------ --------
      • -------- Attack_Type Influence the damage dealt corresponding to the target's armor. --------
      • -------- Damage_Type influence a lot. Seeing it is a physical spell I will put Normal. --------
      • Set RoCu_Attack_Type = Normal
      • Set RoCu_Damage_Type = Normal
      • -------- - --------
      • -------- 3 = Damage occurs every 0.09 seconds. Setting this to 1 is the fastest possible dealing every 0.03 seconds. --------
      • Set RoCu_Damage_Interval = 3
      • -------- - --------
      • -------- Amount of damage is dealt to the target in AoE --------
      • Set RoCu_Damage[1] = 30.00
      • Set RoCu_Damage[2] = 35.00
      • Set RoCu_Damage[3] = 40.00
      • -------- ------------------------------ --------
      • -------- When the projectile deals enough damage, the projectile returns to the caster to end the spell. It may still deal extra damage to enemy in its path but wont slow down for anything. --------
      • Set RoCu_MaxDamage[1] = 1200.00
      • Set RoCu_MaxDamage[2] = 2400.00
      • Set RoCu_MaxDamage[3] = 3600.00
      • -------- --------------------------------------------------------- --------
      • -------- Detects an enemy in range of the projectile and the blade will follow it. In Object editor the blade has 600 vision range, perhaps a good indicator to what enemy it might hit next. --------
      • Set RoCu_Tracking_Range = 700.00
      • -------- ------------------------------ --------
      • -------- Center of Caster just like the Locust Hero ability. If Projectile goes beyond this area it will attempt to return to him. This will override the projectile from tracking if you set it to low number. --------
      • -------- That means you can completely disable the tracking system just by putting this to 0, or make projectile track only enemies near the caster. --------
      • Set RoCu_Max_Proximity[1] = 500.00
      • Set RoCu_Max_Proximity[2] = 1000.00
      • Set RoCu_Max_Proximity[3] = 1500.00
      • -------- ------------------------------ --------
      • -------- Enemies within range of the projectile that will receive damage. --------
      • Set RoCu_AoE[1] = 100.00
      • Set RoCu_AoE[2] = 110.00
      • Set RoCu_AoE[3] = 120.00
      • -------- ------------------------------ --------
      • -------- You can change the dummy size. It only makes sense if you can manipulate the AoE as well. --------
      • Set RoCu_Dummy_Size[1] = 100.00
      • Set RoCu_Dummy_Size[2] = 110.00
      • Set RoCu_Dummy_Size[3] = 120.00
      • -------- ----------------:)----------------- --------
      • -------- How fast the blade moves. --------
      • Set RoCu_Speed[1] = 25.00
      • Set RoCu_Speed[2] = 28.00
      • Set RoCu_Speed[3] = 32.00
      • -------- ------------------------------ --------
      • -------- When projectile hits an enemy it will slow down (RoCu_Lockedin = True). The speed of dummy reduces to random between 5 and 7 --------
      • -------- This is to maximize the damage it can deal to an enemy --------
      • Set RoCu_Slowdown_Speed[1] = 5.00
      • Set RoCu_Slowdown_Speed[2] = 7.00
      • -------- ------------------------------ --------
      • -------- The distance the blade travels before turning. You can set this to 100 so that the blade constantly spins around caster. --------
      • Set RoCu_Dis[1] = 1000.00
      • Set RoCu_Dis[2] = 1000.00
      • Set RoCu_Dis[3] = 1000.00
      • -------- ------------------------------ --------
      • -------- This setting greatly change the behavior of the projectile. --------
      • -------- General rule of thumb is that the value should not be lower than Dis and works best if its at least 150% more than Dis amount --------
      • -------- If Dis is 1000, then DriftDis becomes 1500, the extra 500 fulfills the requirement to make a 180 curve spin. You can change the math to experiment. --------
      • Set RoCu_DriftDis[1] = (RoCu_Dis[1] x 1.50)
      • Set RoCu_DriftDis[2] = (RoCu_Dis[2] x 1.50)
      • Set RoCu_DriftDis[3] = (RoCu_Dis[3] x 1.50)
      • -------- ------------------------------ --------
      • -------- setting for blademaster --------
      • -------- Anim[1] = Horizontal projectile, Anim[2] = Vertical projectile, Anim[3] = Queues animation AFTER he throws the projectile, Anim[4] = Animation played when projectile returns to caster. --------
      • -------- if you dont want to use animation you can delete it in the loop --------
      • Set RoCu_Animation[1] = attack stand
      • Set RoCu_Animation[2] = attack slam
      • Set RoCu_Animation[3] = stand ready
      • Set RoCu_Animation[4] = stand victory
      • -------- --------------------------------------------------------- --------
      • -------- In RoCu Cast, the Blademaster has a 50% chance to summon either a Horizontal Dummy or a Vertical one. --------
      • Set RoCu_Dummy_Type[1] = Blademaster Sword Dummy (Horizontal)
      • Set RoCu_Dummy_Type[2] = Blademaster Sword Dummy (Vertical)
      • -------- --------------------------------------------------------- --------
      • -------- -Wind SFX when projectile is drifting --------
      • Set RoCu_SFX[1] = war3mapImported\WindWeak2.mdx
      • -------- ------------------------------ --------
      • -------- -SFX when hitting mechanical unit --------
      • Set RoCu_SFX[2] = Abilities\Weapons\MakuraMissile\MakuraMissile.mdl
      • -------- ------------------------------ --------
      • -------- -SFX when hitting non-mechanical (random from 3-5) --------
      • Set RoCu_SFX[3] = Abilities\Weapons\WardenMissile\WardenMissile.mdl
      • Set RoCu_SFX[4] = Objects\Spawnmodels\Critters\Albatross\CritterBloodAlbatross.mdl
      • Set RoCu_SFX[5] = Abilities\Spells\Other\Stampede\StampedeMissileDeath.mdl
      • -------- ------------------------------ --------
      • -------- -Special SFX when projectile is vertical --------
      • Set RoCu_SFX[6] = Abilities\Weapons\AncientProtectorMissile\AncientProtectorMissile.mdl
      • -------- ------------------------------ --------
      • -------- Random from 1 to 5 where the SFX will hit on target --------
      • Set RoCu_Bodypart[1] = head
      • Set RoCu_Bodypart[2] = chest
      • Set RoCu_Bodypart[3] = hand, left
      • Set RoCu_Bodypart[4] = hand, right
      • Set RoCu_Bodypart[5] = origin
      • -------- -----------------------Do not touch below---------------------------------- --------
      • Set RoCu_MaxDuration[1] = (RoCu_Duration[1] x (Integer(33.30)))
      • Set RoCu_MaxDuration[2] = (RoCu_Duration[2] x (Integer(33.30)))
      • Set RoCu_MaxDuration[3] = (RoCu_Duration[3] x (Integer(33.30)))
      • -------- ---------------------Check if destructible is a tree-------------------------- --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • RoCu_DestroyTree Equal to True
        • Then - Actions
          • Set harvest_loc = (Center of (Playable map area))
          • Unit - Create 1 Peasant for Neutral Passive at harvest_loc facing Default building facing degrees
          • Set harvester = (Last created unit)
          • Custom script: call UnitAddAbility(udg_harvester, 'Aloc' )
          • Unit - Hide harvester
          • Custom script: call RemoveLocation(udg_harvest_loc)
        • Else - Actions
  • RoCu Cast
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to RoCu_AbilityID
    • Actions
      • -------- Do not touch --------
      • Set RoCu_Index = (RoCu_Index + 1)
      • -------- --------------------------------------------------------- --------
      • Set RoCu_Lockedin[RoCu_Index] = False
      • Set RoCu_CastTime[RoCu_Index] = 0
      • Set RoCu_Timer[RoCu_Index] = 0
      • Set RoCu_SFX_Counter[RoCu_Index] = 0
      • Set RoCu_Counter[RoCu_Index] = 0
      • Set RoCu_DamageCounter[RoCu_Index] = 0.00
      • Set RoCu_Dis_Count[RoCu_Index] = 0.00
      • Set RoCu_AngleCount[RoCu_Index] = 0
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Random integer number between 1 and 2) Equal to 1
        • Then - Actions
          • -------- 50% that the projectile spins either left or right side. --------
          • Set RoCu_RightSpin[RoCu_Index] = True
        • Else - Actions
          • Set RoCu_RightSpin[RoCu_Index] = False
      • -------- --------------------------------------------------------- --------
      • Set RoCu_Caster[RoCu_Index] = (Triggering unit)
      • Set RoCu_AbilLVL[RoCu_Index] = (Level of RoCu_AbilityID for RoCu_Caster[RoCu_Index])
      • -------- - --------
      • Set RoCu_CasterLoc[RoCu_Index] = (Position of RoCu_Caster[RoCu_Index])
      • Set RoCu_TargetLoc[RoCu_Index] = (Target point of ability being cast)
      • -------- - --------
      • -------- You can touch this --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Random integer number between 1 and 2) Equal to 1
        • Then - Actions
          • Animation - Play RoCu_Caster[RoCu_Index]'s RoCu_Animation[1] animation
          • Set RoCu_Summon[RoCu_Index] = RoCu_Dummy_Type[1]
          • Set RoCu_is_vertical[RoCu_Index] = False
        • Else - Actions
          • Set RoCu_Summon[RoCu_Index] = RoCu_Dummy_Type[2]
          • Animation - Play RoCu_Caster[RoCu_Index]'s RoCu_Animation[2] animation
          • Set RoCu_is_vertical[RoCu_Index] = True
      • -------- - --------
      • -------- Do not touch --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • RoCu_Index Equal to 1
        • Then - Actions
          • Trigger - Turn on RoCu Loop <gen>
        • Else - Actions
  • RoCu Loop
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • For each (Integer RoCu_Loop) from 1 to RoCu_Index, do (Actions)
        • Loop - Actions
          • -------- - --------
          • Set RoCu_CastTime[RoCu_Loop] = (RoCu_CastTime[RoCu_Loop] + 1)
          • -------- - --------
          • -------- ||Cast Spell|| --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • RoCu_CastTime[RoCu_Loop] Equal to RoCu_Casting_Time
            • Then - Actions
              • -------- This section will fire only once. After that the spell begins. --------
              • Animation - Queue RoCu_Caster[RoCu_Loop]'s RoCu_Animation[3] animation
              • -------- - --------
              • Set RoCu_Angle[RoCu_Loop] = (Angle from RoCu_CasterLoc[RoCu_Loop] to RoCu_TargetLoc[RoCu_Loop])
              • Set RoCu_TempLoc = (RoCu_CasterLoc[RoCu_Loop] offset by 45.00 towards RoCu_Angle[RoCu_Loop] degrees)
              • -------- - --------
              • Unit - Create 1 RoCu_Summon[RoCu_Loop] for (Owner of RoCu_Caster[RoCu_Loop]) at RoCu_TempLoc facing RoCu_Angle[RoCu_Loop] degrees
              • Set RoCu_Dummy[RoCu_Loop] = (Last created unit)
              • Animation - Change RoCu_Dummy[RoCu_Loop]'s size to (RoCu_Dummy_Size[RoCu_AbilLVL[RoCu_Loop]]%, RoCu_Dummy_Size[RoCu_AbilLVL[RoCu_Loop]]%, RoCu_Dummy_Size[RoCu_AbilLVL[RoCu_Loop]]%) of its original size
              • -------- - --------
              • Custom script: call RemoveLocation(udg_RoCu_CasterLoc[udg_RoCu_Loop])
              • Custom script: call RemoveLocation(udg_RoCu_TargetLoc[udg_RoCu_Loop])
              • Custom script: call RemoveLocation(udg_RoCu_TempLoc)
              • -------- - --------
              • Custom script: set udg_RoCu_TargetLoc[udg_RoCu_Loop] = null
              • Custom script: set udg_RoCu_TempLoc = null
            • Else - Actions
          • -------- - --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • RoCu_CastTime[RoCu_Loop] Greater than RoCu_Casting_Time
            • Then - Actions
              • -------- - --------
              • -------- Timer is used to determine when the spell should end. Counter is used to delay the damage or else its too fast. --------
              • Set RoCu_Timer[RoCu_Loop] = (RoCu_Timer[RoCu_Loop] + 1)
              • Set RoCu_Counter[RoCu_Loop] = (RoCu_Counter[RoCu_Loop] + 1)
              • Set RoCu_SFX_Counter[RoCu_Loop] = (RoCu_SFX_Counter[RoCu_Loop] + 1)
              • -------- - --------
              • Set RoCu_DummyLoc[1] = (Position of RoCu_Dummy[RoCu_Loop])
              • -------- ||Dirt Trail|| --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • RoCu_SFX_Counter[RoCu_Loop] Greater than or equal to 2
                  • RoCu_is_vertical[RoCu_Loop] Equal to True
                • Then - Actions
                  • -------- Special SFX that plays when projectile is vertical, as it is rolling on the dirt. --------
                  • Set RoCu_SFX_Counter[RoCu_Loop] = 0
                  • Special Effect - Create a special effect at RoCu_DummyLoc[1] using RoCu_SFX[6]
                  • Special Effect - Destroy (Last created special effect)
                • Else - Actions
              • -------- - --------
              • -------- ||Destroy Tree|| --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • RoCu_DestroyTree Equal to True
                • Then - Actions
                  • Destructible - Pick every destructible within RoCu_AoE[RoCu_AbilLVL[RoCu_Loop]] of RoCu_DummyLoc[1] and do (Actions)
                    • Loop - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (Current life of (Picked destructible)) Greater than 0.00
                        • Then - Actions
                          • Unit - Order harvester to Harvest (Picked destructible)
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • (Current order of harvester) Equal to (Order(harvest))
                            • Then - Actions
                              • Destructible - Set life of (Picked destructible) to 0.40
                            • Else - Actions
                              • Unit - Order harvester to Stop
                        • Else - Actions
                • Else - Actions
              • -------- - --------
              • -------- ||Damage|| --------
              • -------- custom script to destroy the next group created to prevent leak. --------
              • Custom script: set bj_wantDestroyGroup = true
              • Unit Group - Pick every unit in (Units within RoCu_AoE[RoCu_AbilLVL[RoCu_Loop]] of RoCu_DummyLoc[1]) and do (Actions)
                • Loop - Actions
                  • Set TempUnit = (Picked unit)
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • RoCu_Counter[RoCu_Loop] Greater than or equal to RoCu_Damage_Interval
                      • (TempUnit is alive) Equal to True
                      • (TempUnit is invulnerable) Equal to False
                      • ((Unit-type of TempUnit) is A structure) Equal to False
                      • (TempUnit belongs to an enemy of (Owner of RoCu_Caster[RoCu_Loop])) Equal to True
                    • Then - Actions
                      • -------- RoCu_Counter set to 0 to restart the delay loop --------
                      • Set RoCu_Counter[RoCu_Loop] = 0
                      • -------- RoCu_DamageCounter will end the spell if it reaches a certain number for balance (e.g 1200 per level) --------
                      • Set RoCu_DamageCounter[RoCu_Loop] = (RoCu_DamageCounter[RoCu_Loop] + RoCu_Damage[RoCu_AbilLVL[RoCu_Loop]])
                      • -------- Damage unit in range --------
                      • Unit - Cause RoCu_Caster[RoCu_Loop] to damage TempUnit, dealing RoCu_Damage[RoCu_AbilLVL[RoCu_Loop]] damage of attack type RoCu_Attack_Type and damage type RoCu_Damage_Type
                      • -------- - --------
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (TempUnit is Mechanical) Equal to True
                        • Then - Actions
                          • Special Effect - Create a special effect attached to the RoCu_Bodypart[(Random integer number between 1 and 5)] of TempUnit using RoCu_SFX[2]
                          • Special Effect - Destroy (Last created special effect)
                        • Else - Actions
                          • Special Effect - Create a special effect attached to the RoCu_Bodypart[(Random integer number between 1 and 5)] of TempUnit using RoCu_SFX[(Random integer number between 3 and 5)]
                          • Special Effect - Destroy (Last created special effect)
                    • Else - Actions
              • -------- - --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • RoCu_Timer[RoCu_Loop] Less than RoCu_MaxDuration[RoCu_AbilLVL[RoCu_Loop]]
                • Then - Actions
                  • -------- - --------
                  • -------- ||Damage Threshold|| --------
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • RoCu_DamageCounter[RoCu_Loop] Greater than or equal to RoCu_MaxDamage[RoCu_AbilLVL[RoCu_Loop]]
                    • Then - Actions
                      • -------- RoCu_DamageCounter will end the spell if it reaches a certain number for balance (e.g 1200 per level) --------
                      • Set RoCu_Timer[RoCu_Loop] = RoCu_MaxDuration[RoCu_AbilLVL[RoCu_Loop]]
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • Debug_Mode Equal to True
                        • Then - Actions
                          • Game - Display to (All players) for 2.00 seconds the text: (Damage threshold reached! + ((String(RoCu_DamageCounter[RoCu_Loop])) + was dealt. Returning Projectile now.))
                        • Else - Actions
                    • Else - Actions
                  • -------- - --------
                  • -------- ||Locked In|| --------
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • RoCu_Lockedin[RoCu_Loop] Equal to True
                    • Then - Actions
                      • -------- Locked in is a boolean that becomes true when the dummy detects an enemy in Group[1] --------
                      • -------- it slows down the speed of projectile dummy --------
                      • -------- Visually good looking in my opinion but main function is to deal as much damage to 1 target as possible. --------
                      • Set RoCu_TrueSpeed[RoCu_Loop] = (Random real number between RoCu_Slowdown_Speed[1] and RoCu_Slowdown_Speed[2])
                      • Animation - Change RoCu_Dummy[RoCu_Loop]'s animation speed to 150.00% of its original speed
                    • Else - Actions
                      • Set RoCu_TrueSpeed[RoCu_Loop] = RoCu_Speed[RoCu_AbilLVL[RoCu_Loop]]
                      • Animation - Change RoCu_Dummy[RoCu_Loop]'s animation speed to 250.00% of its original speed
                  • -------- - --------
                  • -------- AngleCount is used to delay drifiting effect --------
                  • Set RoCu_AngleCount[RoCu_Loop] = (RoCu_AngleCount[RoCu_Loop] + 1)
                  • -------- - --------
                  • -------- ||Drift|| --------
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • RoCu_Dis_Count[RoCu_Loop] Greater than or equal to RoCu_Dis[RoCu_AbilLVL[RoCu_Loop]]
                      • RoCu_AngleCount[RoCu_Loop] Greater than or equal to 2
                    • Then - Actions
                      • -------- This section fires every 0.06s thanks to the delay loop. --------
                      • Set RoCu_AngleCount[RoCu_Loop] = 0
                      • -------- - --------
                      • -------- This is the thing that makes the projectile drift --------
                      • -------- The trick is to manipulate its facing angle. When we move him instantly it depends on the angle he is facing. --------
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • RoCu_RightSpin[RoCu_Loop] Equal to True
                        • Then - Actions
                          • -------- Make projectile spin on its right --------
                          • Set RoCu_Angle[RoCu_Loop] = (RoCu_Angle[RoCu_Loop] - (Random real number between 20.00 and 45.00))
                        • Else - Actions
                          • -------- Make projectile spin on its left --------
                          • Set RoCu_Angle[RoCu_Loop] = (RoCu_Angle[RoCu_Loop] + (Random real number between 20.00 and 45.00))
                      • -------- - --------
                      • Unit - Make RoCu_Dummy[RoCu_Loop] face RoCu_Angle[RoCu_Loop] over 0.00 seconds
                      • -------- - --------
                      • Special Effect - Create a special effect at RoCu_DummyLoc[1] using RoCu_SFX[1]
                      • Special Effect - Destroy (Last created special effect)
                      • -------- - --------
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • RoCu_Dis_Count[RoCu_Loop] Greater than or equal to RoCu_DriftDis[RoCu_AbilLVL[RoCu_Loop]]
                        • Then - Actions
                          • -------- After drifiting, this entire row will fire only once, we use this opportunity to make the dummy track a random nearby unit and its location. --------
                          • -------- ||Group 2|| --------
                          • -------- We use Group[2] to detect enemy in range --------
                          • Set RoCu_Group[2] = (Units within RoCu_Tracking_Range of RoCu_DummyLoc[1] matching ((((Matching unit) is alive) Equal to True) and (((((Matching unit) is A structure) Equal to False) and (((Matching unit) is invulnerable) Equal to False)) and (((Matching unit) belongs to an enem
                          • Set RoCu_CasterLoc[RoCu_Loop] = (Position of RoCu_Caster[RoCu_Loop])
                          • -------- - --------
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • (Number of units in RoCu_Group[2]) Greater than 0
                            • Then - Actions
                              • -------- - --------
                              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                • If - Conditions
                                  • (Distance between RoCu_DummyLoc[1] and RoCu_CasterLoc[RoCu_Loop]) Less than or equal to RoCu_Max_Proximity[RoCu_AbilLVL[RoCu_Loop]]
                                • Then - Actions
                                  • Set RoCu_Victim[RoCu_Loop] = (Random unit from RoCu_Group[2])
                                  • Set RoCu_VictimLoc[RoCu_Loop] = (Position of RoCu_Victim[RoCu_Loop])
                                  • Set RoCu_Angle[RoCu_Loop] = (Angle from RoCu_DummyLoc[1] to RoCu_VictimLoc[RoCu_Loop])
                                  • Custom script: call RemoveLocation(udg_RoCu_VictimLoc[udg_RoCu_Loop])
                                  • Custom script: set udg_RoCu_VictimLoc[udg_RoCu_Loop] = null
                                • Else - Actions
                                  • Set RoCu_Angle[RoCu_Loop] = (Angle from RoCu_DummyLoc[1] to RoCu_CasterLoc[RoCu_Loop])
                                  • -------- If no enemy is detected, the projectile moves near the caster. --------
                            • Else - Actions
                              • Set RoCu_Angle[RoCu_Loop] = (Angle from RoCu_DummyLoc[1] to RoCu_CasterLoc[RoCu_Loop])
                              • -------- - --------
                          • -------- - --------
                          • Unit - Make RoCu_Dummy[RoCu_Loop] face RoCu_Angle[RoCu_Loop] over 0.00 seconds
                          • -------- - --------
                          • Custom script: call RemoveLocation(udg_RoCu_CasterLoc[udg_RoCu_Loop])
                          • Custom script: call DestroyGroup(udg_RoCu_Group[2])
                          • -------- - --------
                          • Set RoCu_Dis_Count[RoCu_Loop] = 0.00
                          • -------- - --------
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • (Random integer number between 1 and 2) Equal to 1
                            • Then - Actions
                              • Set RoCu_RightSpin[RoCu_Loop] = True
                            • Else - Actions
                              • Set RoCu_RightSpin[RoCu_Loop] = False
                        • Else - Actions
                    • Else - Actions
                      • Set RoCu_Angle[RoCu_Loop] = (Facing of RoCu_Dummy[RoCu_Loop])
                  • -------- - --------
                  • -------- What is Dis_Count? It accumulates the speed of dummy everytime the loop... loops, if it reach Distance of 1000 it will trigger the drift. --------
                  • Set RoCu_Dis_Count[RoCu_Loop] = (RoCu_Dis_Count[RoCu_Loop] + RoCu_TrueSpeed[RoCu_Loop])
                  • Set RoCu_DummyLoc[2] = (RoCu_DummyLoc[1] offset by RoCu_TrueSpeed[RoCu_Loop] towards RoCu_Angle[RoCu_Loop] degrees)
                  • Unit - Move RoCu_Dummy[RoCu_Loop] instantly to RoCu_DummyLoc[2]
                  • -------- ------------------------------------------------------- --------
                  • -------- ||Group 1|| --------
                  • -------- This group is used to detect enemy in range to see if theres more than 0 unit. --------
                  • Set RoCu_Group[1] = (Units within RoCu_AoE[RoCu_AbilLVL[RoCu_Loop]] of RoCu_DummyLoc[1] matching ((((Matching unit) is alive) Equal to True) and (((((Matching unit) is A structure) Equal to False) and (((Matching unit) is invulnerable) Equal to False)) and (((Matching unit) belo
                  • -------- ------------------------------------------------------- --------
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Number of units in RoCu_Group[1]) Greater than 0
                    • Then - Actions
                      • Set RoCu_Lockedin[RoCu_Loop] = True
                    • Else - Actions
                      • Set RoCu_Lockedin[RoCu_Loop] = False
                  • -------- ------------------------------------------------------- --------
                  • Custom script: call RemoveLocation(udg_RoCu_DummyLoc[2])
                  • Custom script: call DestroyGroup(udg_RoCu_Group[1])
                  • -------- - --------
                • Else - Actions
                  • -------- ||End Spell|| --------
                  • -------- The spell basically ended after the timer becomes equal to duration. Everything below makes dummy return to caster then recycle the indexes. --------
                  • Set RoCu_TrueSpeed[RoCu_Loop] = (RoCu_TrueSpeed[RoCu_Loop] + 0.30)
                  • Set RoCu_CasterLoc[RoCu_Loop] = (Position of RoCu_Caster[RoCu_Loop])
                  • Set RoCu_Angle[RoCu_Loop] = (Angle from RoCu_DummyLoc[1] to RoCu_CasterLoc[RoCu_Loop])
                  • Set RoCu_DummyLoc[3] = (RoCu_DummyLoc[1] offset by RoCu_TrueSpeed[RoCu_Loop] towards RoCu_Angle[RoCu_Loop] degrees)
                  • -------- - --------
                  • Unit - Move RoCu_Dummy[RoCu_Loop] instantly to RoCu_DummyLoc[3]
                  • Unit - Make RoCu_Dummy[RoCu_Loop] face RoCu_Angle[RoCu_Loop] over 0.00 seconds
                  • -------- --------------------------------------------------------------- --------
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Distance between RoCu_CasterLoc[RoCu_Loop] and RoCu_DummyLoc[3]) Less than or equal to 45.00
                    • Then - Actions
                      • Animation - Play RoCu_Caster[RoCu_Loop]'s RoCu_Animation[4] animation
                      • Animation - Queue RoCu_Caster[RoCu_Loop]'s stand animation
                      • -------- - --------
                      • Unit - Kill RoCu_Dummy[RoCu_Loop]
                      • -------- - --------
                      • Custom script: set udg_RoCu_Group[1] = null
                      • Custom script: set udg_RoCu_Group[2] = null
                      • Custom script: set udg_RoCu_DummyLoc[2] = null
                      • -------- - --------
                      • Set RoCu_Caster[RoCu_Loop] = RoCu_Caster[RoCu_Index]
                      • Set RoCu_AbilLVL[RoCu_Loop] = RoCu_AbilLVL[RoCu_Index]
                      • Set RoCu_Counter[RoCu_Loop] = RoCu_Counter[RoCu_Index]
                      • Set RoCu_Dummy[RoCu_Loop] = RoCu_Dummy[RoCu_Index]
                      • Set RoCu_Summon[RoCu_Loop] = RoCu_Summon[RoCu_Index]
                      • Set RoCu_CastTime[RoCu_Loop] = RoCu_CastTime[RoCu_Index]
                      • Set RoCu_Timer[RoCu_Loop] = RoCu_Timer[RoCu_Index]
                      • Set RoCu_Dis_Count[RoCu_Loop] = RoCu_Dis_Count[RoCu_Index]
                      • Set RoCu_AngleCount[RoCu_Loop] = RoCu_AngleCount[RoCu_Index]
                      • Set RoCu_SFX_Counter[RoCu_Loop] = RoCu_SFX_Counter[RoCu_Index]
                      • Set RoCu_TrueSpeed[RoCu_Loop] = RoCu_TrueSpeed[RoCu_Index]
                      • Set RoCu_Lockedin[RoCu_Loop] = RoCu_Lockedin[RoCu_Index]
                      • Set RoCu_DamageCounter[RoCu_Loop] = RoCu_DamageCounter[RoCu_Index]
                      • Set RoCu_RightSpin[RoCu_Loop] = RoCu_RightSpin[RoCu_Index]
                      • Set RoCu_is_vertical[RoCu_Loop] = RoCu_is_vertical[RoCu_Index]
                      • Set RoCu_CasterLoc[RoCu_Loop] = RoCu_CasterLoc[RoCu_Index]
                      • Set RoCu_TargetLoc[RoCu_Loop] = RoCu_TargetLoc[RoCu_Index]
                      • -------- - --------
                      • Set RoCu_Index = (RoCu_Index - 1)
                      • Set RoCu_Loop = (RoCu_Loop - 1)
                      • -------- - --------
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • RoCu_Index Equal to 0
                        • Then - Actions
                          • Trigger - Turn off (This trigger)
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • Debug_Mode Equal to True
                            • Then - Actions
                              • Game - Display to (All players) for 2.00 seconds the text: Index = 0
                            • Else - Actions
                        • Else - Actions
                    • Else - Actions
                  • -------- --------------------------------------------------------------- --------
                  • Custom script: call RemoveLocation(udg_RoCu_CasterLoc[udg_RoCu_Loop])
                  • Custom script: call RemoveLocation(udg_RoCu_DummyLoc[3])
                  • Custom script: set udg_RoCu_CasterLoc[udg_RoCu_Loop] = null
                  • Custom script: set udg_RoCu_DummyLoc[3] = null
              • -------- - --------
              • Custom script: call RemoveLocation(udg_RoCu_DummyLoc[1])
              • Custom script: set udg_RoCu_DummyLoc[1] = null
            • Else - Actions
          • -------- --------------------------------------------------------------- --------


1) Go to File -> Preference -> Tick allow unknown variables
2) Go to Import Manager and export if necessary. Credits to blink for wind model and xyzier_24 for blademaster missile!
3) Copy dummy units and custom ability in object editor
4) Finally copy Rolling Cutter trigger folder to your map


1.2 added configuration, can change aoe and dummy size.
1.3 projectile stays near caster if it detects no enemy in range
1.4 no longer targets buildings, fixed leak. added more config for slow down speed, animation, damage interval, cast time and cutting down trees
1.5 removed redundancy, added some things I missed
1.6 added some more documentation, SpellID no longer array, added config that can manipulate the projectile circling, renamed TurningDis to just Dis xD
1.7 dynamic indexing, added dirt trail for vertical projectile, now its really roll cutting the earth
1.8 forgot to recycle some index. Added a max proximity config that can override the tracking (or disable it) with ease.
The projectile can track enemies by default but at v1.8 there is a config that can disable the tracking by putting Max_Proximity to 0 or set it to low so that it only tracks enemies near caster. This makes the spell appear less sentient or not wander too far off. But if you want that then just set to 9999 or something lol.
Previews
Contents

Rolling Cutter v1.8 (Map)

Reviews
Rheiko
Changes were made. A pretty unique spell that can cut down any foe if you're lucky enough. Approved

Rheiko

Spell Reviewer
Level 27
Joined
Aug 27, 2013
Messages
4,215
The spell description made me chuckled. xD
Dude just throws his blade and hopes for the best.
This is the tale of a desperate yet lucky blademaster,
because the blade somehow comes back to him, lol.

This is awesome.

Anyway! I personally prefer to have a configuration in separate trigger. RoCu INI might be just the perfect place to put all your config at.
I'd suggest to create a proper documentation while you're at it. Both in config trigger and the main trigger (cast and loop). It can be helpful for user to adjust the settings to their likings and for fellow coders to save time trying to understand how things work.
 

Rheiko

Spell Reviewer
Level 27
Joined
Aug 27, 2013
Messages
4,215
No worries, you're doing great!

You can try to look at things from the perspective of a normal user who doesn't understand MUI and stuff.
If you were one of them, what would you try to change? From there, you can try to make it configurable. =)

Don't forget to explain what you're doing with different parts of the code. Readability is important!
 

Rheiko

Spell Reviewer
Level 27
Joined
Aug 27, 2013
Messages
4,215
Could have bumped the thread to let us know that you made an update! Here comes my full review.


thread.gif
| Rheiko | Oct 7, 2024

Review:
    • Set RoCu_MaxDuration[1] = (RoCu_Duration[1] x (Integer(33.30)))
    should be at the most bottom section in the config. User doesn't need to know the final calculation. You can also add a warning not to mess with that part of the trigger.
    • Animation - Play RoCu_Caster[RoCu_Mui]'s attack stand animation
    • Animation - Play RoCu_Caster[RoCu_Mui]'s attack slam animation
    • Animation - Queue RoCu_Caster[RoCu_Loop]'s stand ready animation
    all should be easily configurable by the user as different model might have different animation name.
    • RoCu_CastTime[RoCu_Loop] Equal to 21
    "21" should be easily configurable by the user as different model might have different animation timing.
    • Animation - Change RoCu_Dummy[RoCu_Loop]'s size to (RoCu_AoE[RoCu_AbilLVL[RoCu_Loop]]%, RoCu_AoE[RoCu_AbilLVL[RoCu_Loop]]%, RoCu_AoE[RoCu_AbilLVL[RoCu_Loop]]%) of its original size
    is currently tied to RoCu_AoE, the dummy size should have its own configuration. You can name it RoCu_DummySize or something.
    • Set RoCu_TrueSpeed[RoCu_Loop] = (Random real number between 5.00 and 7.00)
    this should also be configurable. MinSpeed & MaxSpeed. Don't forget to put a note when the values are applied.
  • You forgot to use your RoCu_Dummy_Loc[1] variable here:
    • Set RoCu_Angle[RoCu_Loop] = (Angle from (Position of RoCu_Dummy[RoCu_Loop]) to RoCu_CasterLoc[RoCu_Loop])
  • You forgot to use your RoCu_VictimLoc[RoCu_Loop] here:
    • Set RoCu_Angle[RoCu_Loop] = (Angle from RoCu_Dummy_Loc[1] to (Position of RoCu_Victim[RoCu_Loop]))
  • You might want to adjust your RoCu_Group to exclude buildings, I don't see why a blade can cause significant damage to a building and why it would target a building in the first place, but you can make it configurable if you prefer.
  • Attack type and Damage type when dealing damage could also be made configurable.
    • Unit - Cause RoCu_Caster[RoCu_Loop] to damage (Picked unit), dealing RoCu_Damage[RoCu_AbilLVL[RoCu_Loop]] damage of attack type Normal and damage type Normal
    • RoCu_Counter[RoCu_Loop] Greater than or equal to 3
    This could also be configurable. Just let the user know that 3 equals to 0.09 second interval of damage dealt
Aside from configurability issue and a small leak issue, this is such a clever and creative way of triggering. Code wise, this also looks good. I would suggest to make this spell chop down some trees along the way, it only makes sense. One possible issue I could think of is the difficulty to balance this spell. sometimes it deals too much damage and other times it deals way less damage than it should, luckily the damage and max damage values are configurable so user can fine tune the spell to suit their likings. I'll rate it 3 stars for now, but if you can fix the things I mentioned and even add a destroying tree capability. I'm going to rate it 4 stars.

Status:
Awaiting Update

Useful links:

 
Last edited:

Rheiko

Spell Reviewer
Level 27
Joined
Aug 27, 2013
Messages
4,215
Some changes are made. Great! Just to add a few things:
  • You should store the ability ID into a variable and place it inside the config trigger. This can become a failsafe, in case the user make a mistake when importing the spell or if the copied ability has a different ability ID for unknown reason after they import it to their map, they only need to re-assign the variable with the correct ability from config trigger.
    • Set RoCu_AbilityID = Rolling Cutter
    This led to my second point;

  • If you do store the ability into a variable. You should use that variable in your trigger. Some of them are:
    • (Ability being cast) Equal to Rolling Cutter
    =>
    • (Ability being cast) Equal to RoCu_AbilityID
    and also this:
    • Set RoCu_AbilLVL[RoCu_Mui] = (Level of (Ability being cast) for RoCu_Caster[RoCu_Mui])
    =>
    • Set RoCu_AbilLVL[RoCu_Mui] = (Level of RoCu_AbilityID for RoCu_Caster[RoCu_Mui])

    • Set harvest_loc = ((Point(0.00, 0.00)) offset by (0.00, 0.00))
    Location with offset is such an unnecessary thing to do to create your harvester because it calls an unnecessary function to do an unnecessary calculation. You can simply replace it with (Center of (Playable map area)) or Point(0.00, 0.00), whichever you prefer.

  • You should store the initial angle into a variable. I believe RoCu_Angle is usable for that purpose. Use it here:
    • Set RoCu_TempLoc[RoCu_Mui] = (RoCu_CasterLoc[RoCu_Mui] offset by 45.00 towards (Angle from RoCu_CasterLoc[RoCu_Mui] to RoCu_TargetLoc[RoCu_Mui]) degrees)
    and then you should use it again in your loop trigger right here:
    • Unit - Create 1 RoCu_Summon[RoCu_Loop] for (Owner of RoCu_Caster[RoCu_Loop]) at RoCu_TempLoc[RoCu_Loop] facing (Angle from RoCu_CasterLoc[RoCu_Loop] to RoCu_TargetLoc[RoCu_Loop]) degrees
    It's usually a good practice to call a function once and then use a variable to store that information so you can keep reusing it whenever needed. Using a variable is generally faster than calling a function. For this case, you only need to do the angle calculation once and you can use it twice.

  • You have this in your If Condition in your loop trigger:
    • ((Picked unit) is A structure) Equal to False
    You probably forgot to remove it since you already use ((Matching unit) is A structure) in your group variable.

  • In your loop trigger right here:
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • RoCu_RightSpin[RoCu_Loop] Equal to True
      • Then - Actions
        • Set RoCu_Angle[RoCu_Loop] = ((Facing of RoCu_Dummy[RoCu_Loop]) - (Random real number between 20.00 and 45.00))
      • Else - Actions
        • Set RoCu_Angle[RoCu_Loop] = ((Facing of RoCu_Dummy[RoCu_Loop]) + (Random real number between 20.00 and 45.00))
    it should be:
    • Set RoCu_Angle[RoCu_Loop] = (RoCu_Angle[RoCu_Loop] - (Random real number between 20.00 and 45.00))
    • Set RoCu_Angle[RoCu_Loop] = (RoCu_Angle[RoCu_Loop] + (Random real number between 20.00 and 45.00))
    because RoCu_Angle already contains Facing Angle of the dummy.

  • You made Attack Type configurable but forgot about Damage Type.
That should be it for now. I'll look into this again when you update the bundle. If everything's good at that point, this should be approvable.
 

Rheiko

Spell Reviewer
Level 27
Joined
Aug 27, 2013
Messages
4,215
RoCu_AbilityID shouldn't be an array. Also, can you please elaborate more on some parts of the documentation? Explain every option in the config as concise and as clear as possible. We gotta make sure even a 5-year old can understand how to import and configure the spell. Right now, some of them doesn't have explanation and some that do is not clear enough.

Instead of just saying things like "you can experiment with this but I would just leave it as is", you can say something more descriptive like "This is the distance at which the blade will start to drift / move in circular motion". Be more descriptive is what I'm saying.

You can group the changes you made for each version of the spell inside a changelog, you can use the [hidden=Changelog][/hidden] tags for that and place the changelog at the most bottom of your description. You must also include an importing instruction and spell description as well as a spell preview in your description.
 

Rheiko

Spell Reviewer
Level 27
Joined
Aug 27, 2013
Messages
4,215
Nice! I see you've added some things I requested. But perhaps you can explain a little more some of the stuff in config. Like what is DummyType and what should the user do with it. There are multiple of them, what does that mean. For some of the straight forward ones like Damage, MaxDamage, or Aoe, simply put a little note above it on what it does, e.g. This is how much damage you will deal to the enemy units or this is the area of effect of the projectile. And explain what Ability Code is and the reason it's there.
 

Rheiko

Spell Reviewer
Level 27
Joined
Aug 27, 2013
Messages
4,215
Great! But still no explanation for RoCu_AbilityID as well as Attack Type and Damage Type. =(

AT and DT handle the damage modifier when they interact with armor type. I believe I already made a rough explanation on AbilityID and its purpose.

Edit: also post the preview images on your description using the [IMG][/IMG] tag.
 

Rheiko

Spell Reviewer
Level 27
Joined
Aug 27, 2013
Messages
4,215
Here's a thread explaining how Attack Type and Damage Type work, in case you're interested:
Could be handy.
 
Level 30
Joined
Jun 4, 2023
Messages
419
No worries, you're doing great!

You can try to look at things from the perspective of a normal user who doesn't understand MUI and stuff.
If you were one of them, what would you try to change? From there, you can try to make it configurable. =)

Don't forget to explain what you're doing with different parts of the code. Readability is important!
I used to know what MUI meant. Now I've devolved back down to peasant status :sad:
 

Rheiko

Spell Reviewer
Level 27
Joined
Aug 27, 2013
Messages
4,215
No need to be so hard on yourself, @Bleeq . MUI stands for Multiple Unit Instanceability.
It simply means an ability can be used at any time by any reasonable number of units without any unexpected behavior occurring.

Let's say we have a DoT (Damage overtime) spell, that last for 3 seconds.
If unit A cast the spell first and unit B cast the spell one second later.
unit B shouldn't interrupt unit A's spell duration.
Unit A's effect should still have 2 seconds left before it expires and unit B's should have 3 seconds to expire as it just begins.
Let's say for some reason, unit A's effect is now permanent after unit B's spell cast or unit A's effect duration restarts when a unit B cast the spell, it's definitely not the expected behavior. It's not MUI. We have some methods to make a spell MUI.

One of the methods is Visualize: Dynamic Indexing, and I want to take this opportunity to recommend it to @Sindobato . Because currently, your way of indexing is, although not a problem, could be optimized further. Currently, your way of indexing keeps increasing the index and waits until there's not a single instance left before the index resets back to zero. Although it is pretty unrealistic to hit the max array index (which is 32768, quite a high number), I believe it's a good practice to reuse the unused instance instead, so you don't unnecessarily loop through inactive instances. It is achievable with Dynamic Indexing and Linked List. Bribe's Unit Indexer also works.
 
Last edited:
Level 1
Joined
Oct 22, 2024
Messages
2
hi, why does the spell always stops working after upgrading it beyond lvl 3? ive already attempted to adjust the corresponding real arrays to each levels in the world editor, except ofc, the RoCu_MaxDuration integer arrays (essentially triggers in "Do not touch" areas) but to no avail, the problem persists. i would appreciate it if someone can help me ☹️ thx very much.
 
Level 6
Joined
Jun 18, 2024
Messages
28
hi, why does the spell always stops working after upgrading it beyond lvl 3? ive already attempted to adjust the corresponding real arrays to each levels in the world editor, except ofc, the RoCu_MaxDuration integer arrays (essentially triggers in "Do not touch" areas) but to no avail, the problem persists. i would appreciate it if someone can help me ☹️ thx very much.
Hi, there is no problem in the loop but maybe in the INI Config you forgot to adjust specifically this line
  • Set RoCu_DriftDis[4] = (RoCu_Dis[4] x 1.50)
and
  • Set RoCu_MaxDuration[4] = (RoCu_Duration[4] x (Integer(33.30)))
You must change the array for variable name and the array inside the math too :)

I know this is the problem because the spell runs on timer, if you did not declare the variable for duration it will automatically be 0, therefore the spell will end as soon as you start it.

Forgive my wording for do not touch, I meant to say you shouldn't alter the calculation but if you increase the level then you should definitely copy and paste then update the array accordingly.
 
Last edited:
Level 1
Joined
Oct 22, 2024
Messages
2
Hi, there is no problem in the loop but maybe in the INI Config you forgot to adjust specifically this line
  • Set RoCu_DriftDis[4] = (RoCu_Dis[4] x 1.50)
and
  • Set RoCu_MaxDuration[4] = (RoCu_Duration[4] x (Integer(33.30)))
You must change the array for variable name and the array inside the math too :)

I know this is the problem because the spell runs on timer, if you did not declare the variable for duration it will automatically be 0, therefore the spell will end as soon as you start it.

Forgive my wording for do not touch, I meant to say you shouldn't alter the calculation but if you increase the level then you should definitely copy and paste then update the array accordingly.
ayyy, thx for clarifying!! the spell works above lvl 3 now!
 
Top