[JASS] Mysterious crash

Level 6
Joined
Mar 9, 2023
Messages
75
Hello! Since the 2.0 update I've been getting reports of an incredibly specific crash involving one of my heroes. I cannot replicate it and it never occurs during my playtesting. It specifically crashes when there are the following enemies: 1. Illusions. 2. A temporary unit spawned by Pocket Factory. 3. A regular unit.

Can you please look through a couple of my functions and see if I'm messing up anywhere, or if they're just not playing nice with e.g. the illusions. I'm currently reducing the amounts of check that aren't vital as well as trying to fetch crash logs.

Ability: summon a ghost (dummy) which follows enemies around trying to deal damage to them.
JASS:
function CallGuide_Timer takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer t_id = GetHandleId(t)
    local unit uc = LoadUnitHandle(HASH, t_id, 'cauc')
    local unit dummy = LoadUnitHandle(HASH, t_id, 'cadu')
    local unit target = LoadUnitHandle(HASH, t_id, 'catg')
    local real time = LoadReal(HASH, t_id, 'cati') + 0.03
    local real damageTime = LoadReal(HASH, t_id, 'dmgt') + 0.03
    local real lvl = 0.10 + GetUnitAbilityLevel(uc, 'A0CS') * 0.03
    local real damage = GetHeroInt(uc, true) * lvl
    local real targetX
    local real targetY
    local real distanceToTarget
    local real closestDistance = 1000.0
    local real angleToTarget
    local group g = CreateGroup()
    local unit tempUnit
    
    call SaveReal(HASH, t_id, 'cati', time)
    
    if uc == null or dummy == null then
        call RemoveUnit(dummy)
        call PauseTimer(t)
        call DestroyTimer(t)
        call FlushChildHashtable(HASH, t_id)
        return
    endif

    if GetUnitAbilityLevel(uc, 'A0CX') >= 1 then
    set damage = damage * 1.33
    endif
   
   // Target acquisition if there is no target or it died, the functions are all correct
    if target == null or IsUnitDeadBJ(target) then
    if (udg_EnablePVP) then
    if uc == udg_ChosenHeroUnit then
    call GroupEnumUnitsInRange(g, GetUnitX(uc), GetUnitY(uc), 600.0, function AttackHero)
    endif
    if uc != udg_ChosenHeroUnit then
    call GroupEnumUnitsInRange(g, GetUnitX(uc), GetUnitY(uc), 600.0, function AttackLoathing)
    endif
    else
    call GroupEnumUnitsInRange(g, GetUnitX(uc), GetUnitY(uc), 600.0, function AttackBoss)
    endif
   
    // Gets the closest enemy in the loop
    loop
        set tempUnit = FirstOfGroup(g)
        exitwhen tempUnit == null

        call GroupRemoveUnit(g, tempUnit)
        set distanceToTarget = Distance(GetUnitX(uc), GetUnitY(uc), GetUnitX(tempUnit), GetUnitY(tempUnit))
        if distanceToTarget < closestDistance then
        set closestDistance = distanceToTarget
                set target = tempUnit
        endif
    endloop
       
        //Remember target through timer repeat
        if target != null then
            call SaveUnitHandle(HASH, t_id, 'catg', target)
        endif
        call DestroyGroup(g)
    endif
   
    // Move dummy to target and damage it if it's close enough
    if target != null then
        set targetX = GetUnitX(target)
        set targetY = GetUnitY(target)
        set distanceToTarget = Distance(GetUnitX(dummy), GetUnitY(dummy), targetX, targetY)
        
    if distanceToTarget > 70.0 then
         set angleToTarget = bj_RADTODEG * Atan2(targetY - GetUnitY(dummy), targetX - GetUnitX(dummy))
         if RAbsBJ(angleToTarget - GetUnitFacing(dummy)) > 10 then
          call SetUnitFacing(dummy, angleToTarget)
          endif
          call Move_Missile(dummy, 10.0)
        else
        if damageTime >= 0.12 then
                call SetWidgetLife(target, GetWidgetLife(target) - damage)
            call CreateTextTagUnit(I2S(R2I(damage)), target, 0.00, 10.00, 0, 155, 255, 255, 0, 0.03, 1.00, false, true)
            set udg_DMG[GetConvertedPlayerId(GetOwningPlayer(uc))] = (udg_DMG[GetConvertedPlayerId(GetOwningPlayer(uc))] + damage )
            set damageTime = 0
        endif
    call SaveReal(HASH, t_id, 'dmgt', damageTime)
        endif
    endif
   
    // End of duration
    if time > 30.0 then
        call RemoveUnit(dummy)
        call PauseTimer(t)
        call DestroyTimer(t)
        call FlushChildHashtable(HASH, t_id)
    endif
    
    set t = null
    set uc = null
    set dummy = null
    set target = null
    set tempUnit = null
endfunction

//Handler and timer
function CallGuide_Actions takes nothing returns nothing
    local unit uc = GetTriggerUnit()
    local unit dummy = CreateUnit(GetOwningPlayer(uc), 'n05V', GetUnitX(uc), GetUnitY(uc), 0)
    local timer t = CreateTimer()
    local integer t_id = GetHandleId(t)
    call SaveUnitHandle(HASH, t_id, 'cauc', uc)
    call SaveUnitHandle(HASH, t_id, 'cadu', dummy)
    call SaveReal(HASH, t_id, 'dmgt', 0.0)
    call SaveReal(HASH, t_id, 'cati', 0.0)
    call TimerStart(t, 0.03, true, function CallGuide_Timer)
    set uc = null
    set dummy = null
    set t = null
endfunction

The functions Move_Missile and Distance work as intended.

Ability: AoE damage and slow.
JASS:
function TombCries_Actions takes nothing returns nothing
local unit ut
local unit uc = GetSpellAbilityUnit()
local unit dummy
local ability a
local integer abilityId = 'A0CV'
local player p = GetOwningPlayer(uc)
local group g = CreateGroup()
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
local real int = GetHeroInt(uc, true)
local real damage = ((I2R(GetUnitAbilityLevel(uc,'A00B'))*0.15+0.5) * int)
local real speed

if GetUnitAbilityLevel(uc, 'A0CY') >= 1 then
set damage = damage * 1.5
endif

// Group filters
if (udg_EnablePVP) then
if uc == udg_ChosenHeroUnit then
call GroupEnumUnitsInRange(g,x,y,350,function AttackHero)
endif
if uc != udg_ChosenHeroUnit then
call GroupEnumUnitsInRange(g,x,y,350,function AttackLoathing)
endif
else
call GroupEnumUnitsInRange(g,x,y,350,function AttackBoss)
endif
call CreateTextTagUnit(I2S(R2I(damage)) + " damage", uc, 0.00, 12.00, 0, 155, 255, 255, 0, 0.03, 1.00, false, true)

// Damage and slow each unit. Damage is preset, slow amount is randomized.
loop
set ut = FirstOfGroup(g)
exitwhen ut==null
set dummy = CreateUnit(p, 'n00S',x,y, GetUnitFacing(ut))
call UnitAddAbility(dummy,abilityId)
set a = BlzGetUnitAbility(dummy, abilityId)
call IncUnitAbilityLevelSwapped(abilityId, dummy)
if GetUnitAbilityLevel(uc, 'A0CY') >= 1 then
set speed = I2R(GetRandomInt(20, 20 + R2I(int)))
else 
set speed = I2R(GetRandomInt(0, R2I(int)))
endif
call CreateTextTagUnit("- " + I2S(R2I(speed)),ut, 0.00, 8.00, 255, 0, 0, 255, 0, 0.03, 1.00, false, true)
call SetTextTagPos(GetLastCreatedTextTag(), x, y, 100)
set speed = speed/100
call BlzSetAbilityRealLevelField(a, ABILITY_RLF_MOVEMENT_SPEED_INCREASE_PERCENT_BLO2, 0, - speed)
call DecUnitAbilityLevelSwapped(abilityId, dummy)
call IssueTargetOrder(dummy,"bloodlust",ut)
call UnitApplyTimedLifeBJ(3.00, 'BTLF', dummy)
call DestroyEffect(AddSpecialEffectTarget("Soul Beam Blue.mdx",ut,"origin"))
call UnitDamageTarget(uc, ut, damage, true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
call GroupRemoveUnit(g,ut)
endloop

call DestroyGroup(g)

set a = null
set dummy = null
set ut = null
set uc = null
set g = null
endfunction
 
Top