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

cast spell onUse toPosition

Tormented

Banned User
Joined
Jan 13, 2024
Messages
56
Reaction score
23
LUA:
local combat = Combat()

combat:setParameter(COMBAT_PARAM_TYPE, COMBAT_HOLYDAMAGE)

combat:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_HITAREA)

combat:setArea(createCombatArea(AREA_SQUARE1X1))



function onGetFormulaValues(player, skill, attack, factor)

    local min = 1

    local max = 1

    return -min, -max

end



combat:setCallback(CALLBACK_PARAM_SKILLVALUE, "onGetFormulaValues")



local function onCastSpell(creature, variant)

    return combat:execute(creature, variant)

end

 onCastSpell(player, numberToVariant(player:getId()))





function onUse(player, item, fromPosition, target, toPosition, isHotkey)


how can i cast the spell onto toPosition with onUse?>
 
Spell changes are required to make runes work without target (player), but Oen is right. You cannot use sendUseOnCreature on client side, as it does not send 'target position', only it's ID (creature ID), then server calculates toPosition using creature current position (for ex. Action Lua script).

That's exactly what 7.8+ client code does.
On client side you see some creature on position X, when it moves, on server it's immediately moved to X+1, when player press arrow key. On client side it knows that given creature is on position X+1 too, but it starts playing move animation that moves creature from tile to tile smoothly. If you use rune on X position, when creature started it's move (animation), it should send given position to server, as there is no creature on position X anymore, but client (7.8+) detects that there is a 'walking creature' (animation) on position X and that moving creature ID is 123 and it sends packet sendUseOnCreature with ID instead of position.
You can replace:
C++:
    if(toThing->isCreature() && (g_game.getProtocolVersion() >= 780 || g_game.getFeature(Otc::GameForceAllowItemHotkeys)))
        m_protocolGame->sendUseOnCreature(pos, item->getId(), subType ? subType : item->getStackPos(), toThing->getId());
    else
        m_protocolGame->sendUseItemWith(pos, item->getId(), subType ? subType : item->getStackPos(), toThing->getPosition(), toThing->getId(), toThing->getStackPos());
with:
C++:
        m_protocolGame->sendUseItemWith(pos, item->getId(), subType ? subType : item->getStackPos(), toThing->getPosition(), toThing->getId(), toThing->getStackPos());
but shooting through Battle Window will still hit target on it's actual (server) position.

You got to test, if it fixes your problem.
Yeah already tried this, removing:

LUA:
    if(toThing->isCreature() && (g_game.getProtocolVersion() >= 780 || g_game.getFeature(Otc::GameForceAllowItemHotkeys)))
        m_protocolGame->sendUseOnCreature(pos, item->getId(), subType ? subType : item->getStackPos(), toThing->getId());
    else

does not change anything. Maybe thats the change, but something else is needed.

And about hitting target on battle window, that i already solved it, my problem is when using runes manually, not on battle list

Post automatically merged:


this is basically the issue, the sd is following target, instead of poffing when failed to get the player on position:


Post automatically merged:


This is an example of another server which does have this feature, message: "You can only use this rune on creatures."

Post automatically merged:

 
Last edited:
use onCombatArea instead onTargetCombat. use the fixed location which is the toPosition in onUse OR variant.position most probably should contain it, instead executing the combat in the fundemental way provided by tfs you can execute combatArea on specific tile like by position instead pattern very close to setCombatArea but on position instead area take firestorm event as an example.
Post automatically merged:

simple example with onUse

example of how to dynamically create new attacking objects with lua.
LUA:
local MISSILE_EFFECT = CONST_ANI_ENERGY -- Change this to your desired missile effect
local TILE_EFFECT = CONST_ME_ENERGYHIT  -- Change this to your desired tile effect
local DAMAGE_TYPE = COMBAT_ENERGYDAMAGE -- Change this to the desired damage type
local MIN_DAMAGE = 50                   -- Minimum damage
local MAX_DAMAGE = 100                  -- Maximum damage

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    -- Validate the target tile position
    if not toPosition then
        player:sendCancelMessage("Invalid position.")
        return false
    end

    -- Get the player's position
    local fromPos = player:getPosition()

    -- Send a missile from the player to the target tile position
    fromPos:sendDistanceEffect(toPosition, MISSILE_EFFECT)

    -- Send a magic effect on the target tile
    toPosition:sendMagicEffect(TILE_EFFECT)

    -- Check for creatures on the target tile and deal damage
    local creature = Tile(toPosition):getTopCreature()
    if creature then
        local damage = math.random(MIN_DAMAGE, MAX_DAMAGE)
        --creature:addHealth(-damage)
        doAreaCombatHealth(creature, DAMAGE_TYPE, toPosition, 0, -damage, -damage, CONST_ME_MAGIC_RED)
end

    return true
end

another way that can be position based instead player based creating combatArea dynamically based on the position
LUA:
local MISSILE_EFFECT = CONST_ANI_ENERGY    -- The missile effect to be sent
local TILE_EFFECT = CONST_ME_ENERGYHIT     -- The visual effect on the target tile
local DAMAGE_TYPE = COMBAT_ENERGYDAMAGE    -- Type of damage
local MIN_DAMAGE = 50                      -- Minimum damage
local MAX_DAMAGE = 100                     -- Maximum damage

function onCastSpell(creature, variant)
    -- Retrieve the target position from the variant
    local toPosition = variantToPosition(variant)

    -- Validate the target position
    if not toPosition then
        creature:sendCancelMessage("Invalid target position.")
        return false
    end

    -- Send a missile from the caster to the target tile
    local fromPosition = creature:getPosition()
    fromPosition:sendDistanceEffect(toPosition, MISSILE_EFFECT)

    -- Send a visual magic effect on the target tile
    toPosition:sendMagicEffect(TILE_EFFECT)

    -- recursively apply damageArea for the position and creatures on tile.
    local targetCreature = Tile(toPosition):getTopCreature()
    if targetCreature then
        local damage = math.random(MIN_DAMAGE, MAX_DAMAGE)
       doAreaCombatHealth(creature, DAMAGE_TYPE, toPosition, 0, -damage, -damage, CONST_ME_MAGIC_RED)
    end

    return true
end

Code:
       doAreaCombatHealth(creature, DAMAGE_TYPE, toPosition, 0, -damage, -damage, CONST_ME_MAGIC_RED)
yeah but then you ahve to create use case scenario for scanning the tile for invisible creatures e.g warlock I remember i used this approach in tfs 0.4 with onUse to track hit/miss statistics of players and detect botters simply because they never miss a monster or anyone using hotkeys in bot!

also to clear things up You did compile client after changes you did not just change source file like many people here do? I know its stupid but we have to make sure. I had countless people make changes to sources saying stuff does not work where in fact they did not make their IDE do any work.
 
yeah but then you ahve to create use case scenario for scanning the tile for invisible creatures e.g warlock I remember i used this approach in tfs 0.4 with onUse to track hit/miss statistics of players and detect botters simply because they never miss a monster or anyone using hotkeys in bot!

also to clear things up You did compile client after changes you did not just change source file like many people here do? I know its stupid but we have to make sure. I had countless people make changes to sources saying stuff does not work where in fact they did not make their IDE do any work.
I know how to compile a client man, whats that question all about? XDD

It indeed compiles, but makes no change in game
Post automatically merged:

Proof of code replaced:

LUA:
void Game::useWith(const ItemPtr& item, const ThingPtr& toThing, int subType)
{
    if(!canPerformGameAction() || !item || !toThing)
        return;

    Position pos = item->getPosition();
    if(!pos.isValid()) // virtual item
        pos = Position(0xFFFF, 0, 0); // means that is an item in inventory

        m_protocolGame->sendUseItemWith(pos, item->getId(), subType ? subType : item->getStackPos(), toThing->getPosition(), toThing->getId(), toThing->getStackPos());

    g_lua.callGlobalField("g_game", "onUseWith", pos, item->getId(), toThing, subType);
}

Proof of compiling:

1731486982739.webp
 
yeah then u gotta do the onUse way clearly ur spells in engine must be using the target and engine side is doing the handicap and not client ^.^ you removed needTarget from spells.xml after the client change?
 
this is basically the issue, the sd is following target, instead of poffing when failed to get the player on position:
It can be related to modules/game_interface/gameinterface.lua and some tile.cpp code which detect clicking on creatures that are draw on other tile - by checking+/- 1 SQM around - ex. player standing on 3 parcels is draw on left-upper tile from his real position.
There is a fix for magic wall rune in client Lua code:
LUA:
      if selectedThing:isFluidContainer() or selectedThing:isMultiUse() then      
        if selectedThing:getId() == 3180 or selectedThing:getId() == 3156 then
          -- special version for mwall
          g_game.useWith(selectedThing, tile:getTopUseThing(), selectedSubtype)      
        else
          g_game.useWith(selectedThing, tile:getTopMultiUseThingEx(clickedWidget:getPositionOffset(mousePosition)), selectedSubtype)
        end
      else
        g_game.useWith(selectedThing, tile:getTopUseThing(), selectedSubtype)
      end
    end
You can try to add some other rune IDs here, but then it will fail when you use rune on player standing on 3 parcels or player/monster that has outfit 64x64 with offset. To fix this, you would need to rewrite some parts of C++ code.
There is even some code commented with different detection of 'is creature on position' called worse, maybe it will fix your problem:
C++:
bool Creature::isInsideOffset(Point offset)
{
    // for worse precision:
    // Rect rect(getDrawOffset() - (m_walking ? m_walkOffset : Point(0,0)), Size(Otc::TILE_PIXELS - getDisplacementY(), Otc::TILE_PIXELS - getDisplacementX()));
    Rect rect(getDrawOffset() - getDisplacement(), Size(g_sprites.spriteSize(), g_sprites.spriteSize()));
    return rect.contains(offset);
}
 
yeah then u gotta do the onUse way clearly ur spells in engine must be using the target and engine side is doing the handicap and not client ^.^ you removed needTarget from spells.xml after the client change?
Yeah, needtarget is set to 0, also tried removing it and also tried with 1
 
Back
Top