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
This commit is contained in:
parent
76d32b5493
commit
57785d2001
|
@ -28,6 +28,7 @@
|
|||
#include "item.h"
|
||||
#include "game.h"
|
||||
#include "effect.h"
|
||||
#include "luavaluecasts.h"
|
||||
|
||||
#include <framework/graphics/graphics.h>
|
||||
#include <framework/core/eventdispatcher.h>
|
||||
|
@ -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<Creature>();
|
||||
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());
|
||||
|
|
|
@ -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<false> m_showTimedSquare;
|
||||
stdext::boolean<false> m_showStaticSquare;
|
||||
stdext::boolean<false> m_removed;
|
||||
stdext::boolean<true> 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<false> m_walking;
|
||||
stdext::boolean<false> m_footStepDrawn;
|
||||
ScheduledEventPtr m_walkUpdateEvent;
|
||||
EventPtr m_disappearEvent;
|
||||
Point m_walkOffset;
|
||||
Otc::Direction m_walkTurnDirection;
|
||||
Otc::Direction m_lastStepDirection;
|
||||
Position m_oldPosition;
|
||||
};
|
||||
|
||||
// @bindclass
|
||||
|
|
|
@ -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<std::tuple<int, std::string> >& channelList)
|
||||
{
|
||||
g_lua.callGlobalField("g_game", "onChannelList", channelList);
|
||||
|
@ -552,9 +532,11 @@ void Game::autoWalk(const std::vector<Otc::Direction>& 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);
|
||||
|
||||
|
|
|
@ -65,8 +65,6 @@ protected:
|
|||
|
||||
void processGMActions(const std::vector<uint8>& 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);
|
||||
|
||||
|
|
|
@ -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 already walking
|
||||
if(m_walking && !prewalkTimeouted)
|
||||
// cannot walk while locked
|
||||
if(m_walkLockExpiration != 0 && g_clock.millis() < m_walkLockExpiration)
|
||||
return false;
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
|
|
@ -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<LocalPlayer>(); }
|
||||
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<false> m_waitingWalkPong;
|
||||
Timer m_walkPingTimer;
|
||||
std::deque<int> m_lastWalkPings;
|
||||
|
||||
std::array<int, Otc::LastSkill> m_skillsLevel;
|
||||
std::array<int, Otc::LastSkill> 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;
|
||||
|
|
|
@ -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<Missile>());
|
||||
} else if(thing->isAnimatedText()) {
|
||||
m_animatedTexts.push_back(thing->static_self_cast<AnimatedText>());
|
||||
} else if(thing->isStaticText()) {
|
||||
StaticTextPtr staticText = thing->static_self_cast<StaticText>();
|
||||
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<Missile>());
|
||||
thing->onAppear();
|
||||
} else if(thing->isAnimatedText()) {
|
||||
AnimatedTextPtr animatedText = thing->static_self_cast<AnimatedText>();
|
||||
m_animatedTexts.push_back(animatedText);
|
||||
} else if(thing->isStaticText()) {
|
||||
StaticTextPtr staticText = thing->static_self_cast<StaticText>();
|
||||
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<Creature>();
|
||||
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();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -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<Creature>();
|
||||
//Position oldPos = thing->getPosition();
|
||||
//creature->onMove(newPos, oldPos);
|
||||
}
|
||||
|
||||
void ProtocolGame::parseOpenContainer(const InputMessagePtr& msg)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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<Effect>());
|
||||
return;
|
||||
}
|
||||
} 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();
|
||||
|
||||
// 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;
|
||||
m_things.insert(m_things.begin() + stackPos, thing);
|
||||
|
||||
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;
|
||||
}
|
||||
} else if(stackPos > (int)m_things.size())
|
||||
stackPos = m_things.size();
|
||||
|
||||
m_things.insert(m_things.begin() + stackPos, thing);
|
||||
|
||||
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;
|
||||
*/
|
||||
}
|
||||
*/
|
||||
|
||||
thing->setPosition(m_position);
|
||||
thing->onAppear();
|
||||
}
|
||||
|
||||
bool Tile::removeThing(ThingPtr thing)
|
||||
|
@ -219,6 +219,8 @@ bool Tile::removeThing(ThingPtr thing)
|
|||
}
|
||||
}
|
||||
|
||||
thing->onDisappear();
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue