• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[Lua] Problem with Damage Engine (indexing a nil value)

Status
Not open for further replies.
Level 23
Joined
Jun 26, 2020
Messages
1,838
Hello, I'm using the lua damage engine 2.0, and recently I got an error that I'm not sure when exactly happens, but at least happens when I start casting an ability based in channel that has a unit target, the error is in here:
Lua:
local breakCheck = {}   ---@type function[]
local override          ---@type boolean

breakCheck[_DAMAGING]   = function() return override or current.userType == _TYPE_PURE end
breakCheck[_ARMOR]      = function() return current.damage <= 0.00 end
breakCheck[_LETHAL]     = function() return hasLethal and Damage.life > _DEATH_VAL end

---@return boolean
local function damageOrAfter() return current.damageType == DAMAGE_TYPE_UNKNOWN end
breakCheck[_DAMAGED]    = damageOrAfter
breakCheck[_AFTER]      = damageOrAfter

local function defaultCheck() end

---Common function to run any major event in the system.
---@param head damageEventRegistry
---@return boolean ran_yn
local function runEvent(head)
    local check = breakCheck[head] or defaultCheck
    if dreaming or check() then
        return
    end
    userIndex = head.next
    if userIndex ~= head then
        Damage.enable(false)
        enableT(t3)
        dreaming = true
      
        --print("Start of event running")
        repeat
            if not userIndex.trigFrozen and userIndex.filters[userIndex.eFilter] and checkConfig() and not hasSource or (head ~= _SOURCE or (userIndex.minAOE and sourceAOE > userIndex.minAOE)) then
                userIndex.func()
            end
            userIndex = userIndex.next
        until userIndex == head or check()
        --print("End of event running")
      
        dreaming = nil
        Damage.enable(true)
        disableT(t3)
    end
    return true
end
The value current is nil and is used, using my Lua GetStackTrace I found the error comes from this event (look where I commented the word "HERE"):
Lua:
t1 = CreateTrigger()
TriggerRegisterAnyUnitEventBJ(t1, EVENT_PLAYER_UNIT_DAMAGING)
TriggerAddCondition(t1, Filter(function()
    local d = createFromEvent()
    --print("Pre-damage event running for " .. GetUnitName(GetTriggerUnit()))
    if alarmSet then
        if totem then --WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
            if d.damageType == DAMAGE_TYPE_SPIRIT_LINK or d.damageType == DAMAGE_TYPE_DEFENSIVE or d.damageType == DAMAGE_TYPE_PLANT then
                lastInstance    = current
                totem           = nil
                canKick         = nil
            else
                failsafeClear() --HERE | Not an overlapping event - just wrap it up
            end
        else
            finish() --wrap up any previous damage index
        end
      
        if _USE_EXTRA then
            if d.source ~= originalSource then
                onAOEEnd()
                originalSource = d.source
                originalTarget = d.target
            elseif d.target == originalTarget then
                sourceStacks = sourceStacks + 1
            elseif not IsUnitInGroup(d.target, Damage.targets) then
                sourceAOE = sourceAOE + 1
            end
        end
    else
        alarmSet = true
        Timed.call(
        function()
            alarmSet, dreaming = nil, nil
            Damage.enable(true)
            if totem then
                failsafeClear() -- AND HERE | WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
            else
                canKick = true
                kicking = nil
                finish()
            end
            onAOEEnd()
            current = nil
            --print("Timer wrapped up")
        end)
        if _USE_EXTRA then
            originalSource  = d.source
            originalTarget  = d.target
        end
    end
    if _USE_EXTRA then GroupAddUnit(Damage.targets, d.target) end
    if doPreEvents(d, true) then
        runEvent(_ZERO)
        canKick = true
        finish()
    end
    totem = not lastInstance or attacksImmune[d.attackType] or damagesImmune[d.damageType] or not CheckUnitType(d.target, UNIT_TYPE_MAGIC_IMMUNE)
end))
I don't know if the reason is because I touched something that I shouldn't, but the system is too complex to me to figure it out.
 
Last edited:
Level 23
Joined
Jun 26, 2020
Messages
1,838
I found also in this function is happening the same error:
Lua:
local function setArmor(reset)
    if _USE_ARMOR_MOD then
        local pierce    ---@type real
        local at        ---@type integer
        local dt        ---@type integer
        if reset then
            pierce  =   current.armorPierced
            at      =   current.prevArmorT
            dt      =   current.prevDefenseT
        else
            pierce  =  -current.armorPierced
            at      =   current.armorType
            dt      =   current.defenseType
        end
        if pierce ~= 0.00 then --Changed condition thanks to bug reported by BLOKKADE
            BlzSetUnitArmor(current.target, BlzGetUnitArmor(current.target) + pierce)
        end
        if current.prevArmorT ~= current.armorType then
            BlzSetUnitIntegerField(current.target, UNIT_IF_ARMOR_TYPE, at)
        end
        if current.prevDefenseT ~= current.defenseType then
            BlzSetUnitIntegerField(current.target, UNIT_IF_DEFENSE_TYPE, dt)
        end
    end
end
In fact this function uses both of them
Lua:
local function failsafeClear()
    setArmor(true) -- Here
    canKick = true
    kicking, totem = nil, nil
    runEvent(_DAMAGED) -- And here
    eventsRun = true
    finish()
end
The function finish() set current to nil but is after of those, and happens me in the 2 calls of that function in the trigger action I pointed out before:
Lua:
t1 = CreateTrigger()
TriggerRegisterAnyUnitEventBJ(t1, EVENT_PLAYER_UNIT_DAMAGING)
TriggerAddCondition(t1, Filter(function()
    local d = createFromEvent()
    --print("Pre-damage event running for " .. GetUnitName(GetTriggerUnit()))
    if alarmSet then
        if totem then --WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
            if d.damageType == DAMAGE_TYPE_SPIRIT_LINK or d.damageType == DAMAGE_TYPE_DEFENSIVE or d.damageType == DAMAGE_TYPE_PLANT then
                lastInstance    = current
                totem           = nil
                canKick         = nil
            else
                failsafeClear() -- HERE | Not an overlapping event - just wrap it up
            end
        else
            finish() --wrap up any previous damage index
        end
    
        if _USE_EXTRA then
            if d.source ~= originalSource then
                onAOEEnd()
                originalSource = d.source
                originalTarget = d.target
            elseif d.target == originalTarget then
                sourceStacks = sourceStacks + 1
            elseif not IsUnitInGroup(d.target, Damage.targets) then
                sourceAOE = sourceAOE + 1
            end
        end
    else
        alarmSet = true
        Timed.call(
        function()
            alarmSet, dreaming = nil, nil
            Damage.enable(true)
            if totem then
                failsafeClear() -- AND HERE | WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
            else
                canKick = true
                kicking = nil
                finish()
            end
            onAOEEnd()
            current = nil
            --print("Timer wrapped up")
        end)
        if _USE_EXTRA then
            originalSource  = d.source
            originalTarget  = d.target
        end
    end
    if _USE_EXTRA then GroupAddUnit(Damage.targets, d.target) end
    if doPreEvents(d, true) then
        runEvent(_ZERO)
        canKick = true
        finish()
    end
    totem = not lastInstance or attacksImmune[d.attackType] or damagesImmune[d.damageType] or not CheckUnitType(d.target, UNIT_TYPE_MAGIC_IMMUNE)
end))
 
Last edited:
Level 23
Joined
Jun 26, 2020
Messages
1,838
Just to be clear, is this happening with just a vanilla install of Damage Engine? Did you change any of the configuration? I'd like to see about reproducing that on my end. As for me, all tests were successful and I didn't spot any thread crashes.
First I though that maybe I touched something, so I copy-pasted again the system, but still happening (the unique change was remove the first paramater of the OnGlobalInit function to make it compatible with the new version).
I don't know exactly when happens, I just know that happens when a unit starts casting an spell with 0 damage to a unit.
 
Level 23
Joined
Jun 26, 2020
Messages
1,838
I found that this also runs the error (the part of the Damage.apply), I think that will make easier find the problem:

Lua:
OnMapInit(function ()
    local Spell = FourCC('A02Z')
    local DmgFactor = 1.5
    local Chance = 15
    local Area = 200.
    local Effect = "Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl"
    local Sound = "Abilities\\Spells\\Orc\\Shockwave\\Shockwave.flac"

    Digimon.preDamageEvent(function (info)
        if udg_IsDamageAttack then
            local source = info.source ---@type Digimon
            if source:hasAbility(Spell) then
                if math.random(0, 100) <= Chance then
                    local target = info.target ---@type Digimon
                    local amount = info.amount * DmgFactor

                    DestroyEffect(AddSpecialEffectTarget(Effect, target.root, "origin"))

                    local snd = CreateSound(Sound, false, true, true, 10, 10, "DefaultEAXON")
                    AttachSoundToUnit(snd, target.root)
                    SetSoundVolume(snd, 127)
                    StartSound(snd)
                    KillSoundWhenDone(snd)

                    ForUnitsInRange(target:getX(), source:getY(), Area, function (u)
                        Damage.apply(source.root, u, amount, true, false, ATTACK_TYPE_MELEE, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
                    end)

                    info.amount = 0.
                end
            end
        end
    end)
end)
 
Status
Not open for further replies.
Top