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

Real-like Cavalry Attack v1.6

This bundle is marked as awaiting update. A staff member has requested changes to it before it can be approved.
Template of the real-like Cavalry Attack. This one will be perfect for medieval maps. Knights are moving like one squad through enemies dealing physical damage and stunning them for 1 sec. Stunned enemies gain additional damage from the cavalry attack.
In this template you can change parameters like speed, damage, hit area, animation speed, stun duration and more.

  • HOW TO IMPORT
    • Events
    • Conditions
    • Actions
      • -------- 1. COPY ALL CUSTOM UNITS --------
      • -------- ////////////////////////////////////////////////////// --------
      • -------- 2. COPY ALL CUSTOM ABILITIES --------
      • -------- ////////////////////////////////////////////////////// --------
      • -------- 3. COPY ALL TRIGGERS FROM THE "CAVALRY ATTACK FOLDER" --------
      • -------- ////////////////////////////////////////////////////// --------
      • -------- 4. BE SURE ALL ABILITIES AND UNITS HAVE RIGHT PLACES LIKE IN THE ORIGINAL TEMPLATE --------
      • -------- ////////////////////////////////////////////////////// --------
      • -------- 5. BE SURE YOUR UNIT HAS Art - Animation: Cast Point = 0.001 like in the template. --------
      • -------- ////////////////////////////////////////////////////// --------
      • -------- 6. IF YOU DON'T LIKE ANIMATION SPEED FOR A CERTAIN UNIT MODEL YOU CAN COPY --------
      • -------- ANIMATION INDEX PARAMETERS FROM "CAV UNIT" TO "CAV USE ABILITY" FOR INDIVIDUAL SETTINGS --------
      • -------- ////////////////////////////////////////////////////// --------
      • -------- ////////////////////////////////////////////////////// --------
      • -------- ////////////////////////////////////////////////////// --------
      • -------- 7. HOW TO DETERMINE ANIMATION INDEX --------
      • -------- IF YOU USE CUSTOM UNIT THAT THE TRIGGER "CAVN INDEX ANIMATION" DOESN'T HAVE --------
      • -------- - COPY TRIGGER "CAV COMMAND" IN YOUR GAME --------
      • -------- -SELECT UNIT INGAME YOU WANT --------
      • -------- -TYPE -anim 0, -anim 1, - anim 2 etc UNTIL YOU GET A PROPER MOVING ANIMATION --------
      • -------- -THEN GO TO TRIGGER "CAV INDEX ANIMATION" --------
      • -------- -ACCORDING TO EXAMPLE ADD YOUR UNIT TYPE AND ADD ANIMATION INDEX YOU GET INGAME --------
      • -------- -ADD CUSTOM SCRIPT "set udg_CAVinteger2 = udg_CAVtemp_unit_type" AFTER INDEX --------
      • -------- -ADD CUSTOM SCRIPT "call SaveIntegerBJ( udg_CAVinteger, 0, udg_CAVinteger2, udg_HASHCAVALRY )" AFTER INDEX --------
      • -------- -OR JUST COPY THESE CUSTOM SCRIPTS FROM THE EXAMPLES --------
      • -------- ////////////////////////////////////////////////////// --------
      • -------- ////////////////////////////////////////////////////// --------
      • -------- ////////////////////////////////////////////////////// --------

In this template you need to destroy the large group of orcs. Knight's attack power rate is low.

ANIMATION TIME PERIOD - Repeating animation timer. It allows to avoid ugly step line on the ground after the charging.
SQUAD ENGAGE RANGE - All selected units by a player units with Cavalry Attack in the S.E.R. range will also use the ability.
SPEED EVERY SECOND - MOVEMENT SPEED WHILE CHARGING
STUN DURATION - Damaged unit gets the stun effect. (0 = no stun, 10 = 1 sec, 15 = 1.5sec)
DISTANCE OF ENDING CHARGE - Stop charging before the knight reaches the point of order.
DAMAGE ON COLLISION WITH THE TAREGT - Deals physical damage to enemy. Damage is doubled against already stunned enemies.
COEFFICIENT OF DAMAGE WHILE HIT ALREADY STUNNED ENEMY - Multiple the damage if the victim is stunned.
TIME OF CHARGE -stop charging while timer fades.
ANIMATION SPEED, % - set aniamtion speed while charging.
AREA OF HIT - Damages all units in the area while charging.
ACCELERATION DISTANCE, % - Knight needs to accelerate. While accelerating the damage dealt and stun duration have the ACCELERATION PENALTY.
ACCELERATION PENALTY, % - While accelerating deals xx % of damage and decreases the stun duration by 100-xx %.
ACCELERATION RATE RESTORATION, % - While accelerating the knight is increasing its movement speed, damage dealt and stun duration back to 100%. (0% means the knight wouldn't restore it's movement speed until passing the ACCELERATION DISTANCE, 100% means the knight restores full efficiency for 1 sec.)
(set 0 for 100% penalty no damage and no stun, 100% - no penalty)
KNOCKBACK DURATION, sec - add knockback ability (0=no knockbakc)
KNOCKBACK RATE - how is strong the knockback will be.
ANIMATION INDEX - see tips above. It depends on the knight model.
ARCHING KNOCKBACK RATE (ANGLE/SEC) - allow to move a damaged unit on rounded trajectory.


1.Now the ability supports multiple level. To add levels go to the CAV USE ABILITY and set paramaters.
2. Variables names aren't generic now.
3. The loop trigger isn't permanent now.


1. Knight can't pass through buildings, doodads and cliffs.
2. Added new parameter which multiples the damage for stunned enemies.
3. More friendly configuration.
4. Example for Huntress and Raider.


1. Added the knockback parameters.
2. Detection abilities were removed. Now I'm using add/remove from group.


1. Removed some leaks in the StunGroup
2. Triggering unit is stored.
3. Added new paramater: Animation Time period.


Increases periodic event interval


1. The system turns off periodic trigger now.
2. Added additional trigger that counts index animation. So you don't need to go in the "CAV USE ABILITY" trigger anymore. But you still have to check animation for your own unit models.
3. Leak removed.


1. Added "rounded" trajectory for the knockback.
2. Leaks are fixed.
3. Fixed minor errors.
4. CAVreal[0] is replaced on CAVLoopPeriod
5. The "INIT" trigger allow to set speceffect for moved cavalry units and speceffect + attachment for damaged unit.
6. The occured dummy units are now neutral. They couldn't hurt the statistic board, I think.


full
full
full


  • CAV INIT
  • CAV INIT
    • Events
      • Time - Elapsed game time is 0.01 seconds
    • Conditions
    • Actions
      • Trigger - Turn off (This trigger)
      • Set CAVDetectGroup = (Units in (Playable map area) matching (((Matching unit) is Plagued) Equal to True))
      • Unit Group - Remove all units from CAVDetectGroup
      • Set CAVKnockbackGroup = (Units in (Playable map area) matching (((Matching unit) is Plagued) Equal to True))
      • Unit Group - Remove all units from CAVKnockbackGroup
      • Set CAVResetGroup = (Units in (Playable map area) matching (((Matching unit) is Plagued) Equal to True))
      • Unit Group - Remove all units from CAVResetGroup
      • Set CAVStunGroup = (Units in (Playable map area) matching (((Matching unit) is Plagued) Equal to True))
      • Unit Group - Remove all units from CAVStunGroup
      • Hashtable - Create a hashtable
      • Set HASHCAVALRY = (Last created hashtable)
      • Trigger - Run CAV INDEX ANIMATION <gen> (checking conditions)
      • -------- CONFIGURATION --------
      • Set CAVMainAbility = Cavalry Attack
      • Set CAVStunAbility = AA Dummy Stun
      • Set CAVDummyUnitType = Dummy Unit (Dummy)
      • Set CAVDamageType = Normal
      • Set CAVAttackType = Normal
      • -------- ANIMATION TIME PERIOD --------
      • Set CAVAnimationSpeed_time[1] = 0.70
      • Set CAVAnimationSpeed_time[2] = 0.70
      • Set CAVAnimationSpeed_time[3] = 0.70
      • -------- SQUAD ENGAGE AREA (TAKES ALL WHO HAVE THIS ABILITY IN THE AREA) --------
      • Set CAVSquadEngage[1] = 475.00
      • Set CAVSquadEngage[2] = 475.00
      • Set CAVSquadEngage[3] = 475.00
      • -------- YOU MAY ADD MORE ARRAYS (IF YOU NEED ABILITY MORE THAN 3 LEVELS) --------
      • -------- MOVEMENT SPEED WHILE CHARGING (DISTANCE EVERY SECOND) --------
      • Set CAVSpeed[1] = 420.00
      • Set CAVSpeed[2] = 470.00
      • Set CAVSpeed[3] = 522.00
      • -------- STUN DURATION (10=1 sec) (0=no stun) --------
      • Set CAVStunDuration[1] = 15.00
      • Set CAVStunDuration[2] = 18.00
      • Set CAVStunDuration[3] = 20.00
      • -------- DAMAGE WHILE COLLIDES WITH ENEMY UNITS --------
      • Set CAVDamage[1] = 70.00
      • Set CAVDamage[2] = 85.00
      • Set CAVDamage[3] = 100.00
      • -------- COEFFICIENT OF DAMAGE WHILE HIT ALREADY STUNNED ENEMY --------
      • Set CAVDamagecCoef[1] = 2.00
      • Set CAVDamagecCoef[2] = 2.30
      • Set CAVDamagecCoef[3] = 2.50
      • -------- HIT AREA --------
      • Set CAVHitArea[1] = 80.00
      • Set CAVHitArea[2] = 80.00
      • Set CAVHitArea[3] = 80.00
      • -------- DURATION OF EFFECT (IF UNIT IS STUCKED) --------
      • Set CAVChargeTime[1] = 3.00
      • Set CAVChargeTime[2] = 3.00
      • Set CAVChargeTime[3] = 3.00
      • -------- ANIMATION SPEED --------
      • Set CAVAnimationSpeed[1] = 150.00
      • Set CAVAnimationSpeed[2] = 170.00
      • Set CAVAnimationSpeed[3] = 185.00
      • -------- DISTANCE OF ENDING CHARGE (STOPS CHARGING WHILE REACHING THE POINT BUT THE UNIT HAVE DISTANCE FROM IT) --------
      • Set CAVDistanceOfEnding[1] = 50.00
      • Set CAVDistanceOfEnding[2] = 50.00
      • Set CAVDistanceOfEnding[3] = 50.00
      • -------- ACCELERATION DISTANCE (% OF TOTAL DISTANCE WHERE STUN DURATION AND DAMAGE WERE DECREASED) --------
      • Set CAVAccDistance[1] = 30.00
      • Set CAVAccDistance[2] = 25.00
      • Set CAVAccDistance[3] = 20.00
      • -------- ACCELERATION PENALTY (% OF TOTAL DURATION AND DAMAGE WHILE ACCELERATING) --------
      • -------- FOR EXAMPLE YOU HAVE TOTAL DAMAGE CAVDamage BUT IF UNIT IS ACCELERATING THEN THE CASTER HITS ENEMY DEALING (CAVAccPenalty / 100) x CAVDamage --------
      • Set CAVAccPenalty[1] = 20.00
      • Set CAVAccPenalty[2] = 35.00
      • Set CAVAccPenalty[3] = 50.00
      • -------- ACCELERATION RESTORE RATE (HOW FAST THE CASTER ACCELERATES THEIR MOVEMENT SPEED TO NORMAL PARAMATERS) --------
      • Set CAVAccRate[1] = 45.00
      • Set CAVAccRate[2] = 50.00
      • Set CAVAccRate[3] = 55.00
      • -------- KNOCKBACK DURATION (0=NO KNOCKBACK) --------
      • Set CAVKnockDur[1] = 1.00
      • Set CAVKnockDur[2] = 1.20
      • Set CAVKnockDur[3] = 1.40
      • -------- KNOCKBACK RATE --------
      • Set CAVKnockRate[1] = 250.00
      • Set CAVKnockRate[2] = 300.00
      • Set CAVKnockRate[3] = 350.00
      • -------- ARCHING KNOCKBACK RATE (ANGLE/SEC) --------
      • Set CAVArchingKnockback[1] = 70.00
      • Set CAVArchingKnockback[2] = 70.00
      • Set CAVArchingKnockback[3] = 70.00
      • -------- SPECEFFECT FOR DAMAGED UNIT --------
      • Set CAVEffectDamageAttach1 = chest
      • Set CAVEffectDamageAttach2 = <Empty String>
      • Set CAVEffectDamageAttach3 = <Empty String>
      • Set CAVEffectDamageVisual1 = Abilities\Spells\Other\Stampede\StampedeMissileDeath.mdl
      • Set CAVEffectDamageVisual2 = <Empty String>
      • Set CAVEffectDamageVisual3 = <Empty String>
      • -------- SPECEFFECT FOR CAVALRY MOVEMENT --------
      • Set CAVEffectMovementVisual1 = Abilities\Spells\Human\FlakCannons\FlakTarget.mdl
      • Set CAVEffectMovementVisual2 = <Empty String>
      • Set CAVEffectMovementVisual3 = <Empty String>
      • -------- LOOP - PERIOD OF LOOP (MUST BE EQUALED LIKE IN THE "CAV LOOP" TRIGGER) --------
      • Set CAVLoopPeriod = 0.05
  • CAV INDEX ANIMATION
    • Events
    • Conditions
    • Actions
      • Set CAVtemp_unit_type = Knight
      • Set CAVinteger = 0
      • Custom script: set udg_CAVinteger2 = udg_CAVtemp_unit_type
      • Custom script: call SaveIntegerBJ( udg_CAVinteger, 0, udg_CAVinteger2, udg_HASHCAVALRY )
      • Set CAVtemp_unit_type = Raider
      • Set CAVinteger = 2
      • Custom script: set udg_CAVinteger2 = udg_CAVtemp_unit_type
      • Custom script: call SaveIntegerBJ( udg_CAVinteger, 0, udg_CAVinteger2, udg_HASHCAVALRY )
      • Set CAVtemp_unit_type = Huntress
      • Set CAVinteger = 1
      • Custom script: set udg_CAVinteger2 = udg_CAVtemp_unit_type
      • Custom script: call SaveIntegerBJ( udg_CAVinteger, 0, udg_CAVinteger2, udg_HASHCAVALRY )
  • CAV LOOP
  • CAV LOOP
    • Events
      • Time - Every 0.05 seconds of game time
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Number of units in CAVResetGroup) Greater than 0
        • Then - Actions
          • Unit Group - Pick every unit in CAVResetGroup and do (Actions)
            • Loop - Actions
              • Set CAVtemp_unit = (Picked unit)
              • Custom script: set udg_CAVinteger = GetHandleIdBJ( udg_CAVtemp_unit)
              • -------- // --------
              • -------- This value 10 as CAVInteger removes the unit from ResetGroup. It is needed for group cast of cavalry attack --------
              • -------- // --------
              • Hashtable - Save ((Load 10 of CAVinteger from HASHCAVALRY) - CAVLoopPeriod) as 10 of CAVinteger in HASHCAVALRY
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Or - Any (Conditions) are true
                    • Conditions
                      • (Load 10 of CAVinteger from HASHCAVALRY) Less than or equal to 0.00
                      • (CAVtemp_unit is alive) Not equal to True
                      • (CAVtemp_unit is hidden) Equal to True
                • Then - Actions
                  • Unit Group - Remove CAVtemp_unit from CAVResetGroup
                • Else - Actions
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Number of units in CAVStunGroup) Greater than 0
        • Then - Actions
          • Unit Group - Pick every unit in CAVStunGroup and do (Actions)
            • Loop - Actions
              • Set CAVtemp_unit = (Picked unit)
              • Custom script: set udg_CAVinteger = GetHandleIdBJ( udg_CAVtemp_unit)
              • -------- // --------
              • -------- 17 as CAVInteger counts the time until Stun effect will removed. --------
              • -------- // --------
              • Set CAVreal[1] = (Load 17 of CAVinteger from HASHCAVALRY)
              • Set CAVreal[1] = (CAVreal[1] - CAVLoopPeriod)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Or - Any (Conditions) are true
                    • Conditions
                      • (CAVtemp_unit is alive) Not equal to True
                      • CAVreal[1] Less than or equal to 0.00
                      • (CAVtemp_unit is hidden) Equal to True
                • Then - Actions
                  • Set CAVreal[1] = 0.00
                  • Unit - Remove Stunned (Pause) buff from CAVtemp_unit
                  • Unit - Remove Stunned buff from CAVtemp_unit
                  • Unit Group - Remove CAVtemp_unit from CAVStunGroup
                • Else - Actions
              • Hashtable - Save CAVreal[1] as 17 of CAVinteger in HASHCAVALRY
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Number of units in CAVDetectGroup) Greater than 0
        • Then - Actions
          • Unit Group - Pick every unit in CAVDetectGroup and do (Actions)
            • Loop - Actions
              • Set CAVtemp_unit = (Picked unit)
              • Custom script: set udg_CAVinteger = GetHandleIdBJ( udg_CAVtemp_unit)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Or - Any (Conditions) are true
                    • Conditions
                      • (CAVtemp_unit has buff Stunned (Pause)) Equal to True
                      • (CAVtemp_unit has buff Stunned) Equal to True
                      • (CAVtemp_unit has buff Volcano) Equal to True
                      • (CAVtemp_unit has buff Impale) Equal to True
                      • (CAVtemp_unit has buff Cluster Rockets) Equal to True
                      • (CAVtemp_unit has buff Aerial Shackles) Equal to True
                      • (CAVtemp_unit has buff Entangling Roots) Equal to True
                      • (CAVtemp_unit is Snared) Equal to True
                      • (CAVtemp_unit is Sleeping) Equal to True
                      • (CAVtemp_unit is alive) Not equal to True
                      • (CAVtemp_unit is hidden) Equal to True
                      • (CAVtemp_unit is paused) Equal to True
                • Then - Actions
                  • Unit - Turn collision for CAVtemp_unit On
                  • Set CAVpoint[4] = (Position of CAVtemp_unit)
                  • Unit - Move CAVtemp_unit instantly to CAVpoint[4]
                  • Custom script: call RemoveLocation( udg_CAVpoint[4] )
                  • Set CAVgroup3 = (Load 0 of CAVinteger in HASHCAVALRY)
                  • Custom script: call DestroyGroup( udg_CAVgroup3 )
                  • Animation - Reset CAVtemp_unit's animation
                  • Unit Group - Remove CAVtemp_unit from CAVDetectGroup
                  • Animation - Change CAVtemp_unit's animation speed to 100.00% of its original speed
                  • Hashtable - Clear all child hashtables of child CAVinteger in HASHCAVALRY
                • Else - Actions
                  • -------- // --------
                  • -------- 7 as CAVInteger counts the time until the unti stop charging --------
                  • -------- // --------
                  • Hashtable - Save ((Load 7 of CAVinteger from HASHCAVALRY) - CAVLoopPeriod) as 7 of CAVinteger in HASHCAVALRY
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Load 7 of CAVinteger from HASHCAVALRY) Greater than 0.00
                    • Then - Actions
                      • -------- // --------
                      • -------- 24 AND 23 CAUSES ANIMATION TIMER. 24 IS INCREASED UNTIL IT BECOMES LARGER THAN 23 AND THE UNIT PLAYS ANIMATION. --------
                      • -------- // --------
                      • Hashtable - Save ((Load 24 of CAVinteger from HASHCAVALRY) + CAVLoopPeriod) as 24 of CAVinteger in HASHCAVALRY
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (Load 24 of CAVinteger from HASHCAVALRY) Greater than or equal to (Load 23 of CAVinteger from HASHCAVALRY)
                        • Then - Actions
                          • Set CAVinteger2 = (Load 20 of CAVinteger from HASHCAVALRY)
                          • Hashtable - Save 0.00 as 24 of CAVinteger in HASHCAVALRY
                          • Custom script: call SetUnitAnimationByIndex( GetEnumUnit(), udg_CAVinteger2 )
                        • Else - Actions
                      • -------- // --------
                      • -------- CAVPOINT[2] is taget point of ability being cast it has coordinates X,Y --------
                      • -------- CAVPOINT[3] is taget point of the caster when it starts charging --------
                      • -------- CAVPOINT[3] and CAVPOINT[2] helps with ACCELERATION EVENT --------
                      • -------- // --------
                      • Set CAVpoint[0] = (Position of CAVtemp_unit)
                      • Set CAVpoint[2] = (Point((Load 3 of CAVinteger from HASHCAVALRY), (Load 4 of CAVinteger from HASHCAVALRY)))
                      • Set CAVpoint[3] = (Point((Load 13 of CAVinteger from HASHCAVALRY), (Load 14 of CAVinteger from HASHCAVALRY)))
                      • -------- // --------
                      • -------- CAVreal[3] is effciency value. It helps for ACCELERATING (if 1 then ACCELERATION is gone and unti moves with normal speed) --------
                      • -------- it also inflicts on animation speed (8 as CAVInteger) --------
                      • -------- // --------
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (Distance between CAVpoint[0] and CAVpoint[3]) Greater than or equal to (((Load 12 of CAVinteger from HASHCAVALRY) / 100.00) x (Distance between CAVpoint[2] and CAVpoint[3]))
                        • Then - Actions
                          • Set CAVreal[3] = 1.00
                        • Else - Actions
                          • Hashtable - Save ((Load 15 of CAVinteger from HASHCAVALRY) + (Load 16 of CAVinteger from HASHCAVALRY)) as 15 of CAVinteger in HASHCAVALRY
                          • Set CAVreal[3] = ((Load 15 of CAVinteger from HASHCAVALRY) / 100.00)
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • CAVreal[3] Greater than or equal to 1.00
                        • Then - Actions
                          • Set CAVreal[3] = 1.00
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • CAVEffectMovementVisual1 Not equal to <Empty String>
                            • Then - Actions
                              • Custom script: call DestroyEffectBJ( AddSpecialEffectLoc(udg_CAVEffectMovementVisual1, udg_CAVpoint[0]) )
                            • Else - Actions
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • CAVEffectMovementVisual2 Not equal to <Empty String>
                            • Then - Actions
                              • Custom script: call DestroyEffectBJ( AddSpecialEffectLoc(udg_CAVEffectMovementVisual2, udg_CAVpoint[0]) )
                            • Else - Actions
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • CAVEffectMovementVisual3 Not equal to <Empty String>
                            • Then - Actions
                              • Custom script: call DestroyEffectBJ( AddSpecialEffectLoc(udg_CAVEffectMovementVisual3, udg_CAVpoint[0]) )
                            • Else - Actions
                        • Else - Actions
                      • Set CAVpoint[1] = (CAVpoint[0] offset by (CAVreal[3] x (Load 0 of CAVinteger from HASHCAVALRY)) towards (Load 6 of CAVinteger from HASHCAVALRY) degrees)
                      • -------- // --------
                      • -------- group4 detects buildings --------
                      • -------- // --------
                      • Set CAVgroup4 = (Units within (1.50 x (Load 9 of CAVinteger from HASHCAVALRY)) of CAVpoint[1] matching (((((Matching unit) is alive) Equal to True) and (((Matching unit) is in CAVgroup3) Not equal to True)) and (((Matching unit) is A structure) Equal to True)))
                      • Custom script: call RemoveLocation( udg_CAVpoint[3] )
                      • -------- CHECK PATHING --------
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • Or - Any (Conditions) are true
                            • Conditions
                              • (Terrain pathing at CAVpoint[1] of type Walkability is off) Equal to True
                              • (Number of units in CAVgroup4) Greater than 0
                        • Then - Actions
                          • Unit - Turn collision for CAVtemp_unit On
                          • Set CAVpoint[4] = (Position of CAVtemp_unit)
                          • Unit - Move CAVtemp_unit instantly to CAVpoint[4]
                          • Custom script: call RemoveLocation( udg_CAVpoint[4] )
                          • Set CAVgroup3 = (Load 0 of CAVinteger in HASHCAVALRY)
                          • Custom script: call DestroyGroup( udg_CAVgroup3 )
                          • Animation - Reset CAVtemp_unit's animation
                          • Unit Group - Remove CAVtemp_unit from CAVDetectGroup
                          • Animation - Change CAVtemp_unit's animation speed to 100.00% of its original speed
                          • Hashtable - Clear all child hashtables of child CAVinteger in HASHCAVALRY
                        • Else - Actions
                          • Unit - Turn collision for CAVtemp_unit Off
                          • Animation - Change CAVtemp_unit's animation speed to (CAVreal[3] x (Load 8 of CAVinteger from HASHCAVALRY))% of its original speed
                          • Unit - Move CAVtemp_unit instantly to CAVpoint[1], facing (Load 6 of CAVinteger from HASHCAVALRY) degrees
                          • Set CAVreal[2] = (Distance between CAVpoint[1] and CAVpoint[2])
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • CAVreal[2] Greater than or equal to (Load 2 of CAVinteger from HASHCAVALRY)
                            • Then - Actions
                              • Set CAVgroup3 = (Load 0 of CAVinteger in HASHCAVALRY)
                              • Set CAVgroup2 = (Units within (Load 9 of CAVinteger from HASHCAVALRY) of CAVpoint[1] matching (((((Matching unit) is alive) Equal to True) and (((Matching unit) is in CAVgroup3) Not equal to True)) and (((((Matching unit) is A flying unit) Not equal to True) and ((((Matching
                              • Unit Group - Pick every unit in CAVgroup2 and do (Actions)
                                • Loop - Actions
                                  • Set CAVtemp_unit2 = (Picked unit)
                                  • Set CAVpoint[3] = (Position of CAVtemp_unit2)
                                  • Unit Group - Add CAVtemp_unit2 to CAVgroup3
                                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    • If - Conditions
                                      • CAVEffectDamageAttach1 Not equal to <Empty String>
                                      • CAVEffectDamageVisual1 Not equal to <Empty String>
                                    • Then - Actions
                                      • Custom script: call DestroyEffectBJ( AddSpecialEffectTarget(udg_CAVEffectDamageVisual1, udg_CAVtemp_unit2, udg_CAVEffectDamageAttach1) )
                                    • Else - Actions
                                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    • If - Conditions
                                      • CAVEffectDamageAttach2 Not equal to <Empty String>
                                      • CAVEffectDamageVisual2 Not equal to <Empty String>
                                    • Then - Actions
                                      • Custom script: call DestroyEffectBJ( AddSpecialEffectTarget(udg_CAVEffectDamageVisual2, udg_CAVtemp_unit2, udg_CAVEffectDamageAttach2) )
                                    • Else - Actions
                                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    • If - Conditions
                                      • CAVEffectDamageAttach3 Not equal to <Empty String>
                                      • CAVEffectDamageVisual3 Not equal to <Empty String>
                                    • Then - Actions
                                      • Custom script: call DestroyEffectBJ( AddSpecialEffectTarget(udg_CAVEffectDamageVisual3, udg_CAVtemp_unit2, udg_CAVEffectDamageAttach3) )
                                    • Else - Actions
                                  • -------- // --------
                                  • -------- If unit is stunned when it deals multiple damage x ( 18 as CAVInteger) --------
                                  • -------- // --------
                                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    • If - Conditions
                                      • Or - Any (Conditions) are true
                                        • Conditions
                                          • (CAVtemp_unit2 has buff Stunned (Pause)) Equal to True
                                          • (CAVtemp_unit2 has buff Stunned) Equal to True
                                          • (CAVtemp_unit2 has buff Volcano) Equal to True
                                          • (CAVtemp_unit2 has buff Impale) Equal to True
                                          • (CAVtemp_unit2 has buff Cluster Rockets) Equal to True
                                    • Then - Actions
                                      • Unit - Cause CAVtemp_unit to damage CAVtemp_unit2, dealing (((Load 18 of CAVinteger from HASHCAVALRY) x CAVreal[3]) x (Load 5 of CAVinteger from HASHCAVALRY)) damage of attack type CAVAttackType and damage type CAVDamageType
                                    • Else - Actions
                                      • Unit - Cause CAVtemp_unit to damage CAVtemp_unit2, dealing (CAVreal[3] x (Load 5 of CAVinteger from HASHCAVALRY)) damage of attack type CAVAttackType and damage type CAVDamageType
                                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    • If - Conditions
                                      • (CAVtemp_unit2 is alive) Equal to True
                                      • (Integer((CAVreal[3] x (Load 11 of CAVinteger from HASHCAVALRY)))) Greater than 0
                                      • (Integer((1.00 x (Load 11 of CAVinteger from HASHCAVALRY)))) Greater than 0
                                    • Then - Actions
                                      • Unit - Grant shared vision of CAVtemp_unit2 to Neutral Extra
                                      • Unit - Create 1 CAVDummyUnitType for Neutral Extra at CAVpoint[3] facing Default building facing degrees
                                      • Unit - Set the custom value of (Last created unit) to (Integer((CAVreal[3] x (Load 11 of CAVinteger from HASHCAVALRY))))
                                      • Unit - Add a 2.00 second Water Elemental expiration timer to (Last created unit)
                                      • Unit - Make (Last created unit) Explode on death
                                      • Unit - Add CAVStunAbility to (Last created unit)
                                      • Unit - Order (Last created unit) to Human Mountain King - Storm Bolt CAVtemp_unit2
                                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                        • If - Conditions
                                          • (Load 18 of CAVinteger from HASHCAVALRY) Greater than 0.00
                                          • (Load 19 of CAVinteger from HASHCAVALRY) Greater than 0.00
                                          • (CAVtemp_unit2 is in CAVKnockbackGroup) Not equal to True
                                          • (CAVtemp_unit2 is in CAVDetectGroup) Not equal to True
                                        • Then - Actions
                                          • -------- // --------
                                          • -------- Knockbacked unit stores duration and speedrate --------
                                          • -------- and aslo angle between the caster and the unit --------
                                          • -------- // --------
                                          • Unit Group - Add CAVtemp_unit2 to CAVKnockbackGroup
                                          • Custom script: set udg_CAVinteger3 = GetHandleIdBJ( udg_CAVtemp_unit2)
                                          • Hashtable - Save (CAVreal[3] x (Load 18 of CAVinteger from HASHCAVALRY)) as 20 of CAVinteger3 in HASHCAVALRY
                                          • Hashtable - Save (CAVreal[3] x (Load 19 of CAVinteger from HASHCAVALRY)) as 21 of CAVinteger3 in HASHCAVALRY
                                          • Hashtable - Save (Angle from CAVpoint[1] to CAVpoint[3]) as 22 of CAVinteger3 in HASHCAVALRY
                                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                            • If - Conditions
                                              • (Load 25 of CAVinteger from HASHCAVALRY) Greater than or equal to 0.01
                                            • Then - Actions
                                              • Hashtable - Save (Angle from CAVpoint[0] to CAVpoint[2]) as 27 of CAVinteger3 in HASHCAVALRY
                                              • Set CAVreal[0] = (Angle from CAVpoint[0] to CAVpoint[2])
                                              • Set CAVreal[1] = (Angle from CAVpoint[1] to CAVpoint[3])
                                              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                                • If - Conditions
                                                  • CAVreal[0] Less than 0.00
                                                • Then - Actions
                                                  • Set CAVreal[0] = (360.00 + CAVreal[0])
                                                • Else - Actions
                                              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                                • If - Conditions
                                                  • CAVreal[1] Less than 0.00
                                                • Then - Actions
                                                  • Set CAVreal[1] = (360.00 + CAVreal[1])
                                                • Else - Actions
                                              • Hashtable - Save ((Sign((CAVreal[1] - CAVreal[0]))) x (Load 25 of CAVinteger from HASHCAVALRY)) as 26 of CAVinteger3 in HASHCAVALRY
                                            • Else - Actions
                                        • Else - Actions
                                    • Else - Actions
                                  • Custom script: call RemoveLocation( udg_CAVpoint[3] )
                              • Custom script: call DestroyGroup( udg_CAVgroup2 )
                            • Else - Actions
                              • Unit - Turn collision for CAVtemp_unit On
                              • Set CAVgroup3 = (Load 0 of CAVinteger in HASHCAVALRY)
                              • Custom script: call DestroyGroup( udg_CAVgroup3 )
                              • Animation - Reset CAVtemp_unit's animation
                              • Unit Group - Remove CAVtemp_unit from CAVDetectGroup
                              • Animation - Change CAVtemp_unit's animation speed to 100.00% of its original speed
                              • Hashtable - Clear all child hashtables of child CAVinteger in HASHCAVALRY
                      • Custom script: call RemoveLocation( udg_CAVpoint[0] )
                      • Custom script: call RemoveLocation( udg_CAVpoint[1] )
                      • Custom script: call RemoveLocation( udg_CAVpoint[2] )
                      • Custom script: call DestroyGroup( udg_CAVgroup4 )
                    • Else - Actions
                      • Unit - Turn collision for CAVtemp_unit On
                      • Set CAVpoint[4] = (Position of CAVtemp_unit)
                      • Unit - Move CAVtemp_unit instantly to CAVpoint[4]
                      • Custom script: call RemoveLocation( udg_CAVpoint[4] )
                      • Set CAVgroup3 = (Load 0 of CAVinteger in HASHCAVALRY)
                      • Custom script: call DestroyGroup( udg_CAVgroup3 )
                      • Animation - Reset CAVtemp_unit's animation
                      • Unit Group - Remove CAVtemp_unit from CAVDetectGroup
                      • Animation - Change CAVtemp_unit's animation speed to 100.00% of its original speed
                      • Hashtable - Clear all child hashtables of child CAVinteger in HASHCAVALRY
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Number of units in CAVKnockbackGroup) Greater than 0
        • Then - Actions
          • Unit Group - Pick every unit in CAVKnockbackGroup and do (Actions)
            • Loop - Actions
              • Set CAVtemp_unit = (Picked unit)
              • Custom script: set udg_CAVinteger = GetHandleIdBJ( udg_CAVtemp_unit)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Or - Any (Conditions) are true
                    • Conditions
                      • (CAVtemp_unit is alive) Not equal to True
                      • (CAVtemp_unit is hidden) Equal to True
                • Then - Actions
                  • Unit - Turn collision for CAVtemp_unit On
                  • Unit Group - Remove CAVtemp_unit from CAVKnockbackGroup
                  • Hashtable - Clear all child hashtables of child CAVinteger in HASHCAVALRY
                • Else - Actions
                  • -------- // --------
                  • -------- 20 as CAVInteger counts the time until the unti stop the knockback --------
                  • -------- // --------
                  • Hashtable - Save ((Load 20 of CAVinteger from HASHCAVALRY) - CAVLoopPeriod) as 20 of CAVinteger in HASHCAVALRY
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Load 20 of CAVinteger from HASHCAVALRY) Greater than 0.00
                    • Then - Actions
                      • -------- // --------
                      • -------- group4 detect buildings one the way --------
                      • -------- // --------
                      • Set CAVpoint[0] = (Position of CAVtemp_unit)
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (Load 26 of CAVinteger from HASHCAVALRY) Greater than or equal to 0.01
                        • Then - Actions
                          • Hashtable - Save ((Load 22 of CAVinteger from HASHCAVALRY) + (CAVLoopPeriod x (Load 26 of CAVinteger from HASHCAVALRY))) as 22 of CAVinteger in HASHCAVALRY
                          • Set CAVpoint[1] = (CAVpoint[0] offset by ((Load 21 of CAVinteger from HASHCAVALRY) x CAVLoopPeriod) towards (Load 22 of CAVinteger from HASHCAVALRY) degrees)
                        • Else - Actions
                          • Set CAVpoint[1] = (CAVpoint[0] offset by ((Load 21 of CAVinteger from HASHCAVALRY) x CAVLoopPeriod) towards (Load 22 of CAVinteger from HASHCAVALRY) degrees)
                      • Set CAVgroup4 = (Units within (1.50 x (Load 9 of CAVinteger from HASHCAVALRY)) of CAVpoint[1] matching (((((Matching unit) is alive) Equal to True) and (((Matching unit) is in CAVgroup3) Not equal to True)) and (((Matching unit) is A structure) Equal to True)))
                      • -------- // --------
                      • -------- CHECK PATHING --------
                      • -------- // --------
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • Or - Any (Conditions) are true
                            • Conditions
                              • (Terrain pathing at CAVpoint[1] of type Walkability is off) Equal to True
                              • (Number of units in CAVgroup4) Greater than 0
                        • Then - Actions
                          • Unit - Turn collision for CAVtemp_unit On
                          • Unit Group - Remove CAVtemp_unit from CAVKnockbackGroup
                          • Hashtable - Clear all child hashtables of child CAVinteger in HASHCAVALRY
                        • Else - Actions
                          • Unit - Turn collision for CAVtemp_unit Off
                          • Unit - Move CAVtemp_unit instantly to CAVpoint[1]
                      • Custom script: call RemoveLocation( udg_CAVpoint[0] )
                      • Custom script: call RemoveLocation( udg_CAVpoint[1] )
                      • Custom script: call DestroyGroup( udg_CAVgroup4 )
                    • Else - Actions
                      • Unit - Turn collision for CAVtemp_unit On
                      • Unit Group - Remove CAVtemp_unit from CAVKnockbackGroup
                      • Hashtable - Clear all child hashtables of child CAVinteger in HASHCAVALRY
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Or - Any (Conditions) are true
            • Conditions
              • (Number of units in CAVDetectGroup) Greater than 0
              • (Number of units in CAVKnockbackGroup) Greater than 0
              • (Number of units in CAVStunGroup) Greater than 0
              • (Number of units in CAVResetGroup) Greater than 0
        • Then - Actions
        • Else - Actions
          • Trigger - Turn off (This trigger)
Contents

Real-like Cavalry Attack (Map)

Reviews
KILLCIDE
Hmm there seems to be a bug with the spell. I was just having them randomly charge as 6, and then all of a sudden... they stopped charging as 6?
I skimmed over the code (will go over more in-depth at a later time, some quick things I noticed:
- You have duplicate code for "Custom script: call RemoveLocation( udg_point[1] )" when you recycle, it would need to be done regardless of the outcome of the IF statement so just use the lines once after the IF statement instead of duplicating the code and putting it in both the then and else actions
- Your variable names are too generic, please attach a meaningful prefix to them like "CavAtk_" or something similar, and make the names match their purpose "real" is too generic to understand the purpose of the variable
- Use an in-game screenshot, there's little to no reason for a spell to not use one
- Your trigger/folder names aren't appropriate "123" as a folder means nothing, and "Init" & "dead", etc. don't mean much either please name them appropriate to their purpose (Prefix also applies here)
- Spells should note have game message code inside them, remove this or put it in separate triggers in a different folder to differentiate them
- The same as above applies for test features
- You lack a proper configuration (this should be in the same location as your hashtable setup, rather than put inside the other triggers
- Your spell doesn't support multiple levels
- Why is temp_unit an array variable? from what I can tell there's no need
- Why do you need two hash tables? this could surely be done with 1 and reserve much less memory
- Your loop should be turned off when the ability isn't in use at all rather than being permanently on

For the time being this will be set to awaiting update due to the above points
 
Level 11
Joined
May 16, 2016
Messages
730
- You lack a proper configuration (this should be in the same location as your hashtable setup, rather than put inside the other triggers
It is made if you want for example add a buff which increases damage of the ability of the certain unit. Spell configuration is more flexible in this way.
- Why do you need two hash tables? this could surely be done with 1 and reserve much less memory
One hashtable is for cavalry attack and second one is for stun duration.
- Your loop should be turned off when the ability isn't in use at all rather than being permanently on
What does it mean? What loop?

EDIT: I FIXED 1,2,4,5,6,8,9,10,11 suggestions of Tank Commander
 
Last edited:
Well that's certainly improved pretty quickly obviously the few things not fixed last time carry over but I digress
  • ((This trigger) is on) Equal to True
Isn't needed - if the trigger is off the trigger will never run that condition check
same goes for
  • Trigger - Turn on (This trigger)
- The method you're using to support multiple levels is not common practice your code should not need to be extended in order to have the support, should be default.
The two methods we use to do this typically are in a config trigger (CAV INIT in this case)
  • Set CAVSpeed[0] = 420
  • Set CAVSpeed[1] = 500
  • Set CAVSpeed[2] = 580
and then in your cast trigger reference
  • Hashtable - Save (CAVSpeed[CAVLevel]) as 0 of CAVinteger2 in HASHCAVALRY
where CAVLevel is the level of the ability cast - 1 (alternatively save the values starting at index 1 rather than 0
Or something like
  • Set CAVSpeedBase = 340
  • Set CAVSpeedPerLevel = 80
and then in your cast trigger reference
  • Hashtable - Save (CAVSpeedBase + (CAVSpeedPerLevel * CAVLevel) as 0 of CAVinteger2 in HASHCAVALRY
We also put all other configurable aspects into the initialization trigger - Map makers don't want to have to go through code looking for where they can modify things, it should be as obvious and easy to find as possible

- Your variable names are still too generic as well (see point 2 last time, I mentioned more than just needing a prefix)
- Your Cavalry Engage range is fixed - this should also be configurable on a per-level basis
- You're still creating the second hashtable, just now you don't set a variable to it
- Abilities used should be configurable
- Handles that are referenced a lot such as "picked unit" should be stored in temporary variables in order to speed up access time
- you use the line
  • Custom script: set udg_CAVeffect = AddSpecialEffectTarget("Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl", GetEnumUnit(), "chest")
and then destroy the effect the next line, if you're going to use custom script to create effects it should look more like
  • Custom script: call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl", GetEnumUnit(), "chest"))
and then you can get rid of the following line, also the special effect used should be a variable that can be configured as well as the attachment point (arguably)
- AttackType and DamageType should be configurable
- Your cavalry can currently go up and over cliffs (which isn't very realistic behaviour if you asked me) see the screenshot I posted below
- Give your spell a proper tooltip and icon ingame, it should be similar to other ingame spell screenshots
 

Attachments

  • Up and Over Cliffs.png
    Up and Over Cliffs.png
    741.1 KB · Views: 281
Level 13
Joined
Oct 12, 2016
Messages
769
I really need something like this for my map, so I sat down and took a look at which variable is doing what. I think what Tank-Commander means by:
Your variable names are too generic
Is, basically, it's really hard to follow what exactly your trigger is doing with all those reassigned "CAVreal" and "CAVinteger" variables, unless you skim through each re-assigned variable constantly. Also, those variable constants by convention usually go in the "init" trigger then are modified when the ability is cast mostly to speed things up, but I don't think this needs a "per-level" configuration since it's better suited for units. (unless there's some techtree stuff to upgrade the charge)
I do agree with this though:
Your cavalry can currently go up and over cliffs (which isn't very realistic behaviour if you asked me)
And came up with a solution. Try this:
Code:
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    If - Conditions
        (Terrain pathing at CAVpoint[1] of type Walkability is off) Equal to True
    Then - Actions
        Unit - Turn collision for (Picked unit) On
        Set CAVgroup3 = (Load 0 of CAVinteger in HASHCAVALRY)
        Custom script:   call DestroyGroup( udg_CAVgroup3 )
        Animation - Reset (Picked unit)'s animation
        Unit - Remove Cavalry Attack Ability 0 from (Picked unit)
        Animation - Change (Picked unit)'s animation speed to 100.00% of its original speed
        Unit - Order (Picked unit) to Stop
        Hashtable - Clear all child hashtables of child CAVinteger in HASHCAVALRY
    Else - Actions
after the variable set in the loop trigger:
Code:
Set CAVpoint[1] = (CAVpoint[0] offset by (CAVreal[3] x (Load 0 of CAVinteger from HASHCAVALRY)) towards (Load 6 of CAVinteger from HASHCAVALRY) degrees)

One thing I cannot understand, however, is the stun duration thing. It doesn't seem like that second hashtable is doing anything, and the stun duration for the dummy ability is zero. How is it working exactly?
I also recommend the "Animal War Training" upgrade icon for the ability, it seems to suit the skill.

Edit:
One more thing, I also suggest a condition in your CAV CLEAN HASH trigger so that it doesn't fire off every time anything and everything dies.

Second Edit:
Had a major problem importing the item abilities for the triggers into another map that already had custom item abilities. I spent a couple hours re-organizing all the trigger spots that checked for "Cavalry Attack" and "Ready to Charge" since it auto-assigned other item abilities, even though I copied those first before the triggers. You may need to assign variables in the "INIT" trigger for all abilities.
 
Last edited:
Level 11
Joined
May 16, 2016
Messages
730
THE SKILL WAS UPDATED.
UPDATE:
-Now Cavalry can't pass through doodads and cliffs.
-Added Friendly INITIALIZATION CONFIGURATION where yoU can set all parameters and even add more ability levels.
-Added additional Paragraph: coefficient of damage for stunning unit. So you may regulate what damage the caster deals to stunned enemy.
-The kinight stop moving while: sutcked with doodads, stunned, immobilised, rooted, sleeping (you may add more non standard buffs)

Had a major problem importing the item abilities for the triggers into another map that already had custom item abilities. I spent a couple hours re-organizing all the trigger spots that checked for "Cavalry Attack" and "Ready to Charge" since it auto-assigned other item abilities, even though I copied those first before the triggers. You may need to assign variables in the "INIT" trigger for all abilities.
Also I made it to import the ability much easier with all abilities and units.
One more thing, I also suggest a condition in your CAV CLEAN HASH trigger so that it doesn't fire off every time anything and everything dies.
Done. Now It will remove leaks only who have detection dummy ability and dummy which stuns victims.
One thing I cannot understand, however, is the stun duration thing. It doesn't seem like that second hashtable is doing anything, and the stun duration for the dummy ability is zero. How is it working exactly?
When unit start casting Dummy Stun ability the system gives to target's ID the certain value. This value is decreased if unit has Stun buff. When value becomes 0 then stun effect is removed.
I also recommend the "Animal War Training" upgrade icon for the ability, it seems to suit the skill.
It's on your own. It's graphic question.


Well that's certainly improved pretty quickly obviously the few things not fixed last time carry over but I digress
- The method you're using to support multiple levels is not common practice your code should not need to be extended in order to have the support, should be default.
- Your variable names are still too generic as well (see point 2 last time, I mentioned more than just needing a prefix)
- Your Cavalry Engage range is fixed - this should also be configurable on a per-level basis
- You're still creating the second hashtable, just now you don't set a variable to it
- Abilities used should be configurable
- Handles that are referenced a lot such as "picked unit" should be stored in temporary variables in order to speed up access time
- you use the line
  • page.gif
    Custom script: set udg_CAVeffect = AddSpecialEffectTarget("Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl", GetEnumUnit(), "chest")
and then destroy the effect the next line, if you're going to use custom script to create effects it should look more like
  • page.gif
    Custom script: call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl", GetEnumUnit(), "chest"))
and then you can get rid of the following line, also the special effect used should be a variable that can be configured as well as the attachment point (arguably)
- AttackType and DamageType should be configurable
- Your cavalry can currently go up and over cliffs (which isn't very realistic behaviour if you asked me) see the screenshot I posted below
- Give your spell a proper tooltip and icon ingame, it should be similar to other ingame spell screenshots
DONE
 
Last edited:
Did a very quick glance over the code and test and I noticed two small things immediately:
- You're leaking points[1] and [2] in your loop in the second last IF statement
- Currently the knights stop animating properly if they collide with a wall (this is later solved by casting the spell again, I assume you forgot to reset their animation completely

as an aside, your group selection in your loop would be better if it didn't select all units that are stunned for any reason (also if the group were more strictly controlled via adding/removing specific units instead of entirely reselecting the entire group it would be better
You also forgot to use the temp variables in a few places (and forgot some temp variables such as one storing the level of the ability being cast)
 
Level 13
Joined
Oct 12, 2016
Messages
769
I just tested it again, and importing it is MUCH better now. I did notice, however, some weird problems with the ability stalling on both the default Raider and Huntress units. Give it a shot, slap "Cavalry Attack" on them units and watch how they react.
For the record, the "walk" animation number (thanks to your -anim command) is 2 for the Raider, 1 for the Huntress.
I don't have any suggestions for solving that problem...
 
Level 11
Joined
May 16, 2016
Messages
730
I just tested it again, and importing it is MUCH better now. I did notice, however, some weird problems with the ability stalling on both the default Raider and Huntress units. Give it a shot, slap "Cavalry Attack" on them units and watch how they react.
For the record, the "walk" animation number (thanks to your -anim command) is 2 for the Raider, 1 for the Huntress.
I don't have any suggestions for solving that problem...
i'm still fixing. Tank Commander noticed some problems. i'll report when it will done.
 
Level 13
Joined
Oct 12, 2016
Messages
769
Keep it up, I really like this concept. I plan to put it in my next map, giving each race a "cavalry" unit. So far, I have it working reliably with modifications on the base Knight unit.
 
Level 11
Joined
May 16, 2016
Messages
730
as an aside, your group selection in your loop would be better if it didn't select all units that are stunned for any reason (also if the group were more strictly controlled via adding/removing specific units instead of entirely reselecting the entire group it would be better
I'm afraid i have lack of skills to operate with it. Anyway the system pick only certain units so the player wouldn't feel lags or something.
You also forgot to use the temp variables in a few places (and forgot some temp variables such as one storing the level of the ability being cast)
DONE
Did a very quick glance over the code and test and I noticed two small things immediately:
- You're leaking points[1] and [2] in your loop in the second last IF statement
- Currently the knights stop animating properly if they collide with a wall (this is later solved by casting the spell again, I assume you forgot to reset their animation completely
DONE
 
Level 11
Joined
May 16, 2016
Messages
730
Keep it up, I really like this concept. I plan to put it in my next map, giving each race a "cavalry" unit. So far, I have it working reliably with modifications on the base Knight unit.
It seems I fixed dangerous bugs. You can download now.
Did you understand how to use animation?
If it didn't I made an example how to implement aniamtion indexes for each unit type: See it in the CAN USE ABILITY, ANIMATION INDEX.
 

Attachments

  • Real-like Cavalry Attack.w3x
    30.3 KB · Views: 119
Level 13
Joined
Oct 12, 2016
Messages
769
I have an understanding of it, and was using some if/then/else statements to assign the animation index variable according to the unit. Let's me take a look-see here.


Edit:
Yea, that's what I did for that animation index number with if/then/else statements. However, there's still that weird stalling problem when using Cavalry Attack on anything that is not a Knight. I'll attach the test map so you can see what I mean: select the Raiders, Huntresses and Knights separately and check, then see what happens when they are all selected.
I am thinking it has something to do with the variable called for each picked unit in the loop, as well as the ability animation for "Serpant Ward" (note how the Raider sits there derpily spamming spell-throw)

Also, I had another idea in case you want to make the effect end when colliding with a structure. In the same condition for checking "Walkability," you can just add this condition within an "Or":

Code:
Or - Any (Conditions) are true
    Conditions
        (Terrain pathing at CAVpoint[1] of type Walkability is off) Equal to True
        (Number of units in (Units within 100.00 of CAVpoint[1] matching (((Matching unit) is A structure) Equal to True))) Greater than 0
 

Attachments

  • Real-like Cavalry Attack - Test.w3x
    34.4 KB · Views: 141
Last edited:
Level 11
Joined
May 16, 2016
Messages
730
I have an understanding of it, and was using some if/then/else statements to assign the animation index variable according to the unit. Let's me take a look-see here.


Edit:
Yea, that's what I did for that animation index number with if/then/else statements. However, there's still that weird stalling problem when using Cavalry Attack on anything that is not a Knight. I'll attach the test map so you can see what I mean: select the Raiders, Huntresses and Knights separately and check, then see what happens when they are all selected.
I am thinking it has something to do with the variable called for each picked unit in the loop, as well as the ability animation for "Serpant Ward" (note how the Raider sits there derpily spamming spell-throw)

Also, I had another idea in case you want to make the effect end when colliding with a structure. In the same condition for checking "Walkability," you can just add this condition within an "Or":
All right. Download now, but see that I changed in unit parameters in the object editor. I didn't add ability only but i also changed the Art parameter.
I also miss Aniamtion speed parameter, but now it works fine.
 
my point was adding units when they cast the spell, rather than every unit that has certain spells - it's possible to make this using only 2 abilities (the stun buff and the spell cast), you half do this already via enabling/disabling the trigger when a spell is cast (just add them to the strict group then, rather than always reselecting) I'm not sure I got that across with my phrasing before
 
Look here Convenient Unit Group Filtering in GUI, there's explained why not tot to write everything in 1line, it gets pretty unreadable in GUI.
Actually, hm, do you know about Visualize: Dynamic Indexing ? I believe it would benefit some from it,
not at last with readability. For example:
(Load 10 of CAVinteger from HASHCAVALRY) Less than or equal to 0.00
^is pretty much none-saying to me what it should mean. One have to lookup each possible thing that is stored there to understand it's purpose.
There is no documentation, too, that helps.

Sometimes variables aren't used, for example in the death trigger (Triggering Unit) is still used multiple times.
By the way, the variable name doesn't need to be specific for temp variables, example
CAVtemp_unit_DEAD
can be
CAV_Unit
explained here [GUI] - GPAG - GUI Proper Application Guide.

Things like (Picked Unit) should be stored into a variable if used very often, as each () is a function call, which is slower than a variable lookup.

You could take usage of a stun system, so you don't create always dummy units on your own, else you might use anyways just 1 dummy for all casts instead of one dummy per stun.
I think BPower has one in spells section.

Does the orc raider animation looks weird? It doesn't "run" properly I think.
 
Level 11
Joined
May 16, 2016
Messages
730
UPDATE 1.3
New parameter: Knockback
The knockback also depends on the ACCELERATION PENALTY
Added new function to detect and undetect units to be knockbacked or to be under Cavalry moving. (Allow to remove CLEAN HASH trigger)
The CODE spoiler is changed (with proper language)

as an aside, your group selection in your loop would be better if it didn't select all units that are stunned for any reason (also if the group were more strictly controlled via adding/removing specific units instead of entirely reselecting the entire group it would be better
DONE.
Is displacing the targets as cavalry runs through them, probably supposed to be knockback ?
DONE
Sometimes variables aren't used, for example in the death trigger (Triggering Unit) is still used multiple times.
THE DEATH TRIGGER WAS REMOVED.
Things like (Picked Unit) should be stored into a variable if used very often, as each () is a function call, which is slower than a variable lookup.
DONE
 
Last edited:
Level 13
Joined
Oct 12, 2016
Messages
769
Yo Fruit Forest, I noticed this version has its periodic event always running. Since my map will have multiple timed systems, I thought it prudent to suggest a check at the end of the loop for when:
CAVResetGroup, CAVStunGroup, CAVKnockbackGroup, and CAVDetectGroup = 0, to turn off that loop. I find it works fine having the loop initially off with that variable check in place.
Also, do you think it would be more effective if you turn on the "CAV LOOP" trigger after setting the variables in the initial spell cast?

Also, is there a parameter to increase the range of the change?
 
Last edited:
Level 11
Joined
May 16, 2016
Messages
730
Also, do you think it would be more effective if you turn on the "CAV LOOP" trigger after setting the variables in the initial spell cast?
The idea is every 00x sec. the system check the number of already created group. Previous variant create every group and destroy it. If you have 999999 units in your map then don't worry - this system will pick only right units without lag spikes. If you have 0 units in each group then then the system just check the integers which "consume" a bit of computer memory.

Also, is there a parameter to increase the range of the change?
Maybe range of the charge? It's the TIME OF CHARGE (IF UNIT IS STUCKED) paramemeter.
 
  • Actions
    • Trigger - Turn off (This trigger)
    • Set CAVDetectGroup = (Units in (Playable map area) matching (((Matching unit) is Plagued) Equal to True))
    • Unit Group - Remove all units from CAVDetectGroup
    • Set CAVKnockbackGroup = (Units in (Playable map area) matching (((Matching unit) is Plagued) Equal to True))
    • Unit Group - Remove all units from CAVKnockbackGroup
    • Set CAVResetGroup = (Units in (Playable map area) matching (((Matching unit) is Plagued) Equal to True))
    • Unit Group - Remove all units from CAVResetGroup
    • Set CAVStunGroup = (Units in (Playable map area) matching (((Matching unit) is Plagued) Equal to True))
    • Unit Group - Remove all units from CAVStunGroup
    • Set CAVinteger = 0
    • Set CAVinteger2 = 0
^hm, what purpose of these lines? : )
The GUI variables are automaticaly initialisized with "null", "0" or "false". The extra group creations leads to memory leak, because you overwrite the already existing group.

Things like (Picked Unit) should be stored into a variable if used very often, as each () is a function call, which is slower than a variable lookup.
There were other things, too, next to (Picked Unit), like any other event responses like (Triggering Unit) etc, -- each time "()" is used like in (Triggering Unit), it means it is a funtion call inside. Variable lookups are better.

The hash's name style differs from rest. ;P

Have a look at other things mentioned in my post.
  • Set CAVgroup = (Units within CAVreal[2] of CAVpoint[0] matching (((((Matching unit) is in CAVDetectGroup) Not equal to True) and ((((Matching unit) is in CAVResetGroup) Not equal to True) and (((Matching unit) is alive) Equal to True))) and (((Level of CAVMainAbility for (M
^something like this is not even readable, because it's too long for GUI. And opening all the tabs is a just huge mess to read it properly.

Add basic documentation, I have no idea why for example do this:
  • Set CAVpoint[2] = (Point(CAVreal[0], CAVreal[1]))
It becomes just all hard to read and to follow.

[GUI] - GPAG - GUI Proper Application Guide

When using custom script you don't need the BJs anymore. Like in the GetHandleId function.

The config for animation index for unit types should happen in the config trigger instead of run per if statements somewhere in the cast trigger.
The hashtable can/should be used to bind the animation index to a unit type.

I still strongly recommend to switch from hashtable instances to dynamic indexing for example. It's very hard to read and maintain at the moment.
The way I see it that hashtables are acceptable is when you don't work directly with the hashtable operations in the core, but only use it to init your variables. Example:
  • Set CAV_Unit = (Triggering Unit)
  • Set CAV_Damage = 50
  • Set CAV_Player = (Triggering Player)
  • Hashtable - Save CAV_Unit as 1 of CAV_Key in CAV_Hash
  • Hashtable - Save CAV_Damage as 2 of CAV_Key in CAV_Hash
  • Hashtable - Save CAV_Player as 3 of CAV_Key in CAV_Hash
  • ..
  • ..
  • // and when load :
  • ..
  • ..
  • Set CAV_Unit = Load 1 of CAV_Key in CAV_Hash
  • Set CAV_Damage = Load 2 of CAV_Key in CAV_Hash
  • Set CAV_Player = Load 3 of CAV_Key in CAV_Hash
And then to operate only with the variables instead of having "Load 13" and "Load 9" everywhere in the actions, and noone knows what it is. It's honestly just very bad for readability.

  • Set CAVDamagecCoef[1] = 2.00
^Is this damage per second? Or only once. It's not very clear, but usually all config data should be in "per second" if not stated otherwise.
 
Level 11
Joined
May 16, 2016
Messages
730
  • set.gif
    Set CAVDamagecCoef[1] = 2.00
^Is this damage per second? Or only once. It's not very clear, but usually all config data should be in "per second" if not stated otherwise.
It's multiplier of damage if canavlry hit stunned unit.
^hm, what purpose of these lines? : )
The GUI variables are automaticaly initialisized with "null", "0" or "false". The extra group creations leads to memory leak, because you overwrite the already existing group.
I thought you need to create group and clear it to use it well.
Add basic documentation, I have no idea why for example do this:
I'll add an additional description, but it will help only for code viewers. For those who are using this ability and don't mind about the "skeleton" it doesn't important.
 
I noticed that sometimes when you order the units as a group to charge at a point 1 or 2 of them won't do it, any idea why this may be the case? it's pretty irritating when not all the units you tell to charge actually do so
Just thought I'd note that you don't need to set your temp unit variables to "no unit" - they're global variables so it doesn't really do anything to do that
 
Level 11
Joined
May 16, 2016
Messages
730
I noticed that sometimes when you order the units as a group to charge at a point 1 or 2 of them won't do it, any idea why this may be the case? it's pretty irritating when not all the units you tell to charge actually do so
Just thought I'd note that you don't need to set your temp unit variables to "no unit" - they're global variables so it doesn't really do anything to do that
V 1.5. I increased the periodic interval. Now units must have more time to cast spell.
 
Apologies that this resource hasn't been moderated in a long time but most of IcemanBo's previous review still stand as issues with the program, in addition to that I noticed the following things:
- There are many execution routes in the loop which result in memory leaks, in the 4th group selection for example there's a clear case where none of the point variables are cleared
- The loop is never turned off
- Since your loop shouldn't even be on if all the groups are empty "Set CAVreal[0] = 0.05" should only need to be set once and by all rights should just be a constant since it's always going to have that value
 
It's been a while since I've looked at the code, some older review points still stand:
- CAV loop still has memory leaks within it, please make sure you have eliminated all of the leaks before updating, my previous point about CAVreal[0] in the loop still stands as well
- You have inconsistent usage of temp variables - you use temp unit a lot but don't use it at all when you create a CAVDummyUnitType - this dummy should also not be owned by a player as this messes up the scoreboard results
- IcemanBo's point of not using BJ functions in custom script still stands
- Special effects you create should use configurable effects (the effect string this being) attachment point is also an option for an added configurable though not necessary

I may have missed previous points brought up in reviews that may still be relevant, please go over these for things that may need to be fixed before updating the system

I appreciate the dedication you have to this resource
 
Level 11
Joined
May 16, 2016
Messages
730
1. Added "rounded" trajectory for the knockback.
2. Leaks are fixed.
3. Fixed minor errors.
4. CAVreal[0] is replaced on CAVLoopPeriod
5. The "INIT" trigger allow to set speceffect for moved cavalry units and speceffect + attachment for damaged unit.
6. The occured dummy units are now neutral. They couldn't hurt the statistic board, I think.
 
Top