impale system glitches and stuffs like that

waaaks!

Zinctified
Reaction score
255
UPDATED the code and looks fine, what i need now is leak check that could possibly lag the game

JASS:
library ImpaleSystem needs GroupUtils, TimerUtils, AutoIndex
//*******************************************************************************************
//*                                                                                     
//*                                    Impale System
//*                                         v.A
//*                                     By: waaaks!
//*
//*******************************************************************************************
//* INTRODUCTION
//*     Having issues with Warcraft III's Impale ability? Want to create abilities based on
//*     Impale but looks so wrong? Worry no more, Impale System will do the job for you.
//*     A System remaking the normal Warcraft III Impale System which is more flexible
//*     and user configurable. With the system you can fully imitate Impale without any
//*     Impale-based issues. The Impale ability is one of the most used abilities in 
//*     Warcraft III, with the use of special effects with the ability, you can create
//*     spells like a line stun ability, but Impale cannot Impale units being Impaled or was
//*     stunned using Impale.
//*
//* PURPOSE
//*     To help users imitate Impale based abilities without the said issues.
//*
//* PROs
//*     -Create spells which imitates Impale without the issue.
//*     -Choose what ability to be casted on unit land.
//*     -Manage wave time.
//*     -Add a second wave special effect.
//*     -Very usefull on maps that require lots of spells based on Impale.
//*     -Removes channeling on Impale which makes the player wait until wave ends.
//*
//* CONs
//*     -There is no option to turn of unit tossing.
//*     -Units will be damaged half when effect starts and half damage on land.
//*     -Impale source will always be on the casting unit.

globals
    private constant real FACT = 0.5                                //Structure damage factor
    private constant real TICK2 = 0.025                             //Timer per Tick
    private constant integer DUMMY_CASTER = 'e000'                  //Your Dummy Caster
    private constant integer FLY  = 'Amrf'                          //The Fly Height Enabler ability
    private group DUMMY_GROUP = CreateGroup()                       //Do not touch
    private integer array FALL
    private integer array ONCE
    private boolean array DONE
endglobals

//*******************************************************************************************
//* Please do not touch anything below this line
//*******************************************************************************************

private struct impaleToss
    unit cast
    unit targ
    real dmg
    integer dspell
    integer splvl
    integer sporder
    
    static method impToss takes nothing returns nothing
        local timer tim = GetExpiredTimer()
        local impaleToss it = GetTimerData(tim)
        local real height = GetUnitFlyHeight(it.targ)
        
        //*****************************************************************************
        //* the unit has reached the maximum height, make it fall (FALL[unit] = 1, and
        //*     ONCE[unit] = 1 for conditional uses only)
        if height > 500.0 and ONCE[GetUnitId(it.targ)] == 0 then
            set FALL[GetUnitId(it.targ)] = 1
            set ONCE[GetUnitId(it.targ)] = 1
        endif
        
        //*****************************************************************************
        //* if unit is not falling then that means it is rising (DUH!), make unit rise
        if FALL[GetUnitId(it.targ)] == 0 then
            call SetUnitFlyHeight(it.targ,height+40.0,0.0)
            call SetUnitPathing(it.targ, false)
            call PauseUnit(it.targ,true)
        else //make unit fall
            call SetUnitFlyHeight(it.targ,height-55.0,0.0)
            call PauseUnit(it.targ,true)
            call SetUnitPathing(it.targ,false)
        endif
        
        //*****************************************************************************
        //* if unit is already near land, also ONCE[unit] is used to check if the unit
        //* is already damaged or not then do some stuffs
        if height <= 15 and ONCE[GetUnitId(it.targ)] == 1 then
            call ReleaseTimer(tim)
            call it.destroy()
        endif
        set tim = null
    endmethod
    
    private method onDestroy takes nothing returns nothing
        local unit dum
        call SetUnitFlyHeight(.targ,0.0,0.0)
        call UnitDamageTarget(.cast,.targ,0.5*.dmg,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null)
        call PauseUnit(.targ,false)
        call SetUnitPathing(.targ,true)
        set dum = CreateUnit(GetOwningPlayer(.cast),DUMMY_CASTER,GetUnitX(.cast),GetUnitY(.cast),0.0)
        call UnitApplyTimedLife(dum,'BTLF',3.0)
        call UnitAddAbility(dum,'Aloc')
        call UnitAddAbility(dum,.dspell)
        call SetUnitAbilityLevel(dum,.dspell,.splvl)
        call IssueTargetOrderById(dum,.sporder,.targ)
        call UnitShareVision(.targ,GetOwningPlayer(.cast),false)
        set FALL[GetUnitId(.targ)] = 0
        set ONCE[GetUnitId(.targ)] = 0
        set DONE[GetUnitId(.targ)] = false
        set dum = null
    endmethod
    
    static method create takes unit ccg, unit tcg, real dmg, integer dspell, integer splvl, integer sporder returns impaleToss
        local impaleToss it = impaleToss.allocate()
        local timer tim = NewTimer()
        set it.cast = ccg
        set it.targ = tcg
        set it.dmg = dmg
        set it.dspell = dspell
        set it.splvl = splvl
        set it.sporder = sporder
        call UnitAddAbility(it.targ,FLY)
        call UnitRemoveAbility(it.targ,FLY)
        call PauseUnit(it.targ,true)
        call SetUnitPathing(it.targ,false)
        call TimerStart(tim,TICK2,true,function impaleToss.impToss)
        call SetTimerData(tim,it)
        set tim = null
        return it
    endmethod
    
endstruct

struct impaleSystem
    public real isRadius = 150.0
    public real isOffset = 100.0
    public real isDamage = 100.0
    public string isSfxTarget = "Abilities\\Spells\\Undead\\Impale\\ImpaleHitTarget.mdl"
    public string isSfxPath1 = "Abilities\\Spells\\Undead\\Impale\\ImpaleMissTarget.mdl"
    public string isSfxPath2 = ""
    public boolean isAffectStructures = false
    public integer isAbilityId = 'A000'
    public integer isLevel = 1
    public integer isOrder = OrderId("thunderbolt")
    unit isCaster = null
    player isOwningPlayer = Player(15)
    real isCasterX = 0.0
    real isCasterY = 0.0
    real isTargetX = 0.0
    real isTargetY = 0.0
    real isRange = 600.0
    boolean isStacking = true
    unit dum
    real rx
    real ry

    static method ImpRun takes nothing returns nothing
        local impaleSystem this = GetTimerData(GetExpiredTimer())
        local group g = NewGroup()
        local unit u
        local real x = GetUnitX(.dum)
        local real y = GetUnitY(.dum)
        local real a = Atan2(.ry-y,.rx-x)
        local real px = x + .isOffset * Cos(a)
        local real py = y + .isOffset * Sin(a)
        local real dx = .rx - x
        local real dy = .ry - y
        local real dis = SquareRoot(dx*dx+dy*dy)
        local impaleToss it
        call GroupEnumUnitsInRange(g,x,y,.isRadius,null)
        call SetUnitX(.dum,px)
        call SetUnitY(.dum,py)
        loop
            set u = FirstOfGroup(g)
            exitwhen u == null
            if .isAffectStructures then
                if IsUnitEnemy(u,.isOwningPlayer) and GetWidgetLife(u) > 0.405 and not IsUnitInGroup(u,DUMMY_GROUP) then
                    if IsUnitType(u, UNIT_TYPE_STRUCTURE) then
                        call UnitDamageTarget(.isCaster,u,.isDamage*0.5,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null)
                        call DestroyEffect(AddSpecialEffect(.isSfxTarget, GetUnitX(u), GetUnitY(u)))
                    endif
                    if GetWidgetLife(u) > 0.405 and not IsUnitType(u,UNIT_TYPE_STRUCTURE) then
                        if .isStacking == false then
                            if DONE[GetUnitId(u)] == false then
                                set DONE[GetUnitId(u)] = true
                                set it = impaleToss.create(.isCaster,u,.isDamage,.isAbilityId,.isLevel,.isOrder)
                                call UnitDamageTarget(.isCaster,u,.isDamage*0.5,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null)
                                call DestroyEffect(AddSpecialEffect(.isSfxTarget, GetUnitX(u), GetUnitY(u)))
                                call UnitShareVision(u,.isOwningPlayer,true)
                            endif
                        else
                            set it = impaleToss.create(.isCaster,u,.isDamage,.isAbilityId,.isLevel,.isOrder)
                            call UnitDamageTarget(.isCaster,u,.isDamage*0.5,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null)
                            call DestroyEffect(AddSpecialEffect(.isSfxTarget, GetUnitX(u), GetUnitY(u)))
                            call UnitShareVision(u,.isOwningPlayer,true)
                        endif
                    endif
                endif
            else
                if IsUnitEnemy(u,.isOwningPlayer) and GetWidgetLife(u) > 0.405 and not IsUnitType(u,UNIT_TYPE_STRUCTURE) and not IsUnitInGroup(u,DUMMY_GROUP) then
                    if GetWidgetLife(u) > 0.405 then
                        if .isStacking == false then
                            if DONE[GetUnitId(u)] == false then
                                set DONE[GetUnitId(u)] = true
                                set it = impaleToss.create(.isCaster,u,.isDamage,.isAbilityId,.isLevel,.isOrder)
                                call UnitDamageTarget(.isCaster,u,.isDamage*0.5,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null)
                                call DestroyEffect(AddSpecialEffect(.isSfxTarget, GetUnitX(u), GetUnitY(u)))
                                call UnitShareVision(u,.isOwningPlayer,true)
                            endif
                        else
                            set it = impaleToss.create(.isCaster,u,.isDamage,.isAbilityId,.isLevel,.isOrder)
                            call UnitDamageTarget(.isCaster,u,.isDamage*0.5,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null)
                            call DestroyEffect(AddSpecialEffect(.isSfxTarget, GetUnitX(u), GetUnitY(u)))
                            call UnitShareVision(u,.isOwningPlayer,true)
                        endif
                    endif
                endif
            endif
            call GroupAddUnit(DUMMY_GROUP,u)
            call GroupRemoveUnit(g,u)
        endloop
        call ReleaseGroup(g)
        if dis <= .isOffset then
            call ReleaseTimer(GetExpiredTimer())
            call GroupClear(DUMMY_GROUP)
            call .destroy()
        else
            call DestroyEffect(AddSpecialEffect(.isSfxPath1,px,py))
            call DestroyEffect(AddSpecialEffect(.isSfxPath2,px,py))
        endif
        set u = null
    endmethod
    
    static method create takes unit cast, real tx, real ty, real range, real wavetime, boolean stacking returns impaleSystem
        local impaleSystem is = impaleSystem.allocate()
        local timer t = NewTimer()
        local location loc = GetUnitLoc(cast)
        local real a
        set is.isStacking = stacking
        set is.isCaster = cast
        set is.isOwningPlayer = GetOwningPlayer(cast)
        set is.isCasterX = GetLocationX(loc)
        set is.isCasterY = GetLocationY(loc)
        set is.isTargetX = tx
        set is.isTargetY = ty
        set is.isRange = range
        set a = Atan2(is.isTargetY-is.isCasterY,is.isTargetX-is.isCasterX)
        set is.dum = CreateUnit(is.isOwningPlayer,DUMMY_CASTER,is.isCasterX,is.isCasterY,0.0)
        call UnitAddAbility(is.dum,'Aloc')
        set is.rx = is.isCasterX + is.isRange * Cos(a)
        set is.ry = is.isCasterY + is.isRange * Sin(a)
        call TimerStart(t,wavetime,true,function impaleSystem.ImpRun)
        call SetTimerData(t,is)
        call RemoveLocation(loc)
        set loc = null
        set t = null
        return is
    endmethod
    
    private method onDestroy takes nothing returns nothing
        call KillUnit(.dum)
        set .dum = null
    endmethod
endstruct

endlibrary


sample usage
JASS:
scope Impale initializer init

private function con takes nothing returns boolean
    return GetSpellAbilityId() == 'A001'
endfunction

private function act takes nothing returns nothing
    local unit cast = GetTriggerUnit()
    local location loc = GetSpellTargetLoc()
    local real x = GetLocationX(loc)
    local real y = GetLocationY(loc)
    local impaleSystem is = impaleSystem.create(cast,x,y,700.0,0.08, true)
    call RemoveLocation(loc)
    set loc = null
    set cast = null
endfunction

private function init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddAction(t,function act)
    call TriggerAddCondition(t,Condition(function con))
endfunction

endscope
 

waaaks!

Zinctified
Reaction score
255
theres no problem on jumping, the only problem is it sometimes stuck the units above the air, i doubt about the MUI-ness of the spell not the jump at all
 

waaaks!

Zinctified
Reaction score
255
i always debug my codes before posting it here, ever tried earth slam by titan in rotg? theres no bug right? but there is this "rare bug" thing, which i hate most, which "sometimes" stuck the unit on the air, and never falls back again, i really dont know whats the cause of that
 

Technomancer

New Member
Reaction score
14
I'd ask a couple of questions:
First of all, does this only happen when using the spell against multiple units at the same time? Or does it happen only when you cast the same spell repeatedly on one unit? Or is it entirely random?

Is the unit still paused after the glitch occurs? How high are the units from the ground (I assume maximum height?)

The only way I would know of to avoid duplicate impales is to put a unit in a struct and give it a boolean beingImpaled, or doing a height check on them at the time impale activates, and you could work from there.
 

waaaks!

Zinctified
Reaction score
255
First of all, does this only happen when using the spell against multiple units at the same time? Or does it happen only when you cast the same spell repeatedly on one unit? Or is it entirely random?
completely random
Is the unit still paused after the glitch occurs?
yes it is still paused
How high are the units from the ground (I assume maximum height?)
i can no longer see the unit

i already dont have any height check i just completely rely on the offset
JASS:
static method impToss takes nothing returns nothing
        local timer tim = GetExpiredTimer()
        local impaleToss it = GetTimerData(tim)
        local real height = GetUnitFlyHeight(it.targ)
        
        //*****************************************************************************
        //* the unit has reached the maximum height, make it fall (FALL[unit] = 1, and
        //*     ONCE[unit] = 1 for conditional uses only)
        if off1[it.targ] < 0.0 and ONCE[it.targ] == 0 then
            set FALL[it.targ] = 1
            set ONCE[it.targ] = 1
        endif
        
        //*****************************************************************************
        //* if unit is not falling then that means it is rising (DUH!), make unit rise
        if FALL[it.targ] == 0 then
            set off1[it.targ] = off1[it.targ] - 3.0
            call SetUnitFlyHeight(it.targ,height+off1[it.targ],0.0)
            call SetUnitPathing(it.targ, false)
            call PauseUnit(it.targ,true)
        else //make unit fall
            set off1[it.targ] = off1[it.targ] + 3.0
            call SetUnitFlyHeight(it.targ,height-off1[it.targ],0.0)
            call PauseUnit(it.targ,true)
            call SetUnitPathing(it.targ,false)
        endif
        
        //*****************************************************************************
        //* if unit is already near land, also ONCE[unit] is used to check if the unit
        //* is already damaged or not then do some stuffs
        if GetUnitFlyHeight(it.targ) <= 15 and ONCE[it.targ] == 1 then
            call ReleaseTimer(tim)
            call it.destroy()
        endif
        set tim = null
    endmethod


i wanted the system to stack with each other, when a unit is being impaled, and when another impale system based spell is casted on that unit, the unit will jump again
 

wraithseeker

Tired.
Reaction score
122
I think it's PUI issue, when my KB system used PUI, it had problem stacking.
Take a look at PUI release macro and see that it does not allow stacking.
 

waaaks!

Zinctified
Reaction score
255
in wc3c.net a user said that i will use autoindex instead of pui, ill try it later
 

waaaks!

Zinctified
Reaction score
255
bump, updated the thread, now i need something like improving the code and some leak check that could possibly lag the game, especially the part when the unit starts jumping, i wanted to use some sort of smooth jumping for this, also i dont know how to initialize the off1 to something like 60 in autoindex (while pui has PUI_PROPERTY), so that i can decrement it, and then increment it when the unit starts falling (to add velocity), which will be useful for smooth jumping

-now replaced PUI with autoindex
 

wraithseeker

Tired.
Reaction score
122
Change those arrays off? Aren't you creating one struct instance per unit since it's a impale system and PUI property is just adding a struct member there for you to use.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top