diff --git a/src/otclient/core/creature.cpp b/src/otclient/core/creature.cpp index 1b566e77..2c3bcec1 100644 --- a/src/otclient/core/creature.cpp +++ b/src/otclient/core/creature.cpp @@ -94,29 +94,44 @@ void Creature::draw(int x, int y) int pixelsWalked = std::floor((g_platform.getTicks() - m_lastTicks) / m_walkTimePerPixel); int remainingTime = (g_platform.getTicks() - m_lastTicks) % (int)m_walkTimePerPixel; - if(m_direction == Otc::North || m_direction == Otc::NorthEast || m_direction == Otc::NorthWest) - m_walkOffsetY = std::max(m_walkOffsetY - pixelsWalked, 0); - else if(m_direction == Otc::South || m_direction == Otc::SouthEast || m_direction == Otc::SouthWest) - m_walkOffsetY = std::min(m_walkOffsetY + pixelsWalked, 0); - - if(m_direction == Otc::East || m_direction == Otc::NorthEast || m_direction == Otc::SouthEast) - m_walkOffsetX = std::min(m_walkOffsetX + pixelsWalked, 0); - else if(m_direction == Otc::West || m_direction == Otc::NorthWest || m_direction == Otc::SouthWest) - m_walkOffsetX = std::max(m_walkOffsetX - pixelsWalked, 0); + if(m_inverseWalking) { + if(m_direction == Otc::North || m_direction == Otc::NorthEast || m_direction == Otc::NorthWest) + m_walkOffsetY = std::max(m_walkOffsetY - pixelsWalked, 0); + else if(m_direction == Otc::South || m_direction == Otc::SouthEast || m_direction == Otc::SouthWest) + m_walkOffsetY = std::min(m_walkOffsetY + pixelsWalked, 0); + + if(m_direction == Otc::East || m_direction == Otc::NorthEast || m_direction == Otc::SouthEast) + m_walkOffsetX = std::min(m_walkOffsetX + pixelsWalked, 0); + else if(m_direction == Otc::West || m_direction == Otc::NorthWest || m_direction == Otc::SouthWest) + m_walkOffsetX = std::max(m_walkOffsetX - pixelsWalked, 0); + + if(m_walkOffsetX == 0 && m_walkOffsetY == 0) + cancelWalk(m_direction); + } + else { + if(m_direction == Otc::North || m_direction == Otc::NorthEast || m_direction == Otc::NorthWest) + m_walkOffsetY = std::max(m_walkOffsetY - pixelsWalked, -32); + else if(m_direction == Otc::South || m_direction == Otc::SouthEast || m_direction == Otc::SouthWest) + m_walkOffsetY = std::min(m_walkOffsetY + pixelsWalked, 32); + + if(m_direction == Otc::East || m_direction == Otc::NorthEast || m_direction == Otc::SouthEast) + m_walkOffsetX = std::min(m_walkOffsetX + pixelsWalked, 32); + else if(m_direction == Otc::West || m_direction == Otc::NorthWest || m_direction == Otc::SouthWest) + m_walkOffsetX = std::max(m_walkOffsetX - pixelsWalked, -32); + + if(std::abs(m_walkOffsetX) == 32 && std::abs(m_walkOffsetY) == 32) + m_animation = 0; + } - int walkOffset = std::max(std::abs(m_walkOffsetX), std::abs(m_walkOffsetY)); + int walkOffset = std::max(std::abs(m_walkOffsetX), std::abs(m_walkOffsetY)) + 32; if(walkOffset % (int)std::ceil(32 / (float)type.animationPhases) == 0) { if((m_lastWalkAnim+1) % type.animationPhases == 0) m_lastWalkAnim = 1; else m_lastWalkAnim++; } - m_animation = m_lastWalkAnim; - - if(((m_walkOffsetX == 0 && m_walkOffsetY == 0) && m_walkOffsetX != m_walkOffsetY) || - ((m_walkOffsetX == 0 || m_walkOffsetY == 0) && m_walkOffsetX == m_walkOffsetY)) { - cancelWalk(m_direction); - } + if(m_walking) + m_animation = m_lastWalkAnim; m_lastTicks = g_platform.getTicks() - remainingTime; } @@ -172,12 +187,11 @@ void Creature::drawInformation(int x, int y, bool useGray, const Rect& rect) m_informationFont->renderText(m_name, textRect, Fw::AlignTopCenter, fillColor); } -void Creature::walk(const Position& position) +void Creature::walk(const Position& position, bool inverse) { // set walking state m_walking = true; - m_walkOffsetX = 0; - m_walkOffsetY = 0; + m_inverseWalking = inverse; int walkTimeFactor = 1; // set new direction @@ -226,9 +240,10 @@ void Creature::walk(const Position& position) m_walking = false; } - // update map tiles - g_map.removeThing(asThing()); - g_map.addThing(asThing(), position); + if(!m_inverseWalking) { + m_walkOffsetX = 0; + m_walkOffsetY = 0; + } if(m_walking) { // Calculate xPattern diff --git a/src/otclient/core/creature.h b/src/otclient/core/creature.h index e547a2f1..618df197 100644 --- a/src/otclient/core/creature.h +++ b/src/otclient/core/creature.h @@ -70,8 +70,8 @@ public: void onHealthPercentChange(int); - void walk(const Position& position); - void cancelWalk(Otc::Direction direction); + virtual void walk(const Position& position, bool inverse = true); + virtual void cancelWalk(Otc::Direction direction); int getWalkOffsetX() { return m_walkOffsetX; } int getWalkOffsetY() { return m_walkOffsetY; } @@ -79,7 +79,7 @@ public: CreaturePtr asCreature() { return std::static_pointer_cast(shared_from_this()); } -private: +protected: std::string m_name; uint8 m_healthPercent; Otc::Direction m_direction; @@ -95,7 +95,7 @@ private: Color m_informationColor; int m_lastTicks; - bool m_walking; + bool m_walking, m_inverseWalking; float m_walkTimePerPixel; Position m_walkingFromPosition; int m_lastWalkAnim; diff --git a/src/otclient/core/game.cpp b/src/otclient/core/game.cpp index 0b949fc7..56ff20f6 100644 --- a/src/otclient/core/game.cpp +++ b/src/otclient/core/game.cpp @@ -104,12 +104,10 @@ void Game::processTextMessage(int type, const std::string& message) void Game::walk(Otc::Direction direction) { - if(!m_online) + if(!m_online || !m_localPlayer->canWalk(direction)) return; - // TODO: check if we can walk. - - m_localPlayer->walk(direction); + m_localPlayer->clientWalk(direction); switch(direction) { case Otc::North: diff --git a/src/otclient/core/localplayer.cpp b/src/otclient/core/localplayer.cpp index c249cc5a..f3dd113b 100644 --- a/src/otclient/core/localplayer.cpp +++ b/src/otclient/core/localplayer.cpp @@ -21,10 +21,59 @@ */ #include "localplayer.h" +#include "map.h" +#include "game.h" +#include "tile.h" -void LocalPlayer::walk(Otc::Direction direction) +LocalPlayer::LocalPlayer() { - //Position newPos = m_position + Position::getPositionFromDirection(direction); + m_clientWalking = false; +} + +void LocalPlayer::clientWalk(Otc::Direction direction) +{ + if(!m_walking) { + Position newPos = m_position + Position::getPositionFromDirection(direction); + Creature::walk(newPos, false); + m_clientWalking = true; + } +} + +void LocalPlayer::walk(const Position& position, bool inverse) +{ + if(m_clientWalking) { + Position pos = Position::getPositionFromDirection(m_direction); + int walkOffsetX = m_walkOffsetX - pos.x * 32; + int walkOffsetY = m_walkOffsetY - pos.y * 32; + + Creature::walk(position, inverse); + + m_walkOffsetX = walkOffsetX; + m_walkOffsetY = walkOffsetY; + m_clientWalking = false; + } + else { + m_walkOffsetX = 0; + m_walkOffsetY = 0; + Creature::walk(position, inverse); + } +} + +void LocalPlayer::cancelWalk(Otc::Direction direction) +{ + m_clientWalking = false; + Creature::cancelWalk(direction); +} + +bool LocalPlayer::canWalk(Otc::Direction direction) +{ + Position newPos = m_position + Position::getPositionFromDirection(direction); + TilePtr tile = g_map.getTile(newPos); + if(!tile->isWalkable()) { + // TODO: create enum for 17, white message on screen bottom and console. + g_game.processTextMessage(17, "Sorry, not possible."); + return false; + } - //asCreature()->walk(newPos); + return !m_clientWalking; } diff --git a/src/otclient/core/localplayer.h b/src/otclient/core/localplayer.h index dbece85c..9d4679fb 100644 --- a/src/otclient/core/localplayer.h +++ b/src/otclient/core/localplayer.h @@ -28,7 +28,7 @@ class LocalPlayer : public Player { public: - LocalPlayer() { } + LocalPlayer(); void setDrawSpeed(uint16 drawSpeed) { m_drawSpeed = drawSpeed; } uint16 getDrawSpeed() { return m_drawSpeed; } @@ -42,13 +42,17 @@ public: void setStatistic(Otc::Statistic statistic, double value) { m_statistics[statistic] = value; } double getStatistic(Otc::Statistic statistic) { return m_statistics[statistic]; } - void walk(Otc::Direction direction); + void clientWalk(Otc::Direction direction); + void walk(const Position& position, bool inverse); + void cancelWalk(Otc::Direction direction); + bool canWalk(Otc::Direction direction); LocalPlayerPtr asLocalPlayer() { return std::static_pointer_cast(shared_from_this()); } private: uint16 m_drawSpeed; bool m_canReportBugs; + bool m_clientWalking; int m_skills[Otc::LastSkill][Otc::LastSkillType]; double m_statistics[Otc::LastStatistic]; diff --git a/src/otclient/core/tile.cpp b/src/otclient/core/tile.cpp index 2d3d1eda..9f85c7a0 100644 --- a/src/otclient/core/tile.cpp +++ b/src/otclient/core/tile.cpp @@ -183,6 +183,19 @@ ItemPtr Tile::getGround() return nullptr; } +bool Tile::isWalkable() +{ + if(!getGround()) + return false; + + for(const ThingPtr& thing : m_things) { + const ThingType& type = thing->getType(); + if(type.isNotWalkable) + return false; + } + return true; +} + bool Tile::isFullGround() { ThingPtr ground = getThing(0); diff --git a/src/otclient/core/tile.h b/src/otclient/core/tile.h index 2cc313d7..ba90c663 100644 --- a/src/otclient/core/tile.h +++ b/src/otclient/core/tile.h @@ -48,6 +48,7 @@ public: int getDrawElevation() { return m_drawElevation; } std::vector getCreatures(); ItemPtr getGround(); + bool isWalkable(); bool isFullGround(); bool isFullyOpaque(); bool isLookPossible(); diff --git a/src/otclient/net/protocolgameparse.cpp b/src/otclient/net/protocolgameparse.cpp index 2db4d03a..c3736f5d 100644 --- a/src/otclient/net/protocolgameparse.cpp +++ b/src/otclient/net/protocolgameparse.cpp @@ -406,6 +406,10 @@ void ProtocolGame::parseCreatureMove(InputMessage& msg) CreaturePtr creature = thing->asCreature(); assert(creature); creature->walk(newPos); + + // update map tiles + g_map.removeThing(thing); + g_map.addThing(thing, newPos); } void ProtocolGame::parseOpenContainer(InputMessage& msg)