HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Infinite Loop

01-29-2010, 10:45 PM#1
Saishy
Collapse JASS:
scope GinreiKojaku initializer in_Ginrei_Kojaku

private struct Ginrei
    unit caster
    integer arrows // (Agility / TIMES)
    integer times
    real damage
    real x
    real y
endstruct

globals
    private constant integer GINREI = 'A042'
    private constant string EFFECT = "Abilities\\Weapons\\ColdArrow\\ColdArrowMissile.mdl"
    private constant string MESSAGE = "Ginrei Kojaku!"
    private constant integer TIMES = 10 // TIMES * TIMER = Ultimate's Duration
    private constant real TIMER = 0.5 // How often happens each sequence
    private constant real ANGLE = 0.35 // 20 DEG, How much variation between arrow's angle
    //private constant real MAXDIST = 400 // Max distance for teleport
    //private Ginrei array ginrei[12]
endglobals

private struct arrowMissile extends xecollider
        unit caster
        real damage

        method onUnitHit takes unit target returns nothing
            if TargetCheck(this.caster, target) then
                if SpellHit(this.caster, target, GINREI) then
                    call UnitDamageTargetEx(this.caster, target, this.damage, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_SPELL, false, true)
                endif
                call this.terminate()
            endif
        endmethod
endstruct

function Ginrei_Kojaku_Conditions takes nothing returns boolean
    return (GetSpellAbilityId() == GINREI)
endfunction

//function Ginrei_Teleport_Location takes unit temp, real tx, real ty returns nothing
//    local integer p = GetPlayerId(GetOwningPlayer(temp))
//    if not(ginrei[p] == null) then
//        set ginrei[p].x = tx
//        set ginrei[p].y = ty
//    endif
//endfunction

//function Ginrei_Check_Ultimate takes unit temp returns boolean
//    if (ginrei[GetPlayerId(GetOwningPlayer(temp))] == null) then
//        return false
//    endif
//    return true
//endfunction

function Ginrei_Kojaku_Fire takes nothing returns nothing
    local Ginrei g = GetTimerData(GetExpiredTimer())
    local arrowMissile xc
    local group tempgroup = CreateGroup()
    local unit tempunit
    local unit minunit
    local integer count = 0
    local real tangle
    local real tx
    local real ty
    local real dx
    local real dy
    local real dist
    local real mindist = 99999 //just a random high value
    
    set g.times = g.times + 1
    set g.x = GetUnitX(g.caster)
    set g.y = GetUnitY(g.caster)
    call BJDebugMsg("g.times = " + I2S(g.times))
    
    //Here we get the nearest enemy! DIE!
    call GroupEnumUnitsInRange(tempgroup, g.x, g.y, 1200, null)
    loop
        set tempunit = FirstOfGroup(tempgroup)
        exitwhen (tempunit == null)
        if TargetCheck(g.caster, tempunit) and IsUnitVisible(tempunit, GetOwningPlayer(g.caster)) then
            set dx = GetUnitX(tempunit) - g.x
            set dy = GetUnitY(tempunit) - g.y
            set dist = SquareRoot(dx * dx + dy * dy)
            if (dist < mindist) then
                set minunit = tempunit
                set mindist = dist
            endif
        endif
        call GroupRemoveUnit(tempgroup, tempunit)
    endloop
    call BJDebugMsg("Min Ok")
    call BJDebugMsg("minunit = " + GetUnitName(minunit))
    //Now we must shoot at it, we wanna kill it after all
    if (minunit != null) then
        set dx = GetUnitX(minunit)
        set dy = GetUnitY(minunit)
        set tangle = Atan2(dy - g.y, dx - g.x) //Get our arrow's angle
        loop
            exitwhen (count == g.arrows)
            set xc = arrowMissile.create(g.x, g.y, (tangle + GetRandomReal(-ANGLE, ANGLE))) //Some noise to the angle
            set xc.fxpath         = EFFECT
            set xc.damage         = g.damage
            set xc.speed          = 1500.0
            set xc.expirationTime = 1.13
            set xc.z              = 100.0
            set xc.caster         = g.caster
            set xc.collisionSize  = 80
            set count = count + 1
            call BJDebugMsg("count = " + I2S(count))
        endloop
    endif
    call BJDebugMsg("Shoot ok")
    //Oh, already ended?
    if (g.times == TIMES) then
        call BJDebugMsg("TEH ENDZ")
        set g.caster = null
        call ReleaseTimer(GetExpiredTimer())
        call g.destroy()
    endif
    call BJDebugMsg("End ok")
    call DestroyGroup(tempgroup)
    set tempgroup = null
    set tempunit = null
    set minunit = null
endfunction

function Ginrei_Kojaku_Start takes nothing returns nothing
    local Ginrei g = Ginrei.create()
    local timer t
    local integer arrows
    local integer level
    local real damage
    
    set g.times = 0
    set g.caster = GetTriggerUnit()
    set arrows = R2I(GetHeroAgi(g.caster, true) / TIMES)
    set level = GetUnitAbilityLevel(g.caster, GINREI)
    if (arrows < R2I((50 * level)/TIMES)) then
        set g.arrows = R2I((50 * level)/TIMES)
    else
        set g.arrows = arrows
    endif
    set damage = (0.25 * GetHeroInt(g.caster, true))
    if (damage < (5 * level)) then
        set g.damage = (5 * level)
    else
        set g.damage = damage
    endif
    set g.x = GetUnitX(g.caster)
    set g.y = GetUnitY(g.caster)
    
    call DisplayText(g.caster, MESSAGE, 2)
    set t = NewTimer()
    call SetTimerData(t,g)
    call TimerStart(t, TIMER, true, function Ginrei_Kojaku_Fire)
    call BJDebugMsg("g.arrows = " + I2S(g.arrows))
    call BJDebugMsg("g.damage = " + R2S(g.damage))
endfunction

//===========================================================================
function in_Ginrei_Kojaku takes nothing returns nothing
    local trigger = t_Ginrei_Kojaku = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t_Ginrei_Kojaku, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t_Ginrei_Kojaku, Condition(function Ginrei_Kojaku_Conditions))
    call TriggerAddAction(t_Ginrei_Kojaku, function Ginrei_Kojaku_Start)
    set t_Ginrei_Kojaku = null
endfunction

endscope

This spells is supposed to get the nearest enemy in 1200 range, and shoots arrows at it every 0,5s.
But it never ends!

Display:

When there is no enemy near:

g.times = X
Min Ok
(repeat)

When there is a enemy near:

g.times = X
Min Ok
Shoot Ok
End Ok
(repeat)

And it just keep going, never stops.

Thanks in advance for any help!
01-29-2010, 11:38 PM#2
Themerion
This is what happens when no enemies are nearby (without BJDebugCalls):

Collapse JASS:
 // minunit initialized without a value
local unit minunit

// ....

// Group loop, blahblah
// Doesn't set a value to minunit if nobody's nearby

// ....

// JASS now tries to read minunit and compare it to null
// JASS cannot read minunit, it doesn't have a value
// JASS stops this code right here.

if (minunit != null) then

Initializing minunit to null should solve this.
Collapse JASS:
local unit minunit = null
01-29-2010, 11:47 PM#3
Saishy
I thought jass initialized variables, like Java.
Like integers = 0.

I'm trying it, will edit if it works!
Thanks!
01-30-2010, 12:14 AM#4
Ammorth
Just to clarify, arrays will initialize automotically to their null values (0, "", null, false) but single variables will not. You need to explicitly set them. At one time, they caused threads to crash and wc3 to close when accessed, although I'm not sure on the current effects (as JNGP can prevent crashes).
01-30-2010, 01:36 AM#5
Veev
Yes. I had a loop once where I forgot to set i = 0 and I had something like... exitwhen i > 3 and my 'logic' thought it was already set to 0. Suffice to say, the loop never ran because i was some crazy value.
01-30-2010, 02:56 AM#6
Saishy
Thanks! Its working now!

But how can I force my unit to play the attack animation every time he shoot the arrows?
SetUnitAnimation is not doing anything.
Tried SetUnitAnimationByIndex but its still being overlaped by simply moving commands.
Also, how can I instantly change a unit facing? SetUnitFacing is making the unit turns instead of setting the angle.
01-30-2010, 02:40 PM#7
Michael Peppers
Quote:
Originally Posted by Saishy
But how can I force my unit to play the attack animation every time he shoot the arrows?
SetUnitAnimation is not doing anything.
Tried SetUnitAnimationByIndex but its still being overlaped by simply moving commands.
For the animation issue you could pause the unit until the animation ends.
01-30-2010, 07:31 PM#8
Anitarf
Use of uninitialized variables does cause a thread crash, but not a game crash. JNGP can not prevent these since TFT 1.22 because that is when war3err stopped working.

Unless you somehow lock the unit by either pausing it or making the spell a channeling spell, it will always interrupt the animations you are trying to play with its own actions. There is no way to instantly change the facing of a unit.