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

Shot runes on invisible creatures?

Peonso

Godly Member
Joined
Jan 14, 2008
Messages
1,750
Solutions
30
Reaction score
1,534
I want to be able to SD Warlocks or HMM Stalkers. Single target runes can't hit invisible monsters. I don't want to make the runes area runes (as they can be shot even without target, and would make they go to waste).

TFS 1.X.
 
Perhaps you could turn them into area runes and use tile:getTopCreature() to check if there is a creature on the target area. The variant (var) would contain the target position. I'm not sure if that would work but it's what I could come up with at the moment.
 
Code:
local combat = createCombatObject()
setCombatParam(combat, COMBAT_PARAM_TYPE, COMBAT_ICEDAMAGE)
setCombatParam(combat, COMBAT_PARAM_EFFECT, CONST_ME_ICEAREA)
setCombatParam(combat, COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_ICE)

function onGetFormulaValues(cid, level, maglevel)
    min = -((level / 5) + (maglevel * 1.8) + 12)
    max = -((level / 5) + (maglevel * 3) + 17)
    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
end

this works 100%. just add "if Tile(var:getPosition()):getTopCreature() then" onto your runes and an "end" after ofc.
and change var to variant in tfs 1.2 I think.

like forgee said. that's all you'll need. no need to add area though

also you'll have to change needtarget="1" to needtarget="0" obviously
 
Last edited:
Perhaps you could turn them into area runes and use tile:getTopCreature() to check if there is a creature on the target area. The variant (var) would contain the target position. I'm not sure if that would work but it's what I could come up with at the moment.
Code:
local combat = createCombatObject()
setCombatParam(combat, COMBAT_PARAM_TYPE, COMBAT_ICEDAMAGE)
setCombatParam(combat, COMBAT_PARAM_EFFECT, CONST_ME_ICEAREA)
setCombatParam(combat, COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_ICE)

function onGetFormulaValues(cid, level, maglevel)
    min = -((level / 5) + (maglevel * 1.8) + 12)
    max = -((level / 5) + (maglevel * 3) + 17)
    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
end

this works 100%. just add "if Tile(var:getPosition()):getTopCreature() then" onto your runes and an "end" after ofc.
and change var to variant in tfs 1.2 I think.

like forgee said. that's all you'll need. no need to add area though

also you'll have to change needtarget="1" to needtarget="0" obviously
Thx a lot guys.
 
Code:
function onCastSpell(cid, var, isHotkey)
    if Tile(var:getPosition()):getTopCreature() then
        return doCombat(cid, combat, var)
    else
        cid:sendCancelMessage("You can only use this rune on creatures.")
        cid:getPosition():sendMagicEffect(CONST_ME_POFF)
    end
end
Seems even better.
 
what about
Code:
local combat = Combat()
combat:setParameter(COMBAT_PARAM_DISPEL, CONDITION_INVISIBLE)
combat:setArea(createCombatArea(AREA_CIRCLE3X3))
 
what about
Code:
local combat = Combat()
combat:setParameter(COMBAT_PARAM_DISPEL, CONDITION_INVISIBLE)
combat:setArea(createCombatArea(AREA_CIRCLE3X3))
Well it does dispel invisible, according to @Peonso , else i would also done like that.

Only bcz i like meta, here you go:

Code:
local combat = Combat()
combat:setParameter(COMBAT_PARAM_TYPE, COMBAT_DEATHDAMAGE)
combat:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_MORTAREA)
combat:setParameter(COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_SUDDENDEATH)

function onGetFormulaValues(player, level, maglevel)
    local min = (level / 5) + (maglevel * 4.3) + 32
    local max = (level / 5) + (maglevel * 7.4) + 48
    return -min, -max
end

combat:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues")

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("You can only use this rune on creatures.")
    creature:getPosition():sendMagicEffect(CONST_ME_POFF)
    return false
end
 
are these made for Othire? ive been trying to use the scripts but when im shooting the Sudden Death on the Warlock wich is invisble it says "you can only use this rune on creatures" // SOLVED.
 
Last edited:
this becomes too strong since you can try multiple tiles without any exhaust (return false doesn't apply exhaust, so you're only with the timeBetweenActions delay). I think the best option would be to turn every rune as an area. This would create the need of missing some runes before successfully removing the invisible condition, which is acceptable.

I know this is different than the OP asked but would be the best option to keep things balanced.
 
this becomes too strong since you can try multiple tiles without any exhaust (return false doesn't apply exhaust, so you're only with the timeBetweenActions delay). I think the best option would be to turn every rune as an area. This would create the need of missing some runes before successfully removing the invisible condition, which is acceptable.

I know this is different than the OP asked but would be the best option to keep things balanced.

well the intention is to make it like in oldschool protcols, if you would really need some exhaust if the player missed the target then thats easy to add too.
but in oldschool protocols i believe it worked like this, you didnt get any exhaust if you missed, and it doesnt matter that much since it takes some time for players to aim the rune again
 
It's an old thread, but I recently encountered this problem aswell.
The problem with making it into an area spell is the wasting of runes, which equals to a duct tape fix.

This code isn't functional either and is also a duct tape fix:
C++:
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("You can only use this rune on creatures.")
    creature:getPosition():sendMagicEffect(CONST_ME_POFF)
    return false
end
Due to the fact that you can't aim the runes on creatures in the battle list, which you are supposed to do in oldschool when you hunt.
+ Changing it in the core is the right way to go, since it is a bug.

Maybe these lines in spells.cpp:
C++:
bool Spell::playerRuneSpellCheck(Player* player, const Position& toPos)
{
    if (!playerSpellCheck(player)) {
        return false;
    }

    if (toPos.x == 0xFFFF) {
        return true;
    }

    const Position& playerPos = player->getPosition();
    if (playerPos.z > toPos.z) {
        player->sendCancelMessage(RETURNVALUE_FIRSTGOUPSTAIRS);
        g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
        return false;
    } else if (playerPos.z < toPos.z) {
        player->sendCancelMessage(RETURNVALUE_FIRSTGODOWNSTAIRS);
        g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
        return false;
    }

    Tile* tile = g_game.map.getTile(toPos);
    if (!tile) {
        player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
        g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
        return false;
    }

    if (range != -1 && !g_game.canThrowObjectTo(playerPos, toPos, true, range, range)) {
        player->sendCancelMessage(RETURNVALUE_DESTINATIONOUTOFREACH);
        g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
        return false;
    }

    ReturnValue ret = Combat::canDoCombat(player, tile, aggressive);
    if (ret != RETURNVALUE_NOERROR) {
        player->sendCancelMessage(ret);
        g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
        return false;
    }

    const Creature* topVisibleCreature = tile->getBottomVisibleCreature(player);
    if (blockingCreature && topVisibleCreature) {
        player->sendCancelMessage(RETURNVALUE_NOTENOUGHROOM);
        g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
        return false;
    } else if (blockingSolid && tile->hasFlag(TILESTATE_BLOCKSOLID)) {
        player->sendCancelMessage(RETURNVALUE_NOTENOUGHROOM);
        g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
        return false;
    }

    if (needTarget && !topVisibleCreature) {
        player->sendCancelMessage(RETURNVALUE_CANONLYUSETHISRUNEONCREATURES);
        g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
        return false;
    }

    if (aggressive && needTarget && topVisibleCreature && player->hasSecureMode()) {
        const Player* targetPlayer = topVisibleCreature->getPlayer();
        if (targetPlayer && targetPlayer != player && player->getSkullClient(targetPlayer) == SKULL_NONE && !Combat::isInPvpZone(player, targetPlayer)) {
            player->sendCancelMessage(RETURNVALUE_TURNSECUREMODETOATTACKUNMARKEDPLAYERS);
            g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
            return false;
        }
    }
    return true;
}
The error you get when trying to shoot directly on invisible monsters is RETURNVALUE_CANONLYUSETHISRUNEONCREATURES.

Anyone know what to do here?
Maybe the change has to be made in topVisibleCreature?

I have reported this as a bug on git hub since it is also something that needs to be changed in the main TFS distro.
 
Last edited:
Back
Top