Won't run 2 timers at once

D.V.D

Make a wish
Reaction score
73
My code doesn't want to run 2 timers at once. The code is supposed to make a unit be knockbacked and during hes sliding, the caster charges a circle of energy and lets out a beam causing a explosion to happen. Whats not working is the charging. It seems to skip the charging part and skips the wait in the timer and fires the beam right after the unit is knockbacked. Here's the code:

JASS:
scope GentleFist initializer Init

    globals
        private constant attacktype atype1 = ATTACK_TYPE_NORMAL
        private constant attacktype atype2 = ATTACK_TYPE_MAGIC
        
        private constant damagetype dtype1 = DAMAGE_TYPE_NORMAL
        private constant damagetype dtype2 = DAMAGE_TYPE_MAGIC
        
        private constant integer AbilId = 'AHtb'
        private constant integer Castrange = 10
        private constant integer DummyId = 'h000'
        private constant integer DummyId2 = 'h001'
        private constant integer DummyId3 = 'h002'
        private constant integer Laserarray = 200
        
        private constant real dummydist = 50.00
        private constant real laserdamage = 500.00
        private constant real laserdmgradius = 200.00
        private constant real laserdistance = 9.00
        private constant real movedamage = 2.00
        private constant real movedistance = 9.00
        private constant real movedistancefull = 360.00
        private constant real movetime = 0.02
        
        private constant string EffectId = "Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl"
        private constant string EffectId2 = "Abilities\\Spells\\Orc\\EarthQuake\\EarthQuakeTarget.mdl"
        private constant string EffectId3 = "Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl"
        
        private constant weapontype wtype1 = WEAPON_TYPE_WHOKNOWS
        private constant weapontype wtype2 = WEAPON_TYPE_WHOKNOWS
    endglobals
    
    //-------------------\\
    //   CONFIGURABLES:  \\
    //-------------------\\
    
    private function GetDamage takes integer lvl returns real
        return lvl + 1.00
    endfunction
    
    private function GetLaserDamage takes integer lvl returns real
        return 300.00 * lvl
    endfunction
    
    private function GetLaserRadius takes integer lvl returns real
        return 200.00 * lvl
    endfunction
    
    private function GetMoveDistanceFull takes nothing returns real
        return movedistance * 40
    endfunction
    
    private function GetChargeTime takes nothing returns real
        return GetMoveDistanceFull() / movedistance
    endfunction
    
    //-------------------\\
    // DO NOT EDIT BELOW \\
    //-------------------\\
    
    globals
        private unit Explosion
    endglobals
    
    private struct data
        integer count
        integer count1
        real distance
        real sizex
        real sizey
        real sizez
        real x
        real y
        unit caster
        unit charge
        unit array laser [Laserarray]
        unit target
        
        method onDestroy takes nothing returns nothing
            set .caster = null
            set .charge = null
            set .target = null
        endmethod
        
    endstruct

    private function Conditions takes nothing returns boolean
        return ( GetSpellAbilityId() == AbilId )
    endfunction
    
    private function Laser takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local data d = GetTimerData(t)
        local integer lvl = GetUnitAbilityLevel( d.caster, AbilId )
        local real angle = GetUnitFacing(d.caster)
        local real x = GetUnitX(d.caster) + d.distance * Cos(angle * bj_DEGTORAD)
        local real y = GetUnitY(d.caster) + d.distance * Sin(angle * bj_DEGTORAD)
        
        set d.laser[d.count] = CreateUnit( GetOwningPlayer(d.caster), DummyId2, x, y, angle )
        call PauseUnit( d.laser[d.count], true )
        call SetUnitTimeScale( d.laser[d.count], 0.00 )
        
        set d.count = d.count + 1
        set d.distance = d.distance + laserdistance
        
        if ( d.count == GetMoveDistanceFull / movedistance + Castrange ) then
            set d.count = 0
            loop
                exitwhen d.count > movedistancefull / movedistance + 100.00
                call SetUnitTimeScale( d.laser[d.count], 100.00 )
                call SetUnitAnimation( d.laser[d.count], "death" )
                call KillUnit(d.laser[d.count])
                set d.count = d.count + 1
            endloop
            set Explosion = CreateUnit( GetOwningPlayer(d.caster), DummyId3, x, y, angle )
            call UnitApplyTimedLife( Explosion, 'BTLF', 1.00 )
            call UnitDamagePoint( d.caster, 0.00, GetLaserRadius(lvl), x, y, GetLaserDamage(lvl), true, false, atype2, dtype2, wtype2 )
            call ReleaseTimer(t)
            call d.destroy()
        endif
    endfunction
    
    private function Move takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local data d = GetTimerData(t)
        local integer lvl = GetUnitAbilityLevel( d.caster, AbilId )
        local real angle = GetUnitFacing(d.caster)
        local real x = GetUnitX(d.target) + movedistance * Cos(angle * bj_DEGTORAD)
        local real y = GetUnitY(d.target) + movedistance * Sin(angle * bj_DEGTORAD)
        
        call DestroyEffect( AddSpecialEffect( EffectId, x, y ) )
        call SetUnitPosition( d.target, x, y )
        call UnitDamageTarget( d.caster, d.target, GetDamage(lvl), true, false, atype1, dtype1, wtype1 )
        set d.count = d.count + 1
        
        if ( d.count == GetMoveDistanceFull() / movedistance ) then
            call SetUnitAnimation( d.target, "death" )
            call DestroyEffect( AddSpecialEffect( EffectId2, x, y ) )
            set d.count = 1
            set d.distance = 9.00
            set d.x = x
            set d.y = y
            call PauseTimer(t)
            call TimerStart( t, 0.02, true, function Laser )
            set t = null
        endif
        
    endfunction
    
    private function Charge takes nothing returns nothing
        local timer z = GetExpiredTimer()
        local data u = GetTimerData(z)
        
        set u.sizex = u.sizex + 10.00
        set u.sizey = u.sizey + 10.00
        set u.sizez = u.sizez + 10.00
        
        call DestroyEffect( AddSpecialEffectTarget( EffectId3, u.charge,"chest" ) )
        call SetUnitScale( u.charge, u.sizex, u.sizey, u.sizez )
        set u.count1 = u.count1 + 1
        
        if ( u.count1 == GetMoveDistanceFull() / movedistance ) then
            call KillUnit(u.charge)
            call ReleaseTimer(z)
            call u.destroy()
        endif
    endfunction

    private function Actions takes nothing returns nothing
        local data d = data.create()
        local data u = data.create()
        local real face = GetUnitFacing(d.caster) + 50.00
        local real x
        local real y
        local timer t = NewTimer()
        local timer z = NewTimer()
        local unit dummy
        
        set d.count = 0
        set u.count1 = 0
        set d.caster = GetTriggerUnit()
        set d.target = GetSpellTargetUnit()
        set u.sizex = 100.00
        set u.sizey = 100.00
        set u.sizez = 100.00
        set x = GetUnitX(d.caster) + dummydist * Cos(face * bj_DEGTORAD)
        set y = GetUnitY(d.caster) + dummydist * Sin(face * bj_DEGTORAD)
        set dummy = CreateUnit(GetOwningPlayer(d.caster),DummyId,x,y,face)
        
        call PauseUnit(dummy, true)
        call UnitApplyTimedLife( dummy, 'BTLF', 0.30 )
        
        set u.charge = CreateUnit(GetOwningPlayer(d.caster), DummyId3, x, y, face)
        
        call PauseUnit(d.charge, true)
        call SetTimerData( t, d )
        call SetTimerData( z, u )
        call TimerStart( t, movetime, true, function Move )
        call TimerStart( z, 0.07, true, function Charge )
    endfunction

    //===========================================================================
    private function Init takes nothing returns nothing
        local trigger t = CreateTrigger(  )
        call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition( t, Condition( function Conditions ) )
        call TriggerAddAction( t, function Actions )
    endfunction

endscope
 

uberfoop

~=Admiral Stukov=~
Reaction score
177
Ok, firstly, your timers are starting just fine. The reason you THINK your charge timer doesn't work is that you have no clue how the unit scale native works.
1-Only the x input works. y and z scale inputs do absolutely nothing. Just do:
JASS:
call SetUnitScale(u,scale,0,0)

2-Like just about everything in jass, it takes factors, not percents. The reason you can't see anything going on? It's all WAAAY OFF SCREEEN. Because your unit has a scale of 100 TIMES ITS NORMAL SIZE right off the bat.


Now that that's covered, let's get to the reason why, according to the code you posted, your laser is probably creating laser units indefinitely.
See this in your Laser function:
JASS:
if ( d.count == GetMoveDistanceFull / movedistance + Castrange ) then

Two major problems here. First and formost, comparing anything to a real with == is extremely dangerous in wc3. If the real happens to not be an integer, it fails miserably. Put an R2I wrapper around the right side of the comparison. Second problem is, you use GetMoveDistanceFull instead of GetMoveDistanceFull(). This causes vJass to think you want a function integer key instead of an actual useful value from said function. In other words, GetMoveDistanceFull will return a value of like 1 or 36 or something.
I recommend wrapping the R2I around equivalent checks in other functions. Note that you do the same silly GetMoveDistanceFull thing again like 3 lines later. And that ALSO needs the R2I call.

Then there's this in the move function:
JASS:
set t = null

You only change the pointer when you need the ref count to be decremented. This has no purpose for objects that won't be destroyed.

Then there's the inherent aesthetic problem. You move the unit and THEN create a laser going in the same distance and direction but at the same speed and from a DIFFERENT starting point.
Imagine kicking someone backwards, and then having a car park in the same direction of your kick in some nearby parking lot, and then blaiming the cars movement on kicking the guy. It makes no sense.
I dunno, maybe you intended that, which would mean I don't get in any way shape or form WTF you're trying to accomplish.
 

T.s.e

Wish I was old and a little sentimental
Reaction score
133
If I'm not horribly mistaken, you do not need to use R2I here, but instead change this..
JASS:
if ( d.count == GetMoveDistanceFull / movedistance + Castrange ) then

To this:
JASS:
if ( d.count >= GetMoveDistanceFull / movedistance + Castrange ) then
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top