HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

VJASS - Spell Problem

11-12-2008, 08:48 PM#1
anXieTy
I have a problem. At first, what does the spell do?
It picks allied units around the target loc, sending out a missile to each unit starting with offset from caster's position, flying towards target. if it reaches the target, the target gets bonus damage, armor and LifeRegen.

As you can see, i spread the missile and the Bonus-Part. The missile is created with the struct "Data" while the Bonus is added with the struct ApplyBonus.

So here is the actual problem: If i want to target let's say 6 allied unit, there are 6 missiles flying to each of them, but when impacting the level debug message of the ApplyBuff struct is SHOWN but there is no Bonus damage, armor, lifeReg added and there is no EXECUTED Debug-Msg for those timers, which i think is pretty strange.

Did i miss something?

Collapse JASS:
scope UTIF initializer init

globals

    private constant integer spellid ='A001'
    
    private constant real distperinterval = 12.
    private constant real aoe = 250.
    
    private constant integer missileid = 'h004'
    
    private constant integer buffspellid = 'A002'
    private constant integer buffid = 'Basl'
    
    private ApplyBonus array applybonuz
    
    private constant integer armorperlvl = 2
    private constant integer dmgperlvl = 5
    
    private constant integer hpregenperlvl = 1
    
    private boolexpr filter = null
endglobals

private function ApplyBonus_cb takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local ApplyBonus a = GetTimerData(t)
    local integer id = GetUnitId(a.target)
    
    call BJDebugMsg("EXECUTED!")
    call a.destroy()
endfunction

struct ApplyBonus
unit target
timer t
integer lvl
boolean created

    static method Create takes unit target returns ApplyBonus
        local ApplyBonus a = ApplyBonus.allocate()
        
        set a.target = target
        set a.t = CreateTimer()
        call SetTimerData(a.t,a)
        set a.created = true
        set a.lvl = 0
        
        return a
    endmethod
    
    method update takes integer lvl returns nothing
        call UnitAddBonus(.target,BONUS_DAMAGE,.lvl*-dmgperlvl)
        call UnitAddBonus(.target,BONUS_ARMOR,.lvl*-armorperlvl)
        call UnitAddBonus(.target,BONUS_LIFE_REGEN,.lvl*-hpregenperlvl)
        if lvl > .lvl then
            set .lvl = lvl
        endif
                
     //   if GetUnitAbilityLevel(.target,buffspellid) == 0 then
       //     call UnitAddAbility(.target,buffspellid)
     //   endif
        
        if .target == null then
            call BJDebugMsg("TARGET IS NULL")
        endif
        
        call UnitAddBonus(.target,BONUS_DAMAGE,.lvl*dmgperlvl)
        call UnitAddBonus(.target,BONUS_ARMOR,.lvl*armorperlvl)
        call UnitAddBonus(.target,BONUS_LIFE_REGEN,.lvl*hpregenperlvl)
        
        
        call TimerStart(.t,5.,false,function ApplyBonus_cb)
        if .t == null then
            call BJDebugMsg("ROFLTARD")
        endif
        call BJDebugMsg(I2S(.lvl))
    endmethod
    
    method onDestroy takes nothing returns nothing
        call UnitAddBonus(.target,BONUS_DAMAGE,.lvl*-dmgperlvl)
        call UnitAddBonus(.target,BONUS_ARMOR,.lvl*-armorperlvl)
        call UnitAddBonus(.target,BONUS_LIFE_REGEN,.lvl*-hpregenperlvl)
        call UnitRemoveAbility(.target,buffspellid)
        call UnitRemoveAbility(.target,buffid)
        call SetTimerData(.t,0)
        call DestroyTimer(.t)
        set .created = false
        set .target = null
    endmethod

endstruct

private struct Data
unit target
unit missile
integer lvl
integer int

    static method Create takes unit target,integer lvl, integer int returns Data
        local Data a = Data.allocate()
        
        set a.target = target
        set a.lvl = lvl
        set a.int = int
        
        return a
    endmethod
    
    method onDestroy takes nothing returns nothing        
        call KillUnit(.missile)
        
        set .missile = null
        set .target = null
    endmethod
endstruct

private function callback takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local Data a  = GetTimerData(t)
    local real nx = 0
    local real ny = 0
    local real angle = 0
    local integer id = 0
    
    if DistanceBetweenXY(GetUnitX(a.missile),GetUnitY(a.missile),GetUnitX(a.target),GetUnitY(a.target)) >= 35 then
            
            set angle = Atan2(GetUnitY(a.target)-GetUnitY(a.missile),GetUnitX(a.target)-GetUnitX(a.missile))
            set nx = GetUnitX(a.missile) + distperinterval * Cos(angle)
            set ny = GetUnitY(a.missile) + distperinterval * Sin(angle)
            
            call SetUnitX(a.missile,nx)
            call SetUnitY(a.missile,ny)
               
    else
        if a.target == null then
            call BJDebugMsg("IS BULLL ALSDASD")
        endif
        set id = GetUnitId(a.target)
        if applybonuz[id].created == false then
            set applybonuz[id] = applybonuz[id].Create(a.target)
        endif
        call applybonuz[id].update(a.lvl)
        call a.destroy()
        call SetTimerData(t,0)
        call DestroyTimer(t)
    
    endif
endfunction

private function EnchantUnitWithMissile takes unit target, integer lvl, integer int, real cx, real cy returns nothing
    local Data a = Data.Create(target,lvl,int)
    local timer t = CreateTimer()
    local real angle = Atan2(GetUnitY(target)-cy,GetUnitX(target)-cx)
    local real nx = cx + 65 * Cos(angle)
    local real ny = cy + 65 * Sin(angle)
    
    set a.missile = CreateUnit(GetOwningPlayer(target),missileid,nx,ny,angle*bj_RADTODEG)
    
    call SetTimerData(t,a)
    call TimerStart(t,0.03,true,function callback)
endfunction

private function Conds takes nothing returns boolean
    return GetSpellAbilityId() == spellid
endfunction

private function filterfunction takes nothing returns boolean

return IsOrganicAlliedUnit(GetFilterUnit(),tempplayer)
endfunction

private function EnchantThem takes nothing returns nothing
    call EnchantUnitWithMissile(GetEnumUnit(),tempint,tempint2,tempreal,tempreal2)
endfunction

private function Actions takes nothing returns nothing
    local unit caster = GetTriggerUnit()
    local real cx = GetUnitX(caster)
    local real cy = GetUnitY(caster)
    local group g = CreateGroup()
    local location tp = GetSpellTargetLoc()
    
    set tempplayer = GetOwningPlayer(caster)
    set tempreal = cx
    set tempreal2 = cy
    set tempint = GetUnitAbilityLevel(caster,spellid)
    set tempint2 = GetHeroInt(caster,true)
    call GroupEnumUnitsInRange(g,GetLocationX(tp),GetLocationY(tp),aoe,filter)
    call ForGroup(g,function EnchantThem)
    
    call DestroyGroup(g)
    call RemoveLocation(tp)
    
    set g = null
    set tp = null
    set caster = null
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 Conds))
    call TriggerAddAction(t,function Actions)
    
    set filter = Condition(function filterfunction)
endfunction


endscope
11-12-2008, 09:33 PM#2
Vexorian
* GetUnitid is PUI? If so, you should try using PUI_struct for that buff struct, I think that's where your problem is laying.
* if you are using timerutils, better use NewTimer/ReleaseTimer instead of CreateTimer/DestroyTimer

in the part that says "Executed" also add the unit's name and verify the timer is not null
11-13-2008, 12:29 PM#3
tamisrah
Could you try setting the .created boolean to 'false' initially? I don't know what uninitialized booleans return. If they don't return false your applyBuff struct would never be created.

This could be checked with a debugMsg in the Create method displaying the used index or something like that.

EDIT: One thing I just remembered, uninitialized variables could cause a threadkill so this might be a good explanation why the "EXECUTED" message won't be shown.