• 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+ How would you write such a spell?

Addams

OTMadness.com OTSes Services
Staff member
Board Moderator
Joined
Sep 29, 2009
Messages
2,920
Solutions
342
Reaction score
1,688
Location
Egypt
I haven't worked so much with spells, and this is the way I used to write spells (mostly smaller ones), so I wanted to know how you would write a spell like this (just a test spell I got from YouTube).

Lately, I have seen this method, but adding different areas doesn't work.
Lua:
local arr1 = {
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
}

local arr2 = {
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
    {0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0},
    {0, 0, 0, 1, 0, 2, 0, 1, 0, 0, 0},
    {0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0},
    {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
}

local arr3 = {
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0},
    {0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0},
    {0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0},
    {0, 0, 1, 0, 0, 2, 0, 0, 1, 0, 0},
    {0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0},
    {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0},
    {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
}

local arr4 = {
    {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
    {0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0},
    {0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0},
    {0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0},
    {1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1},
    {1, 1, 0, 0, 0, 2, 0, 0, 0, 1, 1},
    {1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1},
    {0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0},
    {0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0},
    {0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0},
    {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0}
}

local combat = Combat()
combat:setParameter(COMBAT_PARAM_TYPE, COMBAT_HOLYDAMAGE)
combat:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_HOLYAREA)
combat:setArea(createCombatArea(arr1))

local combat2 = Combat()
combat2:setParameter(COMBAT_PARAM_TYPE, COMBAT_HOLYDAMAGE)
combat2:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_HOLYDAMAGE)
combat2:setArea(createCombatArea(arr2))

local combat3 = Combat()
combat3:setParameter(COMBAT_PARAM_TYPE, COMBAT_HOLYDAMAGE)
combat3:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_HOLYDAMAGE)
combat3:setArea(createCombatArea(arr3))

local combat4 = Combat()
combat4:setParameter(COMBAT_PARAM_TYPE, COMBAT_HOLYDAMAGE)
combat4:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_GROUNDSHAKER)
combat4:setArea(createCombatArea(arr4))

function onGetFormulaValues(player, level, magicLevel)
    local min = 1
    local max = 1
    return -min, -max
end

function onGetFormulaValues2(player, level, magicLevel)
    local min = 2
    local max = 2
    return -min, -max
end

function onGetFormulaValues3(player, level, magicLevel)
    local min = 3
    local max = 3
    return -min, -max
end

function onGetFormulaValues4(player, level, magicLevel)
    local min = 4
    local max = 4
    return -min, -max
end

function onTargetTile(creature, position)
    creature:getPosition():sendDistanceEffect(position, CONST_ANI_HOLY)
end

function onTargetTileTwo(creature, position)
    creature:getPosition():sendDistanceEffect(position, CONST_ANI_HOLY)
end

function onTargetTileThree(creature, position)
    creature:getPosition():sendDistanceEffect(position, CONST_ANI_HOLY)
end

combat:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues")
combat2:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues2")
combat3:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues3")
combat4:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues4")
combat2:setCallback(CALLBACK_PARAM_TARGETTILE, "onTargetTile")
combat3:setCallback(CALLBACK_PARAM_TARGETTILE, "onTargetTileTwo")
combat4:setCallback(CALLBACK_PARAM_TARGETTILE, "onTargetTileThree")

local function castSpell1(creatureId, variant)
    local creature = Creature(creatureId)
    if not creature then
        return
    end
    combat:execute(creature, variant)
end

local function castSpell2(creatureId, variant)
    local creature = Creature(creatureId)
    if not creature then
        return
    end
    combat2:execute(creature, variant)
end

local function castSpell3(creatureId, variant)
    local creature = Creature(creatureId)
    if not creature then
        return
    end
    combat3:execute(creature, variant)
end

local function castSpell4(creatureId, variant)
    local creature = Creature(creatureId)
    if not creature then
        return
    end
    combat4:execute(creature, variant)
end

function onCastSpell(creature, variant)
    castSpell1(creature, variant)
    addEvent(castSpell2, 100, creature:getId(), variant)
    addEvent(castSpell3, 250, creature:getId(), variant)
    addEvent(castSpell4, 500, creature:getId(), variant)
    return true
end
test spell.gif
I am trying to learn how to make big spell scripts like this one as small as possible.
 
Last edited:
Solution
I really appreciate the effort. Thank you.
I am now trying the first one without a set formula, but I keep getting errors.
Code:
[Warning - CallBack::loadCallBack] Event onGetFormulaValues not found.
[Warning - CallBack::loadCallBack] Event onGetFormulaValues not found.
[Warning - CallBack::loadCallBack] Event onGetFormulaValues not found.
[Warning - CallBack::loadCallBack] Event onTargetTile not found.
[Warning - CallBack::loadCallBack] Event onTargetTile not found.
[Warning - CallBack::loadCallBack] Event onGetFormulaValues not found.
[Warning - CallBack::loadCallBack] Event onGetFormulaValues not found.
[Warning - CallBack::loadCallBack] Event onGetFormulaValues not found.
[Warning - CallBack::loadCallBack] Event onTargetTile not...
It's only a small upgrade, and not where you're asking for it.

But the onCast can be written a bit better / more concisely.

Lua:
local castTimings = {0, 100, 250, 500}

local function castSpell(creatureId, variant, castOrder)
    local creature = Creature(creatureId)
    if not creature then
        return
    end
    
    if castOrder == 1 then
        combat:execute(creature, variant)
    elseif castOrder == 2 then
        combat2:execute(creature, variant)
    elseif castOrder == 3 then
        combat3:execute(creature, variant)
    elseif castOrder == 4 then
        combat4:execute(creature, variant)
    end
end


function onCastSpell(creature, variant)
    for castOrder = 1, #castTimings do
        if castTimings[castOrder] <= 0 then
            castSpell(creature, variant, castOrder)
        else
            addEvent(castSpell, castTimings[castOrder], creature:getId(), variant, castOrder)
        end
    end
    return true
end
 
But the onCast can be written a bit better / more concisely.
Thank you. I never thought about the function castSpell change, but I had a thought about the loop one in onCastSpell and just wasn't sure how to add different unorder delays.
But yeah, mainly I am looking for a way around repeating many combats and, if possible, a better way for the onGetFormulaValues and onTargetTile ones.
 
The above kind of keeps the same thinking you're used to, but you can trim it even more, to have less addEvents running concurrently per spell.
Sorry, I should've thought of this before. xP

Lua:
local function castSpell(creatureId, variant, counter)
    local creature = Creature(creatureId)
    if not creature then
        return
    end
   
    if counter == 0 then
        combat:execute(creature, variant)
    elseif counter == 100 then
        combat2:execute(creature, variant)
    elseif counter == 250 then
        combat3:execute(creature, variant)
    elseif counter == 500 then
        combat4:execute(creature, variant)
    end
   
    if counter < 500 then
        addEvent(castSpell, 50, creatureId, variant, counter + 50)
    end
end


function onCastSpell(creature, variant)
    castSpell(creature:getId(), variant, 0)
    return true
end

But yeah, sorry that's all I can contribute.
 
That helps much. At least now I don't have to repeat the function 4 times, and also the onCastSpell looks really clean.

Final edit note: I think this is largely a waste of time tho. The readability of the code gets pretty muddled. because of the onGetFormulaValues
But if you had a set formula for all the tiles.. it's worth it.
I'll paste a version2, assuming that you have a formula set in place.

---
Okay, I have no idea if this will work or not.. but it looks good in theory.
Because you don't really have a 'set formula' for the damage, there's no way to condense the onGetFormulaValues..

But if we create a table of activeSpells, we can hold the information and modify the damage base on what iteration of the spell it's on.
(Of course since it's currently 1, 2, 3, 4 damage.. We could condence it as min = 1 * iteration.. but that's not always the case)

But yeah..

Try it like this?

Lua:
local arrs = {
    {
        {0, 1, 0},
        {1, 2, 1},
        {0, 1, 0}
    },

    {
        {0, 1, 1, 1, 0},
        {1, 1, 0, 1, 1},
        {1, 0, 2, 0, 1},
        {1, 1, 0, 1, 1},
        {0, 1, 1, 1, 0}
    },

    {
        {0, 0, 1, 0, 1, 0, 0},
        {0, 1, 0, 1, 0, 1, 0},
        {1, 0, 0, 0, 0, 0, 1},
        {1, 0, 0, 2, 0, 0, 1},
        {1, 0, 0, 0, 0, 0, 1},
        {0, 1, 0, 0, 0, 1, 0},
        {0, 0, 1, 1, 1, 0, 0}
    },

    {
        {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
        {0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0},
        {0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0},
        {0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0},
        {1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1},
        {1, 1, 0, 0, 0, 2, 0, 0, 0, 1, 1},
        {1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1},
        {0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0},
        {0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0},
        {0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0},
        {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0}
    }
}

local activeSpells = {}
local combat = {}

for i = 1, 4 do
    combat[i] = Combat()
    combat[i]:setParameter(COMBAT_PARAM_TYPE, COMBAT_HOLYDAMAGE)
    combat[i]:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_HOLYAREA)
    combat[i]:setArea(createCombatArea(arrs[i]))
end


function onGetFormulaValues(player, level, magicLevel)

    local playerId = player:getId()
    local spellIteration = 0
 
    for i = 1, #activeSpells do
        if activeSpells[i].creatureId == playerId then
            spellIteration = i
            break
        end
    end
 
    local min = 0
    local max = 0
 
    if spellIteration == 1 then
        min = 1
        max = 1
    elseif spellIteration == 2 then
        min = 2
        max = 2
    elseif spellIteration == 3 then
        min = 3
        max = 3
    elseif spellIteration == 4 then
        min = 4
        max = 4
    end
    return -min, -max
end

function onTargetTile(creature, position)
    creature:getPosition():sendDistanceEffect(position, CONST_ANI_HOLY)
end

for i = 1, 4 do
    combat[i]:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues")
end

for i = 2, 4 do
    combat[i]:setCallback(CALLBACK_PARAM_TARGETTILE, "onTargetTile")
end


local function clearActiveSpellTable(spellIndex)
    if spellIndex == #activeSpells then
        activeSpells = {}
    end
end

local function castSpell(creatureId, variant, counter, spellIndex)
    local creature = Creature(creatureId)
    if not creature then
        clearActiveSpellTable(spellIndex)
        return
    end
 
    local spellIteration = activeSpells[spellIndex].spellIteration
    local newSpellIteration = spellIteration + 1
 
    if counter == 0 then
        spellIteration = newSpellIteration
        combat[1]:execute(creature, variant)
     
    elseif counter == 100 then
        spellIteration = newSpellIteration
        combat[2]:execute(creature, variant)
     
    elseif counter == 250 then
        spellIteration = newSpellIteration
        combat[3]:execute(creature, variant)
     
    elseif counter == 500 then
        spellIteration = newSpellIteration
        combat[4]:execute(creature, variant)
     
    end
 
    if counter < 500 then
        addEvent(castSpell, 50, creatureId, variant, counter + 50)
    else
        clearActiveSpellTable(spellIndex)
    end
end

function onCastSpell(creature, variant)
    local creatureId = creature:getId()
    local spellIndex = #activeSpells + 1
    activeSpells[spellIndex] = {spellIteration = 0, creatureId = creatureId}
    castSpell(creatureId, variant, 0, spellIndex)
    return true
end

With a set formula
Lua:
local arrs = {
    {
        {0, 1, 0},
        {1, 2, 1},
        {0, 1, 0}
    },

    {
        {0, 1, 1, 1, 0},
        {1, 1, 0, 1, 1},
        {1, 0, 2, 0, 1},
        {1, 1, 0, 1, 1},
        {0, 1, 1, 1, 0}
    },

    {
        {0, 0, 1, 0, 1, 0, 0},
        {0, 1, 0, 1, 0, 1, 0},
        {1, 0, 0, 0, 0, 0, 1},
        {1, 0, 0, 2, 0, 0, 1},
        {1, 0, 0, 0, 0, 0, 1},
        {0, 1, 0, 0, 0, 1, 0},
        {0, 0, 1, 1, 1, 0, 0}
    },

    {
        {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
        {0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0},
        {0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0},
        {0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0},
        {1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1},
        {1, 1, 0, 0, 0, 2, 0, 0, 0, 1, 1},
        {1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1},
        {0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0},
        {0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0},
        {0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0},
        {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0}
    }
}

local combat = {}

for i = 1, 4 do
    combat[i] = Combat()
    combat[i]:setParameter(COMBAT_PARAM_TYPE, COMBAT_HOLYDAMAGE)
    combat[i]:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_HOLYAREA)
    combat[i]:setArea(createCombatArea(arrs[i]))
end

function onGetFormulaValues(player, level, magicLevel)
    local min = (level / 5) + (maglevel * 10)
    local max = (level / 5) + (maglevel * 14)
    return -min, -max
end

function onTargetTile(creature, position)
    creature:getPosition():sendDistanceEffect(position, CONST_ANI_HOLY)
end

for i = 1, 4 do
    combat[i]:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues")
    combat[i]:setCallback(CALLBACK_PARAM_TARGETTILE, "onTargetTile")
end


local function castSpell(creatureId, variant, counter)
    local creature = Creature(creatureId)
    if not creature then
        return
    end
  
    if counter == 0 then
        combat[1]:execute(creature, variant)
    elseif counter == 100 then
        combat[2]:execute(creature, variant)
    elseif counter == 250 then
        combat[3]:execute(creature, variant)
    elseif counter == 500 then
        combat[4]:execute(creature, variant)
    end
  
    if counter < 500 then
        addEvent(castSpell, 50, creatureId, variant, counter + 50)
    end
end

function onCastSpell(creature, variant)
    castSpell(creatureId, variant, 0)
    return true
end
 
Last edited:
Lua:
local arrs = {
    {
        {0, 1, 0},
        {1, 2, 1},
        {0, 1, 0}
    },

    {
        {0, 1, 1, 1, 0},
        {1, 1, 0, 1, 1},
        {1, 0, 2, 0, 1},
        {1, 1, 0, 1, 1},
        {0, 1, 1, 1, 0}
    },

    {
        {0, 0, 1, 0, 1, 0, 0},
        {0, 1, 0, 1, 0, 1, 0},
        {1, 0, 0, 0, 0, 0, 1},
        {1, 0, 0, 2, 0, 0, 1},
        {1, 0, 0, 0, 0, 0, 1},
        {0, 1, 0, 0, 0, 1, 0},
        {0, 0, 1, 1, 1, 0, 0}
    },

    {
        {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
        {0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0},
        {0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0},
        {0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0},
        {1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1},
        {1, 1, 0, 0, 0, 2, 0, 0, 0, 1, 1},
        {1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1},
        {0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0},
        {0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0},
        {0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0},
        {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0}
    }
}

local activeSpells = {}
local combat = {}

for i = 1, 4 do
    combat[i] = Combat()
    combat[i]:setParameter(COMBAT_PARAM_TYPE, COMBAT_HOLYDAMAGE)
    combat[i]:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_HOLYAREA)
    combat[i]:setArea(createCombatArea(arrs[i]))
end


function onGetFormulaValues(player, level, magicLevel)

    local playerId = player:getId()
    local spellIteration = 0
 
    for i = 1, #activeSpells do
        if activeSpells[i].creatureId == playerId then
            spellIteration = i
            break
        end
    end
 
    local min = 0
    local max = 0
 
    if spellIteration == 1 then
        min = 1
        max = 1
    elseif spellIteration == 2 then
        min = 2
        max = 2
    elseif spellIteration == 3 then
        min = 3
        max = 3
    elseif spellIteration == 4 then
        min = 4
        max = 4
    end
    return -min, -max
end

function onTargetTile(creature, position)
    creature:getPosition():sendDistanceEffect(position, CONST_ANI_HOLY)
end

for i = 1, 4 do
    combat[i]:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues")
end

for i = 2, 4 do
    combat[i]:setCallback(CALLBACK_PARAM_TARGETTILE, "onTargetTile")
end


local function clearActiveSpellTable(spellIndex)
    if spellIndex == #activeSpells then
        activeSpells = {}
    end
end

local function castSpell(creatureId, variant, counter, spellIndex)
    local creature = Creature(creatureId)
    if not creature then
        clearActiveSpellTable(spellIndex)
        return
    end
 
    local spellIteration = activeSpells[spellIndex].spellIteration
    local newSpellIteration = spellIteration + 1
 
    if counter == 0 then
        spellIteration = newSpellIteration
        combat[1]:execute(creature, variant)
   
    elseif counter == 100 then
        spellIteration = newSpellIteration
        combat[2]:execute(creature, variant)
   
    elseif counter == 250 then
        spellIteration = newSpellIteration
        combat[3]:execute(creature, variant)
   
    elseif counter == 500 then
        spellIteration = newSpellIteration
        combat[4]:execute(creature, variant)
   
    end
 
    if counter < 500 then
        addEvent(castSpell, 50, creatureId, variant, counter + 50)
    else
        clearActiveSpellTable(spellIndex)
    end
end

function onCastSpell(creature, variant)
    local creatureId = creature:getId()
    local spellIndex = #activeSpells + 1
    activeSpells[spellIndex] = {spellIteration = 0, creatureId = creatureId}
    castSpell(creatureId, variant, 0, spellIndex)
    return true
end
I really appreciate the effort. Thank you.
I am now trying the first one without a set formula, but I keep getting errors.
Code:
[Warning - CallBack::loadCallBack] Event onGetFormulaValues not found.
[Warning - CallBack::loadCallBack] Event onGetFormulaValues not found.
[Warning - CallBack::loadCallBack] Event onGetFormulaValues not found.
[Warning - CallBack::loadCallBack] Event onTargetTile not found.
[Warning - CallBack::loadCallBack] Event onTargetTile not found.
[Warning - CallBack::loadCallBack] Event onGetFormulaValues not found.
[Warning - CallBack::loadCallBack] Event onGetFormulaValues not found.
[Warning - CallBack::loadCallBack] Event onGetFormulaValues not found.
[Warning - CallBack::loadCallBack] Event onTargetTile not found.
[Warning - CallBack::loadCallBack] Event onTargetTile not found.

Lua Script Error: [Main Interface]
in a timer event called from:
(Unknown scriptfile)
data/spells/scripts/attack/test_spell_52.lua:109: attempt to index a nil value
stack traceback:
        [C]: in function '__index'
        data/spells/scripts/attack/test_spell_52.lua:109: in function <data/spells/scripts/attack/test_spell_52.lua:102>
I think for the nil value I can just add a similar check to clearActiveSpellTable but inside castSpell, so when it's a nil value it just adds spellIteration as 0 or something? I'm not sure the whole method is new to me.
and I am not sure about the onGetFormulaValues and onTargetTile ones too.
Lua:
local arrs = {
    {
        {0, 1, 0},
        {1, 2, 1},
        {0, 1, 0}
    },

    {
        {0, 1, 1, 1, 0},
        {1, 1, 0, 1, 1},
        {1, 0, 2, 0, 1},
        {1, 1, 0, 1, 1},
        {0, 1, 1, 1, 0}
    },

    {
        {0, 0, 1, 0, 1, 0, 0},
        {0, 1, 0, 1, 0, 1, 0},
        {1, 0, 0, 0, 0, 0, 1},
        {1, 0, 0, 2, 0, 0, 1},
        {1, 0, 0, 0, 0, 0, 1},
        {0, 1, 0, 0, 0, 1, 0},
        {0, 0, 1, 1, 1, 0, 0}
    },

    {
        {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
        {0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0},
        {0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0},
        {0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0},
        {1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1},
        {1, 1, 0, 0, 0, 2, 0, 0, 0, 1, 1},
        {1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1},
        {0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0},
        {0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0},
        {0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0},
        {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0}
    }
}

local combat = {}

for i = 1, 4 do
    combat[i] = Combat()
    combat[i]:setParameter(COMBAT_PARAM_TYPE, COMBAT_HOLYDAMAGE)
    combat[i]:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_HOLYAREA)
    combat[i]:setArea(createCombatArea(arrs[i]))
end

function onGetFormulaValues(player, level, magicLevel)
    local min = (level / 5) + (maglevel * 10)
    local max = (level / 5) + (maglevel * 14)
    return -min, -max
end

function onTargetTile(creature, position)
    creature:getPosition():sendDistanceEffect(position, CONST_ANI_HOLY)
end

for i = 1, 4 do
    combat[i]:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues")
    combat[i]:setCallback(CALLBACK_PARAM_TARGETTILE, "onTargetTile")
end


local function castSpell(creatureId, variant, counter)
    local creature = Creature(creatureId)
    if not creature then
        return
    end
 
    if counter == 0 then
        combat[1]:execute(creature, variant)
    elseif counter == 100 then
        combat[2]:execute(creature, variant)
    elseif counter == 250 then
        combat[3]:execute(creature, variant)
    elseif counter == 500 then
        combat[4]:execute(creature, variant)
    end
 
    if counter < 500 then
        addEvent(castSpell, 50, creatureId, variant, counter + 50)
    end
end

function onCastSpell(creature, variant)
    castSpell(creatureId, variant, 0)
    return true
end
For the one with the set formula, it is throwing the same onGetFormulaValues and onTargetTile errors.
I will leave the reply here and do some tests myself.
 
 
I really appreciate the effort. Thank you.
I am now trying the first one without a set formula, but I keep getting errors.
Code:
[Warning - CallBack::loadCallBack] Event onGetFormulaValues not found.
[Warning - CallBack::loadCallBack] Event onGetFormulaValues not found.
[Warning - CallBack::loadCallBack] Event onGetFormulaValues not found.
[Warning - CallBack::loadCallBack] Event onTargetTile not found.
[Warning - CallBack::loadCallBack] Event onTargetTile not found.
[Warning - CallBack::loadCallBack] Event onGetFormulaValues not found.
[Warning - CallBack::loadCallBack] Event onGetFormulaValues not found.
[Warning - CallBack::loadCallBack] Event onGetFormulaValues not found.
[Warning - CallBack::loadCallBack] Event onTargetTile not found.
[Warning - CallBack::loadCallBack] Event onTargetTile not found.

Lua Script Error: [Main Interface]
in a timer event called from:
(Unknown scriptfile)
data/spells/scripts/attack/test_spell_52.lua:109: attempt to index a nil value
stack traceback:
        [C]: in function '__index'
        data/spells/scripts/attack/test_spell_52.lua:109: in function <data/spells/scripts/attack/test_spell_52.lua:102>
I think for the nil value I can just add a similar check to clearActiveSpellTable but inside castSpell, so when it's a nil value it just adds spellIteration as 0 or something? I'm not sure the whole method is new to me.
and I am not sure about the onGetFormulaValues and onTargetTile ones too.

For the one with the set formula, it is throwing the same onGetFormulaValues and onTargetTile errors.
I will leave the reply here and do some tests myself.

based on this, I think what we want to do is move the functions into the loop, so we re-create a new function each time we want to use it.

So editing the set formula one..

I'd try this.

Lua:
local arrs = {
    {
        {0, 1, 0},
        {1, 2, 1},
        {0, 1, 0}
    },
    
    {
        {0, 1, 1, 1, 0},
        {1, 1, 0, 1, 1},
        {1, 0, 2, 0, 1},
        {1, 1, 0, 1, 1},
        {0, 1, 1, 1, 0}
    },
    
    {
        {0, 0, 1, 0, 1, 0, 0},
        {0, 1, 0, 1, 0, 1, 0},
        {1, 0, 0, 0, 0, 0, 1},
        {1, 0, 0, 2, 0, 0, 1},
        {1, 0, 0, 0, 0, 0, 1},
        {0, 1, 0, 0, 0, 1, 0},
        {0, 0, 1, 1, 1, 0, 0}
    },
    
    {
        {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
        {0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0},
        {0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0},
        {0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0},
        {1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1},
        {1, 1, 0, 0, 0, 2, 0, 0, 0, 1, 1},
        {1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1},
        {0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0},
        {0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0},
        {0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0},
        {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0}
    }
}

local combat = {}

for i = 1, 4 do
    combat[i] = Combat()
    combat[i]:setParameter(COMBAT_PARAM_TYPE, COMBAT_HOLYDAMAGE)
    combat[i]:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_HOLYAREA)
    combat[i]:setArea(createCombatArea(arrs[i]))


    function onGetFormulaValues(player, level, magicLevel)
        local min = (level / 5) + (maglevel * 10)
        local max = (level / 5) + (maglevel * 14)
        return -min, -max
    end
    
    function onTargetTile(creature, position)
        creature:getPosition():sendDistanceEffect(position, CONST_ANI_HOLY)
    end
    
    
    combat[i]:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues")
    combat[i]:setCallback(CALLBACK_PARAM_TARGETTILE, "onTargetTile")
end


local function castSpell(creatureId, variant, counter)
    local creature = Creature(creatureId)
    if not creature then
        return
    end
    
    if counter == 0 then
        combat[1]:execute(creature, variant)
    elseif counter == 100 then
        combat[2]:execute(creature, variant)
    elseif counter == 250 then
        combat[3]:execute(creature, variant)
    elseif counter == 500 then
        combat[4]:execute(creature, variant)
    end
    
    if counter < 500 then
        addEvent(castSpell, 50, creatureId, variant, counter + 50)
    end
end

function onCastSpell(creature, variant)
    castSpell(creatureId, variant, 0)
    return true
end
 
Solution
based on this, I think what we want to do is move the functions into the loop, so we re-create a new function each time we want to use it.

So editing the set formula one..

I'd try this.
Thank you. Now it looks way better. I will practice writing spells this way and with Gesior's function instead of repeating functions, combats, formulas, etc.
I just had to change 2 typos in it in case anyone else will use the same. unsafe addEvent and creature instead of creatureId in onCastSpell
 
Last edited:
Thank you. Now it looks way better. I will practice writing spells this way and with Gesior's function instead of repeating functions, combats, formulas, etc.
I just had to change 2 typos in it in case anyone else will use the same. unsafe addEvent and creature instead of creatureId in onCastSpell
was fun to learn for me too
 
Back
Top