Spell Diablo II Charge

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
Diablo II - Charge
By Tom_Kazansky

- vJass
- Laggless
- Leakless (I think)
- MUI

Description:
The Hero charges towards a target enemy unit, closing distance with it and delivering a bash on contact.

Code:
JASS:
scope D2Charge initializer Init

globals
    private integer ChargeRawId = 'A000' // raw id of Charge ability
    private integer ChargeSpeedId = 'A001' // raw id of Charge Speed ability
    private integer ChargeBuff = 'B000' //raw id of the Charge buff
    private integer CasterRunAniIndex = 2 //walk animation index of the caster's model, 
    //currently, model Spirit Walker's walk animation index is 2
    //if you use other model, you should change this, if you don't the illusion will not play walk animation
    private real CasterRunSpeed = 180. //Art - Animation - Run Speed of the caster -> this is used for the animation of the illusion (make it more "real")
    private integer DummyId = 'n000' //raw id of the dummy unit, used to cast stun
    private integer ChargeIllusionId = 'n002' //raw id of the dummy unit which is used for the illusion
    private integer ChargeStun = 'A002' //raw id of the stun ability
    private real KnockDist = 160. //knockback distance
    private real KnockDur = 1.2 //knockback duration
    private string HitSFX = "Abilities\\Spells\\Orc\\Devour\\DevourEffectArt.mdl" //string of the effect on contact
    private string HitSFXA = "chest" //string of the attachment point
endglobals

//=================================
private function TJGetPPX takes real x, real dist, real angle returns real
    return x + dist * Cos(angle * bj_DEGTORAD)
endfunction

private function TJGetPPY takes real y, real dist, real angle returns real
    return y + dist * Sin(angle * bj_DEGTORAD)
endfunction
function AngleBetweenUnits takes unit A, unit B returns real
    return bj_RADTODEG * Atan2(GetUnitY(B) - GetUnitY(A), GetUnitX(B) - GetUnitX(A))
endfunction

private struct datax
    unit u
    real dis
    real ang
    real tick
    timer ti
endstruct

private function DestroyTreeEnum takes nothing returns nothing
    local destructable des = GetEnumDestructable()
    if GetDestructableMaxLife(des) == 50.00 and GetDestructableLife(des) > 0 then
        call KillDestructable(des)
    endif
    set des = null
endfunction

private function DestroyTreeInCircle takes real x, real y, real aoe returns nothing
    local rect r
    local location tl = Location(x,y)
    set bj_enumDestructableCenter = tl
    set bj_enumDestructableRadius = aoe
    set r = Rect(x - aoe, y - aoe, x + aoe, y + aoe)
    call EnumDestructablesInRect(r, null,function DestroyTreeEnum)
    call RemoveRect(r)
    call RemoveLocation(tl)
    set tl = null
    set r = null
endfunction

private function KnockBackE takes nothing returns nothing
    local datax d = GetTimerData( GetExpiredTimer() )
    local real x
    local real y
    local real mx
    local real my
    if d.tick > 0 then
        set x = GetUnitX(d.u)
        set y = GetUnitY(d.u)
        set mx = TJGetPPX( x, d.dis, d.ang )
        set my = TJGetPPY( y, d.dis, d.ang )
        call DestroyEffect( AddSpecialEffect("Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl" ,x,y))
        call DestroyTreeInCircle( mx, my,150.00 )
        call SetUnitPosition(d.u, mx, my )
        set d.tick = d.tick - 1
    elseif d.tick <= 0 then
        call datax.destroy(d)
        call ReleaseTimer(d.ti)
    endif
endfunction

function KnockBack takes unit u,real dur, real dis,real ang returns nothing
    local datax d
    if dur == 0. or dis == 0. then
        set u = null
        return
    endif
    set d = datax.create()
    set d.u = u
    set d.tick = R2I(dur/0.04)
    set d.dis = dis/d.tick
    set d.ang = ang
    set d.ti = NewTimer()
    call SetTimerData(d.ti,d)
    call TimerStart( d.ti,0.04,true, function KnockBackE)
    set u = null
endfunction
//=================================
private struct data
    unit caster = null
    unit target = null
    unit d1 = null
    unit d2 = null
    integer tick = 0
    real casterx = 0.
    real castery = 0.
    boolean stop = false
    
    timer ti
endstruct

private function ChargeInterrupted takes unit u, unit a returns boolean
    if GetWidgetLife(u) == 0 then
        return true
    elseif (a != null and GetWidgetLife(a) == 0) then
        return true
    elseif IsUnitType(u,UNIT_TYPE_ETHEREAL) then
        return true
    elseif IsUnitType(u,UNIT_TYPE_POLYMORPHED )  then
        return true
    elseif IsUnitType(u,UNIT_TYPE_STUNNED ) then
        return true
    elseif IsUnitType(u,UNIT_TYPE_SNARED ) then
        return true
    elseif (a != null and IsUnitInvisible(a, GetOwningPlayer(u)))  then
        return true
    elseif OrderId2String( GetUnitCurrentOrder(u) ) != "attack" and OrderId2String( GetUnitCurrentOrder(u) ) != "smart"  then
        return true
    elseif GetUnitAbilityLevel(u,ChargeBuff) == 0 then
        return true
    endif
    set u = null
    set a = null
    return false
endfunction

private function ChargeM takes nothing returns nothing
    local data d = GetTimerData( GetExpiredTimer() )
    local real x = GetUnitX(d.caster)
    local real y = GetUnitY(d.caster)
    local real fa = GetUnitFacing(d.caster)
    local real ang
    local real mx
    local real my
    if x == d.casterx and y == d.castery then
        if not d.stop then
            set d.stop = true
            call SetUnitVertexColor( d.d1,255,255,255,0)
            call SetUnitVertexColor( d.d2,255,255,255,0)
        endif
    else
        if d.stop then
            set d.stop = false
            call SetUnitVertexColor( d.d1,255,255,255,170)
            call SetUnitVertexColor( d.d2,255,255,255,85)
        endif
    endif
    if not d.stop then
        set mx = TJGetPPX(x,-40, fa)
        set my = TJGetPPY(y,-40, fa)
        call SetUnitX(d.d1, mx)
        call SetUnitY(d.d1, my)
        call SetUnitFacing(d.d1, fa )
        
        set mx = TJGetPPX(x,-80, fa)
        set my = TJGetPPY(y,-80, fa)
        call SetUnitX(d.d2, mx)
        call SetUnitY(d.d2, my)
        call SetUnitFacing(d.d2, fa )
    else
        call SetUnitX(d.d1, x)
        call SetUnitY(d.d1, y)
        call SetUnitFacing(d.d1, fa )
        
        call SetUnitX(d.d2, x)
        call SetUnitY(d.d2, y)
        call SetUnitFacing(d.d2, fa )
    endif
    if ChargeInterrupted(d.caster,d.target) then
        call UnitRemoveAbility(d.caster,ChargeSpeedId)
        call UnitRemoveAbility(d.caster,ChargeBuff)
        call RemoveUnit(d.d1)
        call RemoveUnit(d.d2)
        call SetUnitPathing(d.caster,true)
        call data.destroy(d)
        call ReleaseTimer(d.ti)
        return
    endif
    
    set d.casterx = x
    set d.castery = y
endfunction

private function ChargeC takes data d returns nothing
    local real cx = GetUnitX(d.caster)
    local real cy = GetUnitY(d.caster)
    local real fa = GetUnitFacing(d.caster)
    local real mx
    local real my
    call SetUnitPathing(d.caster,false)
    set mx = TJGetPPX(cx,-40,fa)
    set my = TJGetPPY(cy,-40,fa)
    set d.d1 = CreateUnit( GetOwningPlayer(d.caster), ChargeIllusionId, mx, my, fa )
    call SetUnitVertexColor( d.d1,255,255,255,170)
    call SetUnitTimeScale( d.d1,522 / CasterRunSpeed )
    call PauseUnit(d.d1,true)
    call SetUnitPathing(d.d1,false)
    call SetUnitAnimationByIndex(d.d1, CasterRunAniIndex )
    call SetUnitMoveSpeed(d.d1,522)
    call SetUnitPosition(d.d1,cx,cy)
    call SetUnitColor(d.d1,ConvertPlayerColor(GetPlayerId(GetOwningPlayer(d.caster))))

    set mx = TJGetPPX(cx,-80,fa)
    set my = TJGetPPY(cy,-80,fa)
    set d.d2 = CreateUnit( GetOwningPlayer(d.caster), ChargeIllusionId,mx, my,fa )
    call SetUnitVertexColor(d.d2,255,255,255, 85 )
    call SetUnitTimeScale(d.d2,522/CasterRunSpeed)
    call PauseUnit(d.d1,true)
    call SetUnitPathing(d.d2,false)
    call SetUnitAnimationByIndex(d.d2, CasterRunAniIndex )
    call SetUnitMoveSpeed(d.d2,522)
    call SetUnitPosition(d.d2,cx,cy)
    call SetUnitColor(d.d2,ConvertPlayerColor(GetPlayerId(GetOwningPlayer(d.caster))))
    set d.ti = NewTimer()
    call SetTimerData(d.ti,d)
    call TimerStart(d.ti,0.02,true, function ChargeM )
endfunction

//===============================================================================
private function Action takes nothing returns nothing
    local unit c
    local unit a
    local unit dumb
    local location loc
    local integer lvl
    local eventid EID = GetTriggerEventId()
    local data d
    if EID == EVENT_PLAYER_UNIT_SPELL_EFFECT and GetSpellAbilityId() == ChargeRawId then
        set c = GetSpellAbilityUnit()
        set a = GetSpellTargetUnit()
        set loc = GetSpellTargetLoc()
        set lvl = GetUnitAbilityLevel(c, ChargeRawId)
        set d = data.create()
        set d.caster = c
        set d.target = a
        set d.casterx = GetUnitX(c)
        set d.castery = GetUnitY(c)
        if d.target != null then
            call IssueTargetOrder(c,"attack",a)
        else
            call IssuePointOrder(c,"smart",GetLocationX(loc),GetLocationY(loc))
            call RemoveLocation(loc)
        endif
        call ChargeC(d)
        call UnitAddAbility(c, ChargeSpeedId )
        set loc = null
        set c = null
        set a = null
        return
    endif
    if EID == EVENT_PLAYER_UNIT_ATTACKED then
        set c = GetAttacker()
        set a = GetTriggerUnit()
        set lvl = GetUnitAbilityLevel(c, ChargeRawId)
        if GetUnitAbilityLevel( c, ChargeBuff ) > 0 then
            set dumb = CreateUnit( Player(15), DummyId , GetUnitX(a), GetUnitY(a), 0 )
            call UnitAddAbility( dumb , ChargeStun )
            call SetUnitAbilityLevel( dumb, ChargeStun , lvl )
            call IssueTargetOrder(dumb, "firebolt", a )
            call UnitApplyTimedLife(dumb,'BTLF', 1. )
            set dumb = null
            call DestroyEffect( AddSpecialEffectTarget(HitSFX,a,HitSFXA)  )
            call KnockBack(a,KnockDur, KnockDist, AngleBetweenUnits(c,a) )
            call UnitRemoveAbility(c,ChargeSpeedId)
            call UnitRemoveAbility(c,ChargeBuff)
        endif
        set c = null
        set a = null
        return
    endif
    set c = GetTriggerUnit()
    set a = GetOrderTargetUnit()
    if GetUnitAbilityLevel(c,ChargeBuff) > 0 then
        call UnitRemoveAbility(c,ChargeBuff)
    endif
    set c = null
    set a = null
endfunction
//===================================================================================================
private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    local integer index = 0
    call TriggerAddAction(t, function Action)
    set index = 0
    loop
        call TriggerRegisterPlayerUnitEvent(t, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
        call TriggerRegisterPlayerUnitEvent(t, Player(index), EVENT_PLAYER_UNIT_ATTACKED, null)
        call TriggerRegisterPlayerUnitEvent(t, Player(index), EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
        call TriggerRegisterPlayerUnitEvent(t, Player(index), EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null)
        call TriggerRegisterPlayerUnitEvent(t, Player(index), EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, null)
        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop
endfunction

endscope

Screenshot
attachment.php

Readme
D2 Spell: Charge ability by Tom_Kazansky
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

* How to import:
- Copy the Charge, Charge Speed, Charge Stun abilities and the Charge buff
- Copy 2 units: Dummy and Dummy Charge Illusion
- Copy TimerUtils(if you don't have one) and the D2Charge trigger
- Change the RawId of abilities and units in the globals block of D2Charge

* Credit:
- Thanks Vexorian for TimerUtils
- Thanks Tinki3 for the test map template

* Modification:
- Modify the Charge Stun abilitiy for damage and stun duration on contact

Please comment :D

EDIT: Reupload
EDIT2: update, the spell is now compatible with patch 1.24 and use TimerUtils instead of ABCT
 

Attachments

  • [Spell] D2Charge.w3x
    43.6 KB · Views: 299

Kenny

Back for now.
Reaction score
202
I don't think this is working for me, i use the spell, but all the hero does is walk up to the target unit and attack it, thats it. No images, no speed gain, and i only stun when i am up close.

Looks like a good spell though.
 

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
I don't think this is working for me, i use the spell, but all the hero does is walk up to the target unit and attack it, thats it. No images, no speed gain, and i only stun when i am up close.

Looks like a good spell though.

Oops, sorry about that :p, after I took the screenshot, I add a condition for the ChargeInterrupted function, and there is a mistake:
JASS:
OrderId2String( GetUnitCurrentOrder(u) ) != "attack" or OrderId2String( GetUnitCurrentOrder(u) ) != "smart"

=>
JASS:
OrderId2String( GetUnitCurrentOrder(u) ) != "attack" and OrderId2String( GetUnitCurrentOrder(u) ) != "smart" //it has to be "and"


Reuploaded
EDIT: And some functions should be private too. :D
 

Draphoelix

It's not the wintercold that's killing me
Reaction score
132
Nice but, the d2 charge actually works as Point Targeted too and it doesn't stun, it knocksback. Not excactly like d2 but a nice spell :)
 

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
Updated
Now, it like D2 more :D
I added the knockback effect on contact
Can be used as a point target.

And can anyone help me with the tooltip ? :)
 

Draphoelix

It's not the wintercold that's killing me
Reaction score
132
In showing fear, a Paladin displays his lack of faith, and a faithless Paladin is less than a man - let alone a knight. This is vital in that when all else fails, it is faith that will carry the Paladin through to victory. Warriors of faith never shirk from combat, but rush forward with heads down and shields up, allowing their glory to carry them into the thick of battle to deliver the first blow.

Closes the distance with an enemy, delivering a bash on contact.

That's the tooltip from a site
 

waaaks!

Zinctified
Reaction score
255
the spell is good, but i hate spells with lots of object editor stuffs, because u cant mass copy object editor data into ur map unlike triggers
 

Andrewgosu

The Silent Pandaren Helper
Reaction score
716
Code:
private function TJGetPPX takes real x, real dist, real angle returns real
    return x + dist * Cos(angle * bj_DEGTORAD)
endfunction

private function TJGetPPY takes real y, real dist, real angle returns real
    return y + dist * Sin(angle * bj_DEGTORAD)
endfunction

Instead of using PolarProjectionBJ you split it and now do two function calls instead of one...

Why not calculate the values directly?

Code:
function AngleBetweenUnits takes unit A, unit B returns real
    return bj_RADTODEG * Atan2(GetUnitY(B) - GetUnitY(A), GetUnitX(B) - GetUnitX(A))
endfunction

Same applies here, calculate the value directly.


And in the "ChargeInterrupted" function you don't have to null the parameters.
 

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
Instead of using PolarProjectionBJ you split it and now do two function calls instead of one...

Why not calculate the values directly?

Code:
function AngleBetweenUnits takes unit A, unit B returns real
    return bj_RADTODEG * Atan2(GetUnitY(B) - GetUnitY(A), GetUnitX(B) - GetUnitX(A))
endfunction

Same applies here, calculate the value directly.

well, when I calculate the value directly, somtimes I get confused, so I think it is better (for me) to call these functions.

And in the "ChargeInterrupted" function you don't have to null the parameters.

I didn't know that :D
 

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
Another update, the spell now:
- compatible with 1.24b
- use TimerUtils instead of ABCT
 

Sungazer

New Member
Reaction score
0
Some vJass questions

I haven't tested your spell yet, so have no critique to offer, rather I have some questions I was hoping you wouldn't mind answering to educate a fellow editor :p

I've done a few spells in JASS, but haven't touched vJass, so looking over your code was a bit confusing for me.

For one, you call a function called "ReleaseTimer" twice, but I don't see this function defined any where in your code and I don't see it in the list of functions created by Blizzard. What is this function and where is it defined?

Secondly, I see you create and initialize a variable with:

local datax d = GetTimerData ( GetExpiredTimer() )

I understand that this is a specific instance of the struct "datax" that you defined above in your code. What's confusing me is how an entire struct, with 5 of its own "member" or "private" variables, is being defined as a single value, the expired timer. Also, GetTimerData is another mystery function not defined in your code or the standard libraries.

I get the feeling the answer to these questions has to do with vJass, but again, very ignorant in that area. Does vJass have some of its own libraries with its own functions? If so, how are you defining an entire struct as a single value? And when do those other values get defined?

Finally, you call datax.destroy(d). I understand that when you use a struct or a class, the "." is a "member operator" that refers to variables or functions that are "inside" the abstract data-type, and I also understand this is a function call that is destroying the struct from memory, but where is this "destroy" function defined?

I hope you understand what I'm asking, and hope it's not a burden to explain :p Thanks in advance to anyone who can shed some light on this vJass "jibberish" hehe
 

Laiev

Hey Listen!!
Reaction score
188
For one, you call a function called "ReleaseTimer" twice, but I don't see this function defined any where in your code and I don't see it in the list of functions created by Blizzard. What is this function and where is it defined?

JASS:
function ReleaseTimer takes timer t returns nothing
        if(t==null) then
            debug call BJDebugMsg("Warning: attempt to release a null timer")
            return
        endif
        if (tN==ARRAY_SIZE) then
            debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")

            //stack is full, the map already has much more troubles than the chance of bug
            call DestroyTimer(t)
        else
            call PauseTimer(t)
            if(GetTimerData(t)==HELD) then
                debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
                return
            endif
            call SetTimerData(t,HELD)
            set tT[tN]=t
            set tN=tN+1
        endif    
    endfunction


I get the feeling the answer to these questions has to do with vJass, but again, very ignorant in that area. Does vJass have some of its own libraries with its own functions?
no, the diffence of it is what you can do.. you can make things which you can't do in normal jass

here is trigger of TimerUtils:

JASS:
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+)
//* ----------
//*
//*  To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//*  To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass)   More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//*  * Attaching
//*  * Recycling (with double-free protection)
//*
//* set t=NewTimer()      : Get a timer (alternative to CreateTimer)
//* ReleaseTimer(t)       : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2)     : Attach value 2 to timer
//* GetTimerData(t)       : Get the timer's value.
//*                         You can assume a timer's value is 0
//*                         after NewTimer.
//*
//* Multi-flavor:
//*    Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************

//================================================================
    globals
        //How to tweak timer utils:
        // USE_HASH_TABLE = true  (new blue)
        //  * SAFEST
        //  * SLOWEST (though hash tables are kind of fast)
        //
        // USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true  (orange)
        //  * kinda safe (except there is a limit in the number of timers)
        //  * ALMOST FAST
        //
        // USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
        //  * THE FASTEST (though is only  faster than the previous method
        //                  after using the optimizer on the map)
        //  * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
        //                     work)
        //
        private constant boolean USE_HASH_TABLE      = true
        private constant boolean USE_FLEXIBLE_OFFSET = false

        private constant integer OFFSET     = 0x100000
        private          integer VOFFSET    = OFFSET
              
        //Timers to preload at map init:
        private constant integer QUANTITY   = 256
        
        //Changing this  to something big will allow you to keep recycling
        // timers even when there are already AN INCREDIBLE AMOUNT of timers in
        // the stack. But it will make things far slower so that's probably a bad idea...
        private constant integer ARRAY_SIZE = 8190

    endglobals

    //==================================================================================================
    globals
        private integer array data[ARRAY_SIZE]
        private hashtable     ht
    endglobals

    //It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
    function SetTimerData takes timer t, integer value returns nothing
        static if(USE_HASH_TABLE) then
            // new blue
            call SaveInteger(ht,0,GetHandleId(t), value)
            
        elseif (USE_FLEXIBLE_OFFSET) then
            // orange
            static if (DEBUG_MODE) then
                if(GetHandleId(t)-VOFFSET<0) then
                    call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
                endif
            endif
            set data[GetHandleId(t)-VOFFSET]=value
        else
            // new red
            static if (DEBUG_MODE) then
                if(GetHandleId(t)-OFFSET<0) then
                    call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
                endif
            endif
            set data[GetHandleId(t)-OFFSET]=value
        endif        
    endfunction

    function GetTimerData takes timer t returns integer
        static if(USE_HASH_TABLE) then
            // new blue
            return LoadInteger(ht,0,GetHandleId(t) )
            
        elseif (USE_FLEXIBLE_OFFSET) then
            // orange
            static if (DEBUG_MODE) then
                if(GetHandleId(t)-VOFFSET<0) then
                    call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
                endif
            endif
            return data[GetHandleId(t)-VOFFSET]
        else
            // new red
            static if (DEBUG_MODE) then
                if(GetHandleId(t)-OFFSET<0) then
                    call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
                endif
            endif
            return data[GetHandleId(t)-OFFSET]
        endif        
    endfunction

    //==========================================================================================
    globals
        private timer array tT[ARRAY_SIZE]
        private integer tN = 0
        private constant integer HELD=0x28829022
        //use a totally random number here, the more improbable someone uses it, the better.
    endglobals

    //==========================================================================================
    function NewTimer takes nothing returns timer
        if (tN==0) then
            //If this happens then the QUANTITY rule has already been broken, try to fix the
            // issue, else fail.
            debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
            static if( not USE_HASH_TABLE) then
                debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
                set tT[0]=CreateTimer()
                static if( USE_FLEXIBLE_OFFSET) then
                    if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
                        //all right, couldn't fix it
                        call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
                        return null
                    endif
                else
                    if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
                        //all right, couldn't fix it
                        call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
                        return null
                    endif
                endif
            endif
        else
            set tN=tN-1
        endif
        call SetTimerData(tT[tN],0)
     return tT[tN]
    endfunction

    //==========================================================================================
    function ReleaseTimer takes timer t returns nothing
        if(t==null) then
            debug call BJDebugMsg("Warning: attempt to release a null timer")
            return
        endif
        if (tN==ARRAY_SIZE) then
            debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")

            //stack is full, the map already has much more troubles than the chance of bug
            call DestroyTimer(t)
        else
            call PauseTimer(t)
            if(GetTimerData(t)==HELD) then
                debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
                return
            endif
            call SetTimerData(t,HELD)
            set tT[tN]=t
            set tN=tN+1
        endif    
    endfunction

    private function init takes nothing returns nothing
     local integer i=0
     local integer o=-1
     local boolean oops = false
     
        static if( USE_HASH_TABLE ) then
            set ht = InitHashtable()
            loop
                exitwhen(i==QUANTITY)
                set tT<i>=CreateTimer()
                call SetTimerData(tT<i>, HELD)
                set i=i+1
            endloop
            set tN = QUANTITY
        else
            loop
                set i=0
                loop
                    exitwhen (i==QUANTITY)
                    set tT<i> = CreateTimer()
                    if(i==0) then
                        set VOFFSET = GetHandleId(tT<i>)
                        static if(USE_FLEXIBLE_OFFSET) then
                            set o=VOFFSET
                        else
                            set o=OFFSET
                        endif
                    endif
                    if (GetHandleId(tT<i>)-o&gt;=ARRAY_SIZE) then
                        exitwhen true
                    endif
                    if (GetHandleId(tT<i>)-o&gt;=0)  then
                        set i=i+1
                    endif
                endloop
                set tN = i
                exitwhen(tN == QUANTITY)
                set oops = true
                exitwhen not USE_FLEXIBLE_OFFSET
                debug call BJDebugMsg(&quot;TimerUtils_init: Failed a initialization attempt, will try again&quot;)               
            endloop
            
            if(oops) then
                static if ( USE_FLEXIBLE_OFFSET) then
                    debug call BJDebugMsg(&quot;The problem has been fixed.&quot;)
                    //If this message doesn&#039;t appear then there is so much
                    //handle id fragmentation that it was impossible to preload
                    //so many timers and the thread crashed! Therefore this
                    //debug message is useful.
                elseif(DEBUG_MODE) then
                    call BJDebugMsg(&quot;There were problems and the new timer limit is &quot;+I2S(i))
                    call BJDebugMsg(&quot;This is a rare ocurrence, if the timer limit is too low:&quot;)
                    call BJDebugMsg(&quot;a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)&quot;)
                    call BJDebugMsg(&quot;b) or try changing OFFSET to &quot;+I2S(VOFFSET) )
                endif
            endif
        endif

    endfunction

endlibrary
</i></i></i></i></i></i>
 

Sungazer

New Member
Reaction score
0
Quote:
I get the feeling the answer to these questions has to do with vJass, but again, very ignorant in that area. Does vJass have some of its own libraries with its own functions?

no, the diffence of it is what you can do.. you can make things which you can't do in normal jass

library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+)
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.


Um, I see the word library there, twice. I was right, vJass users do create their own libraries of functions. Thanks for pointing me to this one!

Still doesn't answer my question about structs, but I should probably search for vJass tutorials if I want an authoritative answer.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top