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

Impale System 1.1c

Basically, it allows you to create custom impales


JASS:
/*
    Impale System 1.1c requires T32, Table, JumpInPlace, StunSystem, *MapBound*
    by Adiktuz
    
    Credits to Bribe, Magtheridon96 and iAyanami for their system that were used
               on this library and the sample spells
    
    An impale system which allows you to create custom impale-like spells
    
    Features:
    
        - Allows creation of more than one-type of impale spell
        - *Can multi-impale a unit (requires balancing with the settings of the JumpInPlace library)
        - *Can easily change which units can be hit
        - *Can easily change the way damage is dealt
        - *Can set actions for when the impale wave ends and for when the unit falls 
           back to it's initial height (dependent on JumpInPlace library)
        
        *Can be set per impale-type spell
    
    How to Import:
    
        1)If you don't have the dummy.mdx and a dummy unit yet, 
          export it and the Dummy unit and import into your map
        2)Copy the whole Spell folder into your map
        3)Enable the Objects Trigger
        4)Save your map
        5)Close map
        6)Reopen map
        7)Disable/Delete the objects trigger
        8)Save your map
        9)Edit the configurables below and read the How to use
        10)Enjoy!
        
    Stub methods:
        
        //onStop action, can be overwritten by structs that extend this struct
        stub method Stop takes nothing returns nothing
            //place your actions here
            //It is important that you don't remove these three function calls
            call this.unitTable.destroy()
            call this.stopPeriodic()
            call this.destroy()
        endmethod
        
        //onDamage action, can be overwritten by structs that extend this struct
        stub method onDamage takes unit target returns nothing
            -placed it here so that they can change the way the damage and "flying" are done
            We added the stun duration and the air-time duration for the real duration of the stun
            since the given stun duration is counted after the unit lands but we will stun
            it right after it is hit by impale-
            call Stun.apply(target, this.duration + this.stduration, false)
            call UnitDamageTarget(this.caster, target, GetRandomReal(this.lowdamage, this.highdamage), false, false, this.at, this.dt, null)
            call JumpIP.Fire(target, this.caster, this.duration, this.maxheight, this.abil)
        endmethod
        
        //determines which units can be hit by impale, can be overwritten by structs that extend this struct
        stub method hitFilter takes unit target returns boolean
            return IsUnitEnemy(target, this.owner) and GetWidgetLife(target) > .405 and this.unitTable[GetHandleId(target)] == 0
        endmethod
    
    How to Use:
        
        For normal usage (if you're not gonna replace any of the stub methods)
        
            -> Impale.CreateFire()
            -> Impale.CreateFireCID()
            -> Impale.CreateFireEX()
            
            call Impale.CreateFire(takes unit caster, integer level, string model, string modelhit,
                real angle, real scale, real aoe, real distance, real distanceperwave,
                real damage returns nothing)
            
            unit Caster -> the unit that casted the impale
            integer level -> level of the spell
            string model -> path to the model of the impale wave
            string modelhit -> path to the model of the hit effect
            real angle -> angle to which the impale is going
            real scale -> scale of each impale wave
            real aoe -> filter aoe for each impale wave
            real distance -> max range of the impale
            real distanceperwave -> distance between each impale wave
            real damage -> damage of the impale
            
            call Impale.CreateFireCID(takes unit caster, integer level, string model, string modelhit,
                real angle, real scale, real aoe, real distance, real distanceperwave,
                real damage, intger abil returns nothing)
            
            integer abil -> rawcode of the spell
            
            call Impale.CreateFireEX(takes unit caster, integer level, string model, string modelhit, real x,real y,
                real angle, real wave, real scale, real aoe, real distance, real distanceperwave,
                real damagelow, real damagehigh, real stduration, real duration, 
                real maxheight, integer abil, attacktype at, damagetype dt, integer jumptype)
            
            real x -> starting x coordinate of the impale
            real y -> starting y coordinate of the impale
            real wave -> time interval between each impale wave
            real damagelow -> lower bound damage of the impale
            real damagehigh -> higher bound damage of the impale
            real stduration -> duration of stun (counted from after the unit lands)
            real duration -> duration of the air-time
            real maxheight -> max height of the air-time
            integer abil -> rawcode of the spell
            attacktype at -> attack type of the spell
            damagetype dt -> damage type of the spell
            integer jumptype -> jump type, refer to JIP library
            
            For more info, look at the sample spells
            
        If you're gonna replace the stub methods
        
            Method list are same as above, but without the Create word
            -> StructVariableName.Fire()
            -> StructVariableName.FireCID()
            -> StructVariableName.FireEX()
        
            First you need to create a struct which extends the Impale struct
                ex. struct A extends Impale
                    endstruct
            
            then you create the replacement method for the stub method that you want to replace
            without the stub word anymore
                ex. struct A extends Impale
                        method onDamage takes unit target returns nothing
                        endmethod
                    endstruct
            Note: make sure that they still have the same parameter list as the original method
                 else, it will cause an error
            
            then you create a local variable of type Impale and set it to an instance of your 
            new struct, then use that local variable to call the function you need
                ex. local Impale ex = A.create()
                    call ex.Fire()
                    
            Note: It is important that the type of the local variable should be Impale
                  You can view the Death Siphon trigger for a working example
              
    How to set action for when the unit returns to it's original height:
        call JumpIP.RegisterStopEvent(integer abil, code action)
        
        integer abil => the rawcode of the spell in which you want to add the action
        code action => the function which will be run
        
    Variables you can use for the StopEvent
        JumpIP.tmpFlyUnit => unit that triggered the StopEvent (the jumping unit)
        JumpIP.tmpCauseUnit => the unit that caused the FlyUnit to jump

     See the Death Siphon trigger for a working example   
*/

library ImpaleSystem requires T32, Table, JumpInPlace, StunSystem, MapBounds
    
    globals
        //rawcode of dummy unit
        private constant integer DUMMY_ID = 'e000'
        /*
        The next set of data is for impales created using the Fire and FireCID methods
        */
        //sets the time interval for each impale wave
        private constant real DEF_WAVE = .09
        //sets the air-time duration
        private constant real DEF_DURATION = 1.00
        //sets the stun duration (counted from when the unit lands)
        private constant real DEF_STDURATION = 1.00
        //max height of the air-time
        private constant real DEF_HEIGHT = 300.0
        //default jump type
        //see the JIP library for definition
        private constant integer JUMP = JUMP_TYPE_HEIGHT_STACK
        //used for registering stop event for the normal impales
        //you can set it to the rawcode of the dummy stun spell
        //since it won't probably be used to register an impale anyway
        //or you can also use the rawcode of any passive/aura spell
        private constant integer DUMMY_SPELL = 'A002'
        //set this to false if you won't use the onEnd event for the default impales
        private constant boolean USE_ON_END = false
        //attack type of the impale
        private constant attacktype DEF_AT = ATTACK_TYPE_MAGIC
        //damage type of the impale
        private constant damagetype DEF_DT = DAMAGE_TYPE_NORMAL
        //required, DO NOT EDIT
        private group tmpGroup = CreateGroup()
    endglobals
    
    //End of Configuration
    
    struct Impale
        unit caster
        integer level
        integer jumptype
        string model
        real wave
        real waved
        real scale
        real aoe
        real distance
        real distx
        real disty
        real lowdamage
        real highdamage
        real duration
        real stduration
        real maxheight
        real angle
        real x
        real y
        real current
        real total
        player owner
        integer abil
        attacktype at
        damagetype dt
        string modelhit
        Table unitTable
        static unit tmpUnit
        
        /*
        registered as the stop action for all normal/simple impales
        this is run after the air-time ends
        make sure to set USE_ON_END to true if you're gonna put actions
        into this method
        */
        static method onEnd takes nothing returns nothing
        endmethod
        
        //onStop action, can be overwritten by structs that extend this struct
        stub method stop takes nothing returns nothing
        //It is important that you don't remove these three function calls
            call this.unitTable.destroy()
            call this.stopPeriodic()
            call this.destroy()
        endmethod
        
        //onDamage action, can be overwritten by structs that extend this struct
        stub method onDamage takes unit target returns nothing
            /*
            placed it here so that they can change the way the damage and "flying" are done
            We added the stun duration and the air-time duration for the real duration of the stun
            since the given stun duration is counted after the unit lands but we will stun
            it right after it is hit by impale
            */
            call Stun.apply(target, this.duration + this.stduration, false)
            call UnitDamageTarget(this.caster, target, GetRandomReal(this.lowdamage, this.highdamage), false, false, this.at, this.dt, null)
            call JumpInPlace.fire(target, this.caster, this.duration, this.maxheight, this.abil,this.jumptype)
        endmethod
        
        //determines which units can be hit by impale, can be overwritten by structs that extend this struct
        stub method hitFilter takes unit target returns boolean
            return IsUnitEnemy(target, this.owner) and GetWidgetLife(target) > .405 and this.unitTable[GetHandleId(target)] == 0
        endmethod
        
        method periodic takes nothing returns nothing
            set this.current = this.current + T32_PERIOD
            if this.current >= this.wave then
                set this.wave = this.wave + this.waved
                set this.x = this.x + this.distx
                set this.y = this.y + this.disty
                if not (mapIncludeX(this.x) and mapIncludeY(this.y))then
                    call this.stop()
                    return
                endif
                call GroupEnumUnitsInRange(tmpGroup, this.x,this.y,this.aoe, null)
                set tmpUnit = CreateUnit(Player(15), DUMMY_ID, this.x, this.y, 0.0)
                call SetUnitScale(tmpUnit, this.scale, 0, 0) 
                call UnitApplyTimedLife(tmpUnit, 'BTLF', 1.00)
                call DestroyEffect(AddSpecialEffectTarget(this.model, tmpUnit, "origin"))
                loop
                    set tmpUnit = FirstOfGroup(tmpGroup)
                    exitwhen tmpUnit == null
                    if this.hitFilter(tmpUnit) then
                        set this.unitTable[GetHandleId(tmpUnit)] = 1
                        //made the hit effect on the ground because attaching it to the unit 
                        //causes visual bugs if the unit is hit by multiple impales
                        //and the effect stays for a while after the destroy is called (both effects will show)
                        call DestroyEffect(AddSpecialEffect(this.modelhit, GetUnitX(tmpUnit), GetUnitY(tmpUnit)))
                        call this.onDamage(tmpUnit)
                    endif
                    call GroupRemoveUnit(tmpGroup, tmpUnit)
                endloop
                if this.current >= this.total then
                    call this.stop()
                endif
            else
            endif
        endmethod
        
        implement T32x
        
        //Methods to be used if you're gonna replace any of the stub methods
        
        method fireEX takes unit caster, integer level, string model, string modelhit, real x,real y, /*
        */real angle, real wave, real scale, real aoe, real distance, real distanceperwave,/*
        */real damagelow, real damagehigh, real stduration, real duration, /*
        */real maxheight, integer abil, attacktype at, damagetype dt,integer jumptype returns nothing
            set this.caster = caster
            set this.level = level
            set this.model = model
            set this.wave = wave
            set this.angle = angle
            set this.scale = scale
            set this.aoe = aoe
            set this.distance = distance
            set this.distx = distanceperwave*Cos(this.angle)
            set this.disty = distanceperwave*Sin(this.angle)
            set this.lowdamage = damagelow
            set this.highdamage = damagehigh
            set this.stduration = stduration
            set this.duration = duration
            set this.maxheight = maxheight
            set this.x = x
            set this.y = y
            set this.current = 0.0
            set this.waved = this.wave
            set this.total = (distance/distanceperwave)*this.wave
            set this.unitTable = Table.create()
            set this.at = at
            set this.dt = dt
            set this.owner = GetOwningPlayer(caster)
            set this.modelhit = modelhit
            set this.abil = abil
            set this.jumptype = jumptype
            call this.startPeriodic()
        endmethod
        
        method fire takes unit caster, integer level, string model, string modelhit,/*
        */real angle, real scale, real aoe, real distance, real distanceperwave,/*
        */real damage returns nothing
            set this.caster = caster
            set this.level = level
            set this.model = model
            set this.scale = scale
            set this.angle = angle
            set this.aoe = aoe
            set this.distance = distance
            set this.distx = distanceperwave*Cos(this.angle)
            set this.disty = distanceperwave*Sin(this.angle)
            set this.lowdamage = damage
            set this.highdamage = damage
            set this.duration = DEF_DURATION
            set this.stduration = DEF_STDURATION
            set this.maxheight = DEF_HEIGHT
            set this.wave = DEF_WAVE
            set this.x = GetUnitX(caster)
            set this.y = GetUnitY(caster)
            set this.current = 0.0
            set this.waved = this.wave
            set this.total = (distance/distanceperwave)*this.wave
            set this.unitTable = Table.create()
            set this.at = DEF_AT
            set this.dt = DEF_DT
            set this.owner = GetOwningPlayer(caster)
            set this.modelhit = modelhit
            set this.abil = DUMMY_SPELL
            set this.jumptype = JUMP
            call this.startPeriodic()
        endmethod
        
        method fireCID takes unit caster, integer level, string model, string modelhit,/*
        */real angle, real scale, real aoe, real distance, real distanceperwave,/*
        */real damage, integer abil returns nothing
            set this.caster = caster
            set this.level = level
            set this.model = model
            set this.scale = scale
            set this.angle = angle
            set this.aoe = aoe
            set this.distance = distance
            set this.distx = distanceperwave*Cos(this.angle)
            set this.disty = distanceperwave*Sin(this.angle)
            set this.lowdamage = damage
            set this.highdamage = damage
            set this.duration = DEF_DURATION
            set this.stduration = DEF_STDURATION
            set this.maxheight = DEF_HEIGHT
            set this.wave = DEF_WAVE
            set this.x = GetUnitX(caster)
            set this.y = GetUnitY(caster)
            set this.current = 0.0
            set this.waved = this.wave
            set this.total = (distance/distanceperwave)*this.wave
            set this.unitTable = Table.create()
            set this.at = DEF_AT
            set this.dt = DEF_DT
            set this.owner = GetOwningPlayer(caster)
            set this.modelhit = modelhit
            set this.abil = abil
            set this.jumptype = JUMP
            call this.startPeriodic()
        endmethod
        
        //Methods to be used if you're not gonna replace any of the stub methods
        
        static method createFireEX takes unit caster, integer level, string model, string modelhit, real x,real y, /*
        */real angle, real wave, real scale, real aoe, real distance, real distanceperwave,/*
        */real damagelow, real damagehigh, real stduration, real duration, /*
        */real maxheight, integer abil, attacktype at, damagetype dt,integer jumptype returns nothing
            local thistype this = .allocate()
            set this.caster = caster
            set this.level = level
            set this.model = model
            set this.wave = wave
            set this.angle = angle
            set this.scale = scale
            set this.aoe = aoe
            set this.distance = distance
            set this.distx = distanceperwave*Cos(this.angle)
            set this.disty = distanceperwave*Sin(this.angle)
            set this.lowdamage = damagelow
            set this.highdamage = damagehigh
            set this.stduration = stduration
            set this.duration = duration
            set this.maxheight = maxheight
            set this.x = x
            set this.y = y
            set this.current = 0.0
            set this.waved = this.wave
            set this.total = (distance/distanceperwave)*this.wave
            set this.unitTable = Table.create()
            set this.at = at
            set this.dt = dt
            set this.owner = GetOwningPlayer(caster)
            set this.modelhit = modelhit
            set this.abil = abil
            set this.jumptype = jumptype
            call this.startPeriodic()
        endmethod
        
        static method createFire takes unit caster, integer level, string model, string modelhit,/*
        */real angle, real scale, real aoe, real distance, real distanceperwave,/*
        */real damage returns nothing
            local thistype this = .allocate()
            set this.caster = caster
            set this.level = level
            set this.model = model
            set this.scale = scale
            set this.angle = angle
            set this.aoe = aoe
            set this.distance = distance
            set this.distx = distanceperwave*Cos(this.angle)
            set this.disty = distanceperwave*Sin(this.angle)
            set this.lowdamage = damage
            set this.highdamage = damage
            set this.duration = DEF_DURATION
            set this.stduration = DEF_STDURATION
            set this.maxheight = DEF_HEIGHT
            set this.wave = DEF_WAVE
            set this.x = GetUnitX(caster)
            set this.y = GetUnitY(caster)
            set this.current = 0.0
            set this.waved = this.wave
            set this.total = (distance/distanceperwave)*this.wave
            set this.unitTable = Table.create()
            set this.at = DEF_AT
            set this.dt = DEF_DT
            set this.owner = GetOwningPlayer(caster)
            set this.modelhit = modelhit
            set this.abil = DUMMY_SPELL
            call this.startPeriodic()
        endmethod
        
        static method createFireCID takes unit caster, integer level, string model, string modelhit,/*
        */real angle, real scale, real aoe, real distance, real distanceperwave,/*
        */real damage, integer abil returns nothing
            local thistype this = .allocate()
            set this.caster = caster
            set this.level = level
            set this.model = model
            set this.scale = scale
            set this.angle = angle
            set this.aoe = aoe
            set this.distance = distance
            set this.distx = distanceperwave*Cos(this.angle)
            set this.disty = distanceperwave*Sin(this.angle)
            set this.lowdamage = damage
            set this.highdamage = damage
            set this.duration = DEF_DURATION
            set this.stduration = DEF_STDURATION
            set this.maxheight = DEF_HEIGHT
            set this.wave = DEF_WAVE
            set this.x = GetUnitX(caster)
            set this.y = GetUnitY(caster)
            set this.current = 0.0
            set this.waved = this.wave
            set this.total = (distance/distanceperwave)*this.wave
            set this.unitTable = Table.create()
            set this.at = DEF_AT
            set this.dt = DEF_DT
            set this.owner = GetOwningPlayer(caster)
            set this.modelhit = modelhit
            set this.abil = abil
            set this.jumptype = JUMP
            call this.startPeriodic()
        endmethod
        
        //I didn't use a module initializer because it returns an error
        //on the impale samples
        static method onInit takes nothing returns nothing
            static if USE_ON_END then
                call JumpInPlace.RegisterStopEvent(DUMMY_SPELL, function thistype.onEnd)
            endif
        endmethod
        
    endstruct
    
endlibrary



JASS:
scope NormalImpale initializer init //Requires ImpaleSystem, SpellEvent

    globals
        private constant integer IMPALE_ID = 'A000'
        private constant string IMPALE_MODEL = "Abilities\\Spells\\Undead\\Impale\\ImpaleMissTarget.mdl"
        private constant string IMPALE_HIT_MODEL = "Abilities\\Spells\\Undead\\Impale\\ImpaleHitTarget.mdl"
        private constant real WAVE_DISTANCE = 200.0
        private constant real WAVE_AOE = 100.0
    endglobals
    
    private function GetDamage takes unit u, integer level returns real
        return 75.00*level
    endfunction
    
    private function GetDistance takes unit u, integer level returns real
        return 400 + 200.00*level
    endfunction
    
    private function action takes nothing returns nothing
        local unit caster = GetTriggerUnit()
        local real x = GetUnitX(caster)
        local real y = GetUnitY(caster)
        local real tx = GetSpellTargetX()
        local real ty = GetSpellTargetY()
        local real angle = Atan2(ty-y,tx-x)
        local integer level = GetUnitAbilityLevel(caster, IMPALE_ID)
        //Since were not gonna replace any stub method, we use the CreateFire method
        call Impale.createFire(caster, level, IMPALE_MODEL,IMPALE_HIT_MODEL,/*
        */angle, 1.00, WAVE_AOE, GetDistance(caster,level), WAVE_DISTANCE,/*
        */GetDamage(caster,level))
        set caster = null
    endfunction
    
    private function init takes nothing returns nothing
        call RegisterSpellEffectEvent(IMPALE_ID,function action)
    endfunction
    
endscope

JASS:
scope AquaBanisher initializer init //Requires AQUASystem, SpellEvent
    
    //Take note that in this spell, units can be hit by more than 1 aqua banisher line
    //meaning the damage and fly height can all stack-up.
    //Units near the caster will experience the most number of hits on this case
    
    globals
        private constant integer AQUA_ID = 'A001'
        private constant string AQUA_MODEL = "Objects\\Spawnmodels\\Naga\\NagaDeath\\NagaDeath.mdl"
        private constant string AQUA_HIT_MODEL = "Abilities\\Spells\\Other\\CrushingWave\\CrushingWaveDamage.mdl"
        private constant real WAVE_DISTANCE = 200.0
        private constant real WAVE_AOE = 120.0
    endglobals
    
    private function GetDamage takes unit u, integer level returns real
        return 75.00*level
    endfunction
    
    private function GetDistance takes unit u, integer level returns real
        return 400 + 200.00*level
    endfunction
    
    struct Aqua extends Impale
        //replaces the original Stop method
        method Stop takes nothing returns nothing
            call BJDebugMsg("Aqua Banisher End")
            //It is important that you don't remove these three function calls
            call this.unitTable.destroy()
            call this.stopPeriodic()
            call this.destroy()
        endmethod
    endstruct
    
    private function action takes nothing returns nothing
        local unit caster = GetTriggerUnit()
        local real x = GetUnitX(caster)
        local real y = GetUnitY(caster)
        local real tx = GetSpellTargetX()
        local real ty = GetSpellTargetY()
        local real angle = Atan2(ty-y,tx-x)
        local integer level = GetUnitAbilityLevel(caster, AQUA_ID)
        //we create an impale object and set it to an instance
        //of our new struct in order for the stub methods to be 
        //replaceable
        local Impale aqua = Aqua.create()
        call aqua.fire(caster, level, AQUA_MODEL,AQUA_HIT_MODEL,/*
        */angle, 0.50, WAVE_AOE, GetDistance(caster,level), WAVE_DISTANCE,/*
        */GetDamage(caster,level))
        set caster = null
    endfunction
    
    private function init takes nothing returns nothing
        call RegisterSpellEffectEvent(AQUA_ID,function action)
    endfunction
    
endscope

JASS:
scope DeathSiphon initializer init //Requires ImpaleSystem, SpellEvent

    globals
        private constant integer DS_ID = 'A003'
        private constant string DS_MODEL = "Abilities\\Spells\\Undead\\AnimateDead\\AnimateDeadTarget.mdl"
        private constant string DS_HIT_MODEL = "Abilities\\Spells\\NightElf\\ManaBurn\\ManaBurnTarget.mdl"
        private constant real WAVE_DISTANCE = 200.0
        private constant real WAVE_AOE = 100.0
    endglobals
    
    private function GetDamage takes unit u, integer level returns real
        return 50.00*level
    endfunction
    
    private function GetDistance takes unit u, integer level returns real
        return 400 + 200.00*level
    endfunction
    
    struct DS extends Impale
        //replaces the onDamage stub method of the original Impale struct
        method onDamage takes unit target returns nothing
            //No stun here
            call UnitDamageTarget(this.caster, target, this.lowdamage, false, false, this.at, this.dt, null) 
            call SetWidgetLife(this.caster, GetWidgetLife(this.caster) + this.lowdamage)
            call DestroyEffect(AddSpecialEffectTarget(DS_HIT_MODEL, this.caster,"chest"))
            call JumpInPlace.fire(target, this.caster, this.duration, this.maxheight, this.abil,this.jumptype)
        endmethod
    endstruct
    
    private function onStop takes nothing returns nothing
        call BJDebugMsg(GetUnitName(JumpInPlace.tmpFlyUnit) + " was Death Siphoned by " + GetHeroProperName(JumpInPlace.tmpCauseUnit))
    endfunction
    
    private function action takes nothing returns nothing
        local unit caster = GetTriggerUnit()
        local real x = GetUnitX(caster)
        local real y = GetUnitY(caster)
        local real tx = GetSpellTargetX()
        local real ty = GetSpellTargetY()
        local real angle = Atan2(ty-y,tx-x)
        local integer level = GetUnitAbilityLevel(caster, DS_ID)
        //we create an impale object and set it to an instance
        //of our new struct in order for the stub methods to be 
        //replaceable
        local Impale Siphon = DS.create()
        call Siphon.fireCID(caster, level, DS_MODEL,DS_HIT_MODEL,/*
        */angle, 0.75, WAVE_AOE, GetDistance(caster,level), WAVE_DISTANCE,/*
        */GetDamage(caster,level),DS_ID)
        set caster = null
    endfunction
    
    private function init takes nothing returns nothing
        call RegisterSpellEffectEvent(DS_ID,function action)
        call JumpInPlace.registerStopEvent(DS_ID,function onStop)
    endfunction
    
endscope

JASS:
scope BlindingFlash initializer init //Requires ImpaleSystem, SpellEvent

    globals
        private constant integer BF_ID = 'A006'
        private constant string BF_MODEL = "Abilities\\Spells\\Human\\Invisibility\\InvisibilityTarget.mdl"
        private constant string BF_HIT_MODEL = ""
        private constant real WAVE_DISTANCE = 200.0
        private constant real WAVE_AOE = 150.0
        private constant integer DUMMY_ID = 'sTUN'
        private constant integer BLIND_ID = 'ABLN'
        //I used Drunken haze as a base because I can't seem to make the dummy units 
        //cast a curse-based spell
        private constant string COMMAND = "drunkenhaze"
    endglobals
    
    private function GetDamage takes unit u, integer level returns real
        return 200.00*level
    endfunction
    
    private function GetDistance takes unit u, integer level returns real
        return 400 + 200.00*level
    endfunction
    
    struct BF
        static unit dummycaster
        
        static method onFall takes nothing returns nothing
            call SetUnitAbilityLevel(dummycaster, BLIND_ID, GetUnitAbilityLevel(JumpInPlace.tmpCauseUnit,BF_ID))
            call IssueTargetOrder(dummycaster, COMMAND, JumpInPlace.tmpFlyUnit)
        endmethod
        
        static method onInit takes nothing returns nothing
            set dummycaster = CreateUnit(Player(13), DUMMY_ID,0.0, 0.0,0.0)
            call UnitAddAbility(dummycaster, BLIND_ID)
        endmethod
    endstruct
    
    
    private function action takes nothing returns nothing
        local unit caster = GetTriggerUnit()
        local real x = GetUnitX(caster)
        local real y = GetUnitY(caster)
        local real tx = GetSpellTargetX()
        local real ty = GetSpellTargetY()
        local real angle = Atan2(ty-y,tx-x)
        local integer level = GetUnitAbilityLevel(caster, BF_ID)
        //we create an impale object and set it to an instance
        //of our new struct in order for the stub methoBF to be 
        //replaceable
        call Impale.createFireCID(caster, level, BF_MODEL,BF_HIT_MODEL,/*
        */angle, 0.75, WAVE_AOE, GetDistance(caster,level), WAVE_DISTANCE,/*
        */GetDamage(caster,level),BF_ID)
        set caster = null
    endfunction
    
    private function init takes nothing returns nothing
        call RegisterSpellEffectEvent(BF_ID,function action)
        call JumpInPlace.registerStopEvent(BF_ID,function BF.onFall )
    endfunction
    
endscope





Version 1.1 - camelcased the struct methods
- made the jump type configurable in the impale settings and impaleEx calls
Version 1.1b - updated due to JumpInPlace update that caused minor changes in syntax
Version 1.1c - quick fix


Keywords:
adiktuz,impale,system,fly,table,stun,custom,nerubian
Contents

Impale System 1.1c (Map)

Reviews
16:07, 19th Sep 2012 Magtheridon96: Approved. This is an excellent resource, and thus deserves a solid 4/5. Good job ;D (Very, very close to 5/5, a rating I've never given before.) edit Bleh, this deserves a 5/5.

Moderator

M

Moderator

16:07, 19th Sep 2012
Magtheridon96: Approved.
This is an excellent resource, and thus deserves a solid 4/5. Good job ;D (Very, very close to 5/5, a rating I've never given before.)

edit
Bleh, this deserves a 5/5.
 
[offtopic]the hit filter wasn't part of the interface... And I've also now removed the interface, found a better way to register events [which I learned from reading SpellEffectEvent]... XD... still cleaning up the code though maybe I'd update the resource by friday...[/offtopic]

the user can add that... I'm too lazy to add that right now...
 
Not really, not yet... I still have a month left at school [and lots of schoolwork that would well determine if I'll be seeing the next semester]... It's just that my current pile of requirements basically needs the things on the internet so when I'm stressed out, I check The Hive and look for ideas so that I have something to do to freshen up... :)
 
Level 16
Joined
Aug 7, 2009
Messages
1,403
It's rather "flat", if you ask me. The idea is sort of original as I don't know about any impale systems (I also needed one but I couldn't find any of them, so I had to write my own), but the formula, the shape, the formula could be improved IMO.
 
Level 14
Joined
Aug 8, 2010
Messages
1,022
I haven't looked at the code but i have one suggestion. Add acceleration/deceleration to the impale. For example, Var1 and Var2 are reals.
Set Var1 = Var1+Amount (this is the acceleration)
Set Var2 = Var2+Var1 (this is the height of the unit, Var2 holds it)

So you have to do this. The impale hits, you set the acceleration (Var1) to like 6 (i don't know how you move the unit in the air but let's say we move it every 0.03 seconds). Every loop you increase the unit's height to it's current height + Var1 and set Var1 = Var1 - 0.1 (for example). When Var1 becomes 0, start to increase Var1 with 0.1 instead, and decrease the unit's height (Set Var2 = Var2-Var1) until it reaches 0.

The unit's move trough the air is kinda crappy, at least in my opinion, it's not realistic (like in the original impale).
 
I do hope you have... :)

Updates are currently being made for the Jump library so an update for this resource will come before the weekend ends (coz I'll be going to school again next week)...

EDIT: I will add a global event handler for impale start so that you can fire a general event for all impales that have started...
 
Last edited:
Level 17
Joined
Feb 11, 2011
Messages
1,860
I think I've found a bug.
With the "Impale.createFireEX" method, you don't set .lowDamage and .highDamage properly.
It is like this:

JASS:
set this.lowdamage = lowdamage 
set this.highdamage = highdamage
Which is just setting the data member to itself, i.e. 0.
It should be:

JASS:
set this.lowdamage = damageLow
set this.highdamage = damageHigh
Anyway, great system! Well done :p
 
Level 3
Joined
May 28, 2012
Messages
32
Wrong Damage & Buggy Hitbox

There is one little mistake with the damage. It is multiplied with a number between 1,7 - 1,9. The level 1 damage of the impale spell is supposed to do 75 damage but it does 133 damage. At level 2 it does 277 damage instead of 150. And at level 3 it does 401 damage instead of 225.
The bonus damage doesnt come from attack/spell type. I tested it on every armor type.

I didn't found the multiplicator but I found another way to fix the problem.

Do this in the "Normal Impale" Trigger:

JASS:
    private function GetDamage takes unit u, integer level returns real
->      return  1 + 75.00 * level
    endfunction

and this in the Impale System Trigger:

JASS:
        stub method onDamage takes unit target returns nothing
            /*
            placed it here so that they can change the way the damage and "flying" are done
            We added the stun duration and the air-time duration for the real duration of the stun
            since the given stun duration is counted after the unit lands but we will stun
            it right after it is hit by impale
            */
            call Stun.apply(target, this.duration + this.stduration, false)
->          call UnitDamageTarget(this.caster, target, GetRandomReal(this.lowdamage, this.highdamage)/1.8, false, false, this.at, this.dt, null)
            call JumpInPlace.fire(target, this.caster, this.duration, this.maxheight, this.abil,this.jumptype)
        endmethod

Then it does EXACTLY the damage which is set in the "Normal Impale" Trigger.
In this case: 75 damage at level 1, 150 damage at level 2, 225 damage at level 3.

There is also a bug with the Hitbox of the spell.
If a unit is right next to the caster, the unit isnt hit by the spell.
 
Last edited:
Top