summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/net/eathena/beinghandler.cpp450
-rw-r--r--src/net/eathena/beinghandler.h6
-rw-r--r--src/net/tmwa/beinghandler.cpp508
-rw-r--r--src/net/tmwa/beinghandler.h6
4 files changed, 964 insertions, 6 deletions
diff --git a/src/net/eathena/beinghandler.cpp b/src/net/eathena/beinghandler.cpp
index 649f2fe54..eb5bf4b41 100644
--- a/src/net/eathena/beinghandler.cpp
+++ b/src/net/eathena/beinghandler.cpp
@@ -194,9 +194,15 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
break;
case SMSG_PLAYER_UPDATE_1:
+ processPlayerUpdate1(msg);
+ break;
+
case SMSG_PLAYER_UPDATE_2:
+ processPlayerUpdate2(msg);
+ break;
+
case SMSG_PLAYER_MOVE:
- processPlayerMoveUpdate(msg);
+ processPlayerMove(msg);
break;
case SMSG_PLAYER_STOP:
@@ -446,7 +452,447 @@ void BeingHandler::processNameResponse2(Net::MessageIn &msg)
}
}
-void BeingHandler::processPlayerMoveUpdate(Net::MessageIn &msg) const
+void BeingHandler::processPlayerUpdate1(Net::MessageIn &msg) const
+{
+ if (!actorManager || !localPlayer)
+ return;
+
+ int msgType;
+ switch (msg.getId())
+ {
+ case SMSG_PLAYER_UPDATE_1:
+ msgType = 1;
+ break;
+ case SMSG_PLAYER_UPDATE_2:
+ msgType = 2;
+ break;
+ case SMSG_PLAYER_MOVE:
+ msgType = 3;
+ break;
+ default:
+ return;
+ }
+
+ // An update about a player, potentially including movement.
+ const int id = msg.readInt32("account id");
+ const int16_t speed = msg.readInt16("speed");
+ const uint16_t stunMode = msg.readInt16("opt1");
+ uint32_t statusEffects = msg.readInt16("opt2");
+ statusEffects |= (static_cast<uint16_t>(msg.readInt16("options"))) << 16U;
+ const int16_t job = msg.readInt16("class");
+ int disguiseId = 0;
+ if (id < 110000000 && job >= 1000)
+ disguiseId = job;
+
+ Being *dstBeing = actorManager->findBeing(id);
+
+ if (!dstBeing)
+ {
+ if (actorManager->isBlocked(id) == true)
+ return;
+
+ dstBeing = createBeing(id, job);
+
+ if (!dstBeing)
+ return;
+ }
+ else if (disguiseId)
+ {
+ actorManager->undelete(dstBeing);
+ if (serverVersion < 1)
+ requestNameById(id);
+ }
+
+ uint8_t dir = dstBeing->getDirectionDelayed();
+ if (dir)
+ {
+ if (dir != dstBeing->getDirection())
+ dstBeing->setDirection(dir);
+ }
+
+ if (Party *const party = localPlayer->getParty())
+ {
+ if (party->isMember(id))
+ dstBeing->setParty(party);
+ }
+
+ dstBeing->setWalkSpeed(Vector(speed, speed, 0));
+ dstBeing->setSubtype(job, 0);
+
+ const int hairStyle = msg.readInt16("hair style");
+ const uint16_t weapon = msg.readInt16("weapon");
+ const uint16_t shield = msg.readInt16("shield");
+ const uint16_t headBottom = msg.readInt16("head bottom");
+
+ if (msgType == 3)
+ msg.readInt32("tick");
+
+ const uint16_t headTop = msg.readInt16("head top");
+ const uint16_t headMid = msg.readInt16("head mid");
+ const int hairColor = msg.readInt16("hair color");
+
+ msg.readUInt8("unused?");
+ msg.readUInt8("unused?");
+ msg.readUInt8("unused?");
+ msg.readUInt8("unused?");
+
+ const int guild = msg.readInt32("guild");
+
+ if (!guildManager || !GuildManager::getEnableGuildBot())
+ {
+ if (guild == 0)
+ dstBeing->clearGuilds();
+ else
+ dstBeing->setGuild(Guild::getGuild(static_cast<int16_t>(guild)));
+ }
+
+ msg.readInt16("emblem");
+ msg.readInt16("manner");
+ dstBeing->setStatusEffectBlock(32, msg.readInt16("opt3"));
+ msg.readUInt8("karma");
+ // reserving bit for future usage
+ dstBeing->setGender(Being::intToGender(msg.readUInt8("gender")));
+
+ if (!disguiseId)
+ {
+ // Set these after the gender, as the sprites may be gender-specific
+ dstBeing->updateSprite(SPRITE_WEAPON, weapon, "", 1, true);
+ if (!mHideShield)
+ dstBeing->updateSprite(SPRITE_SHIELD, shield);
+ dstBeing->updateSprite(SPRITE_BOTTOMCLOTHES, headBottom);
+ dstBeing->updateSprite(SPRITE_TOPCLOTHES, headMid);
+ dstBeing->updateSprite(SPRITE_HAT, headTop);
+ dstBeing->updateSprite(SPRITE_HAIR, hairStyle * -1,
+ ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
+ }
+ localPlayer->imitateOutfit(dstBeing);
+
+ if (msgType == 3)
+ {
+ uint16_t srcX, srcY, dstX, dstY;
+ msg.readCoordinatePair(srcX, srcY, dstX, dstY, "move path");
+ msg.readUInt8("(sx<<4) | (sy&0x0f)");
+
+ localPlayer->followMoveTo(dstBeing, srcX, srcY, dstX, dstY);
+
+ dstBeing->setTileCoords(srcX, srcY);
+ dstBeing->setDestination(dstX, dstY);
+
+ // because server don't send direction in move packet,
+ // we fixing it
+
+ if (srcX != dstX || srcY != dstY)
+ {
+ const int d = dstBeing->calcDirection(dstX, dstY);
+
+ if (d && dstBeing->getDirection() != d)
+ dstBeing->setDirectionDelayed(static_cast<uint8_t>(d));
+ }
+
+ if (localPlayer->getCurrentAction() != BeingAction::STAND)
+ localPlayer->imitateAction(dstBeing, BeingAction::STAND);
+ if (localPlayer->getDirection() != dstBeing->getDirection())
+ {
+ localPlayer->imitateDirection(dstBeing,
+ dstBeing->getDirection());
+ }
+ }
+ else
+ {
+ uint16_t x, y;
+ msg.readCoordinates(x, y, dir, "position");
+ dstBeing->setTileCoords(x, y);
+ dstBeing->setDirection(dir);
+
+ localPlayer->imitateDirection(dstBeing, dir);
+ }
+
+ const uint16_t gmstatus = msg.readInt16("gm status");
+
+ if (gmstatus & 0x80)
+ dstBeing->setGM(true);
+
+ if (msgType == 1 || msgType == 2)
+ {
+ const uint8_t type = msg.readUInt8("action type");
+ switch (type)
+ {
+ case 0:
+ dstBeing->setAction(BeingAction::STAND, 0);
+ localPlayer->imitateAction(dstBeing, BeingAction::STAND);
+ break;
+
+ case 1:
+ if (dstBeing->getCurrentAction() != BeingAction::DEAD)
+ {
+ dstBeing->setAction(BeingAction::DEAD, 0);
+ dstBeing->recalcSpritesOrder();
+ }
+ break;
+
+ case 2:
+ dstBeing->setAction(BeingAction::SIT, 0);
+ localPlayer->imitateAction(dstBeing, BeingAction::SIT);
+ break;
+
+ default:
+ // need set stay state?
+ logger->log("QQQ2 SMSG_PLAYER_UPDATE_1:"
+ + toString(id) + " " + toString(type));
+ logger->log("dstBeing id:" + toString(dstBeing->getId()));
+ logger->log("dstBeing name:" + dstBeing->getName());
+ break;
+ }
+ }
+ else if (msgType == 3)
+ {
+ msg.readUInt8("unknown?");
+ }
+
+ const int level = static_cast<int>(msg.readUInt8("level"));
+
+ if (level)
+ dstBeing->setLevel(level);
+
+ msg.readUInt8("unknown");
+
+ if (dstBeing->getType() != ActorType::PLAYER
+ || msgType != 3)
+ {
+ dstBeing->setActionTime(tick_time);
+ }
+
+ dstBeing->setStunMode(stunMode);
+ dstBeing->setStatusEffectBlock(0, static_cast<uint16_t>(
+ (statusEffects >> 16) & 0xffffU));
+ dstBeing->setStatusEffectBlock(16, static_cast<uint16_t>(
+ statusEffects & 0xffffU));
+
+ if (msgType == 3 && dstBeing->getType() == ActorType::PLAYER)
+ dstBeing->setMoveTime();
+}
+
+void BeingHandler::processPlayerUpdate2(Net::MessageIn &msg) const
+{
+ if (!actorManager || !localPlayer)
+ return;
+
+ int msgType;
+ switch (msg.getId())
+ {
+ case SMSG_PLAYER_UPDATE_1:
+ msgType = 1;
+ break;
+ case SMSG_PLAYER_UPDATE_2:
+ msgType = 2;
+ break;
+ case SMSG_PLAYER_MOVE:
+ msgType = 3;
+ break;
+ default:
+ return;
+ }
+
+ // An update about a player, potentially including movement.
+ const int id = msg.readInt32("account id");
+ const int16_t speed = msg.readInt16("speed");
+ const uint16_t stunMode = msg.readInt16("opt1");
+ uint32_t statusEffects = msg.readInt16("opt2");
+ statusEffects |= (static_cast<uint16_t>(msg.readInt16("options"))) << 16U;
+ const int16_t job = msg.readInt16("class");
+ int disguiseId = 0;
+ if (id < 110000000 && job >= 1000)
+ disguiseId = job;
+
+ Being *dstBeing = actorManager->findBeing(id);
+
+ if (!dstBeing)
+ {
+ if (actorManager->isBlocked(id) == true)
+ return;
+
+ dstBeing = createBeing(id, job);
+
+ if (!dstBeing)
+ return;
+ }
+ else if (disguiseId)
+ {
+ actorManager->undelete(dstBeing);
+ if (serverVersion < 1)
+ requestNameById(id);
+ }
+
+ uint8_t dir = dstBeing->getDirectionDelayed();
+ if (dir)
+ {
+ if (dir != dstBeing->getDirection())
+ dstBeing->setDirection(dir);
+ }
+
+ if (Party *const party = localPlayer->getParty())
+ {
+ if (party->isMember(id))
+ dstBeing->setParty(party);
+ }
+
+ dstBeing->setWalkSpeed(Vector(speed, speed, 0));
+ dstBeing->setSubtype(job, 0);
+
+ const int hairStyle = msg.readInt16("hair style");
+ const uint16_t weapon = msg.readInt16("weapon");
+ const uint16_t shield = msg.readInt16("shield");
+ const uint16_t headBottom = msg.readInt16("head bottom");
+
+ if (msgType == 3)
+ msg.readInt32("tick");
+
+ const uint16_t headTop = msg.readInt16("head top");
+ const uint16_t headMid = msg.readInt16("head mid");
+ const int hairColor = msg.readInt16("hair color");
+
+ msg.readUInt8("unused?");
+ msg.readUInt8("unused?");
+ msg.readUInt8("unused?");
+ msg.readUInt8("unused?");
+
+ const int guild = msg.readInt32("guild");
+
+ if (!guildManager || !GuildManager::getEnableGuildBot())
+ {
+ if (guild == 0)
+ dstBeing->clearGuilds();
+ else
+ dstBeing->setGuild(Guild::getGuild(static_cast<int16_t>(guild)));
+ }
+
+ msg.readInt16("emblem");
+ msg.readInt16("manner");
+ dstBeing->setStatusEffectBlock(32, msg.readInt16("opt3"));
+ msg.readUInt8("karma");
+ // reserving bit for future usage
+ dstBeing->setGender(Being::intToGender(msg.readUInt8("gender")));
+
+ if (!disguiseId)
+ {
+ // Set these after the gender, as the sprites may be gender-specific
+ dstBeing->updateSprite(SPRITE_WEAPON, weapon, "", 1, true);
+ if (!mHideShield)
+ dstBeing->updateSprite(SPRITE_SHIELD, shield);
+ dstBeing->updateSprite(SPRITE_BOTTOMCLOTHES, headBottom);
+ dstBeing->updateSprite(SPRITE_TOPCLOTHES, headMid);
+ dstBeing->updateSprite(SPRITE_HAT, headTop);
+ dstBeing->updateSprite(SPRITE_HAIR, hairStyle * -1,
+ ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
+ }
+ localPlayer->imitateOutfit(dstBeing);
+
+ if (msgType == 3)
+ {
+ uint16_t srcX, srcY, dstX, dstY;
+ msg.readCoordinatePair(srcX, srcY, dstX, dstY, "move path");
+ msg.readUInt8("(sx<<4) | (sy&0x0f)");
+
+ localPlayer->followMoveTo(dstBeing, srcX, srcY, dstX, dstY);
+
+ dstBeing->setTileCoords(srcX, srcY);
+ dstBeing->setDestination(dstX, dstY);
+
+ // because server don't send direction in move packet,
+ // we fixing it
+
+ if (srcX != dstX || srcY != dstY)
+ {
+ const int d = dstBeing->calcDirection(dstX, dstY);
+
+ if (d && dstBeing->getDirection() != d)
+ dstBeing->setDirectionDelayed(static_cast<uint8_t>(d));
+ }
+
+ if (localPlayer->getCurrentAction() != BeingAction::STAND)
+ localPlayer->imitateAction(dstBeing, BeingAction::STAND);
+ if (localPlayer->getDirection() != dstBeing->getDirection())
+ {
+ localPlayer->imitateDirection(dstBeing,
+ dstBeing->getDirection());
+ }
+ }
+ else
+ {
+ uint16_t x, y;
+ msg.readCoordinates(x, y, dir, "position");
+ dstBeing->setTileCoords(x, y);
+ dstBeing->setDirection(dir);
+
+ localPlayer->imitateDirection(dstBeing, dir);
+ }
+
+ const uint16_t gmstatus = msg.readInt16("gm status");
+
+ if (gmstatus & 0x80)
+ dstBeing->setGM(true);
+
+ if (msgType == 1 || msgType == 2)
+ {
+ const uint8_t type = msg.readUInt8("action type");
+ switch (type)
+ {
+ case 0:
+ dstBeing->setAction(BeingAction::STAND, 0);
+ localPlayer->imitateAction(dstBeing, BeingAction::STAND);
+ break;
+
+ case 1:
+ if (dstBeing->getCurrentAction() != BeingAction::DEAD)
+ {
+ dstBeing->setAction(BeingAction::DEAD, 0);
+ dstBeing->recalcSpritesOrder();
+ }
+ break;
+
+ case 2:
+ dstBeing->setAction(BeingAction::SIT, 0);
+ localPlayer->imitateAction(dstBeing, BeingAction::SIT);
+ break;
+
+ default:
+ // need set stay state?
+ logger->log("QQQ2 SMSG_PLAYER_UPDATE_1:"
+ + toString(id) + " " + toString(type));
+ logger->log("dstBeing id:" + toString(dstBeing->getId()));
+ logger->log("dstBeing name:" + dstBeing->getName());
+ break;
+ }
+ }
+ else if (msgType == 3)
+ {
+ msg.readUInt8("unknown?");
+ }
+
+ const int level = static_cast<int>(msg.readUInt8("level"));
+
+ if (level)
+ dstBeing->setLevel(level);
+
+ msg.readUInt8("unknown");
+
+ if (dstBeing->getType() != ActorType::PLAYER
+ || msgType != 3)
+ {
+ dstBeing->setActionTime(tick_time);
+ }
+
+ dstBeing->setStunMode(stunMode);
+ dstBeing->setStatusEffectBlock(0, static_cast<uint16_t>(
+ (statusEffects >> 16) & 0xffffU));
+ dstBeing->setStatusEffectBlock(16, static_cast<uint16_t>(
+ statusEffects & 0xffffU));
+
+ if (msgType == 3 && dstBeing->getType() == ActorType::PLAYER)
+ dstBeing->setMoveTime();
+}
+
+void BeingHandler::processPlayerMove(Net::MessageIn &msg) const
{
if (!actorManager || !localPlayer)
return;
diff --git a/src/net/eathena/beinghandler.h b/src/net/eathena/beinghandler.h
index 2ddd60d6a..3f951870f 100644
--- a/src/net/eathena/beinghandler.h
+++ b/src/net/eathena/beinghandler.h
@@ -58,7 +58,11 @@ class BeingHandler final : public MessageHandler, public Ea::BeingHandler
static void processNameResponse2(Net::MessageIn &msg);
- void processPlayerMoveUpdate(Net::MessageIn &msg) const;
+ void processPlayerUpdate1(Net::MessageIn &msg) const;
+
+ void processPlayerUpdate2(Net::MessageIn &msg) const;
+
+ void processPlayerMove(Net::MessageIn &msg) const;
void processMapTypeProperty(Net::MessageIn &msg) const;
diff --git a/src/net/tmwa/beinghandler.cpp b/src/net/tmwa/beinghandler.cpp
index 70649ac02..f1d362cb6 100644
--- a/src/net/tmwa/beinghandler.cpp
+++ b/src/net/tmwa/beinghandler.cpp
@@ -187,9 +187,15 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
break;
case SMSG_PLAYER_UPDATE_1:
+ processPlayerUpdate1(msg);
+ break;
+
case SMSG_PLAYER_UPDATE_2:
+ processPlayerUpdate2(msg);
+ break;
+
case SMSG_PLAYER_MOVE:
- processPlayerMoveUpdate(msg);
+ processPlayerMove(msg);
break;
case SMSG_PLAYER_STOP:
@@ -459,7 +465,505 @@ void BeingHandler::processNameResponse2(Net::MessageIn &msg)
BLOCK_END("BeingHandler::processNameResponse2")
}
-void BeingHandler::processPlayerMoveUpdate(Net::MessageIn &msg) const
+void BeingHandler::processPlayerUpdate1(Net::MessageIn &msg) const
+{
+ BLOCK_START("BeingHandler::processPlayerMoveUpdate")
+ if (!actorManager || !localPlayer)
+ {
+ BLOCK_END("BeingHandler::processPlayerMoveUpdate")
+ return;
+ }
+
+ int msgType;
+ switch (msg.getId())
+ {
+ case SMSG_PLAYER_UPDATE_1:
+ msgType = 1;
+ break;
+ case SMSG_PLAYER_UPDATE_2:
+ msgType = 2;
+ break;
+ case SMSG_PLAYER_MOVE:
+ msgType = 3;
+ break;
+ default:
+ return;
+ }
+
+ // An update about a player, potentially including movement.
+ const int id = msg.readInt32("account id");
+ const int16_t speed = msg.readInt16("speed");
+ const uint16_t stunMode = msg.readInt16("opt1");
+ uint32_t statusEffects = msg.readInt16("opt2");
+ statusEffects |= (static_cast<uint32_t>(msg.readInt16("options")))
+ << 16;
+ const int16_t job = msg.readInt16("job");
+ int disguiseId = 0;
+ if (id < 110000000 && job >= 1000)
+ disguiseId = job;
+
+ Being *dstBeing = actorManager->findBeing(id);
+ if (!dstBeing)
+ {
+ if (actorManager->isBlocked(id) == true)
+ {
+ BLOCK_END("BeingHandler::processPlayerMoveUpdate")
+ return;
+ }
+
+ dstBeing = createBeing(id, job);
+
+ if (!dstBeing)
+ {
+ BLOCK_END("BeingHandler::processPlayerMoveUpdate")
+ return;
+ }
+ }
+ else if (disguiseId)
+ {
+ actorManager->undelete(dstBeing);
+ if (serverVersion < 1)
+ requestNameById(id);
+ }
+
+ uint8_t dir = dstBeing->getDirectionDelayed();
+ if (dir)
+ {
+ if (dir != dstBeing->getDirection())
+ dstBeing->setDirection(dir);
+ }
+
+ if (Party *const party = localPlayer->getParty())
+ {
+ if (party->isMember(id))
+ dstBeing->setParty(party);
+ }
+
+ dstBeing->setWalkSpeed(Vector(speed, speed, 0));
+
+ const uint8_t hairStyle = msg.readUInt8("hair style");
+ const uint8_t look = msg.readUInt8("look");
+ dstBeing->setSubtype(job, look);
+ const uint16_t weapon = msg.readInt16("weapon");
+ const uint16_t shield = msg.readInt16("shield");
+ const uint16_t headBottom = msg.readInt16("head bottom");
+
+ if (msgType == 3)
+ msg.readInt32("tick");
+
+ const uint16_t headTop = msg.readInt16("head top");
+ const uint16_t headMid = msg.readInt16("head mid");
+ const uint8_t hairColor = msg.readUInt8("hair color");
+ msg.readUInt8("unused");
+
+ uint8_t colors[9];
+ colors[0] = msg.readUInt8("color 0");
+ colors[1] = msg.readUInt8("color 1");
+ colors[2] = msg.readUInt8("color 2");
+
+ msg.readUInt8("unused");
+
+ const int guild = msg.readInt32("guild");
+
+ if (!guildManager || !GuildManager::getEnableGuildBot())
+ {
+ if (guild == 0)
+ dstBeing->clearGuilds();
+ else
+ dstBeing->setGuild(Guild::getGuild(static_cast<int16_t>(guild)));
+ }
+
+ msg.readInt16("emblem");
+ msg.readInt16("manner");
+ dstBeing->setStatusEffectBlock(32, msg.readInt16("opt3"));
+ msg.readUInt8("karma");
+ // reserving bit for future usage
+ dstBeing->setGender(Being::intToGender(
+ static_cast<uint8_t>(msg.readUInt8("gender") & 3)));
+
+ if (!disguiseId)
+ {
+ // Set these after the gender, as the sprites may be gender-specific
+ dstBeing->updateSprite(SPRITE_WEAPON, weapon, "", 1, true);
+ if (!mHideShield)
+ dstBeing->updateSprite(SPRITE_SHIELD, shield);
+ if (serverVersion > 0)
+ {
+ dstBeing->updateSprite(SPRITE_BOTTOMCLOTHES, headBottom,
+ "", colors[0]);
+ dstBeing->updateSprite(SPRITE_TOPCLOTHES, headMid, "", colors[2]);
+ dstBeing->updateSprite(SPRITE_HAT, headTop, "", colors[1]);
+ }
+ else
+ {
+ dstBeing->updateSprite(SPRITE_BOTTOMCLOTHES, headBottom);
+ dstBeing->updateSprite(SPRITE_TOPCLOTHES, headMid);
+ dstBeing->updateSprite(SPRITE_HAT, headTop);
+ }
+ dstBeing->updateSprite(SPRITE_HAIR, hairStyle * -1,
+ ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
+ dstBeing->setHairColor(hairColor);
+ }
+ localPlayer->imitateOutfit(dstBeing);
+
+ if (msgType == 3)
+ {
+ uint16_t srcX, srcY, dstX, dstY;
+ msg.readCoordinatePair(srcX, srcY, dstX, dstY, "moving path");
+
+ localPlayer->followMoveTo(dstBeing, srcX, srcY, dstX, dstY);
+
+ dstBeing->setTileCoords(srcX, srcY);
+ dstBeing->setDestination(dstX, dstY);
+
+ // because server don't send direction in move packet,
+ // we fixing it
+
+ if (srcX != dstX || srcY != dstY)
+ {
+ const int d = dstBeing->calcDirection(dstX, dstY);
+
+ if (d && dstBeing->getDirection() != d)
+ dstBeing->setDirectionDelayed(static_cast<uint8_t>(d));
+ }
+
+ if (localPlayer->getCurrentAction() != BeingAction::STAND)
+ localPlayer->imitateAction(dstBeing, BeingAction::STAND);
+ if (localPlayer->getDirection() != dstBeing->getDirection())
+ {
+ localPlayer->imitateDirection(dstBeing,
+ dstBeing->getDirection());
+ }
+ }
+ else
+ {
+// uint8_t dir;
+ uint16_t x, y;
+ msg.readCoordinates(x, y, dir, "position");
+ dstBeing->setTileCoords(x, y);
+ dstBeing->setDirection(dir);
+
+ localPlayer->imitateDirection(dstBeing, dir);
+ }
+
+ const uint16_t gmstatus = msg.readInt16("gm status");
+
+ if (gmstatus & 0x80)
+ dstBeing->setGM(true);
+
+ if (msgType == 1 || msgType == 2)
+ {
+ const uint8_t type = msg.readUInt8("action type");
+ switch (type)
+ {
+ case 0:
+ dstBeing->setAction(BeingAction::STAND, 0);
+ localPlayer->imitateAction(dstBeing, BeingAction::STAND);
+ break;
+
+ case 1:
+ if (dstBeing->getCurrentAction() != BeingAction::DEAD)
+ {
+ dstBeing->setAction(BeingAction::DEAD, 0);
+ dstBeing->recalcSpritesOrder();
+ }
+ break;
+
+ case 2:
+ dstBeing->setAction(BeingAction::SIT, 0);
+ localPlayer->imitateAction(dstBeing, BeingAction::SIT);
+ break;
+
+ default:
+ // need set stand state?
+ logger->log("QQQ2 SMSG_PLAYER_UPDATE_1:"
+ + toString(id) + " " + toString(type));
+ logger->log("dstBeing id:"
+ + toString(dstBeing->getId()));
+ logger->log("dstBeing name:"
+ + dstBeing->getName());
+ break;
+ }
+ }
+ else if (msgType == 3)
+ {
+ msg.readUInt8("unused");
+ }
+
+ const int level = static_cast<int>(msg.readUInt8("level"));
+ if (level)
+ dstBeing->setLevel(level);
+
+ if (msgType != 2)
+ msg.readUInt8("unused");
+
+ if (dstBeing->getType() != ActorType::PLAYER
+ || msgType != 3)
+ {
+ dstBeing->setActionTime(tick_time);
+ }
+
+ dstBeing->setStunMode(stunMode);
+ dstBeing->setStatusEffectBlock(0, static_cast<uint16_t>(
+ (statusEffects >> 16) & 0xffff));
+ dstBeing->setStatusEffectBlock(16, static_cast<uint16_t>(
+ statusEffects & 0xffff));
+
+ if (msgType == 3 && dstBeing->getType() == ActorType::PLAYER)
+ dstBeing->setMoveTime();
+ BLOCK_END("BeingHandler::processPlayerMoveUpdate")
+}
+
+void BeingHandler::processPlayerUpdate2(Net::MessageIn &msg) const
+{
+ BLOCK_START("BeingHandler::processPlayerMoveUpdate")
+ if (!actorManager || !localPlayer)
+ {
+ BLOCK_END("BeingHandler::processPlayerMoveUpdate")
+ return;
+ }
+
+ int msgType;
+ switch (msg.getId())
+ {
+ case SMSG_PLAYER_UPDATE_1:
+ msgType = 1;
+ break;
+ case SMSG_PLAYER_UPDATE_2:
+ msgType = 2;
+ break;
+ case SMSG_PLAYER_MOVE:
+ msgType = 3;
+ break;
+ default:
+ return;
+ }
+
+ // An update about a player, potentially including movement.
+ const int id = msg.readInt32("account id");
+ const int16_t speed = msg.readInt16("speed");
+ const uint16_t stunMode = msg.readInt16("opt1");
+ uint32_t statusEffects = msg.readInt16("opt2");
+ statusEffects |= (static_cast<uint32_t>(msg.readInt16("options")))
+ << 16;
+ const int16_t job = msg.readInt16("job");
+ int disguiseId = 0;
+ if (id < 110000000 && job >= 1000)
+ disguiseId = job;
+
+ Being *dstBeing = actorManager->findBeing(id);
+ if (!dstBeing)
+ {
+ if (actorManager->isBlocked(id) == true)
+ {
+ BLOCK_END("BeingHandler::processPlayerMoveUpdate")
+ return;
+ }
+
+ dstBeing = createBeing(id, job);
+
+ if (!dstBeing)
+ {
+ BLOCK_END("BeingHandler::processPlayerMoveUpdate")
+ return;
+ }
+ }
+ else if (disguiseId)
+ {
+ actorManager->undelete(dstBeing);
+ if (serverVersion < 1)
+ requestNameById(id);
+ }
+
+ uint8_t dir = dstBeing->getDirectionDelayed();
+ if (dir)
+ {
+ if (dir != dstBeing->getDirection())
+ dstBeing->setDirection(dir);
+ }
+
+ if (Party *const party = localPlayer->getParty())
+ {
+ if (party->isMember(id))
+ dstBeing->setParty(party);
+ }
+
+ dstBeing->setWalkSpeed(Vector(speed, speed, 0));
+
+ const uint8_t hairStyle = msg.readUInt8("hair style");
+ const uint8_t look = msg.readUInt8("look");
+ dstBeing->setSubtype(job, look);
+ const uint16_t weapon = msg.readInt16("weapon");
+ const uint16_t shield = msg.readInt16("shield");
+ const uint16_t headBottom = msg.readInt16("head bottom");
+
+ if (msgType == 3)
+ msg.readInt32("tick");
+
+ const uint16_t headTop = msg.readInt16("head top");
+ const uint16_t headMid = msg.readInt16("head mid");
+ const uint8_t hairColor = msg.readUInt8("hair color");
+ msg.readUInt8("unused");
+
+ uint8_t colors[9];
+ colors[0] = msg.readUInt8("color 0");
+ colors[1] = msg.readUInt8("color 1");
+ colors[2] = msg.readUInt8("color 2");
+
+ msg.readUInt8("unused");
+
+ const int guild = msg.readInt32("guild");
+
+ if (!guildManager || !GuildManager::getEnableGuildBot())
+ {
+ if (guild == 0)
+ dstBeing->clearGuilds();
+ else
+ dstBeing->setGuild(Guild::getGuild(static_cast<int16_t>(guild)));
+ }
+
+ msg.readInt16("emblem");
+ msg.readInt16("manner");
+ dstBeing->setStatusEffectBlock(32, msg.readInt16("opt3"));
+ msg.readUInt8("karma");
+ // reserving bit for future usage
+ dstBeing->setGender(Being::intToGender(
+ static_cast<uint8_t>(msg.readUInt8("gender") & 3)));
+
+ if (!disguiseId)
+ {
+ // Set these after the gender, as the sprites may be gender-specific
+ dstBeing->updateSprite(SPRITE_WEAPON, weapon, "", 1, true);
+ if (!mHideShield)
+ dstBeing->updateSprite(SPRITE_SHIELD, shield);
+ if (serverVersion > 0)
+ {
+ dstBeing->updateSprite(SPRITE_BOTTOMCLOTHES, headBottom,
+ "", colors[0]);
+ dstBeing->updateSprite(SPRITE_TOPCLOTHES, headMid, "", colors[2]);
+ dstBeing->updateSprite(SPRITE_HAT, headTop, "", colors[1]);
+ }
+ else
+ {
+ dstBeing->updateSprite(SPRITE_BOTTOMCLOTHES, headBottom);
+ dstBeing->updateSprite(SPRITE_TOPCLOTHES, headMid);
+ dstBeing->updateSprite(SPRITE_HAT, headTop);
+ }
+ dstBeing->updateSprite(SPRITE_HAIR, hairStyle * -1,
+ ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
+ dstBeing->setHairColor(hairColor);
+ }
+ localPlayer->imitateOutfit(dstBeing);
+
+ if (msgType == 3)
+ {
+ uint16_t srcX, srcY, dstX, dstY;
+ msg.readCoordinatePair(srcX, srcY, dstX, dstY, "moving path");
+
+ localPlayer->followMoveTo(dstBeing, srcX, srcY, dstX, dstY);
+
+ dstBeing->setTileCoords(srcX, srcY);
+ dstBeing->setDestination(dstX, dstY);
+
+ // because server don't send direction in move packet,
+ // we fixing it
+
+ if (srcX != dstX || srcY != dstY)
+ {
+ const int d = dstBeing->calcDirection(dstX, dstY);
+
+ if (d && dstBeing->getDirection() != d)
+ dstBeing->setDirectionDelayed(static_cast<uint8_t>(d));
+ }
+
+ if (localPlayer->getCurrentAction() != BeingAction::STAND)
+ localPlayer->imitateAction(dstBeing, BeingAction::STAND);
+ if (localPlayer->getDirection() != dstBeing->getDirection())
+ {
+ localPlayer->imitateDirection(dstBeing,
+ dstBeing->getDirection());
+ }
+ }
+ else
+ {
+// uint8_t dir;
+ uint16_t x, y;
+ msg.readCoordinates(x, y, dir, "position");
+ dstBeing->setTileCoords(x, y);
+ dstBeing->setDirection(dir);
+
+ localPlayer->imitateDirection(dstBeing, dir);
+ }
+
+ const uint16_t gmstatus = msg.readInt16("gm status");
+
+ if (gmstatus & 0x80)
+ dstBeing->setGM(true);
+
+ if (msgType == 1 || msgType == 2)
+ {
+ const uint8_t type = msg.readUInt8("action type");
+ switch (type)
+ {
+ case 0:
+ dstBeing->setAction(BeingAction::STAND, 0);
+ localPlayer->imitateAction(dstBeing, BeingAction::STAND);
+ break;
+
+ case 1:
+ if (dstBeing->getCurrentAction() != BeingAction::DEAD)
+ {
+ dstBeing->setAction(BeingAction::DEAD, 0);
+ dstBeing->recalcSpritesOrder();
+ }
+ break;
+
+ case 2:
+ dstBeing->setAction(BeingAction::SIT, 0);
+ localPlayer->imitateAction(dstBeing, BeingAction::SIT);
+ break;
+
+ default:
+ // need set stand state?
+ logger->log("QQQ2 SMSG_PLAYER_UPDATE_1:"
+ + toString(id) + " " + toString(type));
+ logger->log("dstBeing id:"
+ + toString(dstBeing->getId()));
+ logger->log("dstBeing name:"
+ + dstBeing->getName());
+ break;
+ }
+ }
+ else if (msgType == 3)
+ {
+ msg.readUInt8("unused");
+ }
+
+ const int level = static_cast<int>(msg.readUInt8("level"));
+ if (level)
+ dstBeing->setLevel(level);
+
+ if (msgType != 2)
+ msg.readUInt8("unused");
+
+ if (dstBeing->getType() != ActorType::PLAYER
+ || msgType != 3)
+ {
+ dstBeing->setActionTime(tick_time);
+ }
+
+ dstBeing->setStunMode(stunMode);
+ dstBeing->setStatusEffectBlock(0, static_cast<uint16_t>(
+ (statusEffects >> 16) & 0xffff));
+ dstBeing->setStatusEffectBlock(16, static_cast<uint16_t>(
+ statusEffects & 0xffff));
+
+ if (msgType == 3 && dstBeing->getType() == ActorType::PLAYER)
+ dstBeing->setMoveTime();
+ BLOCK_END("BeingHandler::processPlayerMoveUpdate")
+}
+
+void BeingHandler::processPlayerMove(Net::MessageIn &msg) const
{
BLOCK_START("BeingHandler::processPlayerMoveUpdate")
if (!actorManager || !localPlayer)
diff --git a/src/net/tmwa/beinghandler.h b/src/net/tmwa/beinghandler.h
index 996b054ba..08e8ae7ca 100644
--- a/src/net/tmwa/beinghandler.h
+++ b/src/net/tmwa/beinghandler.h
@@ -56,7 +56,11 @@ class BeingHandler final : public MessageHandler, public Ea::BeingHandler
static void processNameResponse2(Net::MessageIn &msg);
- void processPlayerMoveUpdate(Net::MessageIn &msg) const;
+ void processPlayerUpdate1(Net::MessageIn &msg) const;
+
+ void processPlayerUpdate2(Net::MessageIn &msg) const;
+
+ void processPlayerMove(Net::MessageIn &msg) const;
static void processBeingMove3(Net::MessageIn &msg);