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

C++ [TFS 1.3] Using manually aimed runes on invisible monsters.

Demnish

Tibian Hero
Joined
Sep 28, 2011
Messages
402
Solutions
2
Reaction score
65
Location
Sweden
So I've been looking at this for some time now but since I've just started working with C++ it's quite hard to actually find where to make this edit.

What?: Basically; Making needTarget runes available for use on invisible monsters with manual aim.
Like shooting an SD on an invisible Warlock.
Why?: I'm getting rid of hotkeys and at least in oldschool Tibia, you could manually shoot SD's at invisible creatures like the Warlock, you weren't forced to use an AOE attack if you knew their position. Runes are expensive and weigh a lot; People would string me up if I keep this in the distro.

The bug reports on this matter would clutter other reports that might be serious, so this needs to go. Alternatively I will try and make this into a config.lua option and then share the code here so others can use it if they choose to with a simple switch button to go with it.

If anyone can help me out I would appreciate it a lot.
If you know in which files the edit will take place or what function needs to be edited, please share.

Thanks in advance.
 
Solution
local position = variant:getPosition()
Also fix your spell in xml, you are not using needTarget with that one, cause variant will pass creature Id not position.

And dont touch sources, cause your problem is the lua script.
Its weird, but its like 5th same topic I see this week.
On my TFS 1.2 I use this SD spell script and its function may be a pattern for the others:
Code:
local combat = createCombatObject()
setCombatParam(combat, COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
setCombatParam(combat, COMBAT_PARAM_EFFECT, CONST_ME_MORTAREA)
setCombatParam(combat, COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_DEATH)
function onGetFormulaValues(cid, level, maglevel)
    min = -(level * 2 + maglevel * 3) * 1.3
    max = -(level * 2 + maglevel * 3) * 1.7
    return min, max
end

setCombatCallback(combat, CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues")

function onCastSpell(cid, var, isHotkey)
    if Tile(var:getPosition()):getTopCreature() then
        return doCombat(cid, combat, var)
    end
    doPlayerSendCancel(cid,"You can only use this rune on creatures.")
    getCreaturePosition(cid):sendMagicEffect(CONST_ME_POFF)
    return false
end

EDIT: I see I've already answered you here, but didn't get any feedback if it worked in your case.
 
Ah, I either didn't get a pop up you've answered on that thread or I simply missed it.
I'll try it out!
Post automatically merged:

EDIT1: I'll have to edit it since it doesn't work for TFS 1.3, but I'll try to fix it tomorrow.

Anyway I posted this in another thread and the code looks very similar to something I've already tried and encountered a problem with, please take a look at my post in this thread: Shot runes on invisible creatures? (https://otland.net/threads/shot-runes-on-invisible-creatures.237444/post-2592874)
Post automatically merged:

EDIT2: Quickly checked it anyway, indeed that script does not work.
Getting met with the cancel message.

In any case, a source edit seems like the best solution.
 
Last edited:
Hmm, in my case it looks like this:
sdrune.gif


also it works with this:
Code:
function onCastSpell(cid, var, isHotkey)
    if Tile(var:getPosition()):getTopCreature() then
        return doCombat(cid, combat, var)
       else
        doPlayerSendCancel(cid,"You can only use this rune on creatures.")
        getCreaturePosition(cid):sendMagicEffect(CONST_ME_POFF)
    end
    return false
end
 
Have you made any changes to your libs or compat or anything? Cuz I get errors running your script and I'm on TFS Master from git hub.
It should work though, since the code looks right, but it doesn't for some reason.
Post automatically merged:

Lua:
function onCastSpell(creature, variant, isHotkey)
    local tile = Tile(Variant.getPosition(variant))
    if tile and tile:getTopCreature() then
        return combat:execute(creature, var)
    end

    creature:sendCancelMessage(RETURNVALUE_CANONLYUSETHISRUNEONCREATURES)
    creature:getPosition():sendMagicEffect(CONST_ME_POFF)
    return false
end
This takes me straight to the cancel message, but at least I don't get any errors.
So it has potential.

How does your spells.lua and spells lib look when it comes to the Sudden Death Rune?
 
Last edited:
Found this in tile.cpp:
C++:
Creature* Tile::getTopVisibleCreature(const Creature* creature) const
{
    if (const CreatureVector* creatures = getCreatures()) {
        if (creature) {
            const Player* player = creature->getPlayer();
            if (player && player->isAccessPlayer()) {
                return getTopCreature();
            }

            for (Creature* tileCreature : *creatures) {
                if (creature->canSeeCreature(tileCreature)) {
                    return tileCreature;
                }
            }
        } else {
            for (Creature* tileCreature : *creatures) {
                if (!tileCreature->isInvisible()) {
                    const Player* player = tileCreature->getPlayer();
                    if (!player || !player->isInGhostMode()) {
                        return tileCreature;
                    }
                }
            }
        }
    }
    return nullptr;
}

const Creature* Tile::getBottomVisibleCreature(const Creature* creature) const
{
    if (const CreatureVector* creatures = getCreatures()) {
        if (creature) {
            const Player* player = creature->getPlayer();
            if (player && player->isAccessPlayer()) {
                return getBottomCreature();
            }

            for (auto it = creatures->rbegin(), end = creatures->rend(); it != end; ++it) {
                if (creature->canSeeCreature(*it)) {
                    return *it;
                }
            }
        } else {
            for (auto it = creatures->rbegin(), end = creatures->rend(); it != end; ++it) {
                if (!(*it)->isInvisible()) {
                    const Player* player = (*it)->getPlayer();
                    if (!player || !player->isInGhostMode()) {
                        return *it;
                    }
                }
            }
        }
    }
    return nullptr;
}

Feels related, could it be?
Post automatically merged:

EDIT: Okay, so I'm using this script to try and find where the error is and it seems to be when its trying to find the Tile:
Lua:
function onCastSpell(creature, variant, isHotkey)
    local position = Variant.getPosition(variant)
    local tile = Tile(position)
    if position ~= nil then
        if tile ~= nil then
            local targetCreature = tile:getTopCreature()
            if targetCreature then
                return combat:execute(targetCreature, variant)
            end
         
            creature:sendCancelMessage("DEBUG: Can not find creature.")
            creature:getPosition():sendMagicEffect(CONST_ME_POFF)
            return false
        end
     
        creature:sendCancelMessage("DEBUG: Can not find tile.") -- This is the error that pops up
        creature:getPosition():sendMagicEffect(CONST_ME_POFF)
        return false
    end
 
    creature:sendCancelMessage("DEBUG: Can not find variant position.") -- I have no idea if this can actually run
    creature:getPosition():sendMagicEffect(CONST_ME_POFF)
    return false
end
 
Last edited:
local position = variant:getPosition()
Also fix your spell in xml, you are not using needTarget with that one, cause variant will pass creature Id not position.

And dont touch sources, cause your problem is the lua script.
 
Last edited:
Solution
Yeah I removed needTarget from the rune and changed return combat:execute(targetCreature, variant) -> creature.
So now it works, with the added bonus that the runes damages all targets on the same square, also making UH trap work.

Anyway, thanks Nekiro, while I did manage to fix this myself moments before your post, you still provided with the same solution I used.
So I'll add your post as the best answer so others can benefit from it if they encounter this problem.

Functional code:
Lua:
function onCastSpell(creature, variant, isHotkey)
    local position = variant:getPosition()
    local tile = Tile(position)
    if tile:getTopCreature() then
        return combat:execute(creature, variant)
    end
         
    creature:sendCancelMessage(RETURNVALUE_CANONLYUSETHISRUNEONCREATURES)
    creature:getPosition():sendMagicEffect(CONST_ME_POFF)
    return false
end
 
Last edited:
Could anyone tell me what this type of script would look like? I use tfs 1.5


Lua:
local spell = Spell(SPELL_INSTANT)

spell:needLearn(true)
spell:mana(220)
spell:magicLevel(25)
spell:soul(0)
spell:isAggressive(false)
spell:name("Sudden Death Rune")
spell:vocation("Sorcerer", "Master Sorcerer")
spell:words("ad,ori, vita, vis")

function spell.onCastSpell(creature, variant)
    return creature:conjureItem(220, 2260, 2268, 1)
end

spell:register()

local combat = Combat()
combat:setParameter(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
combat:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_MORTAREA)
combat:setParameter(COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_DEATH)
combat:setParameter(COMBAT_PARAM_AGGRESSIVE, true)
combat:setParameter(COMBAT_PARAM_BLOCKARMOR, true)
combat:setParameter(COMBAT_PARAM_BLOCKSHIELD, false)
combat:setArea(createCombatArea(AREA_SINGLE))



function onGetFormulaValues(player, level, magicLevel)
    return player:computeDamage(150, 20)
end

combat:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues")

local rune = Spell(SPELL_RUNE)

function rune.onCastSpell(creature, variant)
    return combat:execute(creature, variant)
end

rune:cooldown(1800)
rune:runeMagicLevel(15)
rune:runeId(2268)
rune:charges(1)
rune:allowFarUse(true)
rune:blockWalls(true)
rune:checkFloor(true)
rune:isBlocking(true)
rune:needTarget(true)
rune:isAggressive(true)
rune:register()
 
bpm91 You must past the fragment of code to sudden dead rune, not sudden dead spell. Everything should be in spell folder.
 
Back
Top