• 🏆 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!

[Solved] Lua - blindness ?

Status
Not open for further replies.
Level 12
Joined
Jan 30, 2020
Messages
875
Hello guys !!

I don't know if it is because I have worked all night, but I am stuck on tracking a compile bug with my latest spell implementation.

I have this really long Lua function that fires a "unknown error" when WE tries to save the map.

I have narrowed the problem down to a very small part of the code.

If I comment out lines like that, the map saves and the Lua script does not trigger any compile error :
Lua:
-- other actions
            Roast[r]={CreateTrigger(), CreateTrigger(), b, bn} -- Initializing Roasting Ball data
            TriggerRegisterUnitEvent(Roast[r][1], r, EVENT_UNIT_DAMAGED)
            TriggerRegisterUnitEvent(Roast[r][2], r, EVENT_UNIT_DEATH)
            TriggerAddCondition(Roast[r][1], Condition(DamagedBallActions)) -- Roasting Balls can be damaged like normal Balls
            -- TriggerAddCondition(Roast[r][2], Condition(function() -- Roasting Balls require specific actions when killed
            --    local r=GetTriggerUnit()
            --    local bn=Roast[r][4]
            --    PlayCleanSFX(SFXCubes, GetUnitX(r), GetUnitY(r), math.random()*0.4+0.2, math.random()*Pi2, 0, 3.0)
            --    StoreBall(Roast[r][3], bn, math.floor((bn-1)/BallsPerLevel)+1)
            --    DestroyTrigger(Roast[r][1])
            --    DestroyTrigger(Roast[r][2])
            --    RemoveUnit(r)
            --    return false
            -- ))
            TimerData[t]={b, r} -- Setting up the data for the timer expiring at the end of the duration of Torrefaction.
-- other actions

If I remove the comments from the second TriggerAddCondition (but keep the comments inside), the script triggers the unknown compile error near ")" at the line with "))" :

Lua:
-- other actions
            Roast[r]={CreateTrigger(), CreateTrigger(), b, bn} -- Initializing Roasting Ball data
            TriggerRegisterUnitEvent(Roast[r][1], r, EVENT_UNIT_DAMAGED)
            TriggerRegisterUnitEvent(Roast[r][2], r, EVENT_UNIT_DEATH)
            TriggerAddCondition(Roast[r][1], Condition(DamagedBallActions)) -- Roasting Balls can be damaged like normal Balls
            TriggerAddCondition(Roast[r][2], Condition(function() -- Roasting Balls require specific actions when killed
            --    local r=GetTriggerUnit()
            --    local bn=Roast[r][4]
            --    PlayCleanSFX(SFXCubes, GetUnitX(r), GetUnitY(r), math.random()*0.4+0.2, math.random()*Pi2, 0, 3.0)
            --    StoreBall(Roast[r][3], bn, math.floor((bn-1)/BallsPerLevel)+1)
            --    DestroyTrigger(Roast[r][1])
            --    DestroyTrigger(Roast[r][2])
            --    RemoveUnit(r)
            --    return false
            ))
            TimerData[t]={b, r} -- Setting up the data for the timer expiring at the end of the duration of Torrefaction.
-- other actions

I know I am tired, but honestly even after looking at this for hours, I still can not see anything wrong with my adding of the trigger condition.

Can anyone identify what is wrong there ?

Just in case here is the full function :

Lua:
function SpellEffects()
    local spellEffects=CreateTrigger()
    for i=1, 4 do
        if Playing[i] then
            TriggerRegisterPlayerUnitEvent(spellEffects, Player(i-1), EVENT_PLAYER_UNIT_SPELL_EFFECT, nil)
        end
    end
    TriggerAddCondition(spellEffects, Condition(function ()
        local sId=GetSpellAbilityId()
        if (sId==SpellID[14]) then -- Restore Tower
            local c,t=GetTriggerUnit(),GetSpellTargetUnit()
            local pn,on,maxlife=GetPlayerId(GetOwningPlayer(c))+1,GetPlayerId(GetOwningPlayer(t))+1,BlzGetUnitMaxHP(t)
            PlayCleanSFX(SFXHeal, GetUnitX(c), GetUnitY(c), 1.4, 0.0, 0, 4.0)
            PlayCleanSFX(SFXHealed, GetUnitX(t), GetUnitY(t), 1.4, 0.0, 0, 4.0)
            if (pn==LocalPn) then
                PlayGlobalSound(SNDHeal, SNDHealDur)
            end
            for i=1,4 do
                if (t==Select[i]) then
                    UpdateHP(t, maxlife, maxlife, on, i, true)
                end
            end
        elseif (sId==SpellID[9]) then -- Go Back Home
            local b=GetSpellTargetUnit()
            PlaySFXSound(SNDGBH, GetUnitX(b), GetUnitY(b), 120, SNDGBHDur)
            UnitAddAbility(b, GBHTextID)
            local bn=GetUnitUserData(b)
            local d=math.floor((bn-1)/BallsPerLevel+1)*10+1
            Destination[bn]=d
            IssueDelayedPointOrder(b, "move", WPx[d], WPy[d], 0.1)
        elseif (sId==SpellID[10]) then -- Flash Forward
            local b=GetSpellTargetUnit()
            local bn=GetUnitUserData(b)
            PlayCleanSFX(SFXFF, GetUnitX(b), GetUnitY(b), 1.4, 0.0, 0, 1.0)
            local d=Destination[bn]
            local life=GetWidgetLife(b)*0.66 -- reduced life by 33%
            SetWidgetLife(b, life)
            if (math.fmod(d, 10)<7) then
                local tX,tY=WPx[d],WPy[d]
                PauseUnit(b, true)
                SetUnitInvulnerable(b, true)
                ShowUnit(b, false)
                PlayCleanSFX(SFXFF, tX, tY, 1.4, 0.0, 0, 1.0)
                SetUnitPosition(b, tX, tY)
                SetUnitInvulnerable(b, false)
                ShowUnit(b, true)
                PauseUnit(b, false)
                for i=1,4 do
                    if (b==Select[i]) then
                        if (i==LocalPn) then
                            SelectUnit(b, true)
                        end
                        UpdateHP(b, life, CurrentMaxHP, 9, i, true)
                    end
                end
                d=d+1
                Destination[un]=d
                IssueDelayedPointOrder(b, "move", WPx[d], WPy[d], 0.1)
            end
        elseif (sId==SpellID[15]) then -- Torrefaction
            local t,b,type,select=CreateTimer(),GetSpellTargetUnit(),BallType[5],__jarray(false)
            local bn,bx,by,ba,life=GetUnitUserData(b),GetUnitX(b),GetUnitY(b),GetUnitFacing(b),GetWidgetLife(b)
            PlayCleanSFX(SFXTor, GetUnitX(b), GetUnitY(b), 1.0, 0.0, 0, 1.5)
            if IsFlying then
                type=BallType[6]
            end
            for i=1, 4 do -- saving the selection state of the Ball for all players
                if IsUnitSelected(b, Player(i-1)) then
                    select[i]=true
                end
            end
            ShowUnit(b, false)
            PauseUnit(b, true)
            SetUnitInvulnerable(b, true)
            DisableBallTriggers(bn)
            local r=CreateUnit(BallsMaster, type, bx, by, ba)
            SetUnitUserData(r, bn)
            BlzSetUnitMaxHP(r, CurrentMaxHP)
            SetWidgetLife(r, life)
            local size=life*ResizeFactor
            if (size<MinSize) then
                size=MinSize
            end
            SetUnitScale(r, size, size, size)
            for i=1, 4 do -- Selecting the Roasting Ball if the normal Ball was selected
                if select[i] and (i==LocalPn) then
                    SelectUnit(r, true)
                end
            end
            Roast[r]={CreateTrigger(), CreateTrigger(), b, bn} -- Initializing Roasting Ball data
            TriggerRegisterUnitEvent(Roast[r][1], r, EVENT_UNIT_DAMAGED)
            TriggerRegisterUnitEvent(Roast[r][2], r, EVENT_UNIT_DEATH)
            TriggerAddCondition(Roast[r][1], Condition(DamagedBallActions)) -- Roasting Balls can be damaged like normal Balls
            TriggerAddCondition(Roast[r][2], Condition(function() -- Roasting Balls require specific actions when killed
            --    local r=GetTriggerAnit()
            --    local bn=Roast[r][4]
            --    PlayCleanSFX(SFXCubes, GetUnitX(r), GetUnitY(r), math.random()*0.4+0.2, math.random()*Pi2, 0, 3.0)
            --    StoreBall(Roast[r][3], bn, math.floor((bn-1)/BallsPerLevel)+1)
            --    DestroyTrigger(Roast[r][1])
            --    DestroyTrigger(Roast[r][2])
            --    RemoveUnit(r)
            --    return false
            ))
            TimerData[t]={b, r} -- Setting up the data for the timer expiring at the end of the duration of Torrefaction.
            TimerStart(t, 2+2*GetUnitAbilityLevel(GetTriggerUnit(), sId), false, function()
                local t=GetExpiredTimer()
                local b,r=TimerData[t][1],TimerData[t][2]
                DestroyTimer(t)
                -- if the Roasting Ball is dead it has been removed and then it will be nil. Its Ball is stored so we don't have to do anything
                if (r~=nil) then
                    local life=GetWidgetLife(r)
                    SetWidgetLife(b, life)
                    local size,select=life*ResizeFactor,__jarray(false)
                    if (size<MinSize) then
                        size=MinSize
                    end
                    SetUnitScale(b, size, size, size)
                    for i=1, 4 do -- saving the selection state of the Roasting ball for all players
                        if IsUnitSelected(r, Player(i-1)) then
                            select[i]=true
                        end
                    end
                    PlayCleanSFX(SFXTor, GetUnitX(b), GetUnitY(b), 1.0, 0.0, 0, 1.5)
                    DestroyTrigger(Roast[r][1])
                    DestroyTrigger(Roast[r][2])
                    RemoveUnit(r)
                    EnableBallTriggers(bn)
                    SetUnitInvulnerable(b, false)
                    PauseUnit(b, false)
                    ShowUnit(b, true)
                    for i=1, 4 do -- Selecting the Ball if the Roasting Ball was selected
                        if select[i] and (i==LocalPn) then
                            SelectUnit(b, true)
                        end
                    end
                    local d=Destination[GetUnitUserData(b)]
                    IssueDelayedPointOrder(b, "move", WPx[d], WPy[d], 0.0)
                end
            end)
        end
        return false
    end))
end
 
Last edited:
Level 12
Joined
Jan 30, 2020
Messages
875
Thanks for trying to find out, I do appreciate helping hands :)

I found the problem : It seems Lua in Warcraft 3 Reforge does not tolerate extensive nesting of conditions :
As soon as I created a separate function containing the actions, everything started working like a charm.

Here is the resulting final working function (tested ingame too) :
Lua:
function RoastDeathActions()
    local r=GetTriggerUnit()
    local bn,t=Roast[r][4],Roast[r][5]
    PlayCleanSFX(SFXCubes, GetUnitX(r), GetUnitY(r), math.random()*0.4+0.2, math.random()*Pi2, 0, 3.0)
    StoreBall(Roast[r][3], bn, math.floor((bn-1)/BallsPerLevel)+1)
    DestroyTrigger(Roast[r][1])
    RemoveUnit(r)
    PauseTimer(t) -- If the Roasting Ball is killed, we don't need to let the Torrefaction timer anymore
    DestroyTimer(t)
    DestroyTrigger(GetTriggeringTrigger())
    return false
end

function SpellEffects()
    local spellEffects=CreateTrigger()
    for i=1, 4 do
        if Playing[i] then
            TriggerRegisterPlayerUnitEvent(spellEffects, Player(i-1), EVENT_PLAYER_UNIT_SPELL_EFFECT, nil)
        end
    end
    TriggerAddCondition(spellEffects, Condition(function ()
        local sId=GetSpellAbilityId()
        if (sId==SpellID[14]) then -- Restore Tower
            local c,t=GetTriggerUnit(),GetSpellTargetUnit()
            local pn,on,maxlife=GetPlayerId(GetOwningPlayer(c))+1,GetPlayerId(GetOwningPlayer(t))+1,BlzGetUnitMaxHP(t)
            PlayCleanSFX(SFXHeal, GetUnitX(c), GetUnitY(c), 1.4, 0.0, 0, 4.0)
            PlayCleanSFX(SFXHealed, GetUnitX(t), GetUnitY(t), 1.4, 0.0, 0, 4.0)
            if (pn==LocalPn) then
                PlayGlobalSound(SNDHeal, SNDHealDur)
            end
            for i=1,4 do
                if (t==Select[i]) then
                    UpdateHP(t, maxlife, maxlife, on, i, true)
                end
            end
        elseif (sId==SpellID[9]) then -- Go Back Home
            local b=GetSpellTargetUnit()
            PlaySFXSound(SNDGBH, GetUnitX(b), GetUnitY(b), 120, SNDGBHDur)
            UnitAddAbility(b, GBHTextID)
            local bn=GetUnitUserData(b)
            local d=math.floor((bn-1)/BallsPerLevel+1)*10+1
            Destination[bn]=d
            IssueDelayedPointOrder(b, "move", WPx[d], WPy[d], 0.1)
        elseif (sId==SpellID[10]) then -- Flash Forward
            local b=GetSpellTargetUnit()
            local bn=GetUnitUserData(b)
            PlayCleanSFX(SFXFF, GetUnitX(b), GetUnitY(b), 1.4, 0.0, 0, 1.0)
            local d=Destination[bn]
            local life=GetWidgetLife(b)*0.66 -- reduced life by 33%
            SetWidgetLife(b, life)
            if (math.fmod(d, 10)<7) then
                local tX,tY=WPx[d],WPy[d]
                PauseUnit(b, true)
                SetUnitInvulnerable(b, true)
                ShowUnit(b, false)
                PlayCleanSFX(SFXFF, tX, tY, 1.4, 0.0, 0, 1.0)
                SetUnitPosition(b, tX, tY)
                SetUnitInvulnerable(b, false)
                ShowUnit(b, true)
                PauseUnit(b, false)
                for i=1,4 do
                    if (b==Select[i]) then
                        if (i==LocalPn) then
                            SelectUnit(b, true)
                        end
                        UpdateHP(b, life, CurrentMaxHP, 9, i, true)
                    end
                end
                d=d+1
                Destination[un]=d
                IssueDelayedPointOrder(b, "move", WPx[d], WPy[d], 0.1)
            end
        elseif (sId==SpellID[15]) then -- Torrefaction
            local t,b,type,select=CreateTimer(),GetSpellTargetUnit(),BallType[5],__jarray(false)
            local bn,bx,by,ba,life=GetUnitUserData(b),GetUnitX(b),GetUnitY(b),GetUnitFacing(b),GetWidgetLife(b)
            PlayCleanSFX(SFXTor, GetUnitX(b), GetUnitY(b), 1.0, 0.0, 0, 1.5)
            if IsFlying then
                type=BallType[6]
            end
            for i=1, 4 do -- saving the selection state of the Ball for all players
                if IsUnitSelected(b, Player(i-1)) then
                    select[i]=true
                end
            end
            ShowUnit(b, false)
            PauseUnit(b, true)
            SetUnitInvulnerable(b, true)
            DisableBallTriggers(bn)
            local r=CreateUnit(BallsMaster, type, bx, by, ba)
            SetUnitUserData(r, bn)
            BlzSetUnitMaxHP(r, CurrentMaxHP)
            SetWidgetLife(r, life)
            local size=life*ResizeFactor
            if (size<MinSize) then
                size=MinSize
            end
            SetUnitScale(r, size, size, size)
            for i=1, 4 do -- Selecting the Roasting Ball if the normal Ball was selected
                if select[i] and (i==LocalPn) then
                    SelectUnit(r, true)
                end
            end
            Roast[r]={CreateTrigger(), CreateTrigger(), b, bn, t} -- Initializing Roasting Ball data
            TriggerRegisterUnitEvent(Roast[r][1], r, EVENT_UNIT_DAMAGED)
            TriggerRegisterUnitEvent(Roast[r][2], r, EVENT_UNIT_DEATH)
            TriggerAddCondition(Roast[r][1], Condition(DamagedBallActions)) -- Roasting Balls can be damaged like normal Balls
            TriggerAddCondition(Roast[r][2], Condition(RoastDeathActions)) -- Roasting Balls require specific actions when killed
            TimerData[t]={b, r} -- Setting up the data for the timer expiring at the end of the duration of Torrefaction.
            TimerStart(t, 10+2*GetUnitAbilityLevel(GetTriggerUnit(), sId), false, function()
                local t=GetExpiredTimer()
                local b,r=TimerData[t][1],TimerData[t][2]
                DestroyTimer(t)
                local life=GetWidgetLife(r)
                SetWidgetLife(b, life)
                local size,select=life*ResizeFactor,__jarray(false)
                if (size<MinSize) then
                    size=MinSize
                end
                SetUnitScale(b, size, size, size)
                for i=1, 4 do -- saving the selection state of the Roasting ball for all players
                    if IsUnitSelected(r, Player(i-1)) then
                        select[i]=true
                    end
                end
                PlayCleanSFX(SFXTor, GetUnitX(b), GetUnitY(b), 1.0, 0.0, 0, 1.5)
                DestroyTrigger(Roast[r][1])
                DestroyTrigger(Roast[r][2])
                RemoveUnit(r)
                EnableBallTriggers(bn)
                SetUnitInvulnerable(b, false)
                PauseUnit(b, false)
                ShowUnit(b, true)
                for i=1, 4 do -- Selecting the Ball if the Roasting Ball was selected
                    if select[i] and (i==LocalPn) then
                        SelectUnit(b, true)
                    end
                end
                local d=Destination[GetUnitUserData(b)]
                IssueDelayedPointOrder(b, "move", WPx[d], WPy[d], 0.0)
            end)
        end
        return false
    end))
end

EDIT :
Ffixed a typo (that kind of error Lua can never tell you about) that made the callback function fail.

Indeed , "local r=GetTriggerAnit()" had little chance to work :D

At the same time, it really sucks that Lua cannot track these syntax errors, if it did, there wouldn't be people around who become fed up with this and have to switch so typed languages like Wurst or TypeScript !!!

So many hours lost to try to find these stupid mistakes !
 
Last edited:
Status
Not open for further replies.
Top