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

TFS 1.2 playerUseItemEx() problem

whitevo

Feeling good, thats what I do.
Joined
Jan 2, 2015
Messages
3,454
Solutions
1
Reaction score
627
Location
Estonia
In TFS 1.1.x

if you use item what is made so it cant be moved
for example:
Code:
function Player:onMoveItem(item, count, fromPosition, toPosition)
if item:getId() == 2674 then return false end
end
and you try to use it anway on a tile what is not reachable.
Then first you pick up the item!?! and then messages comes.. cant be reached.
But now you cant move that item out of your bag. because well.. it was supposed to be unmoveable item..

How to fix that?
 
Still a very big issue.
If not fixes for this then I have to change all unmoveable item by script with onUse:itemEx effect.. Which is quite annoying.
 
Looks pretty impossible to rearrange them.

Going to try Tarliton solution (github link here)
Problem is that, I have no clue how to create the "check" event.
I assume all I have to is write the "check" >here< after the "{" symbol.

But how the heck make it find the return value from my LUA function in data folder?
At best i could think of something like this:

Code:
if (!g_events->eventPlayerOnMoveItem(fromSpriteId)) {
        return;
    }
 
In the early version of TFS 1.2 source didn't use toCylinder and fromCylinder.
So the small fix by Tarliton worked. > https://github.com/otland/forgottenserver/issues/1572

However now it doesn't, it says function doesn't match.
I assume I need to pass the cylinders too.

I simply gathered similar info from other functions, but not sure is it correct way to do it.
Could someone take look at it and see if anything should be changed. I don't want to cause crashes (don't even know does it compile yet xD)

the added section is between /* and */

Code:
void Game::playerUseItemEx(uint32_t playerId, const Position& fromPos, uint8_t fromStackPos, uint16_t fromSpriteId,
                           const Position& toPos, uint8_t toStackPos, uint16_t toSpriteId)
{
    Player* player = getPlayerByID(playerId);
    if (!player) {
        return;
    }

    bool isHotkey = (fromPos.x == 0xFFFF && fromPos.y == 0 && fromPos.z == 0);
    if (isHotkey && !g_config.getBoolean(ConfigManager::AIMBOT_HOTKEY_ENABLED)) {
        return;
    }

    Thing* thing = internalGetThing(player, fromPos, fromStackPos, fromSpriteId, STACKPOS_USEITEM);
    if (!thing) {
        player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
        return;
    }

    Item* item = thing->getItem();
    if (!item || !item->isUseable() || item->getClientID() != fromSpriteId) {
        player->sendCancelMessage(RETURNVALUE_CANNOTUSETHISOBJECT);
        return;
    }

    Position walkToPos = fromPos;
    ReturnValue ret = g_actions->canUse(player, fromPos);
    if (ret == RETURNVALUE_NOERROR) {
        ret = g_actions->canUse(player, toPos, item);
        if (ret == RETURNVALUE_TOOFARAWAY) {
            walkToPos = toPos;
        }
    }

    if (ret != RETURNVALUE_NOERROR) {
        if (ret == RETURNVALUE_TOOFARAWAY) {
            Position itemPos = fromPos;
            uint8_t itemStackPos = fromStackPos;

            if (fromPos.x != 0xFFFF && toPos.x != 0xFFFF && Position::areInRange<1, 1, 0>(fromPos, player->getPosition()) &&
                    !Position::areInRange<1, 1, 0>(fromPos, toPos)) {
                Item* moveItem = nullptr;

                ret = internalMoveItem(item->getParent(), player, INDEX_WHEREEVER, item, item->getItemCount(), &moveItem);
                if (ret != RETURNVALUE_NOERROR) {
                    player->sendCancelMessage(ret);
                    return;
                }

                //changing the position since its now in the inventory of the player
                internalGetPosition(moveItem, itemPos, itemStackPos);
            }

            std::forward_list<Direction> listDir;
            if (player->getPathTo(walkToPos, listDir, 0, 1, true, true)) {
                g_dispatcher.addTask(createTask(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir)));

                SchedulerTask* task = createSchedulerTask(400, std::bind(&Game::playerUseItemEx, this,
                                      playerId, itemPos, itemStackPos, fromSpriteId, toPos, toStackPos, toSpriteId));
                player->setNextWalkActionTask(task);
            } else {
                player->sendCancelMessage(RETURNVALUE_THEREISNOWAY);
            }
            return;
        }
        
        player->sendCancelMessage(ret);
        return;
    }
    
//* VVVVVVVVVVVVVV
    toCylinder = internalGetCylinder(player, toPos);
    if (toCylinder == nullptr) {
        player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
        return;
    }
    
    const Position& mapFromPos = fromCylinder->getTile()->getPosition();
    Cylinder* fromCylinder = internalGetCylinder(player, fromPos);
    
    if (fromCylinder == nullptr) {
        player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
        return;
    }
    
    const Tile* toCylinderTile = toCylinder->getTile();
    const Position& mapToPos = toCylinderTile->getPosition();
    
    if (!g_events->eventPlayerOnMoveItem(player, item, item->getItemCount(), fromPos, toPos, fromCylinder, toCylinder)) {
        player->sendCancelMessage(RETURNVALUE_CANNOTPICKUP);
        return;
    }
    ^^^^^^^^^^^^^^^^^^  */

    if (!player->canDoAction()) {
        uint32_t delay = player->getNextActionTime();
        SchedulerTask* task = createSchedulerTask(delay, std::bind(&Game::playerUseItemEx, this,
                              playerId, fromPos, fromStackPos, fromSpriteId, toPos, toStackPos, toSpriteId));
        player->setNextActionTask(task);
        return;
    }

    player->resetIdleTime();
    player->setNextActionTask(nullptr);

    g_actions->useItemEx(player, fromPos, toPos, toStackPos, item, isHotkey);
}
 
a "lazy" fix would be using something like
Code:
function Player:onMoveItem(item, count, fromPosition, toPosition)
    if item:getId() == 2674 then
        item:copy():moveTo(item:getPosition())
        item:remove()
        return false
    end
end
should work fine, but if you have the item userdata saved somewhere for whatever reason youd have to change that aswell
 
I will test your solution next update.

However I will use source fix if someone lets me know that above code is fine or gives better solution.
 

Similar threads

Back
Top