• 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?>
 
You must convert toPosition (item target position) to Variant with type VARIANT_TARGETPOSITION:
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")

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    local variant = Variant(toPosition)

    return combat:execute(player, variant)
end
 
Last edited:
why no onCastSpell ? ah yeah cuz its just function that calls combat function my bad...

didnt work actually

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

local function kopanko(player, item, fromPosition, target, toPosition, isHotkey)
    local USES_STORAGE = 2554
    local REAL_USES = 25541
    local howmany = player:getStorageValue(REAL_USES)
    local uses = player:getStorageValue(USES_STORAGE) + 1
    player:setStorageValue(USES_STORAGE, uses)
    player:setStorageValue(REAL_USES, player:getStorageValue(REAL_USES) + 1)

 

    -- Cast the holy damage spell
    onCastSpell(player, numberToVariant(player:getId()))

    -- Check if the player has used the item 10000 times, and reward them with random exp if true
    if uses % 10000 == 0 then
        local reward = math.random(100, 200)
        player:setStorageValue(55656, player:getStorageValue(55656) + 1)
        player:addExperience(reward, true)
     
        player:setStorageValue(USES_STORAGE, 0)
        player:getPosition():sendMagicEffect(24)
    end
end

or i dont know how to use it here is full code.
 
why no onCastSpell ?
For 'spell' scripts C++ calls Lua onCastSpell(creature, variant).
For 'action use' scripts C++ calls Lua onUse function. You get a lot of params, we need to convert toPosition to Variant type, to make it work with combat:execute(creature, variant).

I've edited my code in post above. Removed variant.type = VARIANT_TARGETPOSITION. Now it should work.
 
Last edited:
For 'spell' scripts C++ calls Lua onCastSpell(creature, variant).
For 'action use' scripts C++ calls Lua onUse function. You get a lot of params, we need to convert toPosition to Variant type, to make it work with combat:execute(creature, variant).

I've edited my code in post above. Removed variant.type = VARIANT_TARGETPOSITION. Now it should work.

Trying to use on spells, instead of using onUse for actions, set needtarget to 1 and to 0 and doesnt work either way, any clue how to use it on function onCastSpell?

LUA:
function onCastSpell(creature, variant)
    local target = Tile(variant:getPosition()):getTopCreature()
    if target then
      return combat:execute(creature, variant)
    end
    creature:getPosition():sendMagicEffect(CONST_ME_POFF)
end
 
Trying to use on spells, instead of using onUse for actions, set needtarget to 1 and to 0 and doesnt work either way, any clue how to use it on function onCastSpell?

LUA:
function onCastSpell(creature, variant)
    local target = Tile(variant:getPosition()):getTopCreature()
    if target then
      return combat:execute(creature, variant)
    end
    creature:getPosition():sendMagicEffect(CONST_ME_POFF)
end
please refactor what you mean I do not understand anything you just said.
 
Trying to use on spells, instead of using onUse for actions, set needtarget to 1 and to 0 and doesnt work either way,
Spell .xml configs like needtarget etc. should handle target of spell/rune. As czouski said, we don't understand what you want to achive with custom variant/target in spell Lua.
 
Spell .xml configs like needtarget etc. should handle target of spell/rune. As czouski said, we don't understand what you want to achive with custom variant/target in spell Lua.
I think i missinterpreted the goal of the post, my goal is to change the onCastSpell to variantToPosition or onTargetTile in order to be able to throw the SD or any rune on the TILE, instead of the player, right now on TFS 1.4.2, when you manually target a player with an sd, if the player is moving the rune FOLLOWS the creature to the next position he's going, its kinda like a TARGET ASSIST RUNE, I wanted to be able to throw the rune on TILE, not on the creature itself. I can send you a dm on discord just to send you an example of how i want it to work.
 
I think i missinterpreted the goal of the post, my goal is to change the onCastSpell to variantToPosition or onTargetTile in order to be able to throw the SD or any rune on the TILE, instead of the player, right now on TFS 1.4.2, when you manually target a player with an sd, if the player is moving the rune FOLLOWS the creature to the next position he's going, its kinda like a TARGET ASSIST RUNE, I wanted to be able to throw the rune on TILE, not on the creature itself. I can send you a dm on discord just to send you an example of how i want it to work.
<rune name="adori vita vis" id="2268" allowfaruse="1" maglv="15" charges="1" script="runes/sudden_death_rune.lua" />
just remove needtarget="1" from this place I have done it before but reverted the changes for tests
 
<rune name="adori vita vis" id="2268" allowfaruse="1" maglv="15" charges="1" script="runes/sudden_death_rune.lua" />
just remove needtarget="1" from this place I have done it before but reverted the changes for tests
Tried that way already, but Oen just told me it is a client game.cpp change actually, not related to server side
 
Tried that way already, but Oen just told me it is a client game.cpp change actually, not related to server side
hmm which line so i can have look at my changes.


C++:
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

    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());

    g_lua.callGlobalField("g_game", "onUseWith", pos, item->getId(), toThing, subType);
}
 
Thats exactly the same code Oen told me about, but im trying to figure out what to change exactly, he just told me the code, didnt tell me the solution

''The function then checks if toThing is a creature and if the game protocol version is at least 780 or if a specific game feature (Otc::GameForceAllowItemHotkeys) is enabled. If these conditions are met, it sends a command to use the item on the creature using m_protocolGame-&gt;sendUseOnCreature. Otherwise, it sends a command to use the item with another entity using m_protocolGame-&gt;sendUseItemWith.''
 
C++:
m_protocolGame->sendUseItemWith(pos, item->getId(), subType ? subType : item->getStackPos(), toThing->getPosition(), toThing->getId(), toThing->getStackPos());
you want it to send this no matter what protocol u use because u probably using newer protocol.

C++:
 m_protocolGame->sendUseOnCreature(pos, item->getId(), subType ? subType : item->getStackPos(), toThing->getId());
this code is responsible for hitting a creature target while the useitemwith targets position instead
 
C++:
m_protocolGame->sendUseItemWith(pos, item->getId(), subType ? subType : item->getStackPos(), toThing->getPosition(), toThing->getId(), toThing->getStackPos());
you want it to send this no matter what protocol u use because u probably using newer protocol.

C++:
 m_protocolGame->sendUseOnCreature(pos, item->getId(), subType ? subType : item->getStackPos(), toThing->getId());
this code is responsible for hitting a creature target while the useitemwith targets position instead
I tried removing sendUseOnCreature and it works the same, i removed GameForceAllowItemHotkeys as well and it didnt work
 
I think i missinterpreted the goal of the post, my goal is to change the onCastSpell to variantToPosition or onTargetTile in order to be able to throw the SD or any rune on the TILE, instead of the player, right now on TFS 1.4.2, when you manually target a player with an sd, if the player is moving the rune FOLLOWS the creature to the next position he's going, its kinda like a TARGET ASSIST RUNE, I wanted to be able to throw the rune on TILE, not on the creature itself. I can send you a dm on discord just to send you an example of how i want it to work.
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)
 
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)
Wouldnt this be an action script instead of a spell revscript?
 
So oen is wrong? Its not a change on client's side?
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).
if the player is moving the rune FOLLOWS the creature to the next position he's going, its kinda like a TARGET ASSIST RUNE
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.
 
Back
Top