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

Lua Spell that send a arrow to multiple targets TFS 1.3

Icaraii

Well-Known Member
Joined
Jan 5, 2020
Messages
469
Solutions
1
Reaction score
58
Hello, I would like a spells that the player send arrow shottype to up to 5 monsters in the screen.
The player don't need to have arrow equiped.
The damage can be a normal function onGetFormulaValues.
 
Solution
Lua:
local distanceEffect = 31
local effect = CONST_ME_HOLYAREA
local damageType = COMBAT_HOLYDAMAGE

local function combatExecute(cid, variant)

local player = Player(cid)
local pos = player:getPosition()
local screen = Game.getSpectators(pos, false, false)

local lvl = player:getLevel()
local mlvl = player:getMagicLevel()
local minDmg = -1000 + (lvl * -2424) + (mlvl * -2424)
local maxDmg = -1200 + (lvl * -2424) + (mlvl * -2424)
  
for i = 1, #screen do
    local tile = Tile(screen[i]:getPosition()):hasFlag(TILESTATE_PROTECTIONZONE)
    if tile then
        return true
    end
    if screen[i]:isMonster() then
        local posAll = screen[i]:getPosition()
        pos:sendDistanceEffect(posAll, distanceEffect)...
Lua:
local distanceEffect = 31
local effect = CONST_ME_HOLYAREA
local damageType = COMBAT_HOLYDAMAGE

local function combatExecute(cid, variant)

local player = Player(cid)
local pos = player:getPosition()
local screen = Game.getSpectators(pos, false, false)

local lvl = player:getLevel()
local mlvl = player:getMagicLevel()
local minDmg = -1000 + (lvl * -2424) + (mlvl * -2424)
local maxDmg = -1200 + (lvl * -2424) + (mlvl * -2424)
  
for i = 1, #screen do
    local tile = Tile(screen[i]:getPosition()):hasFlag(TILESTATE_PROTECTIONZONE)
    if tile then
        return true
    end
    if screen[i]:isMonster() then
        local posAll = screen[i]:getPosition()
        pos:sendDistanceEffect(posAll, distanceEffect)
        doAreaCombatHealth(cid, damageType, posAll, nil, minDmg, maxDmg, effect)
        end
    end
end

local spell = Spell(SPELL_INSTANT)

function spell.onCastSpell(creature, variant)
    combatExecute(creature:getId(), variant)
    return true
end

spell:name("test")
spell:words("exura test")
spell:group("attack")
spell:vocation("sorcerer", "master sorecerer")
spell:id(1)
spell:cooldown(1000)
spell:level(200)
spell:manaPercent(1)
spell:blockWalls(true)
spell:register()
 
Last edited:
Solution
Lua:
local distanceEffect = 31
local effect = CONST_ME_HOLYAREA
local damageType = COMBAT_HOLYDAMAGE

local function combatExecute(cid, variant)

local player = Player(cid)
local pos = player:getPosition()
local screen = Game.getSpectators(pos, false, false)

local lvl = player:getLevel()
local mlvl = player:getMagicLevel()
local minDmg = -1000 + (lvl * -2424) + (mlvl * -2424)
local maxDmg = -1200 + (lvl * -2424) + (mlvl * -2424)
 
for i = 1, #screen do
    local tile = Tile(screen[i]:getPosition()):hasFlag(TILESTATE_PROTECTIONZONE)
    if tile then
        return true
    end
    if screen[i]:isMonster() then
        local posAll = screen[i]:getPosition()
        pos:sendDistanceEffect(posAll, distanceEffect)
        doAreaCombatHealth(cid, damageType, posAll, nil, minDmg, maxDmg, effect)
        end
    end
end

local spell = Spell(SPELL_INSTANT)

function spell.onCastSpell(creature, variant)
    combatExecute(creature:getId(), variant)
    return true
end

spell:name("test")
spell:words("exura test")
spell:group("attack")
spell:vocation("sorcerer", "master sorecerer")
spell:id(1)
spell:cooldown(1000)
spell:level(200)
spell:manaPercent(1)
spell:blockWalls(true)
spell:register()
I tried out your spell, but it didn't work. I found a similar script in one of my old servers and it works like I need. Thank you for trying and I will leave the script here for someone else who may need.

Lua:
local combats = {}
local spellConfig = {
    combat = COMBAT_DEATHDAMAGE,
    distanceEffect = CONST_ANI_DEATH,
    effect = CONST_ME_MORTAREA,
    bounces = {
        max = 4,
        chance = 40,
        baseMult = 0.1,
        levelMult = 0.1,
        magicMult = 0.1
    }
}
for i = 1, spellConfig.bounces.max do
    combats[i] = Combat()
    combats[i]:setParameter(COMBAT_PARAM_TYPE, spellConfig.combat)
    combats[i]:setParameter(COMBAT_PARAM_EFFECT, spellConfig.effect)
    function onGetFormulaValues(player, level, magicLevel)
        local min = ((level * (1.0 + (spellConfig.bounces.levelMult * i))) + (magicLevel * (1.0 + (spellConfig.bounces.magicMult * i)))) * (1.0 + (spellConfig.bounces.baseMult * i))
        local max = ((level * (1.2 + (spellConfig.bounces.levelMult * i))) + (magicLevel * (1.2 + (spellConfig.bounces.magicMult * i)))) * (1.2 + (spellConfig.bounces.baseMult * i))
        return -min, -max
    end
    combats[i]:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues")
end
local function getClosedTarget(player, cid, targets)
    local targets = targets or {}
    if #targets >= spellConfig.bounces.max then
        return targets
    end
    local c = Creature(cid)
    if c then
        targets[#targets +1] = cid
        local spectators = Game.getSpectators(c:getPosition(), false, false, 4, 4, 4, 4)
        table.sort(spectators, function(a, b) return a:getPosition():getDistance(c:getPosition()) < b:getPosition():getDistance(c:getPosition()) end)
        for _, spectator in pairs(spectators) do
            local sid = spectator:getId()
            if (spectator:isMonster() or (spectator:isPlayer() and not player:hasSecureMode())) and not table.contains(targets, sid) then
                return getClosedTarget(player, sid, targets)
            end
        end
    end
    return targets
end
local spell = Spell(SPELL_INSTANT)
function spell.onCastSpell(creature, variant)
    local targets = getClosedTarget(creature, variant:getNumber())
    for i, tid in pairs(targets) do
        if i ~= 1 and math.random(100) > spellConfig.bounces.chance then
            break
        end
        addEvent(function(cid, tid, atid)
            local player = Player(cid)
            if player then
                local target = Creature(tid)
                if target then
                    if not atid then
                        player:getPosition():sendDistanceEffect(target:getPosition(), spellConfig.distanceEffect)
                    else
                        local atarget = Creature(atid)
                        if atarget then
                            atarget:getPosition():sendDistanceEffect(target:getPosition(), spellConfig.distanceEffect)
                        end
                    end
                    combats[i]:execute(creature, Variant(tid))
                end
            end
        end, 200 * i-1, creature:getId(), tid, targets[i-1])
    end
    return #targets > 0
end
spell:name("Bounce Spell")
spell:words("exuna test")
spell:group("attack")
spell:vocation("sorcerer", "master sorecerer")
spell:id(1)
spell:cooldown(1000)
spell:level(200)
spell:range(6)
spell:manaPercent(13)
spell:needTarget(true)
spell:blockWalls(true)
spell:isPremium(true)
spell:register()

script made by @Sarah Wesker
 
Last edited:
Now it's working perfectly, thank you very much, didn't know that there was such thing as Game.getSpectators.
 
Now it's working perfectly, thank you very much, didn't know that there was such thing as Game.getSpectators.
Yep. it's a great function and you should generally use it anytime you are searching an area for player/creature/npc
Lua:
Game.getSpectators(position[, multifloor = false[, onlyPlayer = false[, minRangeX = 0[, maxRangeX = 0[, minRangeY = 0[, maxRangeY = 0]]]]]])

position is the 'centre position'

multifloor -> only 1 floor, or all floors?

minRange / maxRange x/y -> minimum range is 1, maximum is like.. 20?
Basically think of it like an exori.

x = 1, y = 1 -> exori shape (3 by 3 tile)
x = 2, y = 2 -> (5 by 5 tile)

Uhh, here's a better example

Untitled.png
 
Thanks for the explanation, very easy to understand.

OBS: for some reason I can't quote you guys on the answers
 
Back
Top