Z Slash v2.3

  • Like
Reactions: Imadori
UPDATED to version 2.3. Changed a lot of things (Most of which I'm too lazy to mention):


- Now uses a linked list and pauses the timer whenever necessary, a more
efficient than before, I guess.
- Now prevents the hero from getting stuck in trees.
- Now you can limit the number of targets
- Now you can decide if an instance is able to damage a unit more than once
- Now uses only one timer for the entire spell and its intances
- It is now more optimized (This is 'A lot of things')
- Removed some unnessecary lines
- Fixed a bug where the caster would move faster with each cast (Thanks to Maker)


-----

The hero launches himself forward, moving quickly along a Z pattern and slashing enemies
on its path.

Level 1 - 100 damage per slash
Level 2 - 200 damage per slash
Level 3 - 300 damage per slash

-----

JASS:
library ZSlash requires UnitIndexer, SpellEffectEvent, IsTerrainWalkable

//====================================================================================================================================
//
//  By Dr.Killer
//
//====================================================================================================================================


//====================================================================================================================================
//  Introduction: The hero launches himself forward, slashing enemies along his path and wounding them. Then he proceeds to slash 
//  more enemies in a Z pattern.
//====================================================================================================================================


//====================================================================================================================================
//  Requirements:
//
// - Table (Bribe's version)
//   http:// ??
//
// - UnitIndexer
//    http://www.hiveworkshop.com/forums/jass-resources-412/system-unit-indexer-172090/
//
// - SpellEffectEvent
//    http://www.hiveworkshop.com/forums/jass-resources-412/snippet-spelleffectevent-187193/?highlight=spelleffect
//
//  The following libraries are required by the above systems:
//
// - RegisterPlayerUnitEvent
//    http://hiveworkshop.com/forums/showthread.php?t=203338
//
// - Event
//    http://hiveworkshop.com/forums/submissions-414/snippet-event-186555/
//
// - WorldBounds
//    http://hiveworkshop.com/forums/jass-functions-413/snippet-worldbounds-180494/
//====================================================================================================================================


//====================================================================================================================================
//  Credits
//
// - Vexorian for TimerUtils, JassHelper and contributions to WC3 modding in general
// - Nestharus for UnitIndexer, Event, WorldBounds :|
// - Magtheridon96 for his awesome MeatMash spell from which I learned a lot (and copied a bit) and RegisterPlayerUnitEvent, also his tutorial
//   "efficient and clean vJass spell models", which can be found at: http://www.hiveworkshop.com/forums/jass-ai-scripts-tutorials-280/efficient-clean-vjass-spell-models-216166/
// - Bribe for SpellEffectEvent, Table (New version)
// - Maker for a few suggestions, found the reason of a weird bug and MADE ME use 
//    linked lists
// - Almia for some other suggestions, such as making more things configurable. 
//
//====================================================================================================================================


//====================================================================================================================================
//  Important Notice
//
//  Feel free to edit, modify, revise or anything that comes to your mind, just remember to credit me as the original creator
//  wherever you use this.
//====================================================================================================================================


//=============================================================
//  Configuration
//=============================================================
globals
    //Editor stuff
    private constant integer ABIL_CODE = 'A001'
    
    //Spell stuff
    private constant integer TARGET_LIMIT  = 0             //Should the maximum number of slashed enemies be limited? if yes, set th limit here,
                                                           //otherwise leave it to be 0.
    private constant boolean LIMIT_INJURY  = true          //Should a victim be able to be damaged more than once?
    private constant boolean INV           = true          //Should the caster turn invulnerable during the spell?
    private constant boolean PAN           = true          //Should I pan the camera to hero's location in the end?
    private constant real    JUMP_DIST     = 450.          //How far the hero launches himself forward (Affects the size of Z)
    private constant real    Z_ANGLE       = (bj_PI) / 4.  //The angle between Z's horizontal and diagonal line. Best looking at Pi/4.
        
    private constant real    DUR           = 1.5           //How long it takes the hero to reach the end of each line in Z
    private constant real    INTERVAL      = 0.03125       //Interval between hero's movements. A lower amount results in a smooth
                                                           //movement but is more demanding.
    
    private constant real    D_JUMP_DIST   = JUMP_DIST/Sin(Z_ANGLE)
    private constant real    TRAVEL_1      = JUMP_DIST / (DUR/INTERVAL)
    private constant real    TRAVEL_2      = D_JUMP_DIST / (DUR/INTERVAL)
    private constant real    PATH_OFFSET   = 32.           //Used when the hero gets stuck somewhere in the end of the spell.
                                                           //That's how much the hero's moved to find a walkable ground
    
    private constant real    RADIUS        = 95.           //How far from the caster are the targets picked to be slashed
    
    private constant real    ADD_ANGLE     = bj_PI/36.
    private constant real    CONE_ANGLE    = (bj_PI/6.)
    
    private constant integer RED           = 255
    private constant integer GREEN         = 255
    private constant integer BLUE          = 255
    private constant integer ALPHA         = 130
                                                        
    private constant attacktype ATTACK_TYPE = ATTACK_TYPE_HERO
    private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_NORMAL
    private constant weapontype WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS
    
    private constant string EFFECT_PATH        = "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile_mini.mdl"
    private constant string BLOOD_EFFECT_PATH  = "Objects\\Spawnmodels\\Human\\HumanBlood\\HumanBloodFootman.mdl"
    private constant string ATTACH_POINT       = "chest"
    
endglobals

//How much damage is dealt upon a slash
private function DamageOnSlash takes integer lvl returns real
    return I2R(lvl*100)
endfunction

//Here you can decide what units will be affected by this spell
private function TargetFilter takes unit target, unit caster , integer slashed returns boolean
    static if LIMIT_INJURY then
        return IsUnitEnemy(target, GetOwningPlayer(caster)) and not (IsUnitType(target, UNIT_TYPE_DEAD) or IsUnitType(target, UNIT_TYPE_MECHANICAL) or IsUnitType(target, UNIT_TYPE_FLYING)) and slashed != 1
    else
        return IsUnitEnemy(target, GetOwningPlayer(caster)) and not (IsUnitType(target, UNIT_TYPE_DEAD) or IsUnitType(target, UNIT_TYPE_MECHANICAL) or IsUnitType(target, UNIT_TYPE_FLYING))
    endif
endfunction

//=============================================================
//  End of Configuration
//=============================================================


//=============================================================
//  Spell Code
//=============================================================
private function IsLineWalkable takes real x, real y, real ang, real dist, real remainingDist returns boolean
    local real nx = x
    local real ny = y
    local real cos = Cos(ang)
    local real sin = Sin(ang)
    local boolean break = false
    local integer i = R2I(remainingDist/dist) + 2
    local integer j = 1
    
    loop
        exitwhen j>i or break
        
        set nx = nx+dist*cos
        set ny = ny+dist*sin
        
        break = not IsTerrainWalkable(nx,ny)
        
        set j=j+1
    endloop
    
    return (not break)
endfunction

private struct Z extends array
    
    private static integer array rn
    private static integer ic = 0
    private static integer rc = 0
    
    private static integer array next
    private static integer array prev
    
    private static unit array hero
    private static real array totalTravel
    private static integer array travelStage
    private static real array angle
    private static effect array sfx
    private static real array dx
    private static real array dy
    private static boolean haveTimer = false
    private static boolean array break
    private static boolean array finished
    private static real array aqq
    private static Table array injured
    private static group tempGroup //Used for unit enumeration
    private static timer globalTimer
    
    private method destroy takes nothing returns nothing
        local real hero_X = GetUnitX(hero[this])
        local real hero_Y = GetUnitY(hero[this])
        
        call SetUnitInvulnerable(hero[this], false)
        if GetLocalPlayer() == GetOwningPlayer(hero[this]) then
            call SelectUnit(hero[this], true)
            if PAN then
                call PanCameraTo(hero_X, hero_Y)
            endif
        endif
        call DestroyEffect(sfx[this])
        call SetUnitVertexColor(hero[this], 255, 255, 255, 255)
        call SetUnitAcquireRange(hero[this], aqq[this])
        
        //Cleanup
        set hero[this] = null
        set sfx[this] = null
        set dx[this] = 0.
        set dy[this] = 0.
        set aqq[this] = 0.
        set break[this] = false
        set finished[this] = true
        call injured[this].flush()
                
        //Deallocate this instance
        set rn[this] = rn[0]
        set rn[0] = this
        
        set prev[next[this]] = prev[this]
        set next[prev[this]] = next[this]
        
        set rc = rc-1
        if rc==0 then
            call PauseTimer(globalTimer)
        endif
    endmethod
    
    private static method onPeriod takes nothing returns nothing
        local thistype this = next[0]
        local real x
        local real y
        local real hero_X
        local real hero_Y 
        local real rem 
        local unit tempUnit
        local integer target_id = 0
        
        
        //Iterate over all spell instances that are active
        loop
            exitwhen this == 0
            set hero_X = GetUnitX(hero[this])
            set hero_Y = GetUnitY(hero[this])
        
        if hero[this] != null and not break[this] and not (IsUnitType(hero[this], UNIT_TYPE_DEAD)) then
        
        if travelStage[this] == 1 then  //We're running along the first line
            //call BJDebugMsg("ic: "+I2S(ic))
            
            if totalTravel[this] < JUMP_DIST then
                
    
                set x = hero_X + dx[this]
                set y = hero_Y + dy[this]
                
                if not IsLineWalkable(hero_X, hero_Y, angle[this], PATH_OFFSET, 150.) then
                    set break[this] = true
                endif
                
                call SetUnitX(hero[this], x)
                call SetUnitY(hero[this], y)
                
                set totalTravel[this] = totalTravel[this] + (JUMP_DIST / (DUR/INTERVAL))
                
                if TARGET_LIMIT == 0 then
                    call GroupEnumUnitsInRange(tempGroup, x, y, RADIUS, null)
                else
                    call GroupEnumUnitsInRangeCounted(tempGroup, x, y, RADIUS, null, TARGET_LIMIT+1)
                endif
                call GroupRemoveUnit(tempGroup, hero[this])
                loop
                    set tempUnit = FirstOfGroup(tempGroup)
                    exitwhen tempUnit == null
                    
                    set target_id = GetUnitId(tempUnit)
                    
                    if TargetFilter(tempUnit, hero[this], injured[this][target_id]) then
                        call UnitDamageTarget(hero[this], tempUnit, DamageOnSlash(GetUnitAbilityLevel(hero[this], ABIL_CODE)), false, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
                        call DestroyEffect(AddSpecialEffectTarget(BLOOD_EFFECT_PATH, tempUnit, ATTACH_POINT))
                        set injured[this][target_id] = 1
                    endif
                    call GroupRemoveUnit(tempGroup, tempUnit)
                endloop
    
            else
                set totalTravel[this] = 0.
                set travelStage[this] = travelStage[this] + 1
                set angle[this] = angle[this] + bj_PI + Z_ANGLE
                set dx[this] = TRAVEL_2*Cos(angle[this])
                set dy[this] = TRAVEL_2*Sin(angle[this])
                //call BJDebugMsg("first ende")
            endif
    
        elseif travelStage[this] == 2 then
            
            if totalTravel[this] < D_JUMP_DIST then
            
                
                set x = hero_X + dx[this]
                set y = hero_Y + dy[this]
                
                if not IsLineWalkable(hero_X, hero_Y, angle[this], PATH_OFFSET, 150.) then
                    set break[this] = true
                endif
                
                call SetUnitX(hero[this], x)
                call SetUnitY(hero[this], y)
                
                set totalTravel[this] = totalTravel[this] + (D_JUMP_DIST / (DUR/INTERVAL))
                                                 
                if TARGET_LIMIT == 0 then
                    call GroupEnumUnitsInRange(tempGroup, x, y, RADIUS, null)
                else
                    call GroupEnumUnitsInRangeCounted(tempGroup, x, y, RADIUS, null, TARGET_LIMIT+1)
                endif
                call GroupRemoveUnit(tempGroup, hero[this])
                loop
                    set tempUnit = FirstOfGroup(tempGroup)
                    exitwhen tempUnit == null
                    
                    set target_id = GetUnitId(tempUnit)
                    
                    if TargetFilter(tempUnit, hero[this], injured[this][target_id]) then
                        call UnitDamageTarget(hero[this], tempUnit, DamageOnSlash(GetUnitAbilityLevel(hero[this], ABIL_CODE)), false, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
                        call DestroyEffect(AddSpecialEffectTarget(BLOOD_EFFECT_PATH, tempUnit, ATTACH_POINT))
                        set injured[this][target_id] = 1
                    endif
                    call GroupRemoveUnit(tempGroup, tempUnit)
                endloop
                //call BJDebugMsg("this: "+I2S(this))
            else
                set totalTravel[this] = 0.
                set travelStage[this] = travelStage[this] + 1
                set angle[this] = angle[this] - bj_PI - Z_ANGLE 
                set dx[this] = TRAVEL_1*Cos(angle[this])
                set dy[this] = TRAVEL_1*Sin(angle[this])
                //call BJDebugMsg("second ende")
            endif
            
        else

            //Third travel stage
            if totalTravel[this] < JUMP_DIST then
            
                
                set x = hero_X + dx[this]
                set y = hero_Y + dy[this]
                
                if not IsLineWalkable(hero_X, hero_Y, angle[this], PATH_OFFSET, 150.) then
                    set break[this] = true
                endif
                
                call SetUnitX(hero[this], x)
                call SetUnitY(hero[this], y)
                
                set totalTravel[this] = totalTravel[this] + (JUMP_DIST / (DUR/INTERVAL))
                
                if TARGET_LIMIT == 0 then
                    call GroupEnumUnitsInRange(tempGroup, x, y, RADIUS, null)
                else
                    call GroupEnumUnitsInRangeCounted(tempGroup, x, y, RADIUS, null, TARGET_LIMIT+1)
                endif
                call GroupRemoveUnit(tempGroup, hero[this])
                loop
                    set tempUnit = FirstOfGroup(tempGroup)
                    exitwhen tempUnit == null
                    
                    set target_id = GetUnitId(tempUnit)
                    
                    if TargetFilter(tempUnit, hero[this], injured[this][target_id]) then
                        call UnitDamageTarget(hero[this], tempUnit, DamageOnSlash(GetUnitAbilityLevel(hero[this], ABIL_CODE)), false, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
                        call DestroyEffect(AddSpecialEffectTarget(BLOOD_EFFECT_PATH, tempUnit, ATTACH_POINT))
                        set injured[this][target_id] = 1
                    endif
                    call GroupRemoveUnit(tempGroup, tempUnit)
                endloop
                //call BJDebugMsg("this: "+I2S(this))
            else
                
                call this.destroy()
                
            endif
            
        endif
        
        elseif not finished[this] then
            //Spell has ended
            call this.destroy()
        
        endif

        set this = next[this]
        endloop
        
        //Cleanup Section
        set tempUnit = null
    endmethod
            
    private static method onCast takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local thistype this = rn[0]
        local real tx = GetSpellTargetX()
        local real ty = GetSpellTargetY()
        local real cx           //These are used for geometric calculations and determining the path of hero
        local real cy           //They actually help draw my Z
        local integer lvl = GetUnitAbilityLevel(u, ABIL_CODE)
        local integer target_id = 0
        
        
        if this == 0 then
            set ic = ic + 1
            set this = ic
        else
            set rn[0] = rn[this]
        endif
        
        set next[this] = 0
        set prev[this] = prev[0]
        set next[prev[0]] = this
        set prev[0] = this
        
        set rc = rc+1

        set injured[this] = Table.create()
        set break[this] = false
        set finished[this] = false
        set hero[this] = u
        set cx = GetUnitX(u)
        set cy = GetUnitY(u)
        set angle[this] = Atan2(ty-cy, tx-cx)
        set totalTravel[this] = 0.
        set travelStage[this] = 1
        set aqq[this] = GetUnitAcquireRange(u)
        call SetUnitAcquireRange(u, 1.)
        set u = null
        
        set dx[this] = TRAVEL_1*Cos(angle[this])
        set dy[this] = TRAVEL_1*Sin(angle[this])
        
        //Apply invunerability
        if INV then
            call SetUnitInvulnerable(hero[this], true)
        endif
        
        //Make hero transparent
        call SetUnitVertexColor(hero[this], RED, GREEN, BLUE, ALPHA)
        
        //Apply eyecandy
        set sfx[this] = AddSpecialEffectTarget(EFFECT_PATH, hero[this], ATTACH_POINT)
        
        //De-select the hero
        if GetLocalPlayer() == GetOwningPlayer(hero[this]) then
            call SelectUnit(hero[this], false)
        endif
        
        //First damage nearby enemies
        if TARGET_LIMIT == 0 then
            call GroupEnumUnitsInRange(tempGroup, cx, cy, RADIUS, null)
        else
            call GroupEnumUnitsInRangeCounted(tempGroup, cx, cy, RADIUS, null, TARGET_LIMIT+1)
        endif
        call GroupRemoveUnit(tempGroup, hero[this])
        loop
            set u = FirstOfGroup(tempGroup)
            exitwhen u==null
            
            set target_id = GetUnitId(u)
            
            if TargetFilter(u, hero[this], 0) then
                call UnitDamageTarget(hero[this], u, DamageOnSlash(GetUnitAbilityLevel(hero[this], ABIL_CODE)), false, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
                call DestroyEffect(AddSpecialEffectTarget(BLOOD_EFFECT_PATH, u, ATTACH_POINT))
                set injured[this][target_id] = 1
            endif
            call GroupRemoveUnit(tempGroup, u)
        endloop
        
        //Now we start the Stage 1 timer that moves our hero every INTEVAL seconds along the top most line of Z
        if rc == 1 then
            call TimerStart(globalTimer, INTERVAL, true, function thistype.onPeriod)
        endif
        
        
        //Cleanup
        set u = null
        
    endmethod
    
    private static method onInit takes nothing returns nothing
        set globalTimer = CreateTimer()
        set tempGroup = CreateGroup()
        call RegisterSpellEffectEvent(ABIL_CODE, function thistype.onCast)
    endmethod
    
endstruct

endlibrary

Credits:
- Vexorian: TimerUtils
- Bribe: SpellEffectEvent
- Magtheridon96: RegisterPlayerUnitEvent; Optimization tips, implemented in v1.1
- Nestharus: UnitIndexer, WorldBounds, Event :|
- Almia, suggested that more things should be configurable, and that's quite right
- Maker, for a few suggestions. Also helped find the cause of a weird bug, also
MADE ME use a linked list. True story.

Notice:
You can change this in any way you want, destroy it if you would. Just credit me as the original creator.


Keywords:
Slash, Omnislash, Blade, Physical, Bleed, Sword, Blademaster,
Contents

Just another Warcraft III map (Map)

Reviews
Z Slash v2.3 | Reviewed by Maker | 28th Apr 2013 APPROVED THe ability works, is MUI and leakless The indentation could be fixed Use static if in if TARGET_LIMIT == 0 then And here if INV then The onPeriod method...

Moderator

M

Moderator


Z Slash v2.3 | Reviewed by Maker | 28th Apr 2013
APPROVED


126248-albums6177-picture66521.png


  • THe ability works, is MUI and leakless
126248-albums6177-picture66523.png


  • The indentation could be fixed
  • Use static if in if TARGET_LIMIT == 0 then
    And here if INV then
  • The onPeriod method could be shorter as you have repeated lines there
  • There is no animation for the spell, it doesn't look good
[tr]



Z Slash v2.2 | Reviewed by Maker | 18th Apr 2013
NEEDS FIX


126248-albums6177-picture66522.png


  • The indexing is wrong, the spell is not MUI
  • The timer is never paused
126248-albums6177-picture66523.png


  • You can use return not break in IsLineWalkable
  • You should enum TARGET_LIMIT + 1 in Z since it enums the caster
    also, but you remove it from the group
  • You have the destroy block twice in the looping method and the code for the
    three phases is almost the same. You could shorten the code
[tr]


Z Slash v2.0 | Reviewed by Maker | 14th Apr 2013
NEEDS FIX


126248-albums6177-picture66522.png


  • There is a debug message in the code, displayed during every loop
  • The timer is never paused
  • The ability can take you through pathing blockers
126248-albums6177-picture66523.png


  • When you set dx and dy the first time, you could use TRAVEL1 global
  • You could abort the movement if the caster is dead
[tr]



Z Slash v1.1 | Reviewed by Maker | 10th Apr 2013
NEEDS FIX


126248-albums6177-picture66521.png


  • The spell is MUI and leakless
126248-albums6177-picture66522.png


  • There is no pathing detection so the unit can get stuck in the middle
    of trees or structures. Additionally, you can go over cliffs and get stuck
    at a point you can get out of
126248-albums6177-picture66523.png


  • By default, the spell could filter out flying units
  • Your SetUnitInvulnerable doesn't use the global boolean
  • You don't need to call GroupClear in onCast
    because the group will be empty anyway
  • You don't need to null tempUnit at the end of onCast
    as the unit group loop sets that to null
  • You could use u instead of tempUnit in onCast
    in the unit group loop
  • With 0.03 interval, it could be better to use a single timer for all instances
  • You should precalculate travel as it is derived from constant globals
    Make it a global also
  • You should precalculate travel*Cos(angle) and travel*Sin(angle)
  • Panning camera could be optional
  • ReleaseTimer pauses the timer, no need to call PauseTimer
[tr]
 
JASS:
                if not IsLineWalkable(hero_X, hero_Y, angle[this], PATH_OFFSET, 150.) then
                    set break[this] = true
                endif
->
set break[this] = not IsLineWalkable(hero_X, hero_Y, angle[this], PATH_OFFSET, 150.)

JASS:
            if totalTravel[this] < JUMP_DIST then
                
    
                set x = hero_X + dx[this]
                set y = hero_Y + dy[this]
                
                if not IsLineWalkable(hero_X, hero_Y, angle[this], PATH_OFFSET, 150.) then
                    set break[this] = true
                endif
                
                call SetUnitX(hero[this], x)
                call SetUnitY(hero[this], y)
                
                set totalTravel[this] = totalTravel[this] + (JUMP_DIST / (DUR/INTERVAL))
                
                if TARGET_LIMIT == 0 then
                    call GroupEnumUnitsInRange(tempGroup, x, y, RADIUS, null)
                else
                    call GroupEnumUnitsInRangeCounted(tempGroup, x, y, RADIUS, null, TARGET_LIMIT+1)
                endif
                call GroupRemoveUnit(tempGroup, hero[this])
                loop
                    set tempUnit = FirstOfGroup(tempGroup)
                    exitwhen tempUnit == null
                    
                    set target_id = GetUnitId(tempUnit)
                    
                    if TargetFilter(tempUnit, hero[this], injured[this][target_id]) then
                        call UnitDamageTarget(hero[this], tempUnit, DamageOnSlash(GetUnitAbilityLevel(hero[this], ABIL_CODE)), false, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
                        call DestroyEffect(AddSpecialEffectTarget(BLOOD_EFFECT_PATH, tempUnit, ATTACH_POINT))
                        set injured[this][target_id] = 1
                    endif
                    call GroupRemoveUnit(tempGroup, tempUnit)
                endloop
    
            else
                set totalTravel[this] = 0.
                set travelStage[this] = travelStage[this] + 1
                set angle[this] = angle[this] + bj_PI + Z_ANGLE
                set dx[this] = TRAVEL_2*Cos(angle[this])
                set dy[this] = TRAVEL_2*Sin(angle[this])
                //call BJDebugMsg("first ende")
            endif
This makes everything longer,cache this into a method.

Indention is messed up.
 
- Remove the TimerUtils coz it's useless
- You could use T32 or TimerTools instead of making your own periodic timer
- You could make the travel stage another static function above onPeriod so that it's more readable...
- You may use the index of the unit instead of Table e.g. injured or slashed, just make a static integer array and set it to 1...
 
Almia said:
Timers for every instance is a bad idea.You should use linked list because you are also using custom allocation/deallocation.

Not really. Timers are quite efficient actually. Linked list is better but a stack is the correct method. None of that matters though because individual timers for a spell that lasts 1.5 seconds is virtually unnoticeable. I suggest you take both versions of the spell and compare how many simultaneous casts are required to lag ;)

Also, the correct reason is not because he's using allocation/deallocation, but because he's using a timer period small enough such that the spell is intended to be smooth (Notice a linked list with one timer can look terrible for effects with timer periods on the order of 1 second)

There's another reason but I'll get to that soon.

Dr.Killer said:
What you said here doesn;t affect the performance I think, and about the indention I'm really too lazy to tab all those lines forward. Forgive me about this

You're correct about the performance, but you really should endeavor to tab lines. You want your spell scripts to teach others good habits.

If you're using JNGP you can select multiple lines and tab them simultaneously (as well as shift-tab them)

Almia said:
We want the code as simple as possible.

The code is simpler with one timer per instanciation actually. What you should have said is "We want code that is indicative of good practices for others to learn from."

mckill2009 said:
- Remove the TimerUtils coz it's useless

That's quite an outrageous claim. If he's not instanciating his own hashtable, everything is fine.

- You may use the index of the unit instead of Table e.g. injured or slashed, just make a static integer array and set it to 1...

Indexing units is terrible practice, I can't believe you guys still suggest it. The correct solution is to use a group.


----


Back to the actual spell:

The Good:
  • Your coding style and attitude is great by comparison to others with similar hive experience.
  • Your spell works as intended and doesn't lag; doesn't have any obvious glitches/bugs.
  • Your script is properly customizable.

The Bad:
  • You don't prevent the caster from moving/attacking while casting. With the default duration of 1.5, you can see many cases of deflection in the slide trajectory and it looks very poor. PauseUnit on its own is unsafe - you have some other options though.
  • You use IsTerrainWalkable but don't list it in your description or requirements (by the way, some others will bash you for using this, and then shut up when you tell them nothing better exists)
  • Honestly I have no idea why you need UnitIndexer, but it's so common I won't complain.

Overall: ***. Will update to ***** if you fix the issue with caster attacking (because there are cases when it completely ruins the spell - take DUR=5. and JUMP_DIST=100. and you will see)
 
Top