• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

TFS 1.X+ Spell Area Error

mackerel

Well-Known Member
Joined
Apr 26, 2017
Messages
398
Solutions
18
Reaction score
72
Hi, just curious if anyone knows how you go about solving this error that comes up in console. I have been working on this script few weeks back but I have forgotten what I meant to fix.

Lua Script Error: [Test Interface]
data/spells/scripts/test.lua
data/spells/scripts/test.lua:39: attempt to get length of global 'area' (a nil value)
stack traceback:
[C]: in function '__len'
data/spells/scripts/test.lua:39: in main chunk
[Warning - Event::checkScript] Can not load script: scripts/test.lua

Here is my code

Lua:
local combat = {
{
    {0,0,0},
    {0,0,0},
    {0,0,0},
    {1,3,1},
    {1,0,1}
},
{
    {0,0,0},
    {0,0,0},
    {0,0,0},
    {1,1,1},
    {0,2,0}
},
{
    {0,0,0},
    {0,0,0},
    {1,1,1},
    {0,0,0},
    {0,2,0}
},
{
    {0,0,0},
    {1,1,1},
    {0,0,0},
    {0,0,0},
    {0,2,0}
},
{
    {1,1,1},
    {0,0,0},
    {0,0,0},
    {0,0,0},
    {0,2,0}
}
}

for i = 1, #area do
    combat[i] = createCombatObject()
    setCombatParam(combat[i], COMBAT_PARAM_TYPE, COMBAT_ENERGYDAMAGE)
    setCombatParam(combat[i], COMBAT_PARAM_EFFECT, 6)
    setCombatArea(combat[i], createCombatArea(area[i]))
   
    function onGetFormulaValues(cid, level, maglevel)
        min = -((level / 5) + (maglevel * 10) + 25)
        max = -((level / 5) + (maglevel * 20) + 50)
        return min, max
    end
   
    setCombatCallback(combat[i], CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues")
end

function onCastSpell(cid, var)

    -- my script here
   
    return doCombat(cid, combat[1], var)
end

I am guessing that there is something wrong with the area so I decided to change the local combat to

Lua:
local area = {

but that just created another console error:

Lua Script Error: [Test Interface]
data/spells/scripts/test.lua
data/spells/scripts/test.lua:40: attempt to index global 'combat' (a number value)
stack traceback:
[C]: in function '__newindex'
data/spells/scripts/test.lua:40: in main chunk
[Warning - Event::checkScript] Can not load script: scripts/test.lua
 
Solution
you need to use two separate tables, one to hold each area of the combats, one to hold all of the combat objects
i've also gone ahead and cleaned up your code + converted it to actual 1.x code
i've also added a loop inside of onCastSpell to execute all combats created within the table
Lua:
local areas = {
    {
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {1,3,1},
        {1,0,1}
    },
    {
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {1,1,1},
        {0,2,0}
    },
    {
        {0,0,0},
        {0,0,0},
        {1,1,1},
        {0,0,0},
        {0,2,0}
    },
    {
        {0,0,0},
        {1,1,1},
        {0,0,0},
        {0,0,0},
        {0,2,0}
    },
    {
        {1,1,1},
        {0,0,0}...
you need to use two separate tables, one to hold each area of the combats, one to hold all of the combat objects
i've also gone ahead and cleaned up your code + converted it to actual 1.x code
i've also added a loop inside of onCastSpell to execute all combats created within the table
Lua:
local areas = {
    {
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {1,3,1},
        {1,0,1}
    },
    {
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {1,1,1},
        {0,2,0}
    },
    {
        {0,0,0},
        {0,0,0},
        {1,1,1},
        {0,0,0},
        {0,2,0}
    },
    {
        {0,0,0},
        {1,1,1},
        {0,0,0},
        {0,0,0},
        {0,2,0}
    },
    {
        {1,1,1},
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {0,2,0}
    }
}

local combats = {}

-- you only need to define this once if all the combats will use the same function
function onGetFormulaValues(cid, level, maglevel)
    min = -((level / 5) + (maglevel * 10) + 25)
    max = -((level / 5) + (maglevel * 20) + 50)
    return min, max
end

for i = 1, #areas do
    combats[i] = Combat()
    combats[i]:setParameter(COMBAT_PARAM_TYPE, COMBAT_ENERGYDAMAGE)
    combats[i]:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_EXPLOSIONHIT)
    combats[i]:setArea(createCombatArea(areas[i]))
    combats[i]:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues")
end

function onCastSpell(creature, variant)

    -- my script here
 
    for i = 1, #combats do
        combats[i]:execute(creature, variant)
    end
    return true
end
 
Solution
you need to use two separate tables, one to hold each area of the combats, one to hold all of the combat objects
i've also gone ahead and cleaned up your code + converted it to actual 1.x code
i've also added a loop inside of onCastSpell to execute all combats created within the table
Lua:
local areas = {
    {
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {1,3,1},
        {1,0,1}
    },
    {
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {1,1,1},
        {0,2,0}
    },
    {
        {0,0,0},
        {0,0,0},
        {1,1,1},
        {0,0,0},
        {0,2,0}
    },
    {
        {0,0,0},
        {1,1,1},
        {0,0,0},
        {0,0,0},
        {0,2,0}
    },
    {
        {1,1,1},
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {0,2,0}
    }
}

local combats = {}

-- you only need to define this once if all the combats will use the same function
function onGetFormulaValues(cid, level, maglevel)
    min = -((level / 5) + (maglevel * 10) + 25)
    max = -((level / 5) + (maglevel * 20) + 50)
    return min, max
end

for i = 1, #areas do
    combats[i] = Combat()
    combats[i]:setParameter(COMBAT_PARAM_TYPE, COMBAT_ENERGYDAMAGE)
    combats[i]:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_EXPLOSIONHIT)
    combats[i]:setArea(createCombatArea(areas[i]))
    combats[i]:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues")
end

function onCastSpell(creature, variant)

    -- my script here
 
    for i = 1, #combats do
        combats[i]:execute(creature, variant)
    end
    return true
end

thanks adding another array 'combat' seem to solved the problem. I need the function 'onGetFormulaValues' inside because otherwise it will only work for the first combat execution. I have others that are executed after X miliseconds. The only problem is that having this functions inside for loop will cause it to change position when player moves, your method is better because the position in which the spell is being executed stays the same when player moves around after casting it.

Here is the full code if you want it

Lua:
local area = {
    {
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {1,3,1},
        {1,0,1}
    },
    {
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {1,1,1},
        {0,2,0}
    },
    {
        {0,0,0},
        {0,0,0},
        {1,1,1},
        {0,0,0},
        {0,2,0}
    },
    {
        {0,0,0},
        {1,1,1},
        {0,0,0},
        {0,0,0},
        {0,2,0}
    },
    {
        {1,1,1},
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {0,2,0}
    }
}

local combat = {}

for i = 1, #area do
    combat[i] = createCombatObject()
    setCombatParam(combat[i], COMBAT_PARAM_TYPE, COMBAT_ENERGYDAMAGE)
    setCombatParam(combat[i], COMBAT_PARAM_EFFECT, 6)
    setCombatArea(combat[i], createCombatArea(area[i]))
   
    function onGetFormulaValues(cid, level, maglevel)
        min = -((level / 5) + (maglevel * 10) + 25)
        max = -((level / 5) + (maglevel * 20) + 50)
        return min, max
    end
   
    setCombatCallback(combat[i], CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues")
end

local function myLoop(myArray, combatType)
    return doCombat(myArray.cid, combatType, myArray.var)
end

function onCastSpell(cid, var)
   
    local myArray = {
        cid = cid,
        var = var
    }
   
    addEvent(myLoop, 250, myArray, combat[2])
    addEvent(myLoop, 500, myArray, combat[3])
    addEvent(myLoop, 750, myArray, combat[4])
    addEvent(myLoop, 1000, myArray, combat[5])
   
    return doCombat(cid, combat[1], var)
end
 
thanks adding another array 'combat' seem to solved the problem. I need the function 'onGetFormulaValues' inside because otherwise it will only work for the first combat execution. I have others that are executed after X miliseconds. The only problem is that having this functions inside for loop will cause it to change position when player moves, your method is better because the position in which the spell is being executed stays the same when player moves around after casting it.

Here is the full code if you want it

Lua:
local area = {
    {
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {1,3,1},
        {1,0,1}
    },
    {
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {1,1,1},
        {0,2,0}
    },
    {
        {0,0,0},
        {0,0,0},
        {1,1,1},
        {0,0,0},
        {0,2,0}
    },
    {
        {0,0,0},
        {1,1,1},
        {0,0,0},
        {0,0,0},
        {0,2,0}
    },
    {
        {1,1,1},
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {0,2,0}
    }
}

local combat = {}

for i = 1, #area do
    combat[i] = createCombatObject()
    setCombatParam(combat[i], COMBAT_PARAM_TYPE, COMBAT_ENERGYDAMAGE)
    setCombatParam(combat[i], COMBAT_PARAM_EFFECT, 6)
    setCombatArea(combat[i], createCombatArea(area[i]))
  
    function onGetFormulaValues(cid, level, maglevel)
        min = -((level / 5) + (maglevel * 10) + 25)
        max = -((level / 5) + (maglevel * 20) + 50)
        return min, max
    end
  
    setCombatCallback(combat[i], CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues")
end

local function myLoop(myArray, combatType)
    return doCombat(myArray.cid, combatType, myArray.var)
end

function onCastSpell(cid, var)
  
    local myArray = {
        cid = cid,
        var = var
    }
  
    addEvent(myLoop, 250, myArray, combat[2])
    addEvent(myLoop, 500, myArray, combat[3])
    addEvent(myLoop, 750, myArray, combat[4])
    addEvent(myLoop, 1000, myArray, combat[5])
  
    return doCombat(cid, combat[1], var)
end
glad the problem was solved
however you should still be using 1.x code, not 0.x but w/e if it works it works
 
Back
Top