• 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!
  • 2026 staff recruitment is open! Check it out and consider applying!

Lua TFS 1.2 - How to access the target of a spell

Joined
Dec 13, 2015
Messages
45
Reaction score
13
I'm trying for hours to find a way to access the target of my spell.

I've searched trough all TFS 1.2 functions and couldn't find anything besides creature:getTarget().

The problem with creature:getTarget() is that the player's target is not always the same as the spell's target, so it won't work for me.
 
Solution
what do you want the spell to do?
heal an area and remove a specific condition subId?

until a solution is found, you could change the spell and make it manually check the area around you (instead of using a combat object with area and condition dispel) and removing paralyze with subId 1, its not the best for efficiency, but if its not being spammed its not that bad

@MatheusMkalo @Omni Cloud sorry for tagging you two, but does any of you know a solution to targets of aoe spells?
if you dont ill ask on the github repo
You can do it using :

combat:setCallback(CALLBACK_PARAM_TARGETCREATURE, "onTargetCreature")
As Dnomyar said or you could do something with:

combat:setCallback(CALLBACK_PARAM_TARGETTILE, "onTargetTile")...
I can't do that yet.

Ill just make it remove paralyze subID=1 from the caster for now and use my time for some other things that I need to fix. But thanks for the idea.
 
getSpectators works good if you want a square, else you can just create a table of positions (that looks just like the combat area, but with positions instead of numbers, i would recommend using offsets to player position and just comparing to them, most efficient) and cast it on them, its not that much code :)
 
getSpectators works good if you want a square, else you can just create a table of positions (that looks just like the combat area, but with positions instead of numbers, i would recommend using offsets to player position and just comparing to them, most efficient) and cast it on them, its not that much code :)

Sure. Well I would use the normal Mass Heal area.
Could you give me a small example of what you are saying? So that I can reproduce the idea later?

:*
 
ok so mass healing area is
Code:
AREA_CIRCLE3X3 = {
{0, 0, 1, 1, 1, 0, 0},
{0, 1, 1, 1, 1, 1, 0},
{1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 3, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1},
{0, 1, 1, 1, 1, 1, 0},
{0, 0, 1, 1, 1, 0, 0}
}
now, you could change it so you have a table in the form of
Code:
AREA_HEAL = {
{x = {-1, 1}, y = -3},
{x = {-2, 2}, y = -2},
{x = {-3, 3}, y = -1},
etc, you catch my drift, a table with the offset for Y, and the offsets for x as {fromX, toX}, then you can have
Code:
onCastSpell(creature, variant)
local pos = creature:getPosition()
local targetTiles = {}
for i=1,#AREA_HEAL,1 do
for n=AREA_HEAL[i].x[1], AREA_HEAL[i].x[2], 1 do
targetTiles[#targetTiles+1] = {x = pos.x+n y = pos.y+AREA_HEAL[i].y, z = pos.z}
end
end
for i=1,#targetTiles,1 do
get creatures from tiles, heal~
end
end
now, it can be written better etc, and you can remove last loop and just heal directly instead of saving all tiles etc, but this is a good base to look at (although sloppy)
 
Code:
case VARIANT_NUMBER: {
       Creature* target = g_game.getCreatureByID(variant.number);
       if (!target) {
         pushBoolean(L, false);
         return 1;
       }

       if (combat->hasArea()) {
         combat->doCombat(creature, target->getPosition());
       } else {
         combat->doCombat(creature, target);
       }
       break;
     }
if the spell has an area it pushes the position of the target, still using the var.number type tho.
EDIT: nvm what I said, this applies only if the player has a target and the spell has an area around the target.
 
set in the xml file the flag to the spell
Code:
selftarget="1"
then you can get the positions with
Code:
Variant(var):getPosition()
this should return the positions of the tiles where it found something and applied combat.
 
Hello. I had a similar problem and I solved it by using the onTargetCreature callback.
The onTargetCreature callback will trigger if you have selected to attack a creature through the right-mouse click or if the tile at which the combat area of your spell hits has any creatures.

So, it looks like this:
Code:
function onTargetCreature(creature, target)
    creature:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Target name: " .. target:getName())
    return true
end

combat:setCallback(CALLBACK_PARAM_TARGETCREATURE, "onTargetCreature")

By the way, you don't need to check if there is a target, as it won't trigger if there aren't.
 
Hello. I had a similar problem and I solved it by using the onTargetCreature callback.
The onTargetCreature callback will trigger if you have selected to attack a creature through the right-mouse click or if the tile at which the combat area of your spell hits has any creatures.

So, it looks like this:
Code:
function onTargetCreature(creature, target)
    creature:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Target name: " .. target:getName())
    return true
end

combat:setCallback(CALLBACK_PARAM_TARGETCREATURE, "onTargetCreature")

By the way, you don't need to check if there is a target, as it won't trigger if there aren't.

OMG, you are so right.

All I needed to do for Mass Heal(which already used the 'onTargetCreature(creature, target)' function)) was add the remove condition lines:
Code:
function onTargetCreature(creature, target)
    local player = creature:getPlayer()
    local min = ((player:getLevel() * 0.3) + (player:getMagicLevel() * 4.6) + 100)
    local max = ((player:getLevel() * 0.3) + (player:getMagicLevel() * 9.6) + 125)

    local master = target:getMaster()
    if target:isMonster() and not master or master and master:isMonster() then
        return true
    end

    doRemoveCondition(target, CONDITION_PARALYZE) -- this
    doRemoveCondition(target, CONDITION_PARALYZE, 1) -- and this
   
    doTargetCombatHealth(0, target, COMBAT_HEALING, min, max, CONST_ME_NONE)
    return true
end

local combat = Combat()
combat:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_MAGIC_BLUE)
combat:setParameter(COMBAT_PARAM_AGGRESSIVE, 0)
combat:setArea(createCombatArea(AREA_CIRCLE3X3))
combat:setCallback(CALLBACK_PARAM_TARGETCREATURE, "onTargetCreature")

function onCastSpell(creature, var)
    return combat:execute(creature, var)
end

All problem solved inside the combat object. Thanks Dnomyar!

Zothion, I tried for hours to make that code work, but I was getting too many bugs on checking creature and executing combat.
I also tried studying the standard tibia party spells, who use a similar code logic. But still no sucess. Thanks for ur help though.
 
what do you want the spell to do?
heal an area and remove a specific condition subId?

until a solution is found, you could change the spell and make it manually check the area around you (instead of using a combat object with area and condition dispel) and removing paralyze with subId 1, its not the best for efficiency, but if its not being spammed its not that bad

@MatheusMkalo @Omni Cloud sorry for tagging you two, but does any of you know a solution to targets of aoe spells?
if you dont ill ask on the github repo
You can do it using :

combat:setCallback(CALLBACK_PARAM_TARGETCREATURE, "onTargetCreature")
As Dnomyar said or you could do something with:

combat:setCallback(CALLBACK_PARAM_TARGETTILE, "onTargetTile")
That iterates over every tile in the area.
 
Solution
You can do it using :

combat:setCallback(CALLBACK_PARAM_TARGETCREATURE, "onTargetCreature")
As Dnomyar said or you could do something with:

combat:setCallback(CALLBACK_PARAM_TARGETTILE, "onTargetTile")
That iterates over every tile in the area.
didnt know that, makes it a bit easier :P
 
Back
Top