From 57785d20012490eef9a9bfd20bee266b486d76f3 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Thu, 2 Aug 2012 04:58:49 -0300 Subject: [PATCH] More walk changes and creature events Improve walking, no more random cancelWalks Add 3 new creatures events onAppear/onDisappear/onWalk Add algorithm that calculates walk ping Fix paralyze animation while walking --- src/otclient/creature.cpp | 120 +++++++++++++++++++++-------- src/otclient/creature.h | 16 ++-- src/otclient/game.cpp | 28 ++----- src/otclient/game.h | 2 - src/otclient/localplayer.cpp | 72 ++++++++++++----- src/otclient/localplayer.h | 12 ++- src/otclient/map.cpp | 64 ++++++--------- src/otclient/protocolgameparse.cpp | 4 - src/otclient/thing.cpp | 3 + src/otclient/thing.h | 4 +- src/otclient/tile.cpp | 70 +++++++++-------- 11 files changed, 226 insertions(+), 169 deletions(-) diff --git a/src/otclient/creature.cpp b/src/otclient/creature.cpp index e24d53eb..48bcccec 100644 --- a/src/otclient/creature.cpp +++ b/src/otclient/creature.cpp @@ -28,6 +28,7 @@ #include "item.h" #include "game.h" #include "effect.h" +#include "luavaluecasts.h" #include #include @@ -46,12 +47,12 @@ Creature::Creature() : Thing() m_speed = 200; m_direction = Otc::South; m_walkAnimationPhase = 0; - m_walkInterval = 0; - m_walkAnimationInterval = 0; + m_walkedPixels = 0; m_walkTurnDirection = Otc::InvalidDirection; m_skull = Otc::SkullNone; m_shield = Otc::ShieldNone; m_emblem = Otc::EmblemNone; + m_lastStepDirection = Otc::InvalidDirection; m_nameCache.setFont(g_fonts.getFont("verdana-11px-rounded")); m_nameCache.setAlign(Fw::AlignTopCenter); m_footStep = 0; @@ -255,34 +256,17 @@ void Creature::walk(const Position& oldPos, const Position& newPos) return; // get walk direction - Otc::Direction direction = oldPos.getDirectionFromPosition(newPos); + m_lastStepDirection = oldPos.getDirectionFromPosition(newPos); // set current walking direction - setDirection(direction); + setDirection(m_lastStepDirection); // starts counting walk m_walking = true; m_walkTimer.restart(); + m_walkedPixels = 0; - // calculates walk interval - int groundSpeed = 0; - TilePtr tile = g_map.getTile(newPos); - if(tile) - groundSpeed = tile->getGroundSpeed(); - - float interval = 1000; - if(groundSpeed > 0 && m_speed > 0) - interval = (1000.0f * groundSpeed) / m_speed; - interval = std::floor(interval / g_game.getServerBeat()) * g_game.getServerBeat(); - - m_walkAnimationInterval = interval; - m_walkInterval = interval; - - // diagonal walking lasts 3 times more. - if(direction == Otc::NorthWest || direction == Otc::NorthEast || direction == Otc::SouthWest || direction == Otc::SouthEast) - m_walkInterval *= 3; - - // no direction needs to be changed when the walk ends + // no direction need to be changed when the walk ends m_walkTurnDirection = Otc::InvalidDirection; // starts updating walk @@ -302,9 +286,50 @@ void Creature::stopWalk() terminateWalk(); } -void Creature::onMove(const Position& newPos, const Position& oldPos) +void Creature::onAppear() { - walk(oldPos, newPos); + // cancel any disappear event + if(m_disappearEvent) { + m_disappearEvent->cancel(); + m_disappearEvent = nullptr; + } + + // creature appeared the first time or wasn't seen for a long time + if(m_removed) { + m_removed = false; + callLuaField("onAppear"); + // walk + } else if(m_oldPosition != m_position && m_oldPosition.isInRange(m_position,1,1)) { + walk(m_oldPosition, m_position); + callLuaField("onWalk", m_oldPosition, m_position); + // teleport + } else if(m_oldPosition != m_position) { + callLuaField("onDisappear"); + callLuaField("onAppear"); + } // else turn +} + +void Creature::onDisappear() +{ + if(m_disappearEvent) + m_disappearEvent->cancel(); + + m_oldPosition = m_position; + + // a pair onDisappear and onAppear events are fired even when creatures walks or turns, + // so we must filter + auto self = static_self_cast(); + m_disappearEvent = g_dispatcher.addEvent([self] { + self->m_removed = true; + self->stopWalk(); + + self->callLuaField("onDisappear"); + + // invalidate this creature position + self->m_position = Position(); + self->m_oldPosition = Position(); + self->m_disappearEvent = nullptr; + }); } void Creature::updateWalkAnimation(int totalPixelsWalked) @@ -316,7 +341,7 @@ void Creature::updateWalkAnimation(int totalPixelsWalked) int footAnimPhases = getAnimationPhases() - 1; if(totalPixelsWalked == 32 || footAnimPhases == 0) m_walkAnimationPhase = 0; - else if(m_footStepDrawn && m_footTimer.ticksElapsed() >= m_walkAnimationInterval / 4 ) { + else if(m_footStepDrawn && m_footTimer.ticksElapsed() >= getStepDuration() / 4 ) { m_footStep++; m_walkAnimationPhase = 1 + (m_footStep % footAnimPhases); m_footStepDrawn = false; @@ -380,22 +405,26 @@ void Creature::nextWalkUpdate() m_walkUpdateEvent = g_dispatcher.scheduleEvent([self] { self->m_walkUpdateEvent = nullptr; self->nextWalkUpdate(); - }, m_walkAnimationInterval / 32); + }, getStepDuration() / 32); } } void Creature::updateWalk() { - float walkTicksPerPixel = m_walkAnimationInterval / 32; + int stepDuration = getStepDuration(); + float walkTicksPerPixel = stepDuration / 32; int totalPixelsWalked = std::min(m_walkTimer.ticksElapsed() / walkTicksPerPixel, 32.0f); + // needed for paralyze effect + m_walkedPixels = std::max(m_walkedPixels, totalPixelsWalked); + // update walk animation and offsets updateWalkAnimation(totalPixelsWalked); - updateWalkOffset(totalPixelsWalked); + updateWalkOffset(m_walkedPixels); updateWalkingTile(); // terminate walk - if(m_walking && m_walkTimer.ticksElapsed() >= m_walkInterval) + if(m_walking && m_walkTimer.ticksElapsed() >= stepDuration) terminateWalk(); } @@ -419,6 +448,7 @@ void Creature::terminateWalk() } m_walking = false; + m_walkedPixels = 0; } void Creature::setName(const std::string& name) @@ -472,6 +502,15 @@ void Creature::setOutfit(const Outfit& outfit) m_outfit = outfit; } +void Creature::setSpeed(uint16 speed) +{ + m_speed = speed; + + // speed can change while walking (utani hur, paralyze, etc..) + if(m_walking) + nextWalkUpdate(); +} + void Creature::setSkull(uint8 skull) { m_skull = skull; @@ -556,6 +595,27 @@ Point Creature::getDrawOffset() return drawOffset; } +int Creature::getStepDuration() +{ + int groundSpeed = 0; + const TilePtr& tile = getTile(); + if(tile) + groundSpeed = tile->getGroundSpeed(); + + int interval = 1000; + if(groundSpeed > 0 && m_speed > 0) + interval = (1000 * groundSpeed) / m_speed; + + if(g_game.getClientVersion() >= 900) + interval = (interval / g_game.getServerBeat()) * g_game.getServerBeat(); + + if(m_lastStepDirection == Otc::NorthWest || m_lastStepDirection == Otc::NorthEast || + m_lastStepDirection == Otc::SouthWest || m_lastStepDirection == Otc::SouthEast) + interval *= 3; + + return interval; +} + const ThingTypePtr& Creature::getThingType() { return g_things.getThingType(m_outfit.getId(), m_outfit.getCategory()); diff --git a/src/otclient/creature.h b/src/otclient/creature.h index 9003ed31..2c7a2544 100644 --- a/src/otclient/creature.h +++ b/src/otclient/creature.h @@ -55,7 +55,7 @@ public: void setDirection(Otc::Direction direction); void setOutfit(const Outfit& outfit); void setLight(const Light& light) { m_light = light; } - void setSpeed(uint16 speed) { m_speed = speed; } + void setSpeed(uint16 speed); void setSkull(uint8 skull); void setShield(uint8 shield); void setEmblem(uint8 emblem); @@ -63,7 +63,6 @@ public: void setShieldTexture(const std::string& filename, bool blink); void setEmblemTexture(const std::string& filename); void setPassable(bool passable) { m_passable = passable; } - void setRemoved(bool removed) { m_removed = removed; } void addTimedSquare(uint8 color); void removeTimedSquare() { m_showTimedSquare = false; } @@ -83,6 +82,7 @@ public: uint8 getEmblem() { return m_emblem; } bool isPassable() { return m_passable; } Point getDrawOffset(); + int getStepDuration(); Point getWalkOffset() { return m_walkOffset; } void updateShield(); @@ -100,8 +100,8 @@ public: const ThingTypePtr& getThingType(); ThingType *rawGetThingType(); -protected: - virtual void onMove(const Position& newPos, const Position& oldPos); + virtual void onAppear(); + virtual void onDisappear(); protected: virtual void updateWalkAnimation(int totalPixelsWalked); @@ -131,23 +131,25 @@ protected: Color m_staticSquareColor; stdext::boolean m_showTimedSquare; stdext::boolean m_showStaticSquare; - stdext::boolean m_removed; + stdext::boolean m_removed; CachedText m_nameCache; Color m_informationColor; // walk related int m_walkAnimationPhase; + int m_walkedPixels; uint m_footStep; Timer m_walkTimer; Timer m_footTimer; TilePtr m_walkingTile; - int m_walkInterval; - int m_walkAnimationInterval; stdext::boolean m_walking; stdext::boolean m_footStepDrawn; ScheduledEventPtr m_walkUpdateEvent; + EventPtr m_disappearEvent; Point m_walkOffset; Otc::Direction m_walkTurnDirection; + Otc::Direction m_lastStepDirection; + Position m_oldPosition; }; // @bindclass diff --git a/src/otclient/game.cpp b/src/otclient/game.cpp index ee5e3343..3de3df9c 100644 --- a/src/otclient/game.cpp +++ b/src/otclient/game.cpp @@ -247,26 +247,6 @@ void Game::processInventoryChange(int slot, const ItemPtr& item) m_localPlayer->setInventoryItem((Otc::InventorySlot)slot, item); } -void Game::processCreatureMove(const CreaturePtr& creature, const Position& oldPos, const Position& newPos) -{ - // animate walk - creature->walk(oldPos, newPos); - - g_lua.callGlobalField("g_game", "onCreatureMove", creature, oldPos, newPos); -} - -void Game::processCreatureTeleport(const CreaturePtr& creature) -{ - // stop walking on creature teleports - creature->stopWalk(); - - // locks the walk for a while when teleporting - if(creature == m_localPlayer) - m_localPlayer->lockWalk(); - - g_lua.callGlobalField("g_game", "onCreatureTeleport", creature); -} - void Game::processChannelList(const std::vector >& channelList) { g_lua.callGlobalField("g_game", "onChannelList", channelList); @@ -552,9 +532,11 @@ void Game::autoWalk(const std::vector& dirs) cancelFollow(); Otc::Direction direction = dirs.front(); - TilePtr toTile = g_map.getTile(m_localPlayer->getPosition().translatedToDirection(direction)); - if(toTile && toTile->isWalkable() && !m_localPlayer->isAutoWalking()) - m_localPlayer->preWalk(direction); + if(m_localPlayer->canWalk(direction)) { + TilePtr toTile = g_map.getTile(m_localPlayer->getPosition().translatedToDirection(direction)); + if(toTile && toTile->isWalkable() && !m_localPlayer->isAutoWalking()) + m_localPlayer->preWalk(direction); + } m_protocolGame->sendAutoWalk(dirs); diff --git a/src/otclient/game.h b/src/otclient/game.h index 5268ea1d..70861a67 100644 --- a/src/otclient/game.h +++ b/src/otclient/game.h @@ -65,8 +65,6 @@ protected: void processGMActions(const std::vector& actions); void processInventoryChange(int slot, const ItemPtr& item); - void processCreatureMove(const CreaturePtr& creature, const Position& oldPos, const Position& newPos); - void processCreatureTeleport(const CreaturePtr& creature); void processAttackCancel(uint seq); void processWalkCancel(Otc::Direction direction); diff --git a/src/otclient/localplayer.cpp b/src/otclient/localplayer.cpp index d70ac00c..b233d6cb 100644 --- a/src/otclient/localplayer.cpp +++ b/src/otclient/localplayer.cpp @@ -29,7 +29,6 @@ LocalPlayer::LocalPlayer() { m_preWalking = false; - m_walkLocked = false; m_lastPrewalkDone = true; m_autoWalking = false; m_known = false; @@ -37,7 +36,7 @@ LocalPlayer::LocalPlayer() m_states = 0; m_vocation = 0; - m_walkLockInterval = 0; + m_walkLockExpiration = 0; m_skillsLevel.fill(-1); m_skillsLevelPercent.fill(-1); @@ -58,33 +57,29 @@ LocalPlayer::LocalPlayer() void LocalPlayer::lockWalk(int millis) { - // prevents double locks - if(m_walkLocked) - return; - - m_walkLocked = true; - m_walkLockTimer.restart(); - m_walkLockInterval = millis; + m_walkLockExpiration = std::max(m_walkLockExpiration, (ticks_t) g_clock.millis() + millis); } bool LocalPlayer::canWalk(Otc::Direction direction) { - // 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() >= m_walkInterval + PREWALK_TIMEOUT; + // cannot walk while locked + if(m_walkLockExpiration != 0 && g_clock.millis() < m_walkLockExpiration) + return false; - // cannot walk while already walking - if(m_walking && !prewalkTimeouted) + // last walk is not done yet + if(m_walkTimer.ticksElapsed() < getStepDuration()) 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() + PREWALK_TIMEOUT; + // 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 locked - if(m_walkLocked && m_walkLockTimer.ticksElapsed() <= m_walkLockInterval) + // cannot walk while already walking + if(m_walking && !prewalkTimeouted) return false; - else - m_walkLocked = false; return true; } @@ -93,6 +88,16 @@ void LocalPlayer::walk(const Position& oldPos, const Position& newPos) { // a prewalk was going on if(m_preWalking) { + if(m_waitingWalkPong) { + if(newPos == m_lastPrewalkDestionation) { + m_lastWalkPings.push_back(m_walkPingTimer.ticksElapsed()); + if(m_lastWalkPings.size() > 10) + m_lastWalkPings.pop_front(); + } + + m_waitingWalkPong = false; + } + // switch to normal walking m_preWalking = false; m_lastPrewalkDone = true; @@ -115,13 +120,18 @@ void LocalPlayer::walk(const Position& oldPos, const Position& newPos) void LocalPlayer::preWalk(Otc::Direction direction) { - // start walking to direction Position newPos = m_position.translatedToDirection(direction); + + // avoid reanimating prewalks + if(m_preWalking && m_lastPrewalkDestionation == newPos) + return; + m_preWalking = true; if(m_autoWalkEndEvent) m_autoWalkEndEvent->cancel(); + // start walking to direction m_lastPrewalkDone = false; m_lastPrewalkDestionation = newPos; Creature::walk(m_position, newPos); @@ -134,6 +144,7 @@ void LocalPlayer::cancelWalk(Otc::Direction direction) stopWalk(); m_lastPrewalkDone = true; + m_waitingWalkPong = false; // turn to the cancel direction if(direction != Otc::InvalidDirection) @@ -167,7 +178,8 @@ void LocalPlayer::updateWalkOffset(int totalPixelsWalked) void LocalPlayer::updateWalk() { - float walkTicksPerPixel = m_walkAnimationInterval / 32.0f; + int stepDuration = getStepDuration(); + float walkTicksPerPixel = stepDuration / 32.0f; int totalPixelsWalked = std::min(m_walkTimer.ticksElapsed() / walkTicksPerPixel, 32.0f); // update walk animation and offsets @@ -176,7 +188,7 @@ void LocalPlayer::updateWalk() updateWalkingTile(); // terminate walk only when client and server side walk are complated - if(m_walking && !m_preWalking && m_walkTimer.ticksElapsed() >= m_walkInterval) + if(m_walking && !m_preWalking && m_walkTimer.ticksElapsed() >= stepDuration) terminateWalk(); } @@ -196,6 +208,15 @@ void LocalPlayer::terminateWalk() } } +void LocalPlayer::onAppear() +{ + Creature::onAppear(); + + // on teleports lock the walk + if(!m_oldPosition.isInRange(m_position,1,1)) + lockWalk(); +} + void LocalPlayer::setStates(int states) { if(m_states != states) { @@ -351,3 +372,14 @@ void LocalPlayer::setPremium(bool premium) callLuaField("onPremiumChange", premium); } } + +double LocalPlayer::getWalkPing() +{ + if(m_lastWalkPings.empty()) + return 9999; + + double sum = 0; + for(int p : m_lastWalkPings) + sum += p; + return sum / (double)m_lastWalkPings.size(); +} diff --git a/src/otclient/localplayer.h b/src/otclient/localplayer.h index cb00aa7a..bfba1f1c 100644 --- a/src/otclient/localplayer.h +++ b/src/otclient/localplayer.h @@ -35,7 +35,7 @@ class LocalPlayer : public Player public: LocalPlayer(); - void unlockWalk() { m_walkLocked = false; } + void unlockWalk() { m_walkLockExpiration = 0; } void lockWalk(int millis = 250); bool canWalk(Otc::Direction direction); @@ -58,6 +58,7 @@ public: int getSkillLevel(Otc::Skill skill) { return m_skillsLevel[skill]; } int getSkillLevelPercent(Otc::Skill skill) { return m_skillsLevelPercent[skill]; } int getVocation() { return m_vocation; } + double getWalkPing(); double getHealth() { return m_health; } double getMaxHealth() { return m_maxHealth; } double getFreeCapacity() { return m_freeCapacity; } @@ -80,6 +81,8 @@ public: LocalPlayerPtr asLocalPlayer() { return static_self_cast(); } bool isLocalPlayer() { return true; } + virtual void onAppear(); + protected: void walk(const Position& oldPos, const Position& newPos); void preWalk(Otc::Direction direction); @@ -97,13 +100,14 @@ private: // walk related bool m_preWalking; bool m_lastPrewalkDone; - bool m_walkLocked; bool m_autoWalking; bool m_premium; Position m_lastPrewalkDestionation; - Timer m_walkLockTimer; ItemPtr m_inventoryItems[Otc::LastInventorySlot]; ScheduledEventPtr m_autoWalkEndEvent; + stdext::boolean m_waitingWalkPong; + Timer m_walkPingTimer; + std::deque m_lastWalkPings; std::array m_skillsLevel; std::array m_skillsLevelPercent; @@ -111,7 +115,7 @@ private: bool m_known; int m_states; int m_vocation; - int m_walkLockInterval; + ticks_t m_walkLockExpiration; double m_health; double m_maxHealth; diff --git a/src/otclient/map.cpp b/src/otclient/map.cpp index 47abee1b..28764f87 100644 --- a/src/otclient/map.cpp +++ b/src/otclient/map.cpp @@ -78,7 +78,6 @@ void Map::cleanDynamicThings() for(const auto& pair : m_knownCreatures) { const CreaturePtr& creature = pair.second; removeThing(creature); - creature->setRemoved(true); } m_knownCreatures.clear(); @@ -99,50 +98,35 @@ void Map::addThing(const ThingPtr& thing, const Position& pos, int stackPos) if(!thing) return; - TilePtr tile = getOrCreateTile(pos); - - Position oldPos = thing->getPosition(); - if(thing->isItem() || thing->isCreature() || thing->isEffect()) { + const TilePtr& tile = getOrCreateTile(pos); tile->addThing(thing, stackPos); - } else if(thing->isMissile()) { - m_floorMissiles[pos.z].push_back(thing->static_self_cast()); - } else if(thing->isAnimatedText()) { - m_animatedTexts.push_back(thing->static_self_cast()); - } else if(thing->isStaticText()) { - StaticTextPtr staticText = thing->static_self_cast(); - bool mustAdd = true; - for(auto it = m_staticTexts.begin(), end = m_staticTexts.end(); it != end; ++it) { - StaticTextPtr cStaticText = *it; - if(cStaticText->getPosition() == pos) { + } else { + if(thing->isMissile()) { + m_floorMissiles[pos.z].push_back(thing->static_self_cast()); + thing->onAppear(); + } else if(thing->isAnimatedText()) { + AnimatedTextPtr animatedText = thing->static_self_cast(); + m_animatedTexts.push_back(animatedText); + } else if(thing->isStaticText()) { + StaticTextPtr staticText = thing->static_self_cast(); + bool mustAdd = true; + for(auto other : m_staticTexts) { // try to combine messages - if(cStaticText->addMessage(staticText->getName(), staticText->getMessageMode(), staticText->getFirstMessage())) { + if(other->getPosition() == pos && other->addMessage(staticText->getName(), staticText->getMessageMode(), staticText->getFirstMessage())) { mustAdd = false; break; - } else { - // must add another message and rearrenge current } } + if(mustAdd) { + m_staticTexts.push_back(staticText); + staticText->onAppear(); + } } - if(mustAdd) - m_staticTexts.push_back(staticText); - } - - if(!thing->isCreature()) + thing->setPosition(pos); thing->onAppear(); - - thing->setPosition(pos); - - if(thing->isCreature()) { - CreaturePtr creature = thing->static_self_cast(); - if(oldPos != pos) { - if(oldPos.isInRange(pos,1,1)) - g_game.processCreatureMove(creature, oldPos, pos); - else - g_game.processCreatureTeleport(creature); - } } notificateTileUpdateToMapViews(pos); @@ -289,9 +273,7 @@ void Map::removeCreatureById(uint32 id) auto it = m_knownCreatures.find(id); if(it != m_knownCreatures.end()) - it->second->setRemoved(true); - - m_knownCreatures.erase(it); + m_knownCreatures.erase(it); } void Map::setCentralPosition(const Position& centralPosition) @@ -318,12 +300,10 @@ void Map::setCentralPosition(const Position& centralPosition) Position oldPos = localPlayer->getPosition(); Position pos = m_centralPosition; - localPlayer->setPosition(pos); if(oldPos != pos) { - if(oldPos.isInRange(pos,1,1)) - g_game.processCreatureMove(localPlayer, oldPos, pos); - else - g_game.processCreatureTeleport(localPlayer); + localPlayer->onDisappear(); + localPlayer->setPosition(pos); + localPlayer->onAppear(); } }); diff --git a/src/otclient/protocolgameparse.cpp b/src/otclient/protocolgameparse.cpp index b69517f0..c3b88a42 100644 --- a/src/otclient/protocolgameparse.cpp +++ b/src/otclient/protocolgameparse.cpp @@ -506,10 +506,6 @@ void ProtocolGame::parseCreatureMove(const InputMessagePtr& msg) g_map.removeThing(thing); g_map.addThing(thing, newPos, stackPos); - - //CreaturePtr creature = thing->static_self_cast(); - //Position oldPos = thing->getPosition(); - //creature->onMove(newPos, oldPos); } void ProtocolGame::parseOpenContainer(const InputMessagePtr& msg) diff --git a/src/otclient/thing.cpp b/src/otclient/thing.cpp index 8cf233bb..31c4e22e 100644 --- a/src/otclient/thing.cpp +++ b/src/otclient/thing.cpp @@ -35,6 +35,9 @@ Thing::Thing() : void Thing::setPosition(const Position& position) { + if(m_position == position) + return; + Position oldPos = m_position; m_position = position; onPositionChange(position, oldPos); diff --git a/src/otclient/thing.h b/src/otclient/thing.h index 2373e547..ac4f8c93 100644 --- a/src/otclient/thing.h +++ b/src/otclient/thing.h @@ -118,13 +118,11 @@ public: bool isMarketable() { return rawGetThingType()->isMarketable(); } MarketData getMarketData() { return rawGetThingType()->getMarketData(); } -protected: virtual void onPositionChange(const Position& newPos, const Position& oldPos) { } virtual void onAppear() { } virtual void onDisappear() { } - friend class Map; - +protected: Position m_position; uint16 m_datId; }; diff --git a/src/otclient/tile.cpp b/src/otclient/tile.cpp index 9ee35983..556b9a8d 100644 --- a/src/otclient/tile.cpp +++ b/src/otclient/tile.cpp @@ -101,8 +101,6 @@ void Tile::draw(const Point& dest, float scaleFactor, int drawFlags) if(drawFlags & Otc::DrawCreatures) { if(animate) { for(const CreaturePtr& creature : m_walkingCreatures) { - if(creature->isRemoved()) - continue; creature->draw(Point(dest.x + ((creature->getPosition().x - m_position.x)*Otc::TILE_PIXELS - m_drawElevation)*scaleFactor, dest.y + ((creature->getPosition().y - m_position.y)*Otc::TILE_PIXELS - m_drawElevation)*scaleFactor), scaleFactor, animate); @@ -159,42 +157,44 @@ void Tile::addThing(const ThingPtr& thing, int stackPos) if(thing->isEffect()) { m_effects.push_back(thing->static_self_cast()); - return; - } - - // the items stackpos follows this order: - // 0 - ground - // 1 - ground borders - // 2 - bottom (walls) - // 3 - on top (doors) - // 4 - creatures, from top to bottom - // 5 - items, from top to bottom - if(stackPos < 0 || stackPos == 255) { - int priority = thing->getStackPriority(); - bool prepend = (stackPos == -2 || priority <= 3); - for(stackPos = 0; stackPos < (int)m_things.size(); ++stackPos) { - int otherPriority = m_things[stackPos]->getStackPriority(); - if((prepend && otherPriority > priority) || (!prepend && otherPriority >= priority)) - break; - } - } else if(stackPos > (int)m_things.size()) - stackPos = m_things.size(); + } else { + // the items stackpos follows this order: + // 0 - ground + // 1 - ground borders + // 2 - bottom (walls) + // 3 - on top (doors) + // 4 - creatures, from top to bottom + // 5 - items, from top to bottom + if(stackPos < 0 || stackPos == 255) { + int priority = thing->getStackPriority(); + bool prepend = (stackPos == -2 || priority <= 3); + for(stackPos = 0; stackPos < (int)m_things.size(); ++stackPos) { + int otherPriority = m_things[stackPos]->getStackPriority(); + if((prepend && otherPriority > priority) || (!prepend && otherPriority >= priority)) + break; + } + } else if(stackPos > (int)m_things.size()) + stackPos = m_things.size(); - m_things.insert(m_things.begin() + stackPos, thing); + m_things.insert(m_things.begin() + stackPos, thing); - if(m_things.size() > MAX_THINGS) - removeThing(m_things[MAX_THINGS]); + if(m_things.size() > MAX_THINGS) + removeThing(m_things[MAX_THINGS]); - /* - // check stack priorities - // this code exists to find stackpos bugs faster - int lastPriority = 0; - for(const ThingPtr& thing : m_things) { - int priority = thing->getStackPriority(); - assert(lastPriority <= priority); - lastPriority = priority; + /* + // check stack priorities + // this code exists to find stackpos bugs faster + int lastPriority = 0; + for(const ThingPtr& thing : m_things) { + int priority = thing->getStackPriority(); + assert(lastPriority <= priority); + lastPriority = priority; + } + */ } - */ + + thing->setPosition(m_position); + thing->onAppear(); } bool Tile::removeThing(ThingPtr thing) @@ -219,6 +219,8 @@ bool Tile::removeThing(ThingPtr thing) } } + thing->onDisappear(); + return removed; }