• 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 0.X] Walkthrough problem - Working just with click

potinho

Advanced OT User
Joined
Oct 11, 2009
Messages
1,458
Solutions
17
Reaction score
175
Location
Brazil
I want to make players can pass through other players in PZ area, but only works on i click on player, with arrow cant pass (in PZ area). Can u guys help me to fix?

C++:
bool Player::canWalkthrough(const Creature* creature) const
{
    if(creature == this || hasFlag(PlayerFlag_CanPassThroughAllCreatures) || creature->isWalkable() ||
        (creature->getMaster() && creature->getMaster() != this && canWalkthrough(creature->getMaster())))
        return true;

    const Player* player = creature->getPlayer();
    if(!player)
        return false;

    if(((g_game.getWorldType() == WORLDTYPE_OPTIONAL &&
        !player->isProtected()) || player->getTile()->hasFlag(TILESTATE_PROTECTIONZONE) || player->isProtected()) && player->getTile()->ground
        && Item::items[player->getTile()->ground->getID()].walkStack && (!player->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges)
        || player->getAccess() <= getAccess()))
        return true;

    return (player->isGhost() && getGhostAccess() < player->getGhostAccess())
        || (isGhost() && getGhostAccess() > player->getGhostAccess());
}
 
When player walks with arrows, it calculates 'path' [1 step 'path'] on client side.
When player 'use item' or use map walk, it calculates 'path' on server side.

Server has up to date information about players, so it allows player to walk thru other player by checking Player::canWalkthrough every step.

Information about 'can I walk thru player' is send to tibia client, when player sees other player for first time. Then it's cached and never updated.
So if player saw other player outside depot, his client will cache 'this player is not walkable' and won't let tibia client walk thru other player. Pressing 'arrow' in client won't even send packet 'make step' to server.

Only real fix for that is to send 'update walkthru' every player step to every other player on screen.

TODO on TFS 0.x:
1. This function is not implemented at all on 0.4:
here is TFS 1.5 code for it:
2. Function to send 'walkthru' to all players on screen does not exist on 0.4. Here is 1.5 code:
3. You got to send update of 'walkthru' every player step, ex. in this line:
under:
Code:
    if(creature != this)
        return;
add:
Code:
g_game.updateCreatureWalkthrough(this);
so it will execute only for player that makes step, not all players 'on his screen' - we want to 'broadcast walkthru' of player that just did step, not X times same information for all players that 'see someone makes step'.

EDIT: Code like that is on Kasteria and it did not affect CPU/network usage heavily.
 
When player walks with arrows, it calculates 'path' [1 step 'path'] on client side.
When player 'use item' or use map walk, it calculates 'path' on server side.

Server has up to date information about players, so it allows player to walk thru other player by checking Player::canWalkthrough every step.

Information about 'can I walk thru player' is send to tibia client, when player sees other player for first time. Then it's cached and never updated.
So if player saw other player outside depot, his client will cache 'this player is not walkable' and won't let tibia client walk thru other player. Pressing 'arrow' in client won't even send packet 'make step' to server.

Only real fix for that is to send 'update walkthru' every player step to every other player on screen.

TODO on TFS 0.x:
1. This function is not implemented at all on 0.4:
here is TFS 1.5 code for it:
2. Function to send 'walkthru' to all players on screen does not exist on 0.4. Here is 1.5 code:
3. You got to send update of 'walkthru' every player step, ex. in this line:
under:
Code:
    if(creature != this)
        return;
add:
Code:
g_game.updateCreatureWalkthrough(this);
so it will execute only for player that makes step, not all players 'on his screen' - we want to 'broadcast walkthru' of player that just did step, not X times same information for all players that 'see someone makes step'.

EDIT: Code like that is on Kasteria and it did not affect CPU/network usage heavily.
sorry but all the links lead to out of date lines of code. now tell me github is good source of information when its constantly updated ? xD now i understand why they do not allow links on the forum.


okay I copied all the features my distro was missing such as canplayerwalktrhough ex stuff etc and then added the code there in player also creating similar function for creatures if getMaster()->getPlayer() ;)

personally I have found in the distro im using this code snipped and thinking if I could not bypass it here somehow

here is my logic for Creature.cpp

C++:
// Check if the creature has a master and if the master is a player
if (g_game.getWorldType() == WORLD_TYPE_NO_PVP) {
    if (this->getMaster()) {
        Player* master = this->getMaster()->getPlayer();
        if (master) {
            // Check if the game world is not PvP
 
                // Send update to the master about the creature's movement
                g_game.updateCreatureWalkthrough(this);
 
        }
    }
}

also i think in case when creature is already on a tile and has not moven e.g summon and player standing in some spot never moving etc we should add it in onCreatureAppear *** does not work in on creature appear im searching elsewhere. maybe it will work onIdleStatus or onThink ( ouch my CPU)
C++:
void Creature::onCreatureAppear(Creature* creature, bool isLogin)
{
    if (creature == this) {
        if (isLogin) {
            setLastPosition(getPosition());
        }
    }

    // Check if the creature has a master and if the master is a player
    if (g_game.getWorldType() == WORLD_TYPE_NO_PVP) {
        if (this->getMaster()) {
            Player* master = this->getMaster()->getPlayer();
            if (master) {
                // Check if the game world is not PvP

                    // Send update to the master about the creature's movement
                g_game.updateCreatureWalkthrough(this);

            }
        }
    }


}

if anyone has any idea where else would we have to input this updatewalkthrough for creatures which dont move let me know :v

e.g AFK players blocking deposit entry and have to still mouse click on em


still trying to figure it out if players / summons do not make step e.g u walk to a creature that is standing still you cant walk through it until YOU push it or IT makes a step.
or essentialy reverse the function to send information to the player about all spectators on screen which we can walk through.
 
Last edited:
Has anyone updated this code the right way?

@Gesior.pl


LUA:
void Player::onCreatureMove(Creature* creature, const Tile* newTile, const Position& newPos,
                            const Tile* oldTile, const Position& oldPos, bool teleport)
{
    Creature::onCreatureMove(creature, newTile, newPos, oldTile, oldPos, teleport);

    if (hasFollowPath && (creature == followCreature || (creature == this && followCreature))) {
        isUpdatingPath = false;
        g_dispatcher.addTask(createTask(std::bind(&Game::updateCreatureWalk, &g_game, getID())));
    }
   
    g_game.updateCreatureWalkthrough(this);

    if (creature != this) {
        return;
    }  

    if (tradeState != TRADE_TRANSFER) {
        //check if we should close trade
        if (tradeItem && !Position::areInRange<1, 1, 0>(tradeItem->getPosition(), getPosition())) {
            g_game.internalCloseTrade(this);
        }

        if (tradePartner && !Position::areInRange<2, 2, 0>(tradePartner->getPosition(), getPosition())) {
            g_game.internalCloseTrade(this);
        }
    }

    // close modal windows
    if (!modalWindows.empty()) {
        // TODO: This shouldn't be hard-coded
        for (uint32_t modalWindowId : modalWindows) {
            if (modalWindowId == std::numeric_limits<uint32_t>::max()) {
                sendTextMessage(MESSAGE_EVENT_ADVANCE, "Offline training aborted.");
                break;
            }
        }
        modalWindows.clear();
    }

    // leave market
    if (inMarket) {
        inMarket = false;
    }

    if (party) {
        party->updateSharedExperience();
    }

    if (teleport || oldPos.z != newPos.z) {
        int32_t ticks = g_config.getNumber(ConfigManager::STAIRHOP_DELAY);
        if (ticks > 0) {
            if (Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_PACIFIED, ticks, 0)) {
                addCondition(condition);
            }
        }
    }
}

This way it worked
 
Last edited:
Back
Top