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

[FIX]Smooth Walking - OTC

Ascuas Funkeln

Rakkedo Game
Joined
Apr 14, 2013
Messages
549
Solutions
32
Reaction score
305
Location
Poland
GitHub
AscuasFunkeln
Hello, after reaching full madness and despair, i managed to achieve half success "for me", I think.
I started building my own server a few years ago with the client based on the original version OTC by @edubart.
I do not have the Mehah and V8 versions, so I do not know anything about the source codes and the changes made by the developers of these versions.
Warning! Its "noobish" fix xD

1.
Read this topic and make changes to your source code
Final thread for fixing OTClient dashing animation issue for TFS 1.3 (https://otland.net/threads/final-thread-for-fixing-otclient-dashing-animation-issue-for-tfs-1-3.263272/)

2.
In modules\game_interface\game_interface.lua set delay to 0
Lua:
function bindKeys()
  gameRootPanel:setAutoRepeatDelay(0)

3.
Now in src\client\localplayer.cpp
Change
C++:
bool LocalPlayer::canWalk(Otc::Direction direction)
{
    // cannot walk while locked
    if(m_walkLockExpiration != 0 && g_clock.millis() < m_walkLockExpiration)
        return false;

    // paralyzed
    if(m_speed == 0)
        return false;

    // last walk is not done yet
    if((m_walkTimer.ticksElapsed() < getStepDuration()) && !isAutoWalking())
        return false;

    // prewalk has a timeout, because for some reason that I don't know yet the server sometimes doesn't answer the prewalk
    bool prewalkTimeouted = m_walking && m_preWalking && m_walkTimer.ticksElapsed() >= getStepDuration();

    // avoid doing more walks than wanted when receiving a lot of walks from server
    if(!m_lastPrewalkDone && m_preWalking && !prewalkTimeouted)
        return false;

    // cannot walk while already walking
    if((m_walking && !isAutoWalking()) && (!prewalkTimeouted || m_secondPreWalk))
        return false;

    return true;
}

To

C++:
bool LocalPlayer::canWalk(Otc::Direction direction)
{
    // cannot walk while locked
    if(m_walkLockExpiration != 0 && g_clock.millis() < m_walkLockExpiration)
        return false;

    // paralyzed
    if(m_speed == 0)
        return false;

    // last walk is not done yet
    if((m_walkTimer.ticksElapsed() < getStepDuration()) && !isAutoWalking())
        return false;

    // prewalk has a timeout, because for some reason that I don't know yet the server sometimes doesn't answer the prewalk
    bool prewalkTimeouted = m_walking && m_preWalking && m_walkTimer.ticksElapsed() >= getStepDuration();

    // avoid doing more walks than wanted when receiving a lot of walks from server
    if(!m_lastPrewalkDone && m_preWalking && !prewalkTimeouted)
        return false;

    // cannot walk while already walking
    if((m_walking && !isAutoWalking()) && (!prewalkTimeouted || m_secondPreWalk))
        return true;

    return true;
}

And change:

C++:
void LocalPlayer::cancelWalk(Otc::Direction direction)
{
    // only cancel client side walks
    if(m_walking && m_preWalking)
        stopWalk();

    m_lastPrewalkDone = true;
    m_idleTimer.restart();
    lockWalk();

    if(m_autoWalkDestination.isValid()) {
        g_game.stop();
        auto self = asLocalPlayer();
        if(m_autoWalkContinueEvent)
            m_autoWalkContinueEvent->cancel();
        m_autoWalkContinueEvent = g_dispatcher.scheduleEvent([self]() {
            if(self->m_autoWalkDestination.isValid())
                self->autoWalk(self->m_autoWalkDestination);
        }, 500);
    }

    // turn to the cancel direction
    if(direction != Otc::InvalidDirection)
        setDirection(direction);

    callLuaField("onCancelWalk", direction);
}

To

C++:
void LocalPlayer::cancelWalk(Otc::Direction direction)
{
    // only cancel client side walks
    if(m_walking && m_preWalking)


    m_lastPrewalkDone = true;
    m_idleTimer.restart();
    lockWalk();

    if(m_autoWalkDestination.isValid()) {
        g_game.stop();
        auto self = asLocalPlayer();
        if(m_autoWalkContinueEvent)
            m_autoWalkContinueEvent->cancel();
        m_autoWalkContinueEvent = g_dispatcher.scheduleEvent([self]() {
            if(self->m_autoWalkDestination.isValid())
                self->autoWalk(self->m_autoWalkDestination);
        }, 500);
    }

    // turn to the cancel direction
    if(direction != Otc::InvalidDirection)
        setDirection(direction);

    callLuaField("onCancelWalk", direction);
}

4.
I change in config.lua maxPacketsPerSecond to 50, but on 25 its look i think the same, just to test it. I increase it just "for sure" xD maxPacketsPerSecond = 50

5.
And this best work on Enabled Vertical Synchronization this will set automic 60 FPS

6.
Check Full Video how its work in mine client, i test in this video 3 characters with different movement speed.
7.
As i said its not PRO FIX, and may cause some problems, but i dont see anything yet :p
Best thing its work with Enabled Vertical Synchronization at 60 FPS so, the usage CPU by OTC highly drop from 15% to 4% on my PC.
 
It looks like the character give more steps and I like that, would like to try this feature on mehah's otclient, but not sure how. It says that methods like m_secondPreWalk are not defined when applying them on msvc, Here's the bool canWalk method from mehah's sources, otclient/localplayer.cpp at main · mehah/otclient (https://github.com/mehah/otclient/blob/main/src/client/localplayer.cpp#L41)

I'm intrested on optimizing the 3 frames walking from 8.6 protocol. Is it possible?

Also saw this change on the repository

Should I switch back this commit?
 
Last edited:
Im using 800OTClient for sabrehaven server, and when I downloaded was without src folder. Do you have any other client that can I use with src file to improve my client?
 
Hello, after reaching full madness and despair, i managed to achieve half success "for me", I think.
I started building my own server a few years ago with the client based on the original version OTC by @edubart.
I do not have the Mehah and V8 versions, so I do not know anything about the source codes and the changes made by the developers of these versions.
Warning! Its "noobish" fix xD

1.
Read this topic and make changes to your source code
Final thread for fixing OTClient dashing animation issue for TFS 1.3 (https://otland.net/threads/final-thread-for-fixing-otclient-dashing-animation-issue-for-tfs-1-3.263272/)

2.
In modules\game_interface\game_interface.lua set delay to 0
Lua:
function bindKeys()
  gameRootPanel:setAutoRepeatDelay(0)

3.
Now in src\client\localplayer.cpp
Change
C++:
bool LocalPlayer::canWalk(Otc::Direction direction)
{
    // cannot walk while locked
    if(m_walkLockExpiration != 0 && g_clock.millis() < m_walkLockExpiration)
        return false;

    // paralyzed
    if(m_speed == 0)
        return false;

    // last walk is not done yet
    if((m_walkTimer.ticksElapsed() < getStepDuration()) && !isAutoWalking())
        return false;

    // prewalk has a timeout, because for some reason that I don't know yet the server sometimes doesn't answer the prewalk
    bool prewalkTimeouted = m_walking && m_preWalking && m_walkTimer.ticksElapsed() >= getStepDuration();

    // avoid doing more walks than wanted when receiving a lot of walks from server
    if(!m_lastPrewalkDone && m_preWalking && !prewalkTimeouted)
        return false;

    // cannot walk while already walking
    if((m_walking && !isAutoWalking()) && (!prewalkTimeouted || m_secondPreWalk))
        return false;

    return true;
}

To

C++:
bool LocalPlayer::canWalk(Otc::Direction direction)
{
    // cannot walk while locked
    if(m_walkLockExpiration != 0 && g_clock.millis() < m_walkLockExpiration)
        return false;

    // paralyzed
    if(m_speed == 0)
        return false;

    // last walk is not done yet
    if((m_walkTimer.ticksElapsed() < getStepDuration()) && !isAutoWalking())
        return false;

    // prewalk has a timeout, because for some reason that I don't know yet the server sometimes doesn't answer the prewalk
    bool prewalkTimeouted = m_walking && m_preWalking && m_walkTimer.ticksElapsed() >= getStepDuration();

    // avoid doing more walks than wanted when receiving a lot of walks from server
    if(!m_lastPrewalkDone && m_preWalking && !prewalkTimeouted)
        return false;

    // cannot walk while already walking
    if((m_walking && !isAutoWalking()) && (!prewalkTimeouted || m_secondPreWalk))
        return true;

    return true;
}

And change:

C++:
void LocalPlayer::cancelWalk(Otc::Direction direction)
{
    // only cancel client side walks
    if(m_walking && m_preWalking)
        stopWalk();

    m_lastPrewalkDone = true;
    m_idleTimer.restart();
    lockWalk();

    if(m_autoWalkDestination.isValid()) {
        g_game.stop();
        auto self = asLocalPlayer();
        if(m_autoWalkContinueEvent)
            m_autoWalkContinueEvent->cancel();
        m_autoWalkContinueEvent = g_dispatcher.scheduleEvent([self]() {
            if(self->m_autoWalkDestination.isValid())
                self->autoWalk(self->m_autoWalkDestination);
        }, 500);
    }

    // turn to the cancel direction
    if(direction != Otc::InvalidDirection)
        setDirection(direction);

    callLuaField("onCancelWalk", direction);
}

To

C++:
void LocalPlayer::cancelWalk(Otc::Direction direction)
{
    // only cancel client side walks
    if(m_walking && m_preWalking)


    m_lastPrewalkDone = true;
    m_idleTimer.restart();
    lockWalk();

    if(m_autoWalkDestination.isValid()) {
        g_game.stop();
        auto self = asLocalPlayer();
        if(m_autoWalkContinueEvent)
            m_autoWalkContinueEvent->cancel();
        m_autoWalkContinueEvent = g_dispatcher.scheduleEvent([self]() {
            if(self->m_autoWalkDestination.isValid())
                self->autoWalk(self->m_autoWalkDestination);
        }, 500);
    }

    // turn to the cancel direction
    if(direction != Otc::InvalidDirection)
        setDirection(direction);

    callLuaField("onCancelWalk", direction);
}

4.
I change in config.lua maxPacketsPerSecond to 50, but on 25 its look i think the same, just to test it. I increase it just "for sure" xD maxPacketsPerSecond = 50

5.
And this best work on Enabled Vertical Synchronization this will set automic 60 FPS

6.
Check Full Video how its work in mine client, i test in this video 3 characters with different movement speed.
7.
As i said its not PRO FIX, and may cause some problems, but i dont see anything yet :p
Best thing its work with Enabled Vertical Synchronization at 60 FPS so, the usage CPU by OTC highly drop from 15% to 4% on my PC.
I think your version is different from mine, can you help me plz?

C++:
bool LocalPlayer::canWalk(Otc::Direction direction, bool ignoreLock)
{
    // cannot walk while locked
    if ((m_walkLockExpiration != 0 && g_clock.millis() < m_walkLockExpiration) && !ignoreLock)
        return false;

    // paralyzed
    if (m_speed == 0)
        return false;

    // last walk is not done yet
    if (m_walking && (m_walkTimer.ticksElapsed() < getStepDuration()) && !isAutoWalking() && !isServerWalking())
        return false;

    auto tile = g_map.getTile(getPrewalkingPosition(true));
    if (isPreWalking() && (!m_lastPrewalkDone || (tile && tile->isBlocking())))
        return false;

    // cannot walk while already walking
    if ((m_walking && !isAutoWalking() && !isServerWalking()) && (!isPreWalking() || !m_lastPrewalkDone))
        return true;

    // Without new walking limit only to 1 prewalk
    if (!m_preWalking.empty() && !g_game.getFeature(Otc::GameNewWalking))
        return false;

    // Limit pre walking steps
    if (m_preWalking.size() >= g_game.getMaxPreWalkingSteps()) { // max 3 extra steps
        if (m_walkTimer.ticksElapsed() >= getStepDuration() + 300)
            return true;
        return false;
    }

    if (!m_preWalking.empty()) { // disallow diagonal extented prewalking walking
        auto dir = m_position.getDirectionFromPosition(m_preWalking.back());
        if ((dir == Otc::NorthWest || dir == Otc::NorthEast || dir == Otc::SouthWest || dir == Otc::SouthEast)) {
            return false;
        }
        if (!g_map.getTile(getPrewalkingPosition())->isWalkable())
            return false;
    }

    return true;
}

And my cancelWalk, when I try use yours, i got error on "&&"
C++:
void LocalPlayer::cancelWalk(Otc::Direction direction)
{
    if (g_game.getFeature(Otc::GameNewWalking)) {
        return;
    }

    return cancelNewWalk(direction);
}
 
I think your version is different from mine, can you help me plz?

C++:
bool LocalPlayer::canWalk(Otc::Direction direction, bool ignoreLock)
{
    // cannot walk while locked
    if ((m_walkLockExpiration != 0 && g_clock.millis() < m_walkLockExpiration) && !ignoreLock)
        return false;

    // paralyzed
    if (m_speed == 0)
        return false;

    // last walk is not done yet
    if (m_walking && (m_walkTimer.ticksElapsed() < getStepDuration()) && !isAutoWalking() && !isServerWalking())
        return false;

    auto tile = g_map.getTile(getPrewalkingPosition(true));
    if (isPreWalking() && (!m_lastPrewalkDone || (tile && tile->isBlocking())))
        return false;

    // cannot walk while already walking
    if ((m_walking && !isAutoWalking() && !isServerWalking()) && (!isPreWalking() || !m_lastPrewalkDone))
        return true;

    // Without new walking limit only to 1 prewalk
    if (!m_preWalking.empty() && !g_game.getFeature(Otc::GameNewWalking))
        return false;

    // Limit pre walking steps
    if (m_preWalking.size() >= g_game.getMaxPreWalkingSteps()) { // max 3 extra steps
        if (m_walkTimer.ticksElapsed() >= getStepDuration() + 300)
            return true;
        return false;
    }

    if (!m_preWalking.empty()) { // disallow diagonal extented prewalking walking
        auto dir = m_position.getDirectionFromPosition(m_preWalking.back());
        if ((dir == Otc::NorthWest || dir == Otc::NorthEast || dir == Otc::SouthWest || dir == Otc::SouthEast)) {
            return false;
        }
        if (!g_map.getTile(getPrewalkingPosition())->isWalkable())
            return false;
    }

    return true;
}

And my cancelWalk, when I try use yours, i got error on "&&"
C++:
void LocalPlayer::cancelWalk(Otc::Direction direction)
{
    if (g_game.getFeature(Otc::GameNewWalking)) {
        return;
    }

    return cancelNewWalk(direction);
}
This solution is not for otcv8. Its for raw OTClient GitHub - edubart/otclient: An alternative tibia client for otserv written in C++11 and Lua, made with a modular system that uses lua scripts for ingame interface and functionality, making otclient flexible and easy to customize (https://github.com/edubart/otclient)
 
Thanks Ascuas, Im using OTClient now, do you know if have any place layouts for him? I want to turn OTClient into a retro client, do you know any tutorial for this?
 
Hello, after reaching full madness and despair, i managed to achieve half success "for me", I think.
I started building my own server a few years ago with the client based on the original version OTC by @edubart.
I do not have the Mehah and V8 versions, so I do not know anything about the source codes and the changes made by the developers of these versions.
Warning! Its "noobish" fix xD

1.
Read this topic and make changes to your source code
Final thread for fixing OTClient dashing animation issue for TFS 1.3 (https://otland.net/threads/final-thread-for-fixing-otclient-dashing-animation-issue-for-tfs-1-3.263272/)

2.
In modules\game_interface\game_interface.lua set delay to 0
Lua:
function bindKeys()
  gameRootPanel:setAutoRepeatDelay(0)

3.
Now in src\client\localplayer.cpp
Change
C++:
bool LocalPlayer::canWalk(Otc::Direction direction)
{
    // cannot walk while locked
    if(m_walkLockExpiration != 0 && g_clock.millis() < m_walkLockExpiration)
        return false;

    // paralyzed
    if(m_speed == 0)
        return false;

    // last walk is not done yet
    if((m_walkTimer.ticksElapsed() < getStepDuration()) && !isAutoWalking())
        return false;

    // prewalk has a timeout, because for some reason that I don't know yet the server sometimes doesn't answer the prewalk
    bool prewalkTimeouted = m_walking && m_preWalking && m_walkTimer.ticksElapsed() >= getStepDuration();

    // avoid doing more walks than wanted when receiving a lot of walks from server
    if(!m_lastPrewalkDone && m_preWalking && !prewalkTimeouted)
        return false;

    // cannot walk while already walking
    if((m_walking && !isAutoWalking()) && (!prewalkTimeouted || m_secondPreWalk))
        return false;

    return true;
}

To

C++:
bool LocalPlayer::canWalk(Otc::Direction direction)
{
    // cannot walk while locked
    if(m_walkLockExpiration != 0 && g_clock.millis() < m_walkLockExpiration)
        return false;

    // paralyzed
    if(m_speed == 0)
        return false;

    // last walk is not done yet
    if((m_walkTimer.ticksElapsed() < getStepDuration()) && !isAutoWalking())
        return false;

    // prewalk has a timeout, because for some reason that I don't know yet the server sometimes doesn't answer the prewalk
    bool prewalkTimeouted = m_walking && m_preWalking && m_walkTimer.ticksElapsed() >= getStepDuration();

    // avoid doing more walks than wanted when receiving a lot of walks from server
    if(!m_lastPrewalkDone && m_preWalking && !prewalkTimeouted)
        return false;

    // cannot walk while already walking
    if((m_walking && !isAutoWalking()) && (!prewalkTimeouted || m_secondPreWalk))
        return true;

    return true;
}

And change:

C++:
void LocalPlayer::cancelWalk(Otc::Direction direction)
{
    // only cancel client side walks
    if(m_walking && m_preWalking)
        stopWalk();

    m_lastPrewalkDone = true;
    m_idleTimer.restart();
    lockWalk();

    if(m_autoWalkDestination.isValid()) {
        g_game.stop();
        auto self = asLocalPlayer();
        if(m_autoWalkContinueEvent)
            m_autoWalkContinueEvent->cancel();
        m_autoWalkContinueEvent = g_dispatcher.scheduleEvent([self]() {
            if(self->m_autoWalkDestination.isValid())
                self->autoWalk(self->m_autoWalkDestination);
        }, 500);
    }

    // turn to the cancel direction
    if(direction != Otc::InvalidDirection)
        setDirection(direction);

    callLuaField("onCancelWalk", direction);
}

To

C++:
void LocalPlayer::cancelWalk(Otc::Direction direction)
{
    // only cancel client side walks
    if(m_walking && m_preWalking)


    m_lastPrewalkDone = true;
    m_idleTimer.restart();
    lockWalk();

    if(m_autoWalkDestination.isValid()) {
        g_game.stop();
        auto self = asLocalPlayer();
        if(m_autoWalkContinueEvent)
            m_autoWalkContinueEvent->cancel();
        m_autoWalkContinueEvent = g_dispatcher.scheduleEvent([self]() {
            if(self->m_autoWalkDestination.isValid())
                self->autoWalk(self->m_autoWalkDestination);
        }, 500);
    }

    // turn to the cancel direction
    if(direction != Otc::InvalidDirection)
        setDirection(direction);

    callLuaField("onCancelWalk", direction);
}

4.
I change in config.lua maxPacketsPerSecond to 50, but on 25 its look i think the same, just to test it. I increase it just "for sure" xD maxPacketsPerSecond = 50

5.
And this best work on Enabled Vertical Synchronization this will set automic 60 FPS

6.
Check Full Video how its work in mine client, i test in this video 3 characters with different movement speed.
7.
As i said its not PRO FIX, and may cause some problems, but i dont see anything yet :p
Best thing its work with Enabled Vertical Synchronization at 60 FPS so, the usage CPU by OTC highly drop from 15% to 4% on my PC.
I will give this a try
 
Back
Top