System Impale System

Angel_Island

Much long, many time, wow
Impale System (IMPS)
By Angel_Island

Code:
JASS:
library IMPS initializer InitTrig
//=====================================================================================\\
//                                                                                     \\
//                                Impale System (IMPS)                                 \\
//                                  By Angel_Island                                    \\
//                                                                                     \\
//      This system makes easy configurable impale spells.                             \\
//      It allows impaling targets multiple times even when the target is in mid-air   \\
//                                                                                     \\
//      Requires:                                                                      \\
//          - A vJASS preprocessor like NewGen.                                        \\
//          - A dummy unit.                                                            \\
//                                                                                     \\
//=====================================================================================\\

//=====================================================================================\\
//                                                                                     \\
//      How to implement:                                                              \\
//                                                                                     \\
//      1. Create a new trigger in your map. Convert it to custom text. Copy this      \\
//         entire script and paste it in the new trigger overwriting what was inside.  \\
//         Or if you want to do it the easy way, just copy this trigger to your map.   \\
//                                                                                     \\
//      2. Create a dummy unit or copy the dummy in this map. Should have Id 'h000'.   \\
//         Else change it below in configurables.                                      \\
//                                                                                     \\
//      3. Done! Try it out by making a spell using this system.                       \\
//                                                                                     \\
//=====================================================================================\\

//==============================================================================================================================================================\\
//                                                                                                                                                              \\
//      How to use:                                                                                                                                             \\
//                                                                                                                                                              \\
//                     call IMPS_Start(Caster,X,Y,Range,Damage,StunDuration,Angle)                                                                              \\
//                             - Gives you a normal impale that uses x,y                                                                                        \\
//                                                                                                                                                              \\
//                                                 or                                                                                                           \\
//                                                                                                                                                              \\
//                   call IMPS_StartLoc(Caster,Point,Range,Damage,StunDuration,Angle)                                                                           \\
//                             - Gives you a normal impale that uses locations                                                                                  \\
//                                                                                                                                                              \\
//                                                 or                                                                                                           \\
//                                                                                                                                                              \\
//call IMPS_StartLocEx(Caster,Point,CastPoint,Range,Damage,StunDuration,Angle,Area,Height,AirTime,SpikeSfx,HitSfx,StunSfx,AttPoint,RangeBased,MoveUnit,HideUnit)\\
//                             - Gives you a more customizable impale that uses locations                                                                       \\
//                                                                                                                                                              \\
//                                                 or                                                                                                           \\
//                                                                                                                                                              \\
//call IMPS_StartEx(Caster,X,Y,CastX,CastY,Range,Damage,StunDuration,Angle,Area,Height,AirTime,SpikeSfx,HitSfx,StunSfx,AttPoint,RangeBased,MoveUnit,HideUnit)   \\
//                             - Gives you a more customizable impale that uses x,y                                                                             \\
//                                                                                                                                                              \\
//      Caster:         The unit who casted the spell or whatever it did.                                                                                       \\
//      Point:          The point where the impale begins.                                                                                                      \\
//      X,Y:            x,y coordinates of the Caster.                                                                                                          \\
//      CastPoint:      The point where the spell is cast. Not needed if RangeBased = false                                                                     \\
//      CastX,CastY:    x,y coordinates of target point. Not needed if RangeBased = false                                                                       \\
//      Range:          How long the impale will go. Not needed if RangeBased = true.                                                                           \\
//      Damage:         How much damage that will be dealt to the targets.                                                                                      \\
//      StunDuration:   How long the impale will stun the targets. Can be set to 0.00 without stunning forever.                                                 \\
//      Angle:          The angle the impale will go. Must be in degrees.                                                                                       \\
//      Area:           How big area the impale will have when picking targets.                                                                                 \\
//      Height:         How high up in the air the targets will fly.                                                                                            \\
//      AirTime:        How long time in the air the targets will be.                                                                                           \\
//      SpikeSfx:       Model for the spikes.                                                                                                                   \\
//      HitSfx:         Effect when targets are hit.                                                                                                            \\
//      StunSfx:        Effect when targets are stunned.                                                                                                        \\
//      AttPoint:       Where StunSfx is attached on the target                                                                                                 \\
//      RangeBased:     This will decide if the impale will be based on how far away you cast your impale. Won't work if                                        \\
//                      there is no target location.                                                                                                            \\
//      MoveUnit:       Decides if the Caster will be moved to the end of the impale.                                                                           \\
//      HideUnit:       Decides if you want to hide the Caster while the impale is in effect. Good for spells like                                              \\
//                      Burrowstrike from DotA where the caster digs underground and pops up at the end of the impale                                           \\
//                                                                                                                                                              \\
//==============================================================================================================================================================\\

//=====================================================================================\\
//                                                                                     \\
//      Other functions:                                                               \\
//                                                                                     \\
//      call IsUnitImpaled(Unit):  Checks if the Unit is in mid-air caused by an impale\\
//                                 Good for making things happen if the Unit is in     \\
//                                 mid-air.                                            \\
//                                                                                     \\
//=====================================================================================\\


//CONFIGURABLES:

globals
    private constant real    HEIGHT         = 500.00
    //How high up the targets will fly. Used in IMPS_Start(Loc).
    
    private constant real    AREA           = 175.00
    //How big area the impale will have when picking targets. Used in IMPS_Start(Loc).
    
    private constant real    AIRTIME        = 1.00
    //How long time in the air the targets will be. Used in IMPS_Start(Loc).
    
    constant         string  SPIKE_SFX      = "Abilities\\Spells\\Undead\\Impale\\ImpaleMissTarget.mdl"
    //Model for the spikes for IMPS_Start(Loc). This is not private so you can use this
    //variable instead of have to type in everything.
    
    constant         string  HIT_SFX        = "Abilities\\Spells\\Undead\\Impale\\ImpaleHitTarget.mdl"
    //Effect when targets are hit for IMPS_Start(Loc). Same reason as above why it isnt private.

    constant         string  STUN_SFX       = "Abilities\\Spells\\Human\\Thunderclap\\ThunderclapTarget.mdl"
    //Effect when targets are stunned for IMPS_Start(Loc).
    
    constant         string  ATT_POINT      = "overhead"
    //Where StunSfx is attached on the targets.
    
    private constant real    SPACE          = 150.00
    //Space between every spike. I recommend you leave this as it is.
    
    private constant real    SPIKE_INTERVAL = 0.10
    //Interval between spawning spikes.
    
    private constant real    INTERVAL       = 0.03
    //Interval between height change. You should leave this as it is.
    
    private constant integer STORM_CROW     = 'Arav'
    //Raw code for Storm crow form.
    
    private constant integer DUMMY          = 'h000'
    //Raw code for Dummy.
    
endglobals

//=====================================================================//
//                                                                     //
//       DON'T TOUCH BELOW HERE UNLESS YOU KNOW WHAT YOU ARE DOING     //
//                                                                     //
//=====================================================================//
private keyword Data

globals
    private Data      array Dt
    private unit      array caster
    private unit      array ImpaledUnit
    private integer   array in
    private integer   array I
    private integer         I2        = 0
    private integer         Instances = 0
    private integer         CusVal    = 0
    private integer         Loop      = 1
    private integer         Loop2     = 1
    private timer           Timer     = CreateTimer()
    private timer           Timer2    = CreateTimer()
    private timer           Timer3    = CreateTimer()
    private real      array n
    private real      array x
    private real      array y
    private real      array damage
    private real      array airtime
    private real      array stunduration
    private real      array height
    private string    array hitsfx
    private string    array stunsfx
    private string    array attpoint
    private group     array G
    private group     array StunG
    private effect    array stuneffect
    private hashtable       h         = InitHashtable()
endglobals

//======================================================================
private struct Data
    unit     caster       = null
    effect   sfx          = null
    real     px           = 0.00
    real     py           = 0.00
    real     castrange    = 0.00
    real     range        = 0.00
    real     stunduration = 0.00
    real     sin          = 0.00
    real     cos          = 0.00
    real     area         = 0.00
    real     airtime      = 0.00
    real     damage       = 0.00
    real     height       = 0.00
    string   spikesfx     = ""
    string   hitsfx       = ""
    string   stunsfx      = ""
    string   attpoint     = ""
    boolean  based        = false
    boolean  moveunit     = false
    boolean  hideunit     = false
    
    static method create takes unit Caster, real X, real Y, real CastX, real CastY, real Range, real Damage, real StunDuration, real Angle, real Area, real Height, real AirTime, string SpikeSfx, string HitSfx, string StunSfx, string AttPoint, boolean RangeBased, boolean MoveUnit, boolean HideUnit returns Data
        local Data d = Data.allocate()
        local real dx = 0.00
        local real dy = 0.00
        
        set dx = CastX - X
        set dy = CastY - Y
        
        set d.caster       = Caster
        set d.px           = X
        set d.py           = Y
        set d.castrange    = SquareRoot(dx * dx + dy * dy)
        set d.range        = Range
        set d.damage       = Damage
        set d.stunduration = StunDuration
        set d.sin          = Sin(Angle)
        set d.cos          = Cos(Angle)
        set d.area         = Area
        set d.height       = Height
        set d.airtime      = AirTime
        set d.spikesfx     = SpikeSfx
        set d.hitsfx       = HitSfx
        set d.stunsfx      = StunSfx
        set d.attpoint     = AttPoint
        set d.based        = RangeBased
        set d.moveunit     = MoveUnit
        set d.hideunit     = HideUnit
        
        return d
    endmethod
    
endstruct

//=====================================================================
private function Check_Units takes nothing returns boolean
    local unit u
    local player p
    set u = GetFilterUnit()
    set p = GetOwningPlayer(caster[Loop])
    return IsUnitEnemy(u,p) and GetWidgetLife(u) > 0 and IsUnitType(u,UNIT_TYPE_STRUCTURE) == false and u != caster[Loop] and IsUnitInGroup(u,G[Loop]) == false
endfunction

private function Check_Dummy takes nothing returns boolean
    return GetUnitTypeId(GetTriggerUnit()) == DUMMY
endfunction

private function CountUnits takes nothing returns nothing
    set bj_groupCountUnits = bj_groupCountUnits + 1
endfunction

//=====================================================================
private function Flying takes nothing returns nothing
    local real xx
    local real yy
    local unit u
    local unit un
    
    set I[Loop2] = I[Loop2] + 1
    set u = GetEnumUnit()
    call PauseUnit(u,true)
    call SaveReal(h,I[Loop2],Loop2,LoadReal(h,I[Loop2],Loop2) + (SquareRoot(height[Loop2]) * 2.00) / (airtime[Loop2] / INTERVAL))
    call SetUnitFlyHeight(u,(height[Loop2]) - (SquareRoot(height[Loop2]) - LoadReal(h,I[Loop2],Loop2)) * (SquareRoot(height[Loop2]) - LoadReal(h,I[Loop2],Loop2)),0.00)
    if GetUnitFlyHeight(u) <= (SquareRoot(height[Loop2]) * 2.00) / (airtime[Loop2] / INTERVAL) then
        set I2 = I2 + 1
        call PauseUnit(u,false)
        call SetUnitPathing(u,true)
        call SetUnitFlyHeight(u,GetUnitDefaultFlyHeight(u),0.00)
        call UnitDamageTarget(caster[Loop2],u,damage[Loop2],true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_UNKNOWN,WEAPON_TYPE_WHOKNOWS)
        call GroupRemoveUnit(G[Loop2],u)
        if GetUnitState(u,UNIT_STATE_LIFE) > 0 and stunduration[Loop2] > 0.00 then
            set CusVal = CusVal + 1
            set StunG[CusVal] = CreateGroup()
            call GroupAddUnit(StunG[CusVal],u)
            set ImpaledUnit[CusVal] = u
            set stuneffect[CusVal] = AddSpecialEffectTarget(stunsfx[Loop2],u,attpoint[Loop2])
            set xx = GetUnitX(u)
            set yy = GetUnitY(u)
            set un = CreateUnit(GetOwningPlayer(caster[Loop2]),DUMMY,xx,yy,270.00)
            call UnitApplyTimedLife(un,'BTLF',stunduration[Loop2])
            call SetUnitUserData(un,CusVal)
        endif
        set bj_groupCountUnits = 0
        call ForGroup(G[Loop2],function CountUnits)
        if bj_groupCountUnits == 0 and Dt[Loop2] == 0 then
            call DestroyGroup(G[Loop2])
            set I2 = 0
        endif
    endif
    set u = null
endfunction

private function Flying_Init takes nothing returns nothing
    local real     xx
    local real     yy
    local effect   e
    local unit     u
    
    set u = GetEnumUnit()
    set xx = GetUnitX(u)
    set yy = GetUnitY(u)
    set e = AddSpecialEffect(hitsfx[Loop],xx,yy)
    call DestroyEffect(e)
    call UnitAddAbility(u,STORM_CROW)
    call UnitRemoveAbility(u,STORM_CROW)
    call PauseUnit(u,true)
    call SetUnitPathing(u,false)
    call GroupAddUnit(G[Loop],u)
    set e = null
    set u = null
endfunction

private function Call_Flying takes nothing returns nothing
    loop
        exitwhen Loop2 > Instances
        call ForGroup(G[Loop2],function Flying)
        set I[Loop2] = I2
        set Loop2 = Loop2 + 1
    endloop
    set Loop2 = 1
endfunction

//=====================================================================
private function Stun takes nothing returns nothing
    local real xx
    local real yy
    
    set xx = GetUnitX(GetEnumUnit())
    set yy = GetUnitY(GetEnumUnit())
    call SetUnitPosition(GetEnumUnit(),xx,yy)
endfunction

private function Call_Stun takes nothing returns nothing
    local integer i = 1

    loop
        exitwhen i > CusVal
        call ForGroup(StunG<i>,function Stun)
        set i = i + 1
    endloop
endfunction

private function Remove_Stun takes nothing returns nothing
    call GroupRemoveUnit(StunG[GetUnitUserData(GetTriggerUnit())],ImpaledUnit[GetUnitUserData(GetTriggerUnit())])
    call DestroyEffect(stuneffect[GetUnitUserData(GetTriggerUnit())])
endfunction

//=====================================================================
private function SpawnSpikes takes nothing returns nothing
    local Data     d = 0
    local group    g = CreateGroup()
    local real     dx = 0.00
    local real     dy = 0.00
    
    loop
        exitwhen Loop &gt; Instances
        if Dt[Loop] != 0 then
            set d = Dt[Loop]
            set caster[Loop] = d.caster
            set airtime[Loop] = d.airtime
            set damage[Loop] = d.damage
            set stunduration[Loop] = d.stunduration
            set height[Loop] = d.height
            set hitsfx[Loop] = d.hitsfx
            set stunsfx[Loop] = d.stunsfx
            set attpoint[Loop] = d.attpoint
            set in[Loop] = in[Loop] + 1
            set x[Loop] = d.px + (SPACE * in[Loop]) * d.cos
            set y[Loop] = d.py + (SPACE * in[Loop]) * d.sin
            set d.sfx = AddSpecialEffect(d.spikesfx,x[Loop],y[Loop])
            call DestroyEffect(d.sfx)
            call GroupEnumUnitsInRange(g,x[Loop],y[Loop],d.area,Condition(function Check_Units))
            call ForGroup(g,function Flying_Init)
            call DestroyGroup(g)
            set g = CreateGroup()
            set dx = d.px - x[Loop]
            set dy = d.py - y[Loop]
                
            if d.based then
                if SquareRoot(dx * dx + dy * dy) &gt;= d.castrange then
                    if d.moveunit then
                        call SetUnitX(d.caster,d.px + (SPACE * in[Loop]) * d.cos)
                        call SetUnitY(d.caster,d.py + (SPACE * in[Loop]) * d.sin)
                    endif
                    if d.hideunit then
                        call ShowUnit(d.caster,true)
                        if GetLocalPlayer() == GetOwningPlayer(d.caster) then
                            call SelectUnit(d.caster, true)
                        endif
                    endif
                    set x[Loop] = 0
                    set y[Loop] = 0
                    set in[Loop] = 0
                    set Dt[Loop] = 0
                    set bj_groupCountUnits = 0
                    call ForGroup(G[Loop],function CountUnits)
                    if bj_groupCountUnits == 0 and Dt[Loop] == 0 then
                        call DestroyGroup(G[Loop])
                        set I2 = 0
                    endif
                endif
            elseif SquareRoot(dx * dx + dy * dy) &gt;= d.range then
                if d.moveunit then
                    call SetUnitX(d.caster,d.px + (SPACE * in[Loop]) * d.cos)
                    call SetUnitY(d.caster,d.py + (SPACE * in[Loop]) * d.sin)
                endif
                if d.hideunit then
                    call ShowUnit(d.caster,true)
                    if GetLocalPlayer() == GetOwningPlayer(d.caster) then
                        call SelectUnit(d.caster, true)
                    endif
                endif
                set x[Loop] = 0
                set y[Loop] = 0
                set in[Loop] = 0
                set Dt[Loop] = 0
                set bj_groupCountUnits = 0
                call ForGroup(G[Loop],function CountUnits)
                if bj_groupCountUnits == 0 and Dt[Loop] == 0 then
                    call DestroyGroup(G[Loop])
                    set I2 = 0
                endif
            endif
        endif
        set Loop = Loop + 1
    endloop
    set Loop = 1
    set g = null
endfunction

//=====================================================================
function IsUnitImpaled takes unit u returns boolean
    local integer i = 1
    
    loop
        exitwhen i &gt; Instances
        if IsUnitInGroup(u,G<i>) then
            return true
        endif
        set i = i + 1
    endloop
    
    return false
endfunction

//=====================================================================
public function StartEx takes unit Caster, real X, real Y, real CastX, real CastY, real Range, real Damage, real StunDuration, real Angle, real Area, real Height, real AirTime, string SpikeSfx, string HitSfx, string StunSfx, string AttPoint, boolean RangeBased, boolean MoveUnit, boolean HideUnit returns boolean
    local Data d = 0
    
    if RangeBased == false then
        if Area &lt; 0.00 or StunDuration &lt; 0.00 or Range &lt;= 0.00 then
            debug call BJDebugMsg(&quot;Error: Invalid input in IMPS_Start()&quot;)
            return false
        endif
    elseif Area &lt; 0.00 or StunDuration &lt; 0.00 then
        debug call BJDebugMsg(&quot;Error: Invalid input in IMPS_Start()&quot;)
        return false
    endif
    
    set d = Data.create(Caster,X,Y,CastX,CastY,Range,Damage,StunDuration,(Angle * 0.01745328),Area,Height,AirTime,SpikeSfx,HitSfx,StunSfx,AttPoint,RangeBased,MoveUnit,HideUnit)
    
    set Instances = Instances + 1
    set G[Instances] = CreateGroup()
    call TimerStart(Timer,SPIKE_INTERVAL,true,function SpawnSpikes)
    call TimerStart(Timer2,INTERVAL,true,function Call_Flying)
    call TimerStart(Timer3,0.03,true,function Call_Stun)
    set Dt[Instances] = d
    if HideUnit then
        call ShowUnit(Caster,false)
    endif
    
    return true
endfunction

//====================================================================
public function StartLocEx takes unit Caster, location Point, location CastPoint, real Range, real Damage, real StunDuration, real Angle, real Area, real Height, real AirTime, string SpikeSfx, string HitSfx, string StunSfx, string AttPoint, boolean RangeBased, boolean MoveUnit, boolean HideUnit returns nothing
    call IMPS_StartEx(Caster,GetLocationX(Point),GetLocationY(Point),GetLocationX(CastPoint),GetLocationY(CastPoint),Range,Damage,StunDuration,Angle,Area,Height,AirTime,SpikeSfx,HitSfx,StunSfx,AttPoint,RangeBased,MoveUnit,HideUnit)
endfunction

public function StartLoc takes unit Caster, location Point, real Range, real Damage, real StunDuration, real Angle returns nothing
    call IMPS_StartEx(Caster,GetLocationX(Point),GetLocationY(Point),0.00,0.00,Range,Damage,StunDuration,Angle,AREA,HEIGHT,AIRTIME,SPIKE_SFX,HIT_SFX,STUN_SFX,ATT_POINT,false,false,false)
endfunction

public function Start takes unit Caster, real X, real Y, real Range, real Damage, real StunDuration, real Angle returns nothing
    call IMPS_StartEx(Caster,X,Y,0.00,0.00,Range,Damage,StunDuration,Angle,AREA,HEIGHT,AIRTIME,SPIKE_SFX,HIT_SFX,STUN_SFX,ATT_POINT,false,false,false)
endfunction
//====================================================================
private function InitTrig takes nothing returns nothing
    local trigger t = CreateTrigger()
    local integer index = 0
    loop
        call TriggerRegisterPlayerUnitEvent(t,Player(index),EVENT_PLAYER_UNIT_DEATH,null)
        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop
    call TriggerAddCondition(t,Condition(function Check_Dummy))
    call TriggerAddAction(t,function Remove_Stun)
endfunction

endlibrary</i></i>

This is my first time coding in vJass. It was little hard to understand at first, but later it became easy and I made this Impale System and I want to know what you think about my first vJass code.

Updates:
Version 1.30: 2 new functions and more configurables

Version 1.20: Some fixes, removed location usage and removed UnitUserData Usage

Version 1.10: Some fixes, code improvement and new function

Version 1.00: Initial Release
 

Attachments

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Remove usage of locations(slower), long function parameters(like worms), BJ(slower), UnitUserData(interrupt the unit indexing system).

JASS:
    call TimerStart(Timer3,0.01,true,function Call_Stun)

Cause performance issue. 0.03125 is good for it.

JASS:
function InitTrig takes nothing returns nothing

Should be private.

JASS:
    private constant string  SPIKE_SFX

You should let users use their custom models.

JASS:
Recommended values are 0.01-0.04.

Recommended values are above 0.03

JASS:
    private constant integer STORM_CROW     = 'Arav'

You can use AutoFly for it.

JASS:
    private integer       Cv        = 0
    private integer       Cv2       = 0

Needs better naming method.

JASS:
private function Check_Units takes nothing returns boolean
    local Data d = 0
    set d = Dt[Loop]
    return IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(d.caster)) and GetUnitState(GetFilterUnit(),UNIT_STATE_LIFE) &gt; 0 and IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE) == false and GetFilterUnit() != d.caster and IsUnitInGroup(GetFilterUnit(),G[Loop]) == false
endfunction

JASS:
private function Flying takes nothing returns nothing

Store the d.caster's owner + GetFilterUnit + GetEnumUnit into variable to reduce function calls.

JASS:
        call BJDebugMsg(&quot;Error: Invalid input in IMPS_Start()&quot;)

Should be debug call BJDebugMsg("...")
 

Executor

I see you
Okay, lets begin:

- Never (!) use UnitUserData, that way you fuck up the most indexing systems.

- Syntax of common create method should be:
JASS:
static method create takes ..arguments.. returns thistype
   local thistype this = thistype.allocate()
   // ... code ...
   // due to the var &quot;this&quot; you can use &quot;.caster&quot; for ex. to access
   // the vars of this instance. &quot;.caster&quot; equals &quot;this.caster&quot;
   return this
endmethod


- Never (!) use locations (except for the known "GetFloorHeight" func). You can nearly always directly access the x,y-coordinates. (SetUnitX+SetUnitY instead of SetUnitPosition!)

- Why 3 timers? combine all in one.

- A neat advantage of vJass is, that you can move all struct related functions as methods into the struct. Globals can also join the struct as static variables (or constants).

Thats a template, how such a system could look like.

JASS:
struct Impale
   // configuration
   private static constant string HIT_SFX = &quot;blabla.mdx&quot;
   
   private static method damageLoss takes real distance returns real
       return - distance * 5.
   endmethod
   // endconfiguration

   private static timer TheTimer
   private static thistype TempInstance // for enumerations
   private static thistype First // for linked list (looping via linked list is faster than an array loop!)

   private unit caster
   private real damage

   private thistype next // linked list
   private thistype last  // linked list

   private static method onTimer takes nothing returns nothing
       local thistype this = .First
       loop
           exitwhen this.next == 0
           // code
           set this = this.next // the linked list magic <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite7" alt=":p" title="Stick Out Tongue    :p" data-shortname=":p" />
       endloop
   endmethod

   private static method cast takes unit caster, real sourcex, real sourcey, real targetx, real targety, real damage ... returns nothing
      local thistype this = thistype.allocate ..
      // ...
   endmethod
   private static method onInit takes nothing returns nothing
       set .TheTimer = CreateTimer()
       call TimerStart(.TheTimer,0.03125,true,function thistype.onTimer)
   endmethod
endstruct
 

Angel_Island

Much long, many time, wow
kingkingyyk3:

- Remove usage of locations(slower), long function parameters(like worms), BJ(slower), UnitUserData(interrupt the unit indexing system).

The system works fine, so why should I need remove usage of locations? I have now created another function that is shorter for easier use. BJs removed. I can't find a solution for replacing UnitUserData right now.

- Cause performance issue. 0.03125 is good for it.

- Should be private.

- You should let users use their custom models.

- Recommended values are above 0.03

- Needs better naming method.

- Store the d.caster's owner + GetFilterUnit + GetEnumUnit into variable to reduce function calls.

- Should be debug call BJDebugMsg("...")

Fixed all above.

- You can use AutoFly for it.

Why do I need that?


Executor:

- Never (!) use UnitUserData, that way you fuck up the most indexing systems.

As I said above I can't find a solution for replacing UnitUserData right now.

- Never (!) use locations (except for the known "GetFloorHeight" func). You can nearly always directly access the x,y-coordinates. (SetUnitX+SetUnitY instead of SetUnitPosition!)

Why not? Is it because it is slower? What is the diffrence?

- Why 3 timers? combine all in one.

How?
 

Executor

I see you
- Remove usage of locations(slower), long function parameters(like worms), BJ(slower), UnitUserData(interrupt the unit indexing system).

The system works fine, so why should I need remove usage of locations? I have now created another function that is shorter for easier use. BJs removed. I can't find a solution for replacing UnitUserData right now.
Locations are slower (!) and can leak when not removed.

- You can use AutoFly for it.

Why do I need that?
Cause AutoFly uses the crow-form-bug on all units exactly once and that when they enter the map. Your code will use the bug on every unit hit even if it can already "fly".

- Why 3 timers? combine all in one.

How?
Reduce an integer in the onTimer function, do the things you want on a specific "tick" and reset it when it becomes 0.

I'd like to help you with UnitUserData and the Timer thing, but I your code is really hard to read (for me).
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Great improvement.

To achieve :
Use XY instead of location
Remove usage of UnitUserData, replace it with hashtable/unit indexing system.
 

eclypt

New Member
JASS:
globals
    private constant real    HEIGHT         = 500.00
    //How high up the targets will fly. Used in IMPS_Start.


whats the wrong with this? i still gotting Syntax Error with this


{My bad english owns xD}
 

Laiev

Hey Listen!!
is just with me or your template don't work?

I mean, the effect happen and etc, everything work except damage lol

EDIT: suggestion: if you don't want to remove location, just ok but make a new function which support x/y, most of people like it and is more safe then location, also a little bit faster :p

EDIT²: well, this version the damage happen but you still using user data and location D: i don't see any thing what you change in changelog in trigger, also you forget to update the code :x
 

BlackRose

Forum User
- Can you make it not hit units already in the air? I know it is like that in DotA and that people will want what DotA has, but I think you should make it hit units only within height range.
- [ljass]GetWidgetLife()[/ljass] is I hear better than [ljass]GetUnitState[/jass].
- [ljass]"Abilities\\Spells\\Human\\Thunderclap\\ThunderclapTarget.mdl"[/ljass], Am I seeing right? An effect NOT configurable?
 

Laiev

Hey Listen!!
Ya, you see it lol

I really don't understand what he update... in the code he still using location and unit date :confused:

here is the updated script from the test map:

JASS:
library IMPS initializer InitTrig
//=====================================================================================\\
//                                                                                     \\
//                                Impale System (IMPS)                                 \\
//                                  By Angel_Island                                    \\
//                                                                                     \\
//      This system makes easy configurable impale spells.                             \\
//      It allows impaling targets multiple times even when the target is in mid-air   \\
//                                                                                     \\
//      Requires:                                                                      \\
//          - A vJASS preprocessor like NewGen.                                        \\
//          - A dummy unit.                                                            \\
//                                                                                     \\
//=====================================================================================\\

//=====================================================================================\\
//                                                                                     \\
//      How to implement:                                                              \\
//                                                                                     \\
//      1. Create a new trigger in your map. Convert it to custom text. Copy this      \\
//         entire script and paste it in the new trigger overwriting what was inside.  \\
//         Or if you want to do it the easy way, just copy this trigger to your map.   \\
//                                                                                     \\
//      2. Create a dummy unit or copy the dummy in this map.                          \\
//                                                                                     \\
//      3. Done! Try it out by making a spell using this system.                                \\
//                                                                                     \\
//=====================================================================================\\

//==========================================================================================================================================\\
//                                                                                                                                          \\
//      How to use:                                                                                                                         \\
//                                                                                                                                          \\
//                     call IMPS_Start(Caster,Point,Range,Damage,StunDuration,Angle)                                                        \\
//                                      - Gives you a normal impale                                                                         \\
//                                                                                                                                          \\
//                                                 or                                                                                       \\
//                                                                                                                                          \\
//call IMPS_StartEx(Caster,Point,CastPoint,Range,Damage,StunDuration,Angle,Area,Height,AirTime,SpikeSfx,HitSfx,RangeBased,MoveUnit,HideUnit)\\
//                                 - Gives you a more customizable impale                                                                   \\
//                                                                                                                                          \\
//      Caster:         The unit who casted the spell or whatever it did.                                                                   \\
//      Point:          The point where the impale begins.                                                                                  \\
//      CastPoint:      The point where the spell is cast. Not needed if RangeBased = false                                                 \\
//      Range:          How long the impale will go. Not needed if RangeBased = true.                                                       \\
//      Damage:         How much damage that will be dealt to the targets.                                                                  \\
//      StunDuration:   How long the impale will stun the targets. Can be set to 0.00 without stunning forever.                             \\
//      Angle:          The angle the impale will go. Must be in degrees.                                                                   \\
//      Area:           How big area the impale will have when picking targets.                                                             \\
//      Height:         How high up in the air the targets will fly.                                                                        \\
//      AirTime:        How long time in the air the targets will be.                                                                       \\
//      RangeBased:     This will decide if the impale will be based on how far away you cast your impale. Won't work if                    \\
//                      there is no target location.                                                                                        \\
//      SpikeSfx:       Model for the spikes.                                                                                               \\
//      HitSfx:         Effect when targets are hit.                                                                                        \\
//      MoveUnit:       Decides if the Caster will be moved to the end of the impale.                                                       \\
//      HideUnit:       Decides if you want to hide the Caster while the impale is in effect. Good for spells like                          \\
//                      Burrowstrike from DotA where the caster digs underground and pops up at the end of the impale                       \\
//                                                                                                                                          \\
//==========================================================================================================================================\\

//=====================================================================================\\
//                                                                                     \\
//      Other functions:                                                               \\
//                                                                                     \\
//      call IsUnitImpaled(Unit):  Checks if the Unit is in mid-air caused by an impale\\
//                                 Good for making things happen if the Unit is in     \\
//                                 mid-air.                                            \\
//                                                                                     \\
//=====================================================================================\\


//CONFIGURABLES:

globals
    private constant real    HEIGHT         = 500.00
    //How high up the targets will fly. Used in IMPS_Start.
    
    private constant real    AREA           = 175.00
    //How big area the impale will have when picking targets. Used in IMPS_Start.
    
    private constant real    AIRTIME        = 1.00
    //How long time in the air the targets will be. Used in IMPS_Start.
    
    constant         string  SPIKE_SFX      = &quot;Abilities\\Spells\\Undead\\Impale\\ImpaleMissTarget.mdl&quot;
    //Model for the spikes for IMPS_Start. This is not private so you can use this
    //variable instead of have to type in everything.
    
    constant         string  HIT_SFX        = &quot;Abilities\\Spells\\Undead\\Impale\\ImpaleHitTarget.mdl&quot;
    //Effect when targets are hit for IMPS_Start. Same reason as above why it isnt private.

    private constant real    SPACE          = 150.00
    //Space between every spike. I recommend you leave this as it is.
    
    private constant real    SPIKE_INTERVAL = 0.10
    //Interval between spawning spikes.
    
    private constant real    INTERVAL       = 0.03
    //Interval between height change. You should leave this as it is.
    
    private constant integer STORM_CROW     = 'Arav'
    //Raw code for Storm crow form.
    
    private constant integer DUMMY          = 'h000'
    //Raw code for Dummy.
    
endglobals

//=====================================================================//
//                                                                     //
//       DON'T TOUCH BELOW HERE UNLESS YOU KNOW WHAT YOU ARE DOING     //
//                                                                     //
//=====================================================================//
private keyword Data

globals
    private Data      array Dt
    private unit      array caster
    private unit      array ImpaledUnit
    private integer   array in
    private integer   array I
    private integer         I2        = 0
    private integer         Instances = 0
    private integer         CusVal    = 0
    private integer         Loop      = 1
    private integer         Loop2     = 1
    private timer           Timer     = CreateTimer()
    private timer           Timer2    = CreateTimer()
    private timer           Timer3    = CreateTimer()
    private real      array n
    private real      array x
    private real      array y
    private real      array damage
    private real      array airtime
    private real      array stunduration
    private real      array height
    private string    array hitsfx
    private group     array G
    private group     array StunG
    private effect    array stuneffect
    private hashtable       h         = InitHashtable()
endglobals

//======================================================================
private struct Data
    unit     caster       = null
    location point        = null
    effect   sfx          = null
    real     castrange    = 0.00
    real     range        = 0.00
    real     stunduration = 0.00
    real     sin          = 0.00
    real     cos          = 0.00
    real     area         = 0.00
    real     airtime      = 0.00
    real     damage       = 0.00
    real     height       = 0.00
    string   spikesfx     = &quot;&quot;
    string   hitsfx       = &quot;&quot;
    boolean  based        = false
    boolean  moveunit     = false
    boolean  hideunit     = false
    
    static method create takes unit Caster, location Point, location CastPoint, real Range, real Damage, real StunDuration, real Angle, real Area, real Height, real AirTime, string SpikeSfx, string HitSfx, boolean RangeBased, boolean MoveUnit, boolean HideUnit returns Data
        local Data d = Data.allocate()
        local real dx = 0.00
        local real dy = 0.00
        
        set dx = GetLocationX(CastPoint) - GetLocationX(Point)
        set dy = GetLocationY(CastPoint) - GetLocationY(Point)
        
        set d.caster       = Caster
        set d.point        = Point
        set d.castrange    = SquareRoot(dx * dx + dy * dy)
        set d.range        = Range
        set d.damage       = Damage
        set d.stunduration = StunDuration
        set d.sin          = Sin(Angle)
        set d.cos          = Cos(Angle)
        set d.area         = Area
        set d.height       = Height
        set d.airtime      = AirTime
        set d.spikesfx     = SpikeSfx
        set d.hitsfx       = HitSfx
        set d.based        = RangeBased
        set d.moveunit     = MoveUnit
        set d.hideunit     = HideUnit
        
        return d
    endmethod
    
endstruct

//=====================================================================
private function Check_Units takes nothing returns boolean
    local unit u
    local player p
    set u = GetFilterUnit()
    set p = GetOwningPlayer(caster[Loop])
    return IsUnitEnemy(u,p) and GetUnitState(u,UNIT_STATE_LIFE) &gt; 0 and IsUnitType(u,UNIT_TYPE_STRUCTURE) == false and u != caster[Loop] and IsUnitInGroup(u,G[Loop]) == false
endfunction

private function Check_Dummy takes nothing returns boolean
    return GetUnitTypeId(GetTriggerUnit()) == DUMMY
endfunction

private function CountUnits takes nothing returns nothing
    set bj_groupCountUnits = bj_groupCountUnits + 1
endfunction

//=====================================================================
private function Flying takes nothing returns nothing
    local real xx
    local real yy
    local unit u
    local unit un
    
    set I[Loop2] = I[Loop2] + 1
    set u = GetEnumUnit()
    call PauseUnit(u,true)
    call SaveReal(h,I[Loop2],Loop2,LoadReal(h,I[Loop2],Loop2) + (SquareRoot(height[Loop2]) * 2.00) / (airtime[Loop2] / INTERVAL))
    call SetUnitFlyHeight(u,(height[Loop2]) - (SquareRoot(height[Loop2]) - LoadReal(h,I[Loop2],Loop2)) * (SquareRoot(height[Loop2]) - LoadReal(h,I[Loop2],Loop2)),0.00)
    if GetUnitFlyHeight(u) &lt;= (SquareRoot(height[Loop2]) * 2.00) / (airtime[Loop2] / INTERVAL) then
        set I2 = I2 + 1
        call PauseUnit(u,false)
        call SetUnitPathing(u,true)
        call SetUnitFlyHeight(u,GetUnitDefaultFlyHeight(u),0.00)
        call UnitDamageTarget(caster[Loop2],u,damage[Loop2],true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_UNKNOWN,WEAPON_TYPE_WHOKNOWS)
        call GroupRemoveUnit(G[Loop2],u)
        if GetUnitState(u,UNIT_STATE_LIFE) &gt; 0 and stunduration[Loop2] &gt; 0.00 then
            set CusVal = CusVal + 1
            set StunG[CusVal] = CreateGroup()
            call GroupAddUnit(StunG[CusVal],u)
            set ImpaledUnit[CusVal] = u
            set stuneffect[CusVal] = AddSpecialEffectTarget(&quot;Abilities\\Spells\\Human\\Thunderclap\\ThunderclapTarget.mdl&quot;,u,&quot;overhead&quot;)
            set xx = GetUnitX(u)
            set yy = GetUnitY(u)
            set un = CreateUnit(GetOwningPlayer(caster[Loop2]),DUMMY,xx,yy,270.00)
            call UnitApplyTimedLife(un,'BTLF',stunduration[Loop2])
            call SetUnitUserData(un,CusVal)
        endif
        set bj_groupCountUnits = 0
        call ForGroup(G[Loop2],function CountUnits)
        if bj_groupCountUnits == 0 and Dt[Loop2] == 0 then
            call DestroyGroup(G[Loop2])
            set I2 = 0
        endif
    endif
    set u = null
endfunction

private function Flying_Init takes nothing returns nothing
    local real     xx
    local real     yy
    local effect   e
    local unit     u
    
    set u = GetEnumUnit()
    set xx = GetUnitX(u)
    set yy = GetUnitY(u)
    set e = AddSpecialEffect(hitsfx[Loop],xx,yy)
    call DestroyEffect(e)
    call UnitAddAbility(u,STORM_CROW)
    call UnitRemoveAbility(u,STORM_CROW)
    call PauseUnit(u,true)
    call SetUnitPathing(u,false)
    call GroupAddUnit(G[Loop],u)
    set e = null
    set u = null
endfunction

private function Call_Flying takes nothing returns nothing
    loop
        exitwhen Loop2 &gt; Instances
        call ForGroup(G[Loop2],function Flying)
        set I[Loop2] = I2
        set Loop2 = Loop2 + 1
    endloop
    set Loop2 = 1
endfunction

//=====================================================================
private function Stun takes nothing returns nothing
    local real xx
    local real yy
    
    set xx = GetUnitX(GetEnumUnit())
    set yy = GetUnitY(GetEnumUnit())
    call SetUnitPosition(GetEnumUnit(),xx,yy)
endfunction

private function Call_Stun takes nothing returns nothing
    local integer i = 1

    loop
        exitwhen i &gt; CusVal
        call ForGroup(StunG<i>,function Stun)
        set i = i + 1
    endloop
endfunction

private function Remove_Stun takes nothing returns nothing
    call GroupRemoveUnit(StunG[GetUnitUserData(GetTriggerUnit())],ImpaledUnit[GetUnitUserData(GetTriggerUnit())])
    call DestroyEffect(stuneffect[GetUnitUserData(GetTriggerUnit())])
endfunction

//=====================================================================
private function SpawnSpikes takes nothing returns nothing
    local Data     d = 0
    local group    g = CreateGroup()
    local real     dx = 0.00
    local real     dy = 0.00
    
    loop
        exitwhen Loop &gt; Instances
        if Dt[Loop] != 0 then
            set d = Dt[Loop]
            set caster[Loop] = d.caster
            set airtime[Loop] = d.airtime
            set damage[Loop] = d.damage
            set stunduration[Loop] = d.stunduration
            set height[Loop] = d.height
            set hitsfx[Loop] = d.hitsfx
            set in[Loop] = in[Loop] + 1
            set x[Loop] = GetLocationX(d.point) + (SPACE * in[Loop]) * d.cos
            set y[Loop] = GetLocationY(d.point) + (SPACE * in[Loop]) * d.sin
            set d.sfx = AddSpecialEffect(d.spikesfx,x[Loop],y[Loop])
            call DestroyEffect(d.sfx)
            call GroupEnumUnitsInRange(g,x[Loop],y[Loop],d.area,Condition(function Check_Units))
            call ForGroup(g,function Flying_Init)
            call DestroyGroup(g)
            set g = CreateGroup()
            set dx = GetLocationX(d.point) - x[Loop]
            set dy = GetLocationY(d.point) - y[Loop]
                
            if d.based then
                if SquareRoot(dx * dx + dy * dy) &gt;= d.castrange then
                    if d.moveunit then
                        call SetUnitX(d.caster,GetLocationX(d.point) + (SPACE * in[Loop]) * d.cos)
                        call SetUnitY(d.caster,GetLocationY(d.point) + (SPACE * in[Loop]) * d.sin)
                    endif
                    if d.hideunit then
                        call ShowUnit(d.caster,true)
                        if GetLocalPlayer() == GetOwningPlayer(d.caster) then
                            call SelectUnit(d.caster, true)
                        endif
                    endif
                    set x[Loop] = 0
                    set y[Loop] = 0
                    set in[Loop] = 0
                    set Dt[Loop] = 0
                    set bj_groupCountUnits = 0
                    call ForGroup(G[Loop],function CountUnits)
                    if bj_groupCountUnits == 0 and Dt[Loop] == 0 then
                        call DestroyGroup(G[Loop])
                        set I2 = 0
                    endif
                endif
            elseif SquareRoot(dx * dx + dy * dy) &gt;= d.range then
                if d.moveunit then
                    call SetUnitX(d.caster,GetLocationX(d.point) + (SPACE * in[Loop]) * d.cos)
                    call SetUnitY(d.caster,GetLocationY(d.point) + (SPACE * in[Loop]) * d.sin)
                endif
                if d.hideunit then
                    call ShowUnit(d.caster,true)
                    if GetLocalPlayer() == GetOwningPlayer(d.caster) then
                        call SelectUnit(d.caster, true)
                    endif
                endif
                set x[Loop] = 0
                set y[Loop] = 0
                set in[Loop] = 0
                set Dt[Loop] = 0
                set bj_groupCountUnits = 0
                call ForGroup(G[Loop],function CountUnits)
                if bj_groupCountUnits == 0 and Dt[Loop] == 0 then
                    call DestroyGroup(G[Loop])
                    set I2 = 0
                endif
            endif
        endif
        set Loop = Loop + 1
    endloop
    set Loop = 1
    set g = null
endfunction

//=====================================================================
function IsUnitImpaled takes unit u returns boolean
    local integer i = 1
    
    loop
        exitwhen i &gt; Instances
        if IsUnitInGroup(u,G<i>) then
            return true
        endif
        set i = i + 1
    endloop
    
    return false
endfunction

//=====================================================================
public function StartEx takes unit Caster, location Point, location CastPoint, real Range, real Damage, real StunDuration, real Angle, real Area, real Height, real AirTime, string SpikeSfx, string HitSfx, boolean RangeBased, boolean MoveUnit, boolean HideUnit returns boolean
    local Data d = 0
    
    if RangeBased == false then
        if Area &lt; 0.00 or StunDuration &lt; 0.00 or Range &lt;= 0.00 then
            debug call BJDebugMsg(&quot;Error: Invalid input in IMPS_Start()&quot;)
            return false
        endif
    elseif Area &lt; 0.00 or StunDuration &lt; 0.00 then
        debug call BJDebugMsg(&quot;Error: Invalid input in IMPS_Start()&quot;)
        return false
    endif
    
    set d = Data.create(Caster,Point,CastPoint,Range,Damage,StunDuration,(Angle * 0.01745328),Area,Height,AirTime,SpikeSfx,HitSfx,RangeBased,MoveUnit,HideUnit)
    
    set Instances = Instances + 1
    set G[Instances] = CreateGroup()
    call TimerStart(Timer,SPIKE_INTERVAL,true,function SpawnSpikes)
    call TimerStart(Timer2,INTERVAL,true,function Call_Flying)
    call TimerStart(Timer3,0.03,true,function Call_Stun)
    set Dt[Instances] = d
    if HideUnit then
        call ShowUnit(Caster,false)
    endif
    
    return true
endfunction

public function Start takes unit Caster, location Point, real Range, real Damage, real StunDuration, real Angle returns nothing
    call IMPS_StartEx(Caster,Point,null,Range,Damage,StunDuration,Angle,AREA,HEIGHT,AIRTIME,SPIKE_SFX,HIT_SFX,false,false,false)
endfunction

//====================================================================
private function InitTrig takes nothing returns nothing
    local trigger t = CreateTrigger()
    local integer index = 0
    loop
        call TriggerRegisterPlayerUnitEvent(t,Player(index),EVENT_PLAYER_UNIT_DEATH,null)
        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop
    call TriggerAddCondition(t,Condition(function Check_Dummy))
    call TriggerAddAction(t,function Remove_Stun)
endfunction

endlibrary</i></i>



EDIT: just a question.. if i use a global dummy <which i use in all map for everything> this system may bug? because it just check if unit type die
 

Angel_Island

Much long, many time, wow
Does it really do anything if you use UnitUserData with a dummy that will die in a few seconds? And where am I using location except d.point? Maybe some users want to use location instead of x,y.
 

Laiev

Hey Listen!!
EDIT: suggestion: if you don't want to remove location, just ok but make a new function which support x/y, most of people like it and is more safe then location, also a little bit faster :p
:rolleyes:
EDIT: just a question.. if i use a global dummy <which i use in all map for everything> this system may bug? because it just check if unit type die
 

Angel_Island

Much long, many time, wow
- EDIT: suggestion: if you don't want to remove location, just ok but make a new function which support x/y, most of people like it and is more safe then location, also a little bit faster

Sure. I will make a new function

- EDIT: just a question.. if i use a global dummy <which i use in all map for everything> this system may bug? because it just check if unit type die

That's true! Guess I have to fix it or you could just create a new dummy, but if your dummy's UserData is 0 then it wont affect this system.
 

Laiev

Hey Listen!!
he do what i say :eek: sweettttttt


now just need to remove the user data and use hashtable and fix the 'bug' with global dummys :rolleyes:
 

Executor

I see you
JASS:
private function Stun takes nothing returns nothing
    local real xx
    local real yy
    
    set xx = GetUnitX(GetEnumUnit())
    set yy = GetUnitY(GetEnumUnit())
    call SetUnitPosition(GetEnumUnit(),xx,yy)
endfunction


JASS:
private function Stun takes nothing returns nothing
    local unit u  = GetEnumUnit()
    local real xx = GetUnitX(u)
    local real yy = GetUnitY(u)

    call SetUnitPosition(u,xx,yy)
endfunction


JASS:
private function Stun takes nothing returns nothing
    local unit u  = GetEnumUnit()
    call SetUnitPosition(u,GetUnitX(u),GetUnitY(u))
endfunction
 

Deaod

Member
  • Using locations
  • NOT using GroupUtils
  • Those non private constants for models are completely unnecessary. Either you let users choose the model, or you dont. If you choose not to, you dont provide such constants.
  • How about giving those timers a descriptive name?
  • How about you reuse code from xe (the dummy unit, the fly height enabler ability, ...)?
  • Global variables with single-letter lower-case names. Good job.
  • [ljass]call SaveReal(h,I[Loop2],Loop2,LoadReal(h,I[Loop2],Loop2) + (SquareRoot(height[Loop2]) * 2.00) / (airtime[Loop2] / INTERVAL))[/ljass]
    What the hell does that do? Why doesnt it use arrays?
  • Checking if group is empty is easy: [ljass]FirstOfGroup(<group>)==null[/ljass]
  • Using SetUnitPathing directly is not exactly smart, if you want to avoid compatibility issues.
  • Your Check_Units function leaks references.
  • Your array of active instances gets filled starting with index 1 instead of 0.
  • Using ShowUnit directly is not a good idea.
  • You restart all timers whenever a new instance is created. Seriously, why?
  • Use a decent name for your library. Then, use a decent name for your currently public function and drop the public key word.
  • Yay, inlined CountUnitsInGroup. Not all BJs are bad.
  • Stunning by resetting a units position? ARE YOU KIDDING? There are multiple libraries out there that facilitate stunning units (at least one here, and one over at wc3c.net). Btw, it fails with instant casts like windwalk and beserk.
 

Angel_Island

Much long, many time, wow
  • Using locations
  • NOT using GroupUtils
  • Those non private constants for models are completely unnecessary. Either you let users choose the model, or you dont. If you choose not to, you dont provide such constants.
  • How about giving those timers a descriptive name?
  • How about you reuse code from xe (the dummy unit, the fly height enabler ability, ...)?
  • Global variables with single-letter lower-case names. Good job.
  • [ljass]call SaveReal(h,I[Loop2],Loop2,LoadReal(h,I[Loop2],Loop2) + (SquareRoot(height[Loop2]) * 2.00) / (airtime[Loop2] / INTERVAL))[/ljass]
    What the hell does that do? Why doesnt it use arrays?
  • Checking if group is empty is easy: [ljass]FirstOfGroup(<group>)==null[/ljass]
  • Using SetUnitPathing directly is not exactly smart, if you want to avoid compatibility issues.
  • Your Check_Units function leaks references.
  • Your array of active instances gets filled starting with index 1 instead of 0.
  • Using ShowUnit directly is not a good idea.
  • You restart all timers whenever a new instance is created. Seriously, why?
  • Use a decent name for your library. Then, use a decent name for your currently public function and drop the public key word.
  • Yay, inlined CountUnitsInGroup. Not all BJs are bad.
  • Stunning by resetting a units position? ARE YOU KIDDING? There are multiple libraries out there that facilitate stunning units (at least one here, and one over at wc3c.net). Btw, it fails with instant casts like windwalk and beserk.
  • Maybe some users want to use locations and there is no location use in the code except in the usable functions.
  • Diffrence?
  • Instead of typing in "Abilities\\Spells\\Undead\\Impale\\ImpaleMissTarget.mdl" all the time they could just use SPIKE_SFX. Simple.
  • [ljass]call TimerStart(Timer,SPIKE_INTERVAL,true,function SpawnSpikes)[/ljass] Isn't "SpawnSpikes" enough information on what it does already?
  • What?
  • Good or bad?
  • If you read it, you can see it saves the real that is in the hashtable h in I[Loop2] of Loop2 + (SquareRoot(height[Loop2]) * 2.00) / (airtime[Loop2] / INTERVAL). Why should it use arrays?
  • Good Idea.
  • How should I do it then?
  • What references?
  • Diffrence?
  • How should I do it then?
  • Good point. Will change it.
  • What is wrong with the name it already has?
  • If you read the other posts, they say I should remove all BJs.
  • Maybe you're right, but I wanted to not be needed to use other systems.
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • Varine Varine:
    Eh, whatever. Thanks for listening guys
  • jonas jonas:
    Sure :) Let us know how it ends
  • Varine Varine:
    All of these things will end happily, they're just stressful. And I still lack many good friends that I can go to, and the ones I can are preoccupied with similar things. Thus general chit chat, cuz for some reason TH and Ghan and Tom all actively keep it up.
  • Varine Varine:
    Just gotta keep Miss Mazie up through the week until her shock wears off and she realizes that she still has family all around her, and bossman will do whatever he's going to do and I'll respond appropriately when it happens. Thank you all for the support, I do very much appreciate everyone being here for me through the years
    +3
  • vypur85 vypur85:
    Best of luck Varine!
  • vypur85 vypur85:
    I just gotten myself an offer to work in China. The pay quadruples my current one. Damn.... Not really ready to start a new life there in China.
  • The Helper The Helper:
    I have heard that they pay pretty good to English teachers in China - you would be an expat
  • jonas jonas:
    Cool, what kind of job?
  • Accname Accname:
    I would be careful with jobs in China. They can be hit and miss depending on where in China you go. Places like hong kong / Shengzen / Beijing can be neat. Other places not so much.
  • Accname Accname:
    I would recommend searching for some first person experiences for the city you got the offer in. Especially now when the political situation in China is deteriorating.
  • jonas jonas:
    Accname, long time no see
  • jonas jonas:
    What have you been up to
  • tom_mai78101 tom_mai78101:
    Hey Accname, welcome back.
  • Accname Accname:
    Not much. Working in the Renewable Energy Sector as an IT Consultant. Its okay, but I think I preferred working at the university. It was more relaxed and you met all kinds of crazy people there.
  • vypur85 vypur85:
    I gotten a teaching position for Biology in a college in Wuhan (yes, there)... I suppose it should be fine there (I hope). Many of my ex colleagues are teaching in China as well currently (none in Wuhan though)
  • vypur85 vypur85:
    And I signed the contract already. I guess there's no turning back....
  • jonas jonas:
    @Accname how many hours do you work? I heard in some sectors IT consultants rack up insane hours
  • jonas jonas:
    @vypur85 sounds nice, have fun : )
  • Accname Accname:
    I am supposed to work 40 hrs a week, but I can work more if I like and I will be paid for those hours (as long as I don't go too far, there are laws and company policies, etc)
  • Accname Accname:
    In practice its basically work as much as you like, as long as the job gets done in time.
  • jonas jonas:
    Haha, my job is like that as well... that usually means I have a few 70-80 hours weeks a year, and lots of 20 hours weeks...
  • jonas jonas:
    a few weeks ago, one of my friends basically said "jonas, I received an invitation to submit something to conference X but I'm too lazy to do it and also the conference isn't advanced enough for my high level of research*, why don't you write something? Oh by the way, the deadline is in two weeks. Enjoy!" so I got two 80 hour weeks out of that kind offer. (*of course he didn't say those parts, but it's a better story this way)
  • jonas jonas:
    now I'll have next week off to make up for overtime :p and I'll play some good old gothic 2
  • The Helper The Helper:
    Hope you are enjoying that gothic 2~
  • jonas jonas:
    Heck yeah :cool: It's unfortunate that the game series wasn't generally well received outside of Europe, but it seems they want to remake Gothic 1 now. I'm very excited but also very scared at the same time. I hope they won't pull a reforged

    Members online

    No members online now.

    Affiliates

    Hive Workshop NUON Dome
    Top