summaryrefslogtreecommitdiff
path: root/src/net
diff options
context:
space:
mode:
Diffstat (limited to 'src/net')
-rw-r--r--src/net/ea/beinghandler.cpp425
-rw-r--r--src/net/ea/beinghandler.h34
-rw-r--r--src/net/ea/beingnet.cpp473
-rw-r--r--src/net/ea/beingnet.h59
-rw-r--r--src/net/eathena/beinghandler.cpp1727
-rw-r--r--src/net/eathena/beinghandler.h119
-rw-r--r--src/net/eathena/beingnet.cpp1670
-rw-r--r--src/net/eathena/beingnet.h101
-rw-r--r--src/net/tmwa/beinghandler.cpp1388
-rw-r--r--src/net/tmwa/beinghandler.h51
-rw-r--r--src/net/tmwa/beingnet.cpp1391
-rw-r--r--src/net/tmwa/beingnet.h66
12 files changed, 3862 insertions, 3642 deletions
diff --git a/src/net/ea/beinghandler.cpp b/src/net/ea/beinghandler.cpp
index 85e04efbc..49e8b4720 100644
--- a/src/net/ea/beinghandler.cpp
+++ b/src/net/ea/beinghandler.cpp
@@ -40,434 +40,17 @@
#include "net/serverfeatures.h"
+#include "net/ea/beingnet.h"
+
#include "debug.h"
namespace Ea
{
-BeingId BeingHandler::mSpawnId = BeingId_zero;
-bool BeingHandler::mSync = false;
BeingHandler::BeingHandler(const bool enableSync)
{
- mSync = enableSync;
- mSpawnId = BeingId_zero;
-}
-
-Being *BeingHandler::createBeing(const BeingId id,
- const int job)
-{
- if (!actorManager)
- return nullptr;
-
- ActorTypeT type = ActorType::Unknown;
- if (job <= 25 || (job >= 4001 && job <= 4049))
- type = ActorType::Player;
- else if (job >= 46 && job <= 1000)
- type = ActorType::Npc;
- else if (job > 1000 && job <= 2000)
- type = ActorType::Monster;
- else if (job == 45)
- type = ActorType::Portal;
-
- Being *const being = actorManager->createBeing(
- id, type, fromInt(job, BeingTypeId));
- return being;
-}
-
-void BeingHandler::setSprite(Being *const being, const unsigned int slot,
- const int id, const std::string &color,
- const ItemColor colorId,
- const bool isWeapon,
- const bool isTempSprite)
-{
- if (!being)
- return;
- being->updateSprite(slot, id, color, colorId, isWeapon, isTempSprite);
-}
-
-void BeingHandler::processBeingRemove(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processBeingRemove")
- if (!actorManager || !localPlayer)
- {
- BLOCK_END("BeingHandler::processBeingRemove")
- return;
- }
-
- // A being should be removed or has died
-
- const BeingId id = msg.readBeingId("being id");
- Being *const dstBeing = actorManager->findBeing(id);
- if (!dstBeing)
- {
- msg.readUInt8("dead flag?");
- BLOCK_END("BeingHandler::processBeingRemove")
- return;
- }
-
- localPlayer->followMoveTo(dstBeing, localPlayer->getNextDestX(),
- localPlayer->getNextDestY());
-
- // If this is player's current target, clear it.
- if (dstBeing == localPlayer->getTarget())
- localPlayer->stopAttack(true);
-
- if (msg.readUInt8("dead flag?") == 1U)
- {
- if (dstBeing->getCurrentAction() != BeingAction::DEAD)
- {
- dstBeing->setAction(BeingAction::DEAD, 0);
- dstBeing->recalcSpritesOrder();
- }
- }
- else
- {
- if (dstBeing->getType() == ActorType::Player)
- {
- if (socialWindow)
- socialWindow->updateActiveList();
- }
- actorManager->destroy(dstBeing);
- }
- BLOCK_END("BeingHandler::processBeingRemove")
-}
-
-void BeingHandler::processSkillDamage(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processSkillDamage")
- if (!actorManager)
- {
- BLOCK_END("BeingHandler::processSkillDamage")
- return;
- }
-
- const int id = msg.readInt16("skill id");
- Being *const srcBeing = actorManager->findBeing(
- msg.readBeingId("src being id"));
- Being *const dstBeing = actorManager->findBeing(
- msg.readBeingId("dst being id"));
- msg.readInt32("tick");
- msg.readInt32("src speed");
- msg.readInt32("dst speed");
- const int param1 = msg.readInt32("damage");
- const int level = msg.readInt16("skill level");
- msg.readInt16("div");
- msg.readUInt8("skill hit/type?");
- if (srcBeing)
- srcBeing->handleSkill(dstBeing, param1, id, level);
- if (dstBeing)
- dstBeing->takeDamage(srcBeing, param1, AttackType::SKILL, id, level);
- BLOCK_END("BeingHandler::processSkillDamage")
-}
-
-void BeingHandler::processBeingAction(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processBeingAction")
- if (!actorManager)
- {
- BLOCK_END("BeingHandler::processBeingAction")
- return;
- }
-
- Being *const srcBeing = actorManager->findBeing(
- msg.readBeingId("src being id"));
- Being *const dstBeing = actorManager->findBeing(
- msg.readBeingId("dst being id"));
-
- msg.readInt32("tick");
- const int srcSpeed = msg.readInt32("src speed");
- msg.readInt32("dst speed");
- const int param1 = msg.readInt16("param1");
- msg.readInt16("param 2");
- const AttackTypeT type = static_cast<AttackTypeT>(
- msg.readUInt8("type"));
- msg.readInt16("param 3");
-
- switch (type)
- {
- case AttackType::HIT: // Damage
- case AttackType::CRITICAL: // Critical Damage
- case AttackType::MULTI: // Critical Damage
- case AttackType::REFLECT: // Reflected Damage
- case AttackType::FLEE: // Lucky Dodge
- if (srcBeing)
- {
- if (srcSpeed && srcBeing->getType() == ActorType::Player)
- srcBeing->setAttackDelay(srcSpeed);
- // attackid=1, type
- srcBeing->handleAttack(dstBeing, param1, 1);
- if (srcBeing->getType() == ActorType::Player)
- srcBeing->setAttackTime();
- }
- if (dstBeing)
- {
- // level not present, using 1
- dstBeing->takeDamage(srcBeing, param1,
- static_cast<AttackTypeT>(type), 1);
- }
- break;
-
- case AttackType::PICKUP:
- break;
- // tmw server can send here garbage?
-// if (srcBeing)
-// srcBeing->setAction(BeingAction::DEAD, 0);
-
- case AttackType::SIT:
- if (srcBeing)
- {
- srcBeing->setAction(BeingAction::SIT, 0);
- if (srcBeing->getType() == ActorType::Player)
- {
- srcBeing->setMoveTime();
- if (localPlayer)
- localPlayer->imitateAction(srcBeing, BeingAction::SIT);
- }
- }
- break;
-
- case AttackType::STAND:
- if (srcBeing)
- {
- srcBeing->setAction(BeingAction::STAND, 0);
- if (srcBeing->getType() == ActorType::Player)
- {
- srcBeing->setMoveTime();
- if (localPlayer)
- {
- localPlayer->imitateAction(srcBeing,
- BeingAction::STAND);
- }
- }
- }
- break;
- default:
- case AttackType::SPLASH:
- case AttackType::SKILL:
- case AttackType::REPEATE:
- case AttackType::MULTI_REFLECT:
- case AttackType::TOUCH_SKILL:
- case AttackType::MISS:
- case AttackType::SKILLMISS:
- UNIMPLIMENTEDPACKET;
- break;
- }
- BLOCK_END("BeingHandler::processBeingAction")
-}
-
-void BeingHandler::processBeingEmotion(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processBeingEmotion")
- if (!localPlayer || !actorManager)
- {
- BLOCK_END("BeingHandler::processBeingEmotion")
- return;
- }
-
- Being *const dstBeing = actorManager->findBeing(
- msg.readBeingId("being id"));
- if (!dstBeing)
- {
- BLOCK_END("BeingHandler::processBeingEmotion")
- return;
- }
-
- if (player_relations.hasPermission(dstBeing, PlayerRelation::EMOTE))
- {
- const uint8_t emote = msg.readUInt8("emote");
- if (emote)
- {
- dstBeing->setEmote(emote, 0);
- localPlayer->imitateEmote(dstBeing, emote);
- }
- }
- if (dstBeing->getType() == ActorType::Player)
- dstBeing->setOtherTime();
- BLOCK_END("BeingHandler::processBeingEmotion")
-}
-
-void BeingHandler::processNameResponse(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processNameResponse")
- if (!localPlayer || !actorManager)
- {
- BLOCK_END("BeingHandler::processNameResponse")
- return;
- }
-
- const BeingId beingId = msg.readBeingId("being id");
- Being *const dstBeing = actorManager->findBeing(beingId);
-
- if (dstBeing)
- {
- if (beingId == localPlayer->getId())
- {
- localPlayer->pingResponse();
- }
- else
- {
- const std::string name = msg.readString(24, "name");
- if (dstBeing->getType() != ActorType::Portal)
- {
- dstBeing->setName(name);
- }
- else if (viewport)
- {
- Map *const map = viewport->getMap();
- if (map)
- {
- map->addPortalTile(name, MapItemType::PORTAL,
- dstBeing->getTileX(), dstBeing->getTileY());
- }
- }
- dstBeing->updateGuild();
- dstBeing->addToCache();
-
- if (dstBeing->getType() == ActorType::Player)
- dstBeing->updateColors();
-
- if (localPlayer)
- {
- const Party *const party = localPlayer->getParty();
- if (party && party->isMember(dstBeing->getId()))
- {
- PartyMember *const member = party->getMember(
- dstBeing->getId());
-
- if (member)
- member->setName(dstBeing->getName());
- }
- localPlayer->checkNewName(dstBeing);
- }
- BLOCK_END("BeingHandler::processNameResponse")
- return;
- }
- }
- msg.readString(24, "name");
- BLOCK_END("BeingHandler::processNameResponse")
-}
-
-void BeingHandler::processPlayerStop(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processPlayerStop")
- if (!actorManager || !localPlayer)
- {
- BLOCK_END("BeingHandler::processPlayerStop")
- return;
- }
-
- const BeingId id = msg.readBeingId("account id");
-
- if (mSync || id != localPlayer->getId())
- {
- Being *const dstBeing = actorManager->findBeing(id);
- if (dstBeing)
- {
- const uint16_t x = msg.readInt16("x");
- const uint16_t y = msg.readInt16("y");
- dstBeing->setTileCoords(x, y);
- if (dstBeing->getCurrentAction() == BeingAction::MOVE)
- dstBeing->setAction(BeingAction::STAND, 0);
- BLOCK_END("BeingHandler::processPlayerStop")
- return;
- }
- }
- msg.readInt16("x");
- msg.readInt16("y");
- BLOCK_END("BeingHandler::processPlayerStop")
-}
-
-void BeingHandler::processPlayerMoveToAttack(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processPlayerStop")
- msg.readInt32("target id");
- msg.readInt16("target x");
- msg.readInt16("target y");
- msg.readInt16("x");
- msg.readInt16("y");
- msg.readInt16("attack range");
-
- if (localPlayer)
- localPlayer->fixAttackTarget();
- BLOCK_END("BeingHandler::processPlayerStop")
-}
-
-void BeingHandler::processSkillNoDamage(Net::MessageIn &msg)
-{
- const int id = msg.readInt16("skill id");
- const int heal = msg.readInt16("heal");
- Being *const dstBeing = actorManager->findBeing(
- msg.readBeingId("dst being id"));
- Being *const srcBeing = actorManager->findBeing(
- msg.readBeingId("src being id"));
- const int flag = msg.readUInt8("fail");
-
- if (srcBeing)
- srcBeing->handleSkill(dstBeing, heal, id, 1);
-}
-
-void BeingHandler::processPvpMapMode(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processPvpMapMode")
- const Game *const game = Game::instance();
- if (!game)
- {
- BLOCK_END("BeingHandler::processPvpMapMode")
- return;
- }
-
- Map *const map = game->getCurrentMap();
- if (map)
- map->setPvpMode(msg.readInt16("pvp mode"));
- BLOCK_END("BeingHandler::processPvpMapMode")
-}
-
-void BeingHandler::processBeingMove3(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processBeingMove3")
- if (!actorManager || !serverFeatures->haveMove3())
- {
- BLOCK_END("BeingHandler::processBeingMove3")
- return;
- }
-
- static const int16_t dirx[8] = {0, -1, -1, -1, 0, 1, 1, 1};
- static const int16_t diry[8] = {1, 1, 0, -1, -1, -1, 0, 1};
-
- const int len = msg.readInt16("len") - 14;
- Being *const dstBeing = actorManager->findBeing(
- msg.readBeingId("being id"));
- if (!dstBeing)
- {
- BLOCK_END("BeingHandler::processBeingMove3")
- return;
- }
- const int16_t speed = msg.readInt16("speed");
- dstBeing->setWalkSpeed(Vector(speed, speed, 0));
- int16_t x = msg.readInt16("x");
- int16_t y = msg.readInt16("y");
- const unsigned char *moves = msg.readBytes(len, "moving path");
- Path path;
- if (moves)
- {
- for (int f = 0; f < len; f ++)
- {
- const unsigned char dir = moves[f];
- if (dir <= 7)
- {
- x += dirx[dir];
- y += diry[dir];
- path.push_back(Position(x, y));
- }
- else
- {
- logger->log("bad move packet: %d", dir);
- }
- }
- delete [] moves;
- }
- dstBeing->setPath(path);
- BLOCK_END("BeingHandler::processBeingMove3")
+ BeingNet::mSync = enableSync;
+ BeingNet::mSpawnId = BeingId_zero;
}
} // namespace Ea
diff --git a/src/net/ea/beinghandler.h b/src/net/ea/beinghandler.h
index 6c372ce1f..660f93f8e 100644
--- a/src/net/ea/beinghandler.h
+++ b/src/net/ea/beinghandler.h
@@ -35,40 +35,6 @@ class BeingHandler notfinal : public Net::BeingHandler
protected:
explicit BeingHandler(const bool enableSync);
-
- static Being *createBeing(const BeingId id,
- const int job) A_WARN_UNUSED;
-
- static void setSprite(Being *const being, const unsigned int slot,
- const int id,
- const std::string &color = "",
- const ItemColor colorId = ItemColor_one,
- const bool isWeapon = false,
- const bool isTempSprite = false);
-
- static void processBeingRemove(Net::MessageIn &msg);
-
- static void processSkillDamage(Net::MessageIn &msg);
-
- static void processBeingAction(Net::MessageIn &msg);
-
- static void processBeingEmotion(Net::MessageIn &msg);
-
- static void processNameResponse(Net::MessageIn &msg);
-
- static void processPlayerStop(Net::MessageIn &msg);
-
- static void processPlayerMoveToAttack(Net::MessageIn &msg);
-
- static void processSkillNoDamage(Net::MessageIn &msg);
-
- static void processPvpMapMode(Net::MessageIn &msg);
-
- static void processBeingMove3(Net::MessageIn &msg);
-
- // Should we honor server "Stop Walking" packets
- static BeingId mSpawnId;
- static bool mSync;
};
} // namespace Ea
diff --git a/src/net/ea/beingnet.cpp b/src/net/ea/beingnet.cpp
new file mode 100644
index 000000000..c7f64aa66
--- /dev/null
+++ b/src/net/ea/beingnet.cpp
@@ -0,0 +1,473 @@
+/*
+ * The ManaPlus Client
+ * Copyright (C) 2004-2009 The Mana World Development Team
+ * Copyright (C) 2009-2010 The Mana Developers
+ * Copyright (C) 2011-2015 The ManaPlus Developers
+ *
+ * This file is part of The ManaPlus Client.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "net/ea/beingnet.h"
+
+#include "actormanager.h"
+#include "game.h"
+#include "party.h"
+
+#include "being/localplayer.h"
+#include "being/playerrelation.h"
+#include "being/playerrelations.h"
+
+#include "enums/resources/map/mapitemtype.h"
+
+#include "gui/viewport.h"
+
+#include "gui/windows/socialwindow.h"
+
+#include "resources/map/map.h"
+
+#include "net/serverfeatures.h"
+
+#include "debug.h"
+
+namespace Ea
+{
+
+namespace BeingNet
+{
+ bool mSync = false;
+ BeingId mSpawnId = BeingId_zero;
+} // namespace BeingNet
+
+void BeingNet::processBeingRemove(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processBeingRemove")
+ if (!actorManager || !localPlayer)
+ {
+ BLOCK_END("BeingNet::processBeingRemove")
+ return;
+ }
+
+ // A being should be removed or has died
+
+ const BeingId id = msg.readBeingId("being id");
+ Being *const dstBeing = actorManager->findBeing(id);
+ if (!dstBeing)
+ {
+ msg.readUInt8("dead flag?");
+ BLOCK_END("BeingNet::processBeingRemove")
+ return;
+ }
+
+ localPlayer->followMoveTo(dstBeing, localPlayer->getNextDestX(),
+ localPlayer->getNextDestY());
+
+ // If this is player's current target, clear it.
+ if (dstBeing == localPlayer->getTarget())
+ localPlayer->stopAttack(true);
+
+ if (msg.readUInt8("dead flag?") == 1U)
+ {
+ if (dstBeing->getCurrentAction() != BeingAction::DEAD)
+ {
+ dstBeing->setAction(BeingAction::DEAD, 0);
+ dstBeing->recalcSpritesOrder();
+ }
+ }
+ else
+ {
+ if (dstBeing->getType() == ActorType::Player)
+ {
+ if (socialWindow)
+ socialWindow->updateActiveList();
+ }
+ actorManager->destroy(dstBeing);
+ }
+ BLOCK_END("BeingNet::processBeingRemove")
+}
+
+void BeingNet::processSkillDamage(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processSkillDamage")
+ if (!actorManager)
+ {
+ BLOCK_END("BeingNet::processSkillDamage")
+ return;
+ }
+
+ const int id = msg.readInt16("skill id");
+ Being *const srcBeing = actorManager->findBeing(
+ msg.readBeingId("src being id"));
+ Being *const dstBeing = actorManager->findBeing(
+ msg.readBeingId("dst being id"));
+ msg.readInt32("tick");
+ msg.readInt32("src speed");
+ msg.readInt32("dst speed");
+ const int param1 = msg.readInt32("damage");
+ const int level = msg.readInt16("skill level");
+ msg.readInt16("div");
+ msg.readUInt8("skill hit/type?");
+ if (srcBeing)
+ srcBeing->handleSkill(dstBeing, param1, id, level);
+ if (dstBeing)
+ dstBeing->takeDamage(srcBeing, param1, AttackType::SKILL, id, level);
+ BLOCK_END("BeingNet::processSkillDamage")
+}
+
+void BeingNet::processBeingAction(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processBeingAction")
+ if (!actorManager)
+ {
+ BLOCK_END("BeingNet::processBeingAction")
+ return;
+ }
+
+ Being *const srcBeing = actorManager->findBeing(
+ msg.readBeingId("src being id"));
+ Being *const dstBeing = actorManager->findBeing(
+ msg.readBeingId("dst being id"));
+
+ msg.readInt32("tick");
+ const int srcSpeed = msg.readInt32("src speed");
+ msg.readInt32("dst speed");
+ const int param1 = msg.readInt16("param1");
+ msg.readInt16("param 2");
+ const AttackTypeT type = static_cast<AttackTypeT>(
+ msg.readUInt8("type"));
+ msg.readInt16("param 3");
+
+ switch (type)
+ {
+ case AttackType::HIT: // Damage
+ case AttackType::CRITICAL: // Critical Damage
+ case AttackType::MULTI: // Critical Damage
+ case AttackType::REFLECT: // Reflected Damage
+ case AttackType::FLEE: // Lucky Dodge
+ if (srcBeing)
+ {
+ if (srcSpeed && srcBeing->getType() == ActorType::Player)
+ srcBeing->setAttackDelay(srcSpeed);
+ // attackid=1, type
+ srcBeing->handleAttack(dstBeing, param1, 1);
+ if (srcBeing->getType() == ActorType::Player)
+ srcBeing->setAttackTime();
+ }
+ if (dstBeing)
+ {
+ // level not present, using 1
+ dstBeing->takeDamage(srcBeing, param1,
+ static_cast<AttackTypeT>(type), 1);
+ }
+ break;
+
+ case AttackType::PICKUP:
+ break;
+ // tmw server can send here garbage?
+// if (srcBeing)
+// srcBeing->setAction(BeingAction::DEAD, 0);
+
+ case AttackType::SIT:
+ if (srcBeing)
+ {
+ srcBeing->setAction(BeingAction::SIT, 0);
+ if (srcBeing->getType() == ActorType::Player)
+ {
+ srcBeing->setMoveTime();
+ if (localPlayer)
+ localPlayer->imitateAction(srcBeing, BeingAction::SIT);
+ }
+ }
+ break;
+
+ case AttackType::STAND:
+ if (srcBeing)
+ {
+ srcBeing->setAction(BeingAction::STAND, 0);
+ if (srcBeing->getType() == ActorType::Player)
+ {
+ srcBeing->setMoveTime();
+ if (localPlayer)
+ {
+ localPlayer->imitateAction(srcBeing,
+ BeingAction::STAND);
+ }
+ }
+ }
+ break;
+ default:
+ case AttackType::SPLASH:
+ case AttackType::SKILL:
+ case AttackType::REPEATE:
+ case AttackType::MULTI_REFLECT:
+ case AttackType::TOUCH_SKILL:
+ case AttackType::MISS:
+ case AttackType::SKILLMISS:
+ UNIMPLIMENTEDPACKET;
+ break;
+ }
+ BLOCK_END("BeingNet::processBeingAction")
+}
+
+void BeingNet::processBeingEmotion(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processBeingEmotion")
+ if (!localPlayer || !actorManager)
+ {
+ BLOCK_END("BeingNet::processBeingEmotion")
+ return;
+ }
+
+ Being *const dstBeing = actorManager->findBeing(
+ msg.readBeingId("being id"));
+ if (!dstBeing)
+ {
+ BLOCK_END("BeingNet::processBeingEmotion")
+ return;
+ }
+
+ if (player_relations.hasPermission(dstBeing, PlayerRelation::EMOTE))
+ {
+ const uint8_t emote = msg.readUInt8("emote");
+ if (emote)
+ {
+ dstBeing->setEmote(emote, 0);
+ localPlayer->imitateEmote(dstBeing, emote);
+ }
+ }
+ if (dstBeing->getType() == ActorType::Player)
+ dstBeing->setOtherTime();
+ BLOCK_END("BeingNet::processBeingEmotion")
+}
+
+void BeingNet::processNameResponse(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processNameResponse")
+ if (!localPlayer || !actorManager)
+ {
+ BLOCK_END("BeingNet::processNameResponse")
+ return;
+ }
+
+ const BeingId beingId = msg.readBeingId("being id");
+ Being *const dstBeing = actorManager->findBeing(beingId);
+
+ if (dstBeing)
+ {
+ if (beingId == localPlayer->getId())
+ {
+ localPlayer->pingResponse();
+ }
+ else
+ {
+ const std::string name = msg.readString(24, "name");
+ if (dstBeing->getType() != ActorType::Portal)
+ {
+ dstBeing->setName(name);
+ }
+ else if (viewport)
+ {
+ Map *const map = viewport->getMap();
+ if (map)
+ {
+ map->addPortalTile(name, MapItemType::PORTAL,
+ dstBeing->getTileX(), dstBeing->getTileY());
+ }
+ }
+ dstBeing->updateGuild();
+ dstBeing->addToCache();
+
+ if (dstBeing->getType() == ActorType::Player)
+ dstBeing->updateColors();
+
+ if (localPlayer)
+ {
+ const Party *const party = localPlayer->getParty();
+ if (party && party->isMember(dstBeing->getId()))
+ {
+ PartyMember *const member = party->getMember(
+ dstBeing->getId());
+
+ if (member)
+ member->setName(dstBeing->getName());
+ }
+ localPlayer->checkNewName(dstBeing);
+ }
+ BLOCK_END("BeingNet::processNameResponse")
+ return;
+ }
+ }
+ msg.readString(24, "name");
+ BLOCK_END("BeingNet::processNameResponse")
+}
+
+void BeingNet::processPlayerStop(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processPlayerStop")
+ if (!actorManager || !localPlayer)
+ {
+ BLOCK_END("BeingNet::processPlayerStop")
+ return;
+ }
+
+ const BeingId id = msg.readBeingId("account id");
+
+ if (mSync || id != localPlayer->getId())
+ {
+ Being *const dstBeing = actorManager->findBeing(id);
+ if (dstBeing)
+ {
+ const uint16_t x = msg.readInt16("x");
+ const uint16_t y = msg.readInt16("y");
+ dstBeing->setTileCoords(x, y);
+ if (dstBeing->getCurrentAction() == BeingAction::MOVE)
+ dstBeing->setAction(BeingAction::STAND, 0);
+ BLOCK_END("BeingNet::processPlayerStop")
+ return;
+ }
+ }
+ msg.readInt16("x");
+ msg.readInt16("y");
+ BLOCK_END("BeingNet::processPlayerStop")
+}
+
+void BeingNet::processPlayerMoveToAttack(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processPlayerStop")
+ msg.readInt32("target id");
+ msg.readInt16("target x");
+ msg.readInt16("target y");
+ msg.readInt16("x");
+ msg.readInt16("y");
+ msg.readInt16("attack range");
+
+ if (localPlayer)
+ localPlayer->fixAttackTarget();
+ BLOCK_END("BeingNet::processPlayerStop")
+}
+
+void BeingNet::processSkillNoDamage(Net::MessageIn &msg)
+{
+ const int id = msg.readInt16("skill id");
+ const int heal = msg.readInt16("heal");
+ Being *const dstBeing = actorManager->findBeing(
+ msg.readBeingId("dst being id"));
+ Being *const srcBeing = actorManager->findBeing(
+ msg.readBeingId("src being id"));
+ const int flag = msg.readUInt8("fail");
+
+ if (srcBeing)
+ srcBeing->handleSkill(dstBeing, heal, id, 1);
+}
+
+void BeingNet::processPvpMapMode(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processPvpMapMode")
+ const Game *const game = Game::instance();
+ if (!game)
+ {
+ BLOCK_END("BeingNet::processPvpMapMode")
+ return;
+ }
+
+ Map *const map = game->getCurrentMap();
+ if (map)
+ map->setPvpMode(msg.readInt16("pvp mode"));
+ BLOCK_END("BeingNet::processPvpMapMode")
+}
+
+void BeingNet::processBeingMove3(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processBeingMove3")
+ if (!actorManager || !serverFeatures->haveMove3())
+ {
+ BLOCK_END("BeingNet::processBeingMove3")
+ return;
+ }
+
+ static const int16_t dirx[8] = {0, -1, -1, -1, 0, 1, 1, 1};
+ static const int16_t diry[8] = {1, 1, 0, -1, -1, -1, 0, 1};
+
+ const int len = msg.readInt16("len") - 14;
+ Being *const dstBeing = actorManager->findBeing(
+ msg.readBeingId("being id"));
+ if (!dstBeing)
+ {
+ BLOCK_END("BeingNet::processBeingMove3")
+ return;
+ }
+ const int16_t speed = msg.readInt16("speed");
+ dstBeing->setWalkSpeed(Vector(speed, speed, 0));
+ int16_t x = msg.readInt16("x");
+ int16_t y = msg.readInt16("y");
+ const unsigned char *moves = msg.readBytes(len, "moving path");
+ Path path;
+ if (moves)
+ {
+ for (int f = 0; f < len; f ++)
+ {
+ const unsigned char dir = moves[f];
+ if (dir <= 7)
+ {
+ x += dirx[dir];
+ y += diry[dir];
+ path.push_back(Position(x, y));
+ }
+ else
+ {
+ logger->log("bad move packet: %d", dir);
+ }
+ }
+ delete [] moves;
+ }
+ dstBeing->setPath(path);
+ BLOCK_END("BeingNet::processBeingMove3")
+}
+
+Being *BeingNet::createBeing(const BeingId id,
+ const int job)
+{
+ if (!actorManager)
+ return nullptr;
+
+ ActorTypeT type = ActorType::Unknown;
+ if (job <= 25 || (job >= 4001 && job <= 4049))
+ type = ActorType::Player;
+ else if (job >= 46 && job <= 1000)
+ type = ActorType::Npc;
+ else if (job > 1000 && job <= 2000)
+ type = ActorType::Monster;
+ else if (job == 45)
+ type = ActorType::Portal;
+
+ Being *const being = actorManager->createBeing(
+ id, type, fromInt(job, BeingTypeId));
+ return being;
+}
+
+void BeingNet::setSprite(Being *const being,
+ const unsigned int slot,
+ const int id,
+ const std::string &color,
+ const ItemColor colorId,
+ const bool isWeapon,
+ const bool isTempSprite)
+{
+ if (!being)
+ return;
+ being->updateSprite(slot, id, color, colorId, isWeapon, isTempSprite);
+}
+
+} // namespace Ea
diff --git a/src/net/ea/beingnet.h b/src/net/ea/beingnet.h
new file mode 100644
index 000000000..c32a49b9f
--- /dev/null
+++ b/src/net/ea/beingnet.h
@@ -0,0 +1,59 @@
+/*
+ * The ManaPlus Client
+ * Copyright (C) 2004-2009 The Mana World Development Team
+ * Copyright (C) 2009-2010 The Mana Developers
+ * Copyright (C) 2011-2015 The ManaPlus Developers
+ *
+ * This file is part of The ManaPlus Client.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NET_EA_BEING_H
+#define NET_EA_BEING_H
+
+#include "net/beinghandler.h"
+
+namespace Ea
+{
+ namespace BeingNet
+ {
+ extern bool mSync;
+ extern BeingId mSpawnId;
+
+ void processBeingRemove(Net::MessageIn &msg);
+ void processSkillDamage(Net::MessageIn &msg);
+ void processBeingAction(Net::MessageIn &msg);
+ void processBeingEmotion(Net::MessageIn &msg);
+ void processNameResponse(Net::MessageIn &msg);
+ void processPlayerStop(Net::MessageIn &msg);
+ void processPlayerMoveToAttack(Net::MessageIn &msg);
+ void processSkillNoDamage(Net::MessageIn &msg);
+ void processPvpMapMode(Net::MessageIn &msg);
+ void processBeingMove3(Net::MessageIn &msg);
+ Being *createBeing(const BeingId id,
+ const int job);
+ void setSprite(Being *const being, const unsigned int slot,
+ const int id,
+ const std::string &color = "",
+ const ItemColor colorId = ItemColor_one,
+ const bool isWeapon = false,
+ const bool isTempSprite = false);
+ } // namespace Being
+
+} // namespace Ea
+
+//extern bool Ea::BeingNet::mSync;
+
+#endif // NET_EA_BEING_H
diff --git a/src/net/eathena/beinghandler.cpp b/src/net/eathena/beinghandler.cpp
index 95800dc0d..11a1ced05 100644
--- a/src/net/eathena/beinghandler.cpp
+++ b/src/net/eathena/beinghandler.cpp
@@ -49,6 +49,9 @@
#include "net/character.h"
+#include "net/ea/beingnet.h"
+
+#include "net/eathena/beingnet.h"
#include "net/eathena/maptypeproperty2.h"
#include "net/eathena/messageout.h"
#include "net/eathena/protocol.h"
@@ -158,126 +161,126 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
switch (msg.getId())
{
case SMSG_BEING_VISIBLE:
- processBeingVisible(msg);
+ BeingNet::processBeingVisible(msg);
break;
case SMSG_BEING_MOVE:
- processBeingMove(msg);
+ BeingNet::processBeingMove(msg);
break;
case SMSG_BEING_SPAWN:
- processBeingSpawn(msg);
+ BeingNet::processBeingSpawn(msg);
break;
case SMSG_BEING_MOVE2:
- processBeingMove2(msg);
+ BeingNet::processBeingMove2(msg);
break;
case SMSG_BEING_REMOVE:
- processBeingRemove(msg);
+ Ea::BeingNet::processBeingRemove(msg);
break;
case SMSG_BEING_REMOVE_SKILL:
- processBeingRemoveSkil(msg);
+ BeingNet::processBeingRemoveSkil(msg);
break;
case SMSG_BEING_RESURRECT:
- processBeingResurrect(msg);
+ BeingNet::processBeingResurrect(msg);
break;
case SMSG_SKILL_DAMAGE:
- processSkillDamage(msg);
+ Ea::BeingNet::processSkillDamage(msg);
break;
case SMSG_SKILL_AUTO_CAST:
- processSkillAutoCast(msg);
+ BeingNet::processSkillAutoCast(msg);
break;
case SMSG_BEING_ACTION:
- processBeingAction(msg);
+ Ea::BeingNet::processBeingAction(msg);
break;
case SMSG_BEING_ACTION2:
- processBeingAction2(msg);
+ BeingNet::processBeingAction2(msg);
break;
case SMSG_BEING_SELFEFFECT:
- processBeingSelfEffect(msg);
+ BeingNet::processBeingSelfEffect(msg);
break;
case SMSG_BEING_SPECIAL_EFFECT:
- processBeingSpecialEffect(msg);
+ BeingNet::processBeingSpecialEffect(msg);
break;
case SMSG_BEING_SPECIAL_EFFECT_NUM:
- processBeingSpecialEffectNum(msg);
+ BeingNet::processBeingSpecialEffectNum(msg);
break;
case SMSG_BEING_SOUND_EFFECT:
- processBeingSoundEffect(msg);
+ BeingNet::processBeingSoundEffect(msg);
break;
case SMSG_BEING_EMOTION:
- processBeingEmotion(msg);
+ Ea::BeingNet::processBeingEmotion(msg);
break;
case SMSG_BEING_CHANGE_LOOKS2:
- processBeingChangeLook2(msg);
+ BeingNet::processBeingChangeLook2(msg);
break;
case SMSG_BEING_CHANGE_LOOKS_CARDS:
- processBeingChangeLookCards(msg);
+ BeingNet::processBeingChangeLookCards(msg);
break;
case SMSG_BEING_NAME_RESPONSE:
- processNameResponse(msg);
+ Ea::BeingNet::processNameResponse(msg);
break;
case SMSG_BEING_NAME_RESPONSE2:
- processNameResponse2(msg);
+ BeingNet::processNameResponse2(msg);
break;
case SMSG_SOLVE_CHAR_NAME:
break;
case SMSG_PLAYER_GUILD_PARTY_INFO:
- processPlayerGuilPartyInfo(msg);
+ BeingNet::processPlayerGuilPartyInfo(msg);
break;
case SMSG_BEING_CHANGE_DIRECTION:
- processBeingChangeDirection(msg);
+ BeingNet::processBeingChangeDirection(msg);
break;
case SMSG_PLAYER_STOP:
- processPlayerStop(msg);
+ Ea::BeingNet::processPlayerStop(msg);
break;
case SMSG_PLAYER_MOVE_TO_ATTACK:
- processPlayerMoveToAttack(msg);
+ Ea::BeingNet::processPlayerMoveToAttack(msg);
break;
case SMSG_PLAYER_STATUS_CHANGE:
- processPlaterStatusChange(msg);
+ BeingNet::processPlaterStatusChange(msg);
break;
case SMSG_PLAYER_STATUS_CHANGE2:
- processPlaterStatusChange2(msg);
+ BeingNet::processPlaterStatusChange2(msg);
break;
case SMSG_PLAYER_STATUS_CHANGE_NO_TICK:
- processPlaterStatusChangeNoTick(msg);
+ BeingNet::processPlaterStatusChangeNoTick(msg);
break;
case SMSG_BEING_STATUS_CHANGE:
- processBeingStatusChange(msg);
+ BeingNet::processBeingStatusChange(msg);
break;
case SMSG_BEING_STATUS_CHANGE2:
- processBeingStatusChange2(msg);
+ BeingNet::processBeingStatusChange2(msg);
break;
case SMSG_SKILL_CASTING:
- processSkillCasting(msg);
+ BeingNet::processSkillCasting(msg);
break;
case SMSG_SKILL_CAST_CANCEL:
@@ -285,136 +288,136 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
break;
case SMSG_SKILL_NO_DAMAGE:
- processSkillNoDamage(msg);
+ Ea::BeingNet::processSkillNoDamage(msg);
break;
case SMSG_SKILL_GROUND_NO_DAMAGE:
- processSkillGroundNoDamage(msg);
+ BeingNet::processSkillGroundNoDamage(msg);
break;
case SMSG_SKILL_ENTRY:
- processSkillEntry(msg);
+ BeingNet::processSkillEntry(msg);
break;
case SMSG_PVP_MAP_MODE:
- processPvpMapMode(msg);
+ Ea::BeingNet::processPvpMapMode(msg);
break;
case SMSG_PVP_SET:
- processPvpSet(msg);
+ BeingNet::processPvpSet(msg);
break;
case SMSG_MAP_TYPE_PROPERTY2:
- processMapTypeProperty(msg);
+ BeingNet::processMapTypeProperty(msg);
break;
case SMSG_MAP_TYPE:
- processMapType(msg);
+ BeingNet::processMapType(msg);
break;
case SMSG_MONSTER_HP:
case SMSG_PLAYER_HP:
- processMonsterHp(msg);
+ BeingNet::processMonsterHp(msg);
break;
case SMSG_RANKS_LIST:
- processRanksList(msg);
+ BeingNet::processRanksList(msg);
break;
case SMSG_BEING_FAKE_NAME:
- processBeingFakeName(msg);
+ BeingNet::processBeingFakeName(msg);
break;
case SMSG_BEING_STAT_UPDATE_1:
- processBeingStatUpdate1(msg);
+ BeingNet::processBeingStatUpdate1(msg);
break;
case SMSG_MOB_INFO:
- processMobInfo(msg);
+ BeingNet::processMobInfo(msg);
break;
case SMSG_BEING_MOVE3:
- processBeingMove3(msg);
+ Ea::BeingNet::processBeingMove3(msg);
break;
case SMSG_BEING_ATTRS:
- processBeingAttrs(msg);
+ BeingNet::processBeingAttrs(msg);
break;
case SMSG_MONSTER_INFO:
- processMonsterInfo(msg);
+ BeingNet::processMonsterInfo(msg);
break;
case SMSG_CLASS_CHANGE:
- processClassChange(msg);
+ BeingNet::processClassChange(msg);
break;
case SMSG_SPIRIT_BALLS:
- processSpiritBalls(msg);
+ BeingNet::processSpiritBalls(msg);
break;
case SMSG_SPIRIT_BALL_SINGLE:
- processSpiritBallSingle(msg);
+ BeingNet::processSpiritBallSingle(msg);
break;
case SMSG_BLADE_STOP:
- processBladeStop(msg);
+ BeingNet::processBladeStop(msg);
break;
case SMSG_COMBO_DELAY:
- processComboDelay(msg);
+ BeingNet::processComboDelay(msg);
break;
case SMSG_WEDDING_EFFECT:
- processWddingEffect(msg);
+ BeingNet::processWddingEffect(msg);
break;
case SMSG_BEING_SLIDE:
- processBeingSlide(msg);
+ BeingNet::processBeingSlide(msg);
break;
case SMSG_STARS_KILL:
- processStarsKill(msg);
+ BeingNet::processStarsKill(msg);
break;
case SMSG_BLACKSMITH_RANKS_LIST:
- processBlacksmithRanksList(msg);
+ BeingNet::processBlacksmithRanksList(msg);
break;
case SMSG_ALCHEMIST_RANKS_LIST:
- processAlchemistRanksList(msg);
+ BeingNet::processAlchemistRanksList(msg);
break;
case SMSG_TAEKWON_RANKS_LIST:
- processTaekwonRanksList(msg);
+ BeingNet::processTaekwonRanksList(msg);
break;
case SMSG_PK_RANKS_LIST:
- processPkRanksList(msg);
+ BeingNet::processPkRanksList(msg);
break;
case SMSG_GLADIATOR_FEEL_REQUEST:
- processGladiatorFeelRequest(msg);
+ BeingNet::processGladiatorFeelRequest(msg);
break;
case SMSG_BOSS_MAP_INFO:
- processBossMapInfo(msg);
+ BeingNet::processBossMapInfo(msg);
break;
case SMSG_BEING_FONT:
- processBeingFont(msg);
+ BeingNet::processBeingFont(msg);
break;
case SMSG_BEING_MILLENIUM_SHIELD:
- processBeingMilleniumShield(msg);
+ BeingNet::processBeingMilleniumShield(msg);
break;
case SMSG_BEING_CHARM:
- processBeingCharm(msg);
+ BeingNet::processBeingCharm(msg);
break;
case SMSG_BEING_VIEW_EQUIPMENT:
- processBeingViewEquipment(msg);
+ BeingNet::processBeingViewEquipment(msg);
break;
default:
@@ -422,69 +425,6 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
}
}
-Being *BeingHandler::createBeing2(Net::MessageIn &msg,
- const BeingId id,
- const int16_t job,
- const BeingType::BeingType beingType)
-{
- if (!actorManager)
- return nullptr;
-
- ActorTypeT type = ActorType::Unknown;
- switch (beingType)
- {
- case BeingType::PC:
- type = ActorType::Player;
- break;
- case BeingType::NPC:
- case BeingType::NPC_EVENT:
- type = ActorType::Npc;
- break;
- case BeingType::MONSTER:
- type = ActorType::Monster;
- break;
- case BeingType::MERSOL:
- type = ActorType::Mercenary;
- break;
- case BeingType::PET:
- type = ActorType::Pet;
- break;
- case BeingType::HOMUN:
- type = ActorType::Homunculus;
- break;
- case BeingType::ITEM:
- case BeingType::SKILL:
- case BeingType::ELEMENTAL:
- logger->log("not supported object type: %d, job: %d",
- static_cast<int>(beingType), static_cast<int>(job));
- break;
- case BeingType::CHAT:
- default:
- UNIMPLIMENTEDPACKET;
- type = ActorType::Monster;
- logger->log("not supported object type: %d, job: %d",
- static_cast<int>(beingType), static_cast<int>(job));
- break;
- }
- if (job == 45 && beingType == BeingType::NPC_EVENT)
- type = ActorType::Portal;
-
- Being *const being = actorManager->createBeing(
- id, type, fromInt(job, BeingTypeId));
- if (beingType == BeingType::MERSOL)
- {
- MercenaryInfo *const info = PlayerInfo::getMercenary();
- if (info && info->id == id)
- PlayerInfo::setMercenaryBeing(being);
- }
- else if (beingType == BeingType::PET)
- {
- if (PlayerInfo::getPetBeingId() == id)
- PlayerInfo::setPetBeing(being);
- }
- return being;
-}
-
void BeingHandler::undress(Being *const being) const
{
if (!being)
@@ -503,1074 +443,6 @@ void BeingHandler::requestRanks(const RankT rank) const
outMsg.writeInt16(static_cast<int16_t>(rank), "type");
}
-void BeingHandler::processBeingChangeLook2(Net::MessageIn &msg)
-{
- if (!actorManager)
- return;
-
- Being *const dstBeing = actorManager->findBeing(
- msg.readBeingId("being id"));
- const uint8_t type = msg.readUInt8("type");
-
- const int id = msg.readInt16("id1");
- unsigned int id2 = msg.readInt16("id2");
- if (type != 2)
- id2 = 1;
-
- if (!localPlayer || !dstBeing)
- return;
-
- processBeingChangeLookContinue(msg, dstBeing, type, id, id2, nullptr);
-}
-
-void BeingHandler::processBeingChangeLookCards(Net::MessageIn &msg)
-{
- Being *dstBeing = nullptr;
- int cards[4];
-
- if (!actorManager)
- { // here can be look from char server
- if (!serverFeatures->haveAdvancedSprites())
- return;
- Net::Characters &chars = Net::CharServerHandler::mCharacters;
- const BeingId id = msg.readBeingId("being id");
-
- FOR_EACH (Net::Characters::iterator, it, chars)
- {
- Net::Character *character = *it;
- if (character->dummy && character->dummy->getId() == id)
- {
- dstBeing = character->dummy;
- break;
- }
- }
- }
- else
- {
- dstBeing = actorManager->findBeing(
- msg.readBeingId("being id"));
- }
-
- const uint8_t type = msg.readUInt8("type");
-
- const int id = msg.readInt16("id1");
- unsigned int id2 = msg.readInt16("id2");
- if (type != 2)
- id2 = 1;
-
- for (int f = 0; f < 4; f ++)
- cards[f] = msg.readInt16("card");
-
- if (!dstBeing)
- return;
-
- processBeingChangeLookContinue(msg, dstBeing, type, id, id2, &cards[0]);
-}
-
-void BeingHandler::processBeingChangeLookContinue(Net::MessageIn &msg,
- Being *const dstBeing,
- const uint8_t type,
- const int id,
- const int id2,
- const int *cards
- A_UNUSED)
-{
- if (dstBeing->getType() == ActorType::Player)
- dstBeing->setOtherTime();
-
- const ItemColor itemColor = ItemColorManager::getColorFromCards(cards);
- const std::string color;
- switch (type)
- {
- case 0: // change race
- dstBeing->setSubtype(fromInt(id, BeingTypeId),
- dstBeing->getLook());
- break;
- case 1: // eAthena LOOK_HAIR
- dstBeing->setHairColor(fromInt(id, ItemColor));
- dstBeing->setSpriteID(SPRITE_HAIR_COLOR, id * -1);
- break;
- case 2: // LOOK_WEAPON Weapon ID in id, Shield ID in id2
- dstBeing->setSprite(SPRITE_BODY, id, "", itemColor, true);
- dstBeing->setSprite(SPRITE_FLOOR, id2);
- if (localPlayer)
- localPlayer->imitateOutfit(dstBeing, SPRITE_FLOOR);
- break;
- case 3: // LOOK_HEAD_BOTTOM
- dstBeing->setSprite(SPRITE_WEAPON, id, color, itemColor);
- if (localPlayer)
- localPlayer->imitateOutfit(dstBeing, SPRITE_WEAPON);
- break;
- case 4: // LOOK_HEAD_TOP Change upper headgear for eAthena, hat for us
- dstBeing->setSprite(SPRITE_CLOTHES_COLOR, id, color, itemColor);
- if (localPlayer)
- localPlayer->imitateOutfit(dstBeing, SPRITE_CLOTHES_COLOR);
- break;
- case 5: // LOOK_HEAD_MID Change middle headgear for eathena,
- // armor for us
- dstBeing->setSprite(SPRITE_HEAD_BOTTOM, id, color, itemColor);
- if (localPlayer)
- localPlayer->imitateOutfit(dstBeing, SPRITE_HEAD_BOTTOM);
- break;
- case 6: // eAthena LOOK_HAIR_COLOR
- dstBeing->setHairColor(fromInt(id, ItemColor));
- dstBeing->setSpriteColor(SPRITE_HAIR_COLOR,
- ItemDB::get(dstBeing->getSpriteID(
- SPRITE_HAIR_COLOR)).getDyeColorsString(
- fromInt(id, ItemColor)));
- break;
- case 7: // Clothes color. Now used as look
- dstBeing->setLook(static_cast<uint8_t>(id));
- break;
- case 8: // eAthena LOOK_SHIELD
- dstBeing->setSprite(SPRITE_FLOOR, id, color, itemColor);
- if (localPlayer)
- localPlayer->imitateOutfit(dstBeing, SPRITE_FLOOR);
- break;
- case 9: // eAthena LOOK_SHOES
- dstBeing->setSprite(SPRITE_HAIR, id, color, itemColor);
- if (localPlayer)
- localPlayer->imitateOutfit(dstBeing, SPRITE_HAIR);
- break;
- case 10: // LOOK_GLOVES
- dstBeing->setSprite(SPRITE_SHOES, id, color, itemColor);
- if (localPlayer)
- localPlayer->imitateOutfit(dstBeing, SPRITE_SHOES);
- break;
- case 11: // LOOK_FLOOR
- dstBeing->setSprite(SPRITE_SHIELD, id, color, itemColor);
- if (localPlayer)
- localPlayer->imitateOutfit(dstBeing, SPRITE_SHIELD);
- break;
- case 12: // LOOK_ROBE
- dstBeing->setSprite(SPRITE_HEAD_TOP, id, color, itemColor);
- if (localPlayer)
- localPlayer->imitateOutfit(dstBeing, SPRITE_HEAD_TOP);
- break;
- case 13: // COSTUME_HEAD_TOP
- dstBeing->setSprite(SPRITE_HEAD_MID, id, color, itemColor);
- if (localPlayer)
- localPlayer->imitateOutfit(dstBeing, SPRITE_HEAD_MID);
- break;
- case 14: // COSTUME_HEAD_MID
- dstBeing->setSprite(SPRITE_ROBE, id, color, itemColor);
- if (localPlayer)
- localPlayer->imitateOutfit(dstBeing, SPRITE_ROBE);
- break;
- case 15: // COSTUME_HEAD_LOW
- dstBeing->setSprite(SPRITE_EVOL2, id, color, itemColor);
- if (localPlayer)
- localPlayer->imitateOutfit(dstBeing, SPRITE_EVOL2);
- break;
- case 16: // COSTUME_GARMENT
- dstBeing->setSprite(SPRITE_EVOL3, id, color, itemColor);
- if (localPlayer)
- localPlayer->imitateOutfit(dstBeing, SPRITE_EVOL3);
- break;
- case 17: // ARMOR
- dstBeing->setSprite(SPRITE_EVOL4, id, color, itemColor);
- if (localPlayer)
- localPlayer->imitateOutfit(dstBeing, SPRITE_EVOL4);
- break;
- default:
- UNIMPLIMENTEDPACKET;
- break;
- }
-}
-
-void BeingHandler::processBeingVisible(Net::MessageIn &msg)
-{
- if (!actorManager)
- return;
-
- msg.readInt16("len");
- const BeingType::BeingType type = static_cast<BeingType::BeingType>(
- msg.readUInt8("object type"));
-
- // Information about a being in range
- const BeingId id = msg.readBeingId("being id");
- BeingId spawnId;
- if (id == mSpawnId)
- spawnId = mSpawnId;
- else
- spawnId = BeingId_zero;
- mSpawnId = BeingId_zero;
-
- int16_t speed = msg.readInt16("speed");
- const uint16_t stunMode = msg.readInt16("opt1");
- // probably wrong effect usage
- const uint32_t statusEffects = msg.readInt16("opt2");
- msg.readInt32("option");
-
- const int16_t job = msg.readInt16("class");
-
- Being *dstBeing = actorManager->findBeing(id);
-
- if (dstBeing && dstBeing->getType() == ActorType::Monster
- && !dstBeing->isAlive())
- {
- actorManager->destroy(dstBeing);
- actorManager->erase(dstBeing);
- dstBeing = nullptr;
- }
-
- if (!dstBeing)
- {
- if (actorManager->isBlocked(id) == true)
- return;
-
- dstBeing = createBeing2(msg, id, job, type);
- if (!dstBeing)
- return;
- }
- else
- {
- // undeleting marked for deletion being
- if (dstBeing->getType() == ActorType::Npc)
- actorManager->undelete(dstBeing);
- }
-
- if (dstBeing->getType() == ActorType::Player)
- dstBeing->setMoveTime();
-
- if (spawnId != BeingId_zero)
- {
- dstBeing->setAction(BeingAction::SPAWN, 0);
- }
- else
- {
- dstBeing->clearPath();
- dstBeing->setActionTime(tick_time);
- dstBeing->setAction(BeingAction::STAND, 0);
- }
-
- // Prevent division by 0 when calculating frame
- if (speed == 0)
- speed = 150;
-
- dstBeing->setWalkSpeed(Vector(speed, speed, 0));
- dstBeing->setSubtype(fromInt(job, BeingTypeId), 0);
- if (dstBeing->getType() == ActorType::Monster && localPlayer)
- localPlayer->checkNewName(dstBeing);
-
- const int hairStyle = msg.readInt16("hair style");
- const uint32_t weapon = static_cast<uint32_t>(msg.readInt32("weapon"));
- const uint16_t headBottom = msg.readInt16("head bottom");
-
- const uint16_t headTop = msg.readInt16("head top");
- const uint16_t headMid = msg.readInt16("head mid");
- const ItemColor hairColor = fromInt(msg.readInt16("hair color"), ItemColor);
- const uint16_t shoes = msg.readInt16("shoes or clothes color?");
-
- const uint16_t gloves = msg.readInt16("head dir / gloves");
- // may be use robe as gloves?
- msg.readInt16("robe");
- msg.readInt32("guild id");
- msg.readInt16("guild emblem");
- dstBeing->setManner(msg.readInt16("manner"));
- dstBeing->setStatusEffectBlock(32, static_cast<uint16_t>(
- msg.readInt32("opt3")));
- dstBeing->setKarma(msg.readUInt8("karma"));
- uint8_t gender = static_cast<uint8_t>(msg.readUInt8("gender") & 3);
-
- if (dstBeing->getType() == ActorType::Player)
- {
- dstBeing->setGender(Being::intToGender(gender));
- dstBeing->setHairColor(hairColor);
- // Set these after the gender, as the sprites may be gender-specific
- setSprite(dstBeing, SPRITE_HAIR_COLOR, hairStyle * -1,
- ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
- setSprite(dstBeing, SPRITE_WEAPON, headBottom);
- setSprite(dstBeing, SPRITE_HEAD_BOTTOM, headMid);
- setSprite(dstBeing, SPRITE_CLOTHES_COLOR, headTop);
- setSprite(dstBeing, SPRITE_HAIR, shoes);
- setSprite(dstBeing, SPRITE_SHOES, gloves);
- setSprite(dstBeing, SPRITE_BODY, weapon, "", ItemColor_one, true);
-// setSprite(dstBeing, SPRITE_FLOOR, shield);
- }
- else if (dstBeing->getType() == ActorType::Npc
- && serverFeatures->haveNpcGender())
- {
- dstBeing->setGender(Being::intToGender(gender));
- }
-
- uint8_t dir;
- uint16_t x, y;
- msg.readCoordinates(x, y, dir, "position");
- msg.readInt8("xs");
- msg.readInt8("ys");
- msg.readUInt8("action type");
- dstBeing->setTileCoords(x, y);
-
- if (job == 45 && socialWindow && outfitWindow)
- {
- const int num = socialWindow->getPortalIndex(x, y);
- if (num >= 0)
- {
- dstBeing->setName(keyboard.getKeyShortString(
- outfitWindow->keyName(num)));
- }
- else
- {
- dstBeing->setName("");
- }
- }
-
- dstBeing->setDirection(dir);
-
- const int level = static_cast<int>(msg.readInt16("level"));
- if (level)
- dstBeing->setLevel(level);
- msg.readInt16("font");
-
- const int maxHP = msg.readInt32("max hp");
- const int hp = msg.readInt32("hp");
- dstBeing->setMaxHP(maxHP);
- dstBeing->setHP(hp);
-
- msg.readInt8("is boss");
-
- dstBeing->setStunMode(stunMode);
- dstBeing->setStatusEffectBlock(0, static_cast<uint16_t>(
- (statusEffects >> 16) & 0xffffU));
- dstBeing->setStatusEffectBlock(16, static_cast<uint16_t>(
- statusEffects & 0xffffU));
-}
-
-void BeingHandler::processBeingMove(Net::MessageIn &msg)
-{
- if (!actorManager)
- return;
-
- msg.readInt16("len");
- const BeingType::BeingType type = static_cast<BeingType::BeingType>(
- msg.readUInt8("object type"));
-
- // Information about a being in range
- const BeingId id = msg.readBeingId("being id");
- BeingId spawnId;
- if (id == mSpawnId)
- spawnId = mSpawnId;
- else
- spawnId = BeingId_zero;
- mSpawnId = BeingId_zero;
- int16_t speed = msg.readInt16("speed");
-// if (visible)
-// {
- const uint16_t stunMode = msg.readInt16("opt1");
- // probably wrong effect usage
- const uint32_t statusEffects = msg.readInt16("opt2");
-// }
-// else
-// {
-// commented for now, probably it can be removed after testing
-// msg.readInt16("body state");
-// msg.readInt16("health state");
-// }
- msg.readInt32("effect state");
-
- const int16_t job = msg.readInt16("class");
-
- Being *dstBeing = actorManager->findBeing(id);
-
- if (dstBeing && dstBeing->getType() == ActorType::Monster
- && !dstBeing->isAlive())
- {
- actorManager->destroy(dstBeing);
- actorManager->erase(dstBeing);
- dstBeing = nullptr;
- }
-
- if (!dstBeing)
- {
- if (actorManager->isBlocked(id) == true)
- return;
-
- dstBeing = createBeing2(msg, id, job, type);
- if (!dstBeing)
- return;
- }
- else
- {
- // undeleting marked for deletion being
- if (dstBeing->getType() == ActorType::Npc)
- actorManager->undelete(dstBeing);
- }
-
- if (dstBeing->getType() == ActorType::Player)
- dstBeing->setMoveTime();
-
- if (spawnId != BeingId_zero)
- dstBeing->setAction(BeingAction::SPAWN, 0);
-
- // Prevent division by 0 when calculating frame
- if (speed == 0)
- speed = 150;
-
- dstBeing->setWalkSpeed(Vector(speed, speed, 0));
- dstBeing->setSubtype(fromInt(job, BeingTypeId), 0);
- if (dstBeing->getType() == ActorType::Monster && localPlayer)
- localPlayer->checkNewName(dstBeing);
-
- const int hairStyle = msg.readInt16("hair style");
- const uint32_t weapon = static_cast<uint32_t>(msg.readInt32("weapon"));
- const uint16_t headBottom = msg.readInt16("head bottom");
-
- msg.readInt32("tick");
-
- const uint16_t headTop = msg.readInt16("head top");
- const uint16_t headMid = msg.readInt16("head mid");
- const ItemColor hairColor = fromInt(
- msg.readInt16("hair color"), ItemColor);
- const uint16_t shoes = msg.readInt16("shoes or clothes color?");
-
- const uint16_t gloves = msg.readInt16("head dir / gloves");
- // may be use robe as gloves?
- msg.readInt16("robe");
- msg.readInt32("guild id");
- msg.readInt16("guild emblem");
- dstBeing->setManner(msg.readInt16("manner"));
- dstBeing->setStatusEffectBlock(32, static_cast<uint16_t>(
- msg.readInt32("opt3")));
- dstBeing->setKarma(msg.readUInt8("karma"));
- uint8_t gender = static_cast<uint8_t>(msg.readUInt8("gender") & 3);
-
- if (dstBeing->getType() == ActorType::Player)
- {
- dstBeing->setGender(Being::intToGender(gender));
- dstBeing->setHairColor(hairColor);
- // Set these after the gender, as the sprites may be gender-specific
- setSprite(dstBeing, SPRITE_HAIR_COLOR, hairStyle * -1,
- ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
- if (!serverFeatures->haveMove3())
- {
- setSprite(dstBeing, SPRITE_WEAPON, headBottom);
- setSprite(dstBeing, SPRITE_HEAD_BOTTOM, headMid);
- setSprite(dstBeing, SPRITE_CLOTHES_COLOR, headTop);
- setSprite(dstBeing, SPRITE_HAIR, shoes);
- setSprite(dstBeing, SPRITE_SHOES, gloves);
- setSprite(dstBeing, SPRITE_BODY, weapon, "", ItemColor_one, true);
- }
-// setSprite(dstBeing, SPRITE_FLOOR, shield);
- }
- else if (dstBeing->getType() == ActorType::Npc
- && serverFeatures->haveNpcGender())
- {
- dstBeing->setGender(Being::intToGender(gender));
- }
-
- uint16_t srcX, srcY, dstX, dstY;
- msg.readCoordinatePair(srcX, srcY, dstX, dstY, "move path");
- msg.readUInt8("(sx<<4) | (sy&0x0f)");
- msg.readInt8("xs");
- msg.readInt8("ys");
- dstBeing->setAction(BeingAction::STAND, 0);
- dstBeing->setTileCoords(srcX, srcY);
- if (localPlayer)
- localPlayer->followMoveTo(dstBeing, srcX, srcY, dstX, dstY);
- if (!serverFeatures->haveMove3())
- dstBeing->setDestination(dstX, dstY);
-
- // because server don't send direction in move packet, we fixing it
-
- uint8_t d = 0;
- if (srcX == dstX && srcY == dstY)
- { // if player did one step from invisible area to visible,
- // move path is broken
- int x2 = localPlayer->getTileX();
- int y2 = localPlayer->getTileY();
- if (abs(x2 - srcX) > abs(y2 - srcY))
- y2 = srcY;
- else
- x2 = srcX;
- d = dstBeing->calcDirection(x2, y2);
- }
- else
- {
- d = dstBeing->calcDirection(dstX, dstY);
- }
- if (d && dstBeing->getDirection() != d)
- dstBeing->setDirection(d);
-
- const int level = static_cast<int>(msg.readInt16("level"));
- if (level)
- dstBeing->setLevel(level);
- msg.readInt16("font");
-
- const int maxHP = msg.readInt32("max hp");
- const int hp = msg.readInt32("hp");
- dstBeing->setMaxHP(maxHP);
- dstBeing->setHP(hp);
-
- msg.readInt8("is boss");
-
- dstBeing->setStunMode(stunMode);
- dstBeing->setStatusEffectBlock(0, static_cast<uint16_t>(
- (statusEffects >> 16) & 0xffffU));
- dstBeing->setStatusEffectBlock(16, static_cast<uint16_t>(
- statusEffects & 0xffffU));
-}
-
-void BeingHandler::processBeingSpawn(Net::MessageIn &msg)
-{
- if (!actorManager)
- return;
-
- msg.readInt16("len");
- const BeingType::BeingType type = static_cast<BeingType::BeingType>(
- msg.readUInt8("object type"));
-
- // Information about a being in range
- const BeingId id = msg.readBeingId("being id");
- mSpawnId = id;
- const BeingId spawnId = id;
- int16_t speed = msg.readInt16("speed");
-// if (visible)
-// {
- const uint16_t stunMode = msg.readInt16("opt1");
- // probably wrong effect usage
- const uint32_t statusEffects = msg.readInt16("opt2");
-// }
-// else
-// {
-// commented for now, probably it can be removed after testing
-// msg.readInt16("body state");
-// msg.readInt16("health state");
-// }
- msg.readInt32("effect state");
-
- const int16_t job = msg.readInt16("class");
-
- Being *dstBeing = actorManager->findBeing(id);
-
- if (dstBeing && dstBeing->getType() == ActorType::Monster
- && !dstBeing->isAlive())
- {
- actorManager->destroy(dstBeing);
- actorManager->erase(dstBeing);
- dstBeing = nullptr;
- }
-
- if (!dstBeing)
- {
- if (actorManager->isBlocked(id) == true)
- return;
-
- dstBeing = createBeing2(msg, id, job, type);
- if (!dstBeing)
- return;
- }
- else
- {
- // undeleting marked for deletion being
- if (dstBeing->getType() == ActorType::Npc)
- actorManager->undelete(dstBeing);
- }
-
- if (dstBeing->getType() == ActorType::Player)
- dstBeing->setMoveTime();
-
- if (spawnId != BeingId_zero)
- dstBeing->setAction(BeingAction::SPAWN, 0);
-
- // Prevent division by 0 when calculating frame
- if (speed == 0)
- speed = 150;
-
- dstBeing->setWalkSpeed(Vector(speed, speed, 0));
- dstBeing->setSubtype(fromInt(job, BeingTypeId), 0);
- if (dstBeing->getType() == ActorType::Monster && localPlayer)
- localPlayer->checkNewName(dstBeing);
-
- const int hairStyle = msg.readInt16("hair style");
- const uint32_t weapon = static_cast<uint32_t>(msg.readInt32("weapon"));
- const uint16_t headBottom = msg.readInt16("head bottom");
-
- const uint16_t headTop = msg.readInt16("head top");
- const uint16_t headMid = msg.readInt16("head mid");
- const ItemColor hairColor = fromInt(
- msg.readInt16("hair color"), ItemColor);
- const uint16_t shoes = msg.readInt16("shoes or clothes color?");
- const uint16_t gloves = msg.readInt16("head dir / gloves");
- // may be use robe as gloves?
- msg.readInt16("robe");
- msg.readInt32("guild id");
- msg.readInt16("guild emblem");
- dstBeing->setManner(msg.readInt16("manner"));
- dstBeing->setStatusEffectBlock(32, static_cast<uint16_t>(
- msg.readInt32("opt3")));
- dstBeing->setKarma(msg.readUInt8("karma"));
- uint8_t gender = static_cast<uint8_t>(msg.readUInt8("gender") & 3);
-
- if (dstBeing->getType() == ActorType::Player)
- {
- dstBeing->setGender(Being::intToGender(gender));
- dstBeing->setHairColor(hairColor);
- // Set these after the gender, as the sprites may be gender-specific
- setSprite(dstBeing, SPRITE_HAIR_COLOR, hairStyle * -1,
- ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
- setSprite(dstBeing, SPRITE_WEAPON, headBottom);
- setSprite(dstBeing, SPRITE_HEAD_BOTTOM, headMid);
- setSprite(dstBeing, SPRITE_CLOTHES_COLOR, headTop);
- setSprite(dstBeing, SPRITE_HAIR, shoes);
- setSprite(dstBeing, SPRITE_SHOES, gloves);
- setSprite(dstBeing, SPRITE_BODY, weapon, "", ItemColor_one, true);
-// setSprite(dstBeing, SPRITE_FLOOR, shield);
- }
- else if (dstBeing->getType() == ActorType::Npc
- && serverFeatures->haveNpcGender())
- {
- dstBeing->setGender(Being::intToGender(gender));
- }
-
- uint8_t dir;
- uint16_t x, y;
- msg.readCoordinates(x, y, dir, "position");
- msg.readInt8("xs");
- msg.readInt8("ys");
- dstBeing->setTileCoords(x, y);
-
- if (job == 45 && socialWindow && outfitWindow)
- {
- const int num = socialWindow->getPortalIndex(x, y);
- if (num >= 0)
- {
- dstBeing->setName(keyboard.getKeyShortString(
- outfitWindow->keyName(num)));
- }
- else
- {
- dstBeing->setName("");
- }
- }
-
- dstBeing->setDirection(dir);
-
- const int level = static_cast<int>(msg.readInt16("level"));
- if (level)
- dstBeing->setLevel(level);
- msg.readInt16("font");
-
- const int maxHP = msg.readInt32("max hp");
- const int hp = msg.readInt32("hp");
- dstBeing->setMaxHP(maxHP);
- dstBeing->setHP(hp);
-
- msg.readInt8("is boss");
-
- dstBeing->setStunMode(stunMode);
- dstBeing->setStatusEffectBlock(0, static_cast<uint16_t>(
- (statusEffects >> 16) & 0xffffU));
- dstBeing->setStatusEffectBlock(16, static_cast<uint16_t>(
- statusEffects & 0xffffU));
-}
-
-void BeingHandler::processMapTypeProperty(Net::MessageIn &msg)
-{
- const int16_t type = msg.readInt16("type");
- const int flags = msg.readInt32("flags");
- if (type == 0x28)
- {
- // +++ need get other flags from here
- MapTypeProperty2 props;
- props.data = static_cast<uint32_t>(flags);
- Game *const game = Game::instance();
- if (!game)
- return;
- Map *const map = game->getCurrentMap();
- if (!map)
- return;
- map->setPvpMode(props.bits.party | (props.bits.guild * 2));
- }
-}
-
-void BeingHandler::processMapType(Net::MessageIn &msg)
-{
- const int16_t type = msg.readInt16("type");
- if (type == 19)
- NotifyManager::notify(NotifyTypes::MAP_TYPE_BATTLEFIELD);
- else
- UNIMPLIMENTEDPACKET;
-}
-
-void BeingHandler::processSkillCasting(Net::MessageIn &msg)
-{
- // +++ need use other parameters
-
- const BeingId srcId = msg.readBeingId("src id");
- const BeingId dstId = msg.readBeingId("dst id");
- const int dstX = msg.readInt16("dst x");
- const int dstY = msg.readInt16("dst y");
- const int skillId = msg.readInt16("skill id");
- msg.readInt32("property"); // can be used to trigger effect
- msg.readInt32("cast time");
- msg.readInt8("dispossable");
-
- if (!effectManager)
- return;
-
- if (srcId == BeingId_zero)
- {
- UNIMPLIMENTEDPACKET;
- return;
- }
- else if (dstId != BeingId_zero)
- { // being to being
- Being *const srcBeing = actorManager->findBeing(srcId);
- Being *const dstBeing = actorManager->findBeing(dstId);
- skillDialog->playCastingSrcEffect(skillId, srcBeing);
- skillDialog->playCastingDstEffect(skillId, dstBeing);
- }
- else if (dstX != 0 || dstY != 0)
- { // being to position
- UNIMPLIMENTEDPACKET;
- }
-}
-
-void BeingHandler::processBeingStatusChange(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processBeingStatusChange")
- if (!actorManager)
- {
- BLOCK_END("BeingHandler::processBeingStatusChange")
- return;
- }
-
- // Status change
- const uint16_t status = msg.readInt16("status");
- const BeingId id = msg.readBeingId("being id");
- const Enable flag = fromBool(
- msg.readUInt8("flag: 0: stop, 1: start"), Enable);
- msg.readInt32("total");
- msg.readInt32("left");
- msg.readInt32("val1");
- msg.readInt32("val2");
- msg.readInt32("val3");
-
- Being *const dstBeing = actorManager->findBeing(id);
- if (dstBeing)
- dstBeing->setStatusEffect(status, flag);
- BLOCK_END("BeingHandler::processBeingStatusChange")
-}
-
-void BeingHandler::processBeingStatusChange2(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processBeingStatusChange")
- if (!actorManager)
- {
- BLOCK_END("BeingHandler::processBeingStatusChange")
- return;
- }
-
- // Status change
- const uint16_t status = msg.readInt16("status");
- const BeingId id = msg.readBeingId("being id");
- const Enable flag = fromBool(
- msg.readUInt8("flag: 0: stop, 1: start"), Enable);
- msg.readInt32("left");
- msg.readInt32("val1");
- msg.readInt32("val2");
- msg.readInt32("val3");
-
- Being *const dstBeing = actorManager->findBeing(id);
- if (dstBeing)
- dstBeing->setStatusEffect(status, flag);
- BLOCK_END("BeingHandler::processBeingStatusChange")
-}
-
-void BeingHandler::processBeingMove2(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processBeingMove2")
- if (!actorManager)
- {
- BLOCK_END("BeingHandler::processBeingMove2")
- return;
- }
-
- /*
- * A simplified movement packet, used by the
- * later versions of eAthena for both mobs and
- * players
- */
- Being *const dstBeing = actorManager->findBeing(
- msg.readBeingId("being id"));
-
- uint16_t srcX, srcY, dstX, dstY;
- msg.readCoordinatePair(srcX, srcY, dstX, dstY, "move path");
- msg.readUInt8("(sx<<4) | (sy&0x0f)");
- msg.readInt32("tick");
-
- /*
- * This packet doesn't have enough info to actually
- * create a new being, so if the being isn't found,
- * we'll just pretend the packet didn't happen
- */
-
- if (!dstBeing)
- {
- BLOCK_END("BeingHandler::processBeingMove2")
- return;
- }
-
- dstBeing->setTileCoords(srcX, srcY);
- if (localPlayer)
- localPlayer->followMoveTo(dstBeing, srcX, srcY, dstX, dstY);
- if (!serverFeatures->haveMove3())
- dstBeing->setDestination(dstX, dstY);
- if (dstBeing->getType() == ActorType::Player)
- dstBeing->setMoveTime();
- BLOCK_END("BeingHandler::processBeingMove2")
-}
-
-void BeingHandler::processBeingAction2(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processBeingAction2")
- if (!actorManager)
- {
- BLOCK_END("BeingHandler::processBeingAction2")
- return;
- }
-
- Being *const srcBeing = actorManager->findBeing(
- msg.readBeingId("src being id"));
- Being *const dstBeing = actorManager->findBeing(
- msg.readBeingId("dst being id"));
-
- msg.readInt32("tick");
- const int srcSpeed = msg.readInt32("src speed");
- msg.readInt32("dst speed");
- const int param1 = msg.readInt32("damage");
- msg.readInt16("count");
- const AttackTypeT type = static_cast<AttackTypeT>(
- msg.readUInt8("action"));
- msg.readInt32("left damage");
-
- switch (type)
- {
- case AttackType::HIT: // Damage
- case AttackType::CRITICAL: // Critical Damage
- case AttackType::MULTI: // Critical Damage
- case AttackType::MULTI_REFLECT:
- case AttackType::REFLECT: // Reflected Damage
- case AttackType::FLEE: // Lucky Dodge
- case AttackType::SPLASH:
- case AttackType::SKILL:
- case AttackType::REPEATE:
- if (srcBeing)
- {
- if (srcSpeed && srcBeing->getType() == ActorType::Player)
- srcBeing->setAttackDelay(srcSpeed);
- // attackid=1, type
- srcBeing->handleAttack(dstBeing, param1, 1);
- if (srcBeing->getType() == ActorType::Player)
- srcBeing->setAttackTime();
- }
- if (dstBeing)
- {
- // level not present, using 1
- dstBeing->takeDamage(srcBeing, param1,
- static_cast<AttackTypeT>(type), 1);
- }
- break;
-
- case AttackType::PICKUP:
- break;
-
- case AttackType::TOUCH_SKILL:
- break;
-
- case AttackType::SIT:
- if (srcBeing)
- {
- srcBeing->setAction(BeingAction::SIT, 0);
- if (srcBeing->getType() == ActorType::Player)
- {
- srcBeing->setMoveTime();
- if (localPlayer)
- localPlayer->imitateAction(srcBeing, BeingAction::SIT);
- }
- }
- break;
-
- case AttackType::STAND:
- if (srcBeing)
- {
- srcBeing->setAction(BeingAction::STAND, 0);
- if (srcBeing->getType() == ActorType::Player)
- {
- srcBeing->setMoveTime();
- if (localPlayer)
- {
- localPlayer->imitateAction(srcBeing,
- BeingAction::STAND);
- }
- }
- }
- break;
- default:
- case AttackType::MISS:
- case AttackType::SKILLMISS:
- UNIMPLIMENTEDPACKET;
- break;
- }
- BLOCK_END("BeingHandler::processBeingAction2")
-}
-
-void BeingHandler::processMonsterHp(Net::MessageIn &msg)
-{
- Being *const dstBeing = actorManager->findBeing(
- msg.readBeingId("monster id"));
- const int hp = msg.readInt32("hp");
- const int maxHP = msg.readInt32("max hp");
- if (dstBeing)
- {
- dstBeing->setHP(hp);
- dstBeing->setMaxHP(maxHP);
- }
-}
-
-void BeingHandler::processSkillAutoCast(Net::MessageIn &msg)
-{
- const int id = msg.readInt16("skill id");
- const int type = msg.readInt16("inf");
- msg.readInt16("unused");
- const int level = msg.readInt16("skill level");
- const int sp = msg.readInt16("sp");
- const int range = msg.readInt16("range");
- msg.readString(24, "skill name");
- msg.readInt8("unused");
-
- if (localPlayer)
- {
- localPlayer->handleSkill(localPlayer, 0, id, level);
- localPlayer->takeDamage(localPlayer, 0, AttackType::SKILL, id, level);
- }
-}
-
-void BeingHandler::processRanksList(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
- // +++ here need window with rank tables.
- msg.readInt16("rank type");
- for (int f = 0; f < 10; f ++)
- msg.readString(24, "name");
- for (int f = 0; f < 10; f ++)
- msg.readInt32("points");
- msg.readInt32("my points");
-}
-
-void BeingHandler::processBlacksmithRanksList(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
- // +++ here need window with rank tables.
- for (int f = 0; f < 10; f ++)
- msg.readString(24, "name");
- for (int f = 0; f < 10; f ++)
- msg.readInt32("points");
-}
-
-void BeingHandler::processAlchemistRanksList(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
- // +++ here need window with rank tables.
- for (int f = 0; f < 10; f ++)
- msg.readString(24, "name");
- for (int f = 0; f < 10; f ++)
- msg.readInt32("points");
-}
-
-void BeingHandler::processTaekwonRanksList(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
- // +++ here need window with rank tables.
- for (int f = 0; f < 10; f ++)
- msg.readString(24, "name");
- for (int f = 0; f < 10; f ++)
- msg.readInt32("points");
-}
-
-void BeingHandler::processPkRanksList(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
- // +++ here need window with rank tables.
- for (int f = 0; f < 10; f ++)
- msg.readString(24, "name");
- for (int f = 0; f < 10; f ++)
- msg.readInt32("points");
-}
-
-void BeingHandler::processBeingChangeDirection(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processBeingChangeDirection")
- if (!actorManager)
- {
- BLOCK_END("BeingHandler::processBeingChangeDirection")
- return;
- }
-
- Being *const dstBeing = actorManager->findBeing(
- msg.readBeingId("being id"));
-
- msg.readInt16("head direction");
-
- const uint8_t dir = Net::MessageIn::fromServerDirection(
- static_cast<uint8_t>(msg.readUInt8("player direction") & 0x0FU));
-
- if (!dstBeing)
- {
- BLOCK_END("BeingHandler::processBeingChangeDirection")
- return;
- }
-
- dstBeing->setDirection(dir);
- if (localPlayer)
- localPlayer->imitateDirection(dstBeing, dir);
- BLOCK_END("BeingHandler::processBeingChangeDirection")
-}
-
-void BeingHandler::processBeingSpecialEffect(Net::MessageIn &msg)
-{
- if (!effectManager || !actorManager)
- return;
-
- const BeingId id = msg.readBeingId("being id");
- Being *const being = actorManager->findBeing(id);
- if (!being)
- return;
-
- const int effectType = msg.readInt32("effect type");
-
- if (Particle::enabled)
- effectManager->trigger(effectType, being);
-
- // +++ need dehard code effectType == 3
- if (effectType == 3 && being->getType() == ActorType::Player
- && socialWindow)
- { // reset received damage
- socialWindow->resetDamage(being->getName());
- }
-}
-
-void BeingHandler::processBeingSpecialEffectNum(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
- // +++ need somhow show this effects.
- // type is not same with self/misc effect.
- msg.readBeingId("account id");
- msg.readInt32("effect type");
- msg.readInt32("num"); // effect variable
-}
-
-void BeingHandler::processBeingSoundEffect(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
- // +++ need play this effect.
- msg.readString(24, "sound effect name");
- msg.readUInt8("type");
- msg.readInt32("unused");
- msg.readInt32("source being id");
-}
-
void BeingHandler::viewPlayerEquipment(const Being *const being)
{
if (!being)
@@ -1580,471 +452,4 @@ void BeingHandler::viewPlayerEquipment(const Being *const being)
outMsg.writeBeingId(being->getId(), "account id");
}
-void BeingHandler::processSkillGroundNoDamage(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
- msg.readInt16("skill id");
- msg.readInt32("src id");
- msg.readInt16("val");
- msg.readInt16("x");
- msg.readInt16("y");
- msg.readInt32("tick");
-}
-
-void BeingHandler::processSkillEntry(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
- msg.readInt16("len");
- msg.readInt32("accound id");
- msg.readInt32("creator accound id");
- msg.readInt16("x");
- msg.readInt16("y");
- msg.readInt32("job");
- msg.readUInt8("radius");
- msg.readUInt8("visible");
- msg.readUInt8("level");
-}
-
-void BeingHandler::processPlaterStatusChange(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processPlayerStop")
- if (!actorManager)
- {
- BLOCK_END("BeingHandler::processPlayerStop")
- return;
- }
-
- // Change in players' flags
- const BeingId id = msg.readBeingId("account id");
- Being *const dstBeing = actorManager->findBeing(id);
- if (!dstBeing)
- return;
-
- const uint16_t stunMode = msg.readInt16("stun mode");
- uint32_t statusEffects = msg.readInt16("status effect");
- statusEffects |= (static_cast<uint32_t>(msg.readInt32("opt?"))) << 16;
- dstBeing->setKarma(msg.readUInt8("karma"));
-
- dstBeing->setStunMode(stunMode);
- dstBeing->setStatusEffectBlock(0, static_cast<uint16_t>(
- (statusEffects >> 16) & 0xffff));
- dstBeing->setStatusEffectBlock(16, static_cast<uint16_t>(
- statusEffects & 0xffff));
- BLOCK_END("BeingHandler::processPlayerStop")
-}
-
-void BeingHandler::processPlaterStatusChange2(Net::MessageIn &msg)
-{
- if (!actorManager)
- return;
-
- const BeingId id = msg.readBeingId("account id");
- Being *const dstBeing = actorManager->findBeing(id);
- if (!dstBeing)
- return;
-
- uint32_t statusEffects = msg.readInt32("status effect");
- dstBeing->setLevel(msg.readInt32("level"));
- msg.readInt32("showEFST");
-
- dstBeing->setStatusEffectBlock(0, static_cast<uint16_t>(
- (statusEffects >> 16) & 0xffff));
- dstBeing->setStatusEffectBlock(16, static_cast<uint16_t>(
- statusEffects & 0xffff));
-}
-
-void BeingHandler::processPlaterStatusChangeNoTick(Net::MessageIn &msg)
-{
- const uint16_t status = msg.readInt16("index");
- const BeingId id = msg.readBeingId("account id");
- const Enable flag = fromBool(msg.readUInt8("state")
- ? true : false, Enable);
-
- Being *const dstBeing = actorManager->findBeing(id);
- if (!dstBeing)
- return;
-
- dstBeing->setStatusEffect(status, flag);
-}
-
-void BeingHandler::processBeingResurrect(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processBeingResurrect")
- if (!actorManager || !localPlayer)
- {
- BLOCK_END("BeingHandler::processBeingResurrect")
- return;
- }
-
- // A being changed mortality status
-
- const BeingId id = msg.readBeingId("being id");
- msg.readInt16("unused");
- Being *const dstBeing = actorManager->findBeing(id);
- if (!dstBeing)
- {
- BLOCK_END("BeingHandler::processBeingResurrect")
- return;
- }
-
- // If this is player's current target, clear it.
- if (dstBeing == localPlayer->getTarget())
- localPlayer->stopAttack();
-
- dstBeing->setAction(BeingAction::STAND, 0);
- BLOCK_END("BeingHandler::processBeingResurrect")
-}
-
-void BeingHandler::processPlayerGuilPartyInfo(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processPlayerGuilPartyInfo")
- if (!actorManager)
- {
- BLOCK_END("BeingHandler::processPlayerGuilPartyInfo")
- return;
- }
-
- Being *const dstBeing = actorManager->findBeing(
- msg.readBeingId("being id"));
-
- if (dstBeing)
- {
- dstBeing->setName(msg.readString(24, "char name"));
- dstBeing->setPartyName(msg.readString(24, "party name"));
- dstBeing->setGuildName(msg.readString(24, "guild name"));
- dstBeing->setGuildPos(msg.readString(24, "guild pos"));
- dstBeing->addToCache();
- }
- BLOCK_END("BeingHandler::processPlayerGuilPartyInfo")
-}
-
-void BeingHandler::processBeingRemoveSkil(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
- // +++ if skill unit was added, here need remove it from actors
- msg.readInt32("skill unit id");
-}
-
-void BeingHandler::processBeingFakeName(Net::MessageIn &msg)
-{
- const BeingType::BeingType type = static_cast<BeingType::BeingType>(
- msg.readUInt8("object type"));
- const BeingId id = msg.readBeingId("npc id");
- msg.skip(8, "unused");
- const uint16_t job = msg.readInt16("class?"); // 111
- msg.skip(30, "unused");
- uint16_t x, y;
- uint8_t dir;
- msg.readCoordinates(x, y, dir, "position");
- msg.readUInt8("sx");
- msg.readUInt8("sy");
- msg.skip(4, "unsued");
-
- Being *const dstBeing = createBeing2(msg, id, job, type);
- if (!dstBeing)
- return;
- dstBeing->setSubtype(fromInt(job, BeingTypeId), 0);
- dstBeing->setTileCoords(x, y);
- dstBeing->setDirection(dir);
-}
-
-void BeingHandler::processBeingStatUpdate1(Net::MessageIn &msg)
-{
- const BeingId id = msg.readBeingId("account id");
- const int type = msg.readInt16("type");
- const int value = msg.readInt32("value");
-
- Being *const dstBeing = actorManager->findBeing(id);
- if (!dstBeing)
- return;
-
- if (type != Ea::MANNER)
- {
- UNIMPLIMENTEDPACKET;
- return;
- }
- dstBeing->setManner(value);
-}
-
-void BeingHandler::processBeingSelfEffect(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processBeingSelfEffect")
- if (!effectManager || !actorManager)
- {
- BLOCK_END("BeingHandler::processBeingSelfEffect")
- return;
- }
-
- const BeingId id = msg.readBeingId("being id");
- Being *const being = actorManager->findBeing(id);
- if (!being)
- {
- BLOCK_END("BeingHandler::processBeingSelfEffect")
- return;
- }
-
- const int effectType = msg.readInt32("effect type");
- if (Particle::enabled)
- effectManager->trigger(effectType, being);
-
- BLOCK_END("BeingHandler::processBeingSelfEffect")
-}
-
-void BeingHandler::processMobInfo(Net::MessageIn &msg)
-{
- const int len = msg.readInt16("len");
- if (len < 12)
- return;
- Being *const dstBeing = actorManager->findBeing(
- msg.readBeingId("monster id"));
- const int attackRange = msg.readInt32("range");
- if (dstBeing)
- dstBeing->setAttackRange(attackRange);
-}
-
-void BeingHandler::processBeingAttrs(Net::MessageIn &msg)
-{
- const int len = msg.readInt16("len");
- if (len < 12)
- return;
- Being *const dstBeing = actorManager->findBeing(
- msg.readBeingId("player id"));
- const int gmLevel = msg.readInt32("gm level");
- if (dstBeing && gmLevel)
- {
- if (dstBeing == localPlayer)
- localPlayer->setGMLevel(gmLevel);
- dstBeing->setGM(true);
- }
- else
- {
- if (dstBeing == localPlayer)
- localPlayer->setGMLevel(0);
- if (dstBeing)
- dstBeing->setGM(false);
- }
-}
-
-void BeingHandler::processMonsterInfo(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
-
- msg.readInt16("class");
- msg.readInt16("level");
- msg.readInt16("size");
- msg.readInt32("hp");
- msg.readInt16("def");
- msg.readInt16("race");
- msg.readInt16("mdef");
- msg.readInt16("ele");
-}
-
-void BeingHandler::processClassChange(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
-
- msg.readBeingId("being id");
- msg.readUInt8("type");
- msg.readInt32("class");
-}
-
-void BeingHandler::processSpiritBalls(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
-
- msg.readBeingId("being id");
- msg.readInt16("spirits amount");
-}
-
-void BeingHandler::processSpiritBallSingle(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
-
- msg.readBeingId("being id");
- msg.readInt16("spirits amount");
-}
-
-void BeingHandler::processBladeStop(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
-
- msg.readInt32("src being id");
- msg.readInt32("dst being id");
- msg.readInt32("flag");
-}
-
-void BeingHandler::processComboDelay(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
-
- msg.readBeingId("being id");
- msg.readInt32("wait");
-}
-
-void BeingHandler::processWddingEffect(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
-
- msg.readBeingId("being id");
-}
-
-void BeingHandler::processBeingSlide(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
-
- msg.readBeingId("being id");
- msg.readInt16("x");
- msg.readInt16("y");
-}
-
-void BeingHandler::processStarsKill(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
-
- msg.readString(24, "map name");
- msg.readInt32("monster id");
- msg.readUInt8("start");
- msg.readUInt8("result");
-}
-
-void BeingHandler::processGladiatorFeelRequest(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
-
- msg.readUInt8("which");
-}
-
-void BeingHandler::processBossMapInfo(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
-
- msg.readUInt8("info type");
- msg.readInt32("x");
- msg.readInt32("y");
- msg.readInt16("min hours");
- msg.readInt16("min minutes");
- msg.readInt16("max hours");
- msg.readInt16("max minutes");
- msg.readString(24, "monster name"); // really can be used 51 byte?
-}
-
-void BeingHandler::processBeingFont(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
-
- msg.readBeingId("account id");
- msg.readInt16("font");
-}
-
-void BeingHandler::processBeingMilleniumShield(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
-
- msg.readBeingId("account id");
- msg.readInt16("shields");
- msg.readInt16("unused");
-}
-
-void BeingHandler::processBeingCharm(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
-
- msg.readBeingId("account id");
- msg.readInt16("charm type");
- msg.readInt16("charm count");
-}
-
-void BeingHandler::processBeingViewEquipment(Net::MessageIn &msg)
-{
- UNIMPLIMENTEDPACKET;
-
- const int count = (msg.readInt16("len") - 45) / 31;
- msg.readString(24, "name");
- msg.readInt16("job");
- msg.readInt16("head");
- msg.readInt16("accessory");
- msg.readInt16("accessory2");
- msg.readInt16("accessory3");
- msg.readInt16("robe");
- msg.readInt16("hair color");
- msg.readInt16("body color");
- msg.readUInt8("gender");
- for (int f = 0; f < count; f ++)
- {
- msg.readInt16("index");
- msg.readInt16("item id");
- msg.readUInt8("item type");
- msg.readInt32("location");
- msg.readInt32("wear state");
- msg.readInt8("refine");
- for (int d = 0; d < 4; d ++)
- msg.readInt16("card");
- msg.readInt32("hire expire date (?)");
- msg.readInt16("equip type");
- msg.readInt16("item sprite number");
- msg.readUInt8("flags");
- }
-}
-
-void BeingHandler::processPvpSet(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processPvpSet")
- const BeingId id = msg.readBeingId("being id");
- const int rank = msg.readInt32("rank");
- msg.readInt32("num");
- if (actorManager)
- {
- Being *const dstBeing = actorManager->findBeing(id);
- if (dstBeing)
- dstBeing->setPvpRank(rank);
- }
- BLOCK_END("BeingHandler::processPvpSet")
-}
-
-void BeingHandler::processNameResponse2(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processNameResponse2")
- if (!actorManager || !localPlayer)
- {
- BLOCK_END("BeingHandler::processNameResponse2")
- return;
- }
-
- const int len = msg.readInt16("len");
- const BeingId beingId = msg.readBeingId("account ic");
- const std::string str = msg.readString(len - 8, "name");
- Being *const dstBeing = actorManager->findBeing(beingId);
- if (dstBeing)
- {
- if (beingId == localPlayer->getId())
- {
- localPlayer->pingResponse();
- }
- else
- {
- dstBeing->setName(str);
- dstBeing->updateGuild();
- dstBeing->addToCache();
-
- if (dstBeing->getType() == ActorType::Player)
- dstBeing->updateColors();
-
- if (localPlayer)
- {
- const Party *const party = localPlayer->getParty();
- if (party && party->isMember(dstBeing->getId()))
- {
- PartyMember *const member = party->getMember(
- dstBeing->getId());
-
- if (member)
- member->setName(dstBeing->getName());
- }
- localPlayer->checkNewName(dstBeing);
- }
- }
- }
- BLOCK_END("BeingHandler::processNameResponse2")
-}
-
} // namespace EAthena
diff --git a/src/net/eathena/beinghandler.h b/src/net/eathena/beinghandler.h
index 7dda4f2cb..1a439c807 100644
--- a/src/net/eathena/beinghandler.h
+++ b/src/net/eathena/beinghandler.h
@@ -47,126 +47,7 @@ class BeingHandler final : public MessageHandler, public Ea::BeingHandler
void requestRanks(const RankT rank) const override final;
protected:
- static Being *createBeing2(Net::MessageIn &msg,
- const BeingId id,
- const int16_t job,
- const BeingType::BeingType beingType);
-
- static void processBeingChangeLook2(Net::MessageIn &msg);
-
- static void processBeingChangeLookCards(Net::MessageIn &msg);
-
- static void processBeingVisible(Net::MessageIn &msg);
-
- static void processBeingMove(Net::MessageIn &msg);
-
- static void processBeingSpawn(Net::MessageIn &msg);
-
- static void processMapTypeProperty(Net::MessageIn &msg);
-
- static void processMapType(Net::MessageIn &msg);
-
- static void processSkillCasting(Net::MessageIn &msg);
-
- static void processBeingStatusChange(Net::MessageIn &msg);
-
- static void processBeingStatusChange2(Net::MessageIn &msg);
-
- static void processBeingMove2(Net::MessageIn &msg);
-
- static void processBeingAction2(Net::MessageIn &msg);
-
- static void processMonsterHp(Net::MessageIn &msg);
-
- static void processSkillAutoCast(Net::MessageIn &msg);
-
- static void processRanksList(Net::MessageIn &msg);
-
- static void processBeingChangeDirection(Net::MessageIn &msg);
-
- static void processBeingChangeLookContinue(Net::MessageIn &msg,
- Being *const dstBeing,
- const uint8_t type,
- const int id,
- const int id2,
- const int *cards)
- A_NONNULL(2);
-
- static void processBeingSpecialEffect(Net::MessageIn &msg);
-
- static void processBeingSpecialEffectNum(Net::MessageIn &msg);
-
- static void processBeingSoundEffect(Net::MessageIn &msg);
-
void viewPlayerEquipment(const Being *const being);
-
- static void processSkillGroundNoDamage(Net::MessageIn &msg);
-
- static void processSkillEntry(Net::MessageIn &msg);
-
- static void processPlaterStatusChange(Net::MessageIn &msg);
-
- static void processPlaterStatusChangeNoTick(Net::MessageIn &msg);
-
- static void processBeingResurrect(Net::MessageIn &msg);
-
- static void processPlayerGuilPartyInfo(Net::MessageIn &msg);
-
- static void processBeingRemoveSkil(Net::MessageIn &msg);
-
- static void processBeingFakeName(Net::MessageIn &msg);
-
- static void processBeingStatUpdate1(Net::MessageIn &msg);
-
- static void processPlaterStatusChange2(Net::MessageIn &msg);
-
- static void processBeingSelfEffect(Net::MessageIn &msg);
-
- static void processMobInfo(Net::MessageIn &msg);
-
- static void processBeingAttrs(Net::MessageIn &msg);
-
- static void processMonsterInfo(Net::MessageIn &msg);
-
- static void processClassChange(Net::MessageIn &msg);
-
- static void processSpiritBalls(Net::MessageIn &msg);
-
- static void processSpiritBallSingle(Net::MessageIn &msg);
-
- static void processBladeStop(Net::MessageIn &msg);
-
- static void processComboDelay(Net::MessageIn &msg);
-
- static void processWddingEffect(Net::MessageIn &msg);
-
- static void processBeingSlide(Net::MessageIn &msg);
-
- static void processStarsKill(Net::MessageIn &msg);
-
- static void processBlacksmithRanksList(Net::MessageIn &msg);
-
- static void processAlchemistRanksList(Net::MessageIn &msg);
-
- static void processTaekwonRanksList(Net::MessageIn &msg);
-
- static void processPkRanksList(Net::MessageIn &msg);
-
- static void processGladiatorFeelRequest(Net::MessageIn &msg);
-
- static void processBossMapInfo(Net::MessageIn &msg);
-
- static void processBeingFont(Net::MessageIn &msg);
-
- static void processBeingMilleniumShield(Net::MessageIn &msg);
-
- static void processBeingCharm(Net::MessageIn &msg);
-
- static void processBeingViewEquipment(Net::MessageIn &msg);
-
- static void processPvpSet(Net::MessageIn &msg);
-
- static void processNameResponse2(Net::MessageIn &msg);
};
} // namespace EAthena
diff --git a/src/net/eathena/beingnet.cpp b/src/net/eathena/beingnet.cpp
new file mode 100644
index 000000000..1da2ddad0
--- /dev/null
+++ b/src/net/eathena/beingnet.cpp
@@ -0,0 +1,1670 @@
+/*
+ * The ManaPlus Client
+ * Copyright (C) 2004-2009 The Mana World Development Team
+ * Copyright (C) 2009-2010 The Mana Developers
+ * Copyright (C) 2011-2015 The ManaPlus Developers
+ *
+ * This file is part of The ManaPlus Client.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "net/eathena/beingnet.h"
+
+#include "actormanager.h"
+#include "effectmanager.h"
+#include "game.h"
+#include "itemcolormanager.h"
+#include "notifymanager.h"
+#include "party.h"
+
+#include "being/mercenaryinfo.h"
+
+#include "enums/resources/notifytypes.h"
+
+#include "particle/particle.h"
+
+#include "input/keyboardconfig.h"
+
+#include "gui/windows/skilldialog.h"
+#include "gui/windows/socialwindow.h"
+#include "gui/windows/outfitwindow.h"
+
+#include "net/serverfeatures.h"
+
+#include "net/ea/beingnet.h"
+#include "net/ea/eaprotocol.h"
+
+#include "net/charserverhandler.h"
+
+#include "net/character.h"
+
+#include "net/eathena/maptypeproperty2.h"
+#include "net/eathena/messageout.h"
+#include "net/eathena/protocol.h"
+#include "net/eathena/sprite.h"
+
+#include "resources/iteminfo.h"
+#include "resources/db/itemdb.h"
+
+#include "resources/map/map.h"
+
+#include "utils/timer.h"
+
+#include "debug.h"
+
+namespace EAthena
+{
+
+void BeingNet::processBeingChangeLook2(Net::MessageIn &msg)
+{
+ if (!actorManager)
+ return;
+
+ Being *const dstBeing = actorManager->findBeing(
+ msg.readBeingId("being id"));
+ const uint8_t type = msg.readUInt8("type");
+
+ const int id = msg.readInt16("id1");
+ unsigned int id2 = msg.readInt16("id2");
+ if (type != 2)
+ id2 = 1;
+
+ if (!localPlayer || !dstBeing)
+ return;
+
+ processBeingChangeLookContinue(msg, dstBeing, type, id, id2, nullptr);
+}
+
+void BeingNet::processBeingChangeLookCards(Net::MessageIn &msg)
+{
+ Being *dstBeing = nullptr;
+ int cards[4];
+
+ if (!actorManager)
+ { // here can be look from char server
+ if (!serverFeatures->haveAdvancedSprites())
+ return;
+ Net::Characters &chars = Net::CharServerHandler::mCharacters;
+ const BeingId id = msg.readBeingId("being id");
+
+ FOR_EACH (Net::Characters::iterator, it, chars)
+ {
+ Net::Character *character = *it;
+ if (character->dummy && character->dummy->getId() == id)
+ {
+ dstBeing = character->dummy;
+ break;
+ }
+ }
+ }
+ else
+ {
+ dstBeing = actorManager->findBeing(
+ msg.readBeingId("being id"));
+ }
+
+ const uint8_t type = msg.readUInt8("type");
+
+ const int id = msg.readInt16("id1");
+ unsigned int id2 = msg.readInt16("id2");
+ if (type != 2)
+ id2 = 1;
+
+ for (int f = 0; f < 4; f ++)
+ cards[f] = msg.readInt16("card");
+
+ if (!dstBeing)
+ return;
+
+ processBeingChangeLookContinue(msg, dstBeing, type, id, id2, &cards[0]);
+}
+
+void BeingNet::processBeingChangeLookContinue(Net::MessageIn &msg,
+ Being *const dstBeing,
+ const uint8_t type,
+ const int id,
+ const int id2,
+ const int *cards A_UNUSED)
+{
+ if (dstBeing->getType() == ActorType::Player)
+ dstBeing->setOtherTime();
+
+ const ItemColor itemColor = ItemColorManager::getColorFromCards(cards);
+ const std::string color;
+ switch (type)
+ {
+ case 0: // change race
+ dstBeing->setSubtype(fromInt(id, BeingTypeId),
+ dstBeing->getLook());
+ break;
+ case 1: // eAthena LOOK_HAIR
+ dstBeing->setHairColor(fromInt(id, ItemColor));
+ dstBeing->setSpriteID(SPRITE_HAIR_COLOR, id * -1);
+ break;
+ case 2: // LOOK_WEAPON Weapon ID in id, Shield ID in id2
+ dstBeing->setSprite(SPRITE_BODY, id, "", itemColor, true);
+ dstBeing->setSprite(SPRITE_FLOOR, id2);
+ if (localPlayer)
+ localPlayer->imitateOutfit(dstBeing, SPRITE_FLOOR);
+ break;
+ case 3: // LOOK_HEAD_BOTTOM
+ dstBeing->setSprite(SPRITE_WEAPON, id, color, itemColor);
+ if (localPlayer)
+ localPlayer->imitateOutfit(dstBeing, SPRITE_WEAPON);
+ break;
+ case 4: // LOOK_HEAD_TOP Change upper headgear for eAthena, hat for us
+ dstBeing->setSprite(SPRITE_CLOTHES_COLOR, id, color, itemColor);
+ if (localPlayer)
+ localPlayer->imitateOutfit(dstBeing, SPRITE_CLOTHES_COLOR);
+ break;
+ case 5: // LOOK_HEAD_MID Change middle headgear for eathena,
+ // armor for us
+ dstBeing->setSprite(SPRITE_HEAD_BOTTOM, id, color, itemColor);
+ if (localPlayer)
+ localPlayer->imitateOutfit(dstBeing, SPRITE_HEAD_BOTTOM);
+ break;
+ case 6: // eAthena LOOK_HAIR_COLOR
+ dstBeing->setHairColor(fromInt(id, ItemColor));
+ dstBeing->setSpriteColor(SPRITE_HAIR_COLOR,
+ ItemDB::get(dstBeing->getSpriteID(
+ SPRITE_HAIR_COLOR)).getDyeColorsString(
+ fromInt(id, ItemColor)));
+ break;
+ case 7: // Clothes color. Now used as look
+ dstBeing->setLook(static_cast<uint8_t>(id));
+ break;
+ case 8: // eAthena LOOK_SHIELD
+ dstBeing->setSprite(SPRITE_FLOOR, id, color, itemColor);
+ if (localPlayer)
+ localPlayer->imitateOutfit(dstBeing, SPRITE_FLOOR);
+ break;
+ case 9: // eAthena LOOK_SHOES
+ dstBeing->setSprite(SPRITE_HAIR, id, color, itemColor);
+ if (localPlayer)
+ localPlayer->imitateOutfit(dstBeing, SPRITE_HAIR);
+ break;
+ case 10: // LOOK_GLOVES
+ dstBeing->setSprite(SPRITE_SHOES, id, color, itemColor);
+ if (localPlayer)
+ localPlayer->imitateOutfit(dstBeing, SPRITE_SHOES);
+ break;
+ case 11: // LOOK_FLOOR
+ dstBeing->setSprite(SPRITE_SHIELD, id, color, itemColor);
+ if (localPlayer)
+ localPlayer->imitateOutfit(dstBeing, SPRITE_SHIELD);
+ break;
+ case 12: // LOOK_ROBE
+ dstBeing->setSprite(SPRITE_HEAD_TOP, id, color, itemColor);
+ if (localPlayer)
+ localPlayer->imitateOutfit(dstBeing, SPRITE_HEAD_TOP);
+ break;
+ case 13: // COSTUME_HEAD_TOP
+ dstBeing->setSprite(SPRITE_HEAD_MID, id, color, itemColor);
+ if (localPlayer)
+ localPlayer->imitateOutfit(dstBeing, SPRITE_HEAD_MID);
+ break;
+ case 14: // COSTUME_HEAD_MID
+ dstBeing->setSprite(SPRITE_ROBE, id, color, itemColor);
+ if (localPlayer)
+ localPlayer->imitateOutfit(dstBeing, SPRITE_ROBE);
+ break;
+ case 15: // COSTUME_HEAD_LOW
+ dstBeing->setSprite(SPRITE_EVOL2, id, color, itemColor);
+ if (localPlayer)
+ localPlayer->imitateOutfit(dstBeing, SPRITE_EVOL2);
+ break;
+ case 16: // COSTUME_GARMENT
+ dstBeing->setSprite(SPRITE_EVOL3, id, color, itemColor);
+ if (localPlayer)
+ localPlayer->imitateOutfit(dstBeing, SPRITE_EVOL3);
+ break;
+ case 17: // ARMOR
+ dstBeing->setSprite(SPRITE_EVOL4, id, color, itemColor);
+ if (localPlayer)
+ localPlayer->imitateOutfit(dstBeing, SPRITE_EVOL4);
+ break;
+ default:
+ UNIMPLIMENTEDPACKET;
+ break;
+ }
+}
+
+void BeingNet::processBeingVisible(Net::MessageIn &msg)
+{
+ if (!actorManager)
+ return;
+
+ msg.readInt16("len");
+ const BeingType::BeingType type = static_cast<BeingType::BeingType>(
+ msg.readUInt8("object type"));
+
+ // Information about a being in range
+ const BeingId id = msg.readBeingId("being id");
+ BeingId spawnId;
+ if (id == Ea::BeingNet::mSpawnId)
+ spawnId = Ea::BeingNet::mSpawnId;
+ else
+ spawnId = BeingId_zero;
+ Ea::BeingNet::mSpawnId = BeingId_zero;
+
+ int16_t speed = msg.readInt16("speed");
+ const uint16_t stunMode = msg.readInt16("opt1");
+ // probably wrong effect usage
+ const uint32_t statusEffects = msg.readInt16("opt2");
+ msg.readInt32("option");
+
+ const int16_t job = msg.readInt16("class");
+
+ Being *dstBeing = actorManager->findBeing(id);
+
+ if (dstBeing && dstBeing->getType() == ActorType::Monster
+ && !dstBeing->isAlive())
+ {
+ actorManager->destroy(dstBeing);
+ actorManager->erase(dstBeing);
+ dstBeing = nullptr;
+ }
+
+ if (!dstBeing)
+ {
+ if (actorManager->isBlocked(id) == true)
+ return;
+
+ dstBeing = createBeing2(msg, id, job, type);
+ if (!dstBeing)
+ return;
+ }
+ else
+ {
+ // undeleting marked for deletion being
+ if (dstBeing->getType() == ActorType::Npc)
+ actorManager->undelete(dstBeing);
+ }
+
+ if (dstBeing->getType() == ActorType::Player)
+ dstBeing->setMoveTime();
+
+ if (spawnId != BeingId_zero)
+ {
+ dstBeing->setAction(BeingAction::SPAWN, 0);
+ }
+ else
+ {
+ dstBeing->clearPath();
+ dstBeing->setActionTime(tick_time);
+ dstBeing->setAction(BeingAction::STAND, 0);
+ }
+
+ // Prevent division by 0 when calculating frame
+ if (speed == 0)
+ speed = 150;
+
+ dstBeing->setWalkSpeed(Vector(speed, speed, 0));
+ dstBeing->setSubtype(fromInt(job, BeingTypeId), 0);
+ if (dstBeing->getType() == ActorType::Monster && localPlayer)
+ localPlayer->checkNewName(dstBeing);
+
+ const int hairStyle = msg.readInt16("hair style");
+ const uint32_t weapon = static_cast<uint32_t>(msg.readInt32("weapon"));
+ const uint16_t headBottom = msg.readInt16("head bottom");
+
+ const uint16_t headTop = msg.readInt16("head top");
+ const uint16_t headMid = msg.readInt16("head mid");
+ const ItemColor hairColor = fromInt(msg.readInt16("hair color"), ItemColor);
+ const uint16_t shoes = msg.readInt16("shoes or clothes color?");
+
+ const uint16_t gloves = msg.readInt16("head dir / gloves");
+ // may be use robe as gloves?
+ msg.readInt16("robe");
+ msg.readInt32("guild id");
+ msg.readInt16("guild emblem");
+ dstBeing->setManner(msg.readInt16("manner"));
+ dstBeing->setStatusEffectBlock(32, static_cast<uint16_t>(
+ msg.readInt32("opt3")));
+ dstBeing->setKarma(msg.readUInt8("karma"));
+ uint8_t gender = static_cast<uint8_t>(msg.readUInt8("gender") & 3);
+
+ if (dstBeing->getType() == ActorType::Player)
+ {
+ dstBeing->setGender(Being::intToGender(gender));
+ dstBeing->setHairColor(hairColor);
+ // Set these after the gender, as the sprites may be gender-specific
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_HAIR_COLOR, hairStyle * -1,
+ ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_WEAPON, headBottom);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_HEAD_BOTTOM, headMid);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_CLOTHES_COLOR, headTop);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_HAIR, shoes);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_SHOES, gloves);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_BODY, weapon, "",
+ ItemColor_one, true);
+// Ea::BeingNet::setSprite(dstBeing, SPRITE_FLOOR, shield);
+ }
+ else if (dstBeing->getType() == ActorType::Npc
+ && serverFeatures->haveNpcGender())
+ {
+ dstBeing->setGender(Being::intToGender(gender));
+ }
+
+ uint8_t dir;
+ uint16_t x, y;
+ msg.readCoordinates(x, y, dir, "position");
+ msg.readInt8("xs");
+ msg.readInt8("ys");
+ msg.readUInt8("action type");
+ dstBeing->setTileCoords(x, y);
+
+ if (job == 45 && socialWindow && outfitWindow)
+ {
+ const int num = socialWindow->getPortalIndex(x, y);
+ if (num >= 0)
+ {
+ dstBeing->setName(keyboard.getKeyShortString(
+ outfitWindow->keyName(num)));
+ }
+ else
+ {
+ dstBeing->setName("");
+ }
+ }
+
+ dstBeing->setDirection(dir);
+
+ const int level = static_cast<int>(msg.readInt16("level"));
+ if (level)
+ dstBeing->setLevel(level);
+ msg.readInt16("font");
+
+ const int maxHP = msg.readInt32("max hp");
+ const int hp = msg.readInt32("hp");
+ dstBeing->setMaxHP(maxHP);
+ dstBeing->setHP(hp);
+
+ msg.readInt8("is boss");
+
+ dstBeing->setStunMode(stunMode);
+ dstBeing->setStatusEffectBlock(0, static_cast<uint16_t>(
+ (statusEffects >> 16) & 0xffffU));
+ dstBeing->setStatusEffectBlock(16, static_cast<uint16_t>(
+ statusEffects & 0xffffU));
+}
+
+void BeingNet::processBeingMove(Net::MessageIn &msg)
+{
+ if (!actorManager)
+ return;
+
+ msg.readInt16("len");
+ const BeingType::BeingType type = static_cast<BeingType::BeingType>(
+ msg.readUInt8("object type"));
+
+ // Information about a being in range
+ const BeingId id = msg.readBeingId("being id");
+ BeingId spawnId;
+ if (id == Ea::BeingNet::mSpawnId)
+ spawnId = Ea::BeingNet::mSpawnId;
+ else
+ spawnId = BeingId_zero;
+ Ea::BeingNet::mSpawnId = BeingId_zero;
+ int16_t speed = msg.readInt16("speed");
+// if (visible)
+// {
+ const uint16_t stunMode = msg.readInt16("opt1");
+ // probably wrong effect usage
+ const uint32_t statusEffects = msg.readInt16("opt2");
+// }
+// else
+// {
+// commented for now, probably it can be removed after testing
+// msg.readInt16("body state");
+// msg.readInt16("health state");
+// }
+ msg.readInt32("effect state");
+
+ const int16_t job = msg.readInt16("class");
+
+ Being *dstBeing = actorManager->findBeing(id);
+
+ if (dstBeing && dstBeing->getType() == ActorType::Monster
+ && !dstBeing->isAlive())
+ {
+ actorManager->destroy(dstBeing);
+ actorManager->erase(dstBeing);
+ dstBeing = nullptr;
+ }
+
+ if (!dstBeing)
+ {
+ if (actorManager->isBlocked(id) == true)
+ return;
+
+ dstBeing = createBeing2(msg, id, job, type);
+ if (!dstBeing)
+ return;
+ }
+ else
+ {
+ // undeleting marked for deletion being
+ if (dstBeing->getType() == ActorType::Npc)
+ actorManager->undelete(dstBeing);
+ }
+
+ if (dstBeing->getType() == ActorType::Player)
+ dstBeing->setMoveTime();
+
+ if (spawnId != BeingId_zero)
+ dstBeing->setAction(BeingAction::SPAWN, 0);
+
+ // Prevent division by 0 when calculating frame
+ if (speed == 0)
+ speed = 150;
+
+ dstBeing->setWalkSpeed(Vector(speed, speed, 0));
+ dstBeing->setSubtype(fromInt(job, BeingTypeId), 0);
+ if (dstBeing->getType() == ActorType::Monster && localPlayer)
+ localPlayer->checkNewName(dstBeing);
+
+ const int hairStyle = msg.readInt16("hair style");
+ const uint32_t weapon = static_cast<uint32_t>(msg.readInt32("weapon"));
+ const uint16_t headBottom = msg.readInt16("head bottom");
+
+ msg.readInt32("tick");
+
+ const uint16_t headTop = msg.readInt16("head top");
+ const uint16_t headMid = msg.readInt16("head mid");
+ const ItemColor hairColor = fromInt(
+ msg.readInt16("hair color"), ItemColor);
+ const uint16_t shoes = msg.readInt16("shoes or clothes color?");
+
+ const uint16_t gloves = msg.readInt16("head dir / gloves");
+ // may be use robe as gloves?
+ msg.readInt16("robe");
+ msg.readInt32("guild id");
+ msg.readInt16("guild emblem");
+ dstBeing->setManner(msg.readInt16("manner"));
+ dstBeing->setStatusEffectBlock(32, static_cast<uint16_t>(
+ msg.readInt32("opt3")));
+ dstBeing->setKarma(msg.readUInt8("karma"));
+ uint8_t gender = static_cast<uint8_t>(msg.readUInt8("gender") & 3);
+
+ if (dstBeing->getType() == ActorType::Player)
+ {
+ dstBeing->setGender(Being::intToGender(gender));
+ dstBeing->setHairColor(hairColor);
+ // Set these after the gender, as the sprites may be gender-specific
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_HAIR_COLOR, hairStyle * -1,
+ ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
+ if (!serverFeatures->haveMove3())
+ {
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_WEAPON, headBottom);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_HEAD_BOTTOM, headMid);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_CLOTHES_COLOR, headTop);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_HAIR, shoes);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_SHOES, gloves);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_BODY, weapon, "",
+ ItemColor_one, true);
+ }
+// Ea::BeingNet::setSprite(dstBeing, SPRITE_FLOOR, shield);
+ }
+ else if (dstBeing->getType() == ActorType::Npc
+ && serverFeatures->haveNpcGender())
+ {
+ dstBeing->setGender(Being::intToGender(gender));
+ }
+
+ uint16_t srcX, srcY, dstX, dstY;
+ msg.readCoordinatePair(srcX, srcY, dstX, dstY, "move path");
+ msg.readUInt8("(sx<<4) | (sy&0x0f)");
+ msg.readInt8("xs");
+ msg.readInt8("ys");
+ dstBeing->setAction(BeingAction::STAND, 0);
+ dstBeing->setTileCoords(srcX, srcY);
+ if (localPlayer)
+ localPlayer->followMoveTo(dstBeing, srcX, srcY, dstX, dstY);
+ if (!serverFeatures->haveMove3())
+ dstBeing->setDestination(dstX, dstY);
+
+ // because server don't send direction in move packet, we fixing it
+
+ uint8_t d = 0;
+ if (srcX == dstX && srcY == dstY)
+ { // if player did one step from invisible area to visible,
+ // move path is broken
+ int x2 = localPlayer->getTileX();
+ int y2 = localPlayer->getTileY();
+ if (abs(x2 - srcX) > abs(y2 - srcY))
+ y2 = srcY;
+ else
+ x2 = srcX;
+ d = dstBeing->calcDirection(x2, y2);
+ }
+ else
+ {
+ d = dstBeing->calcDirection(dstX, dstY);
+ }
+ if (d && dstBeing->getDirection() != d)
+ dstBeing->setDirection(d);
+
+ const int level = static_cast<int>(msg.readInt16("level"));
+ if (level)
+ dstBeing->setLevel(level);
+ msg.readInt16("font");
+
+ const int maxHP = msg.readInt32("max hp");
+ const int hp = msg.readInt32("hp");
+ dstBeing->setMaxHP(maxHP);
+ dstBeing->setHP(hp);
+
+ msg.readInt8("is boss");
+
+ dstBeing->setStunMode(stunMode);
+ dstBeing->setStatusEffectBlock(0, static_cast<uint16_t>(
+ (statusEffects >> 16) & 0xffffU));
+ dstBeing->setStatusEffectBlock(16, static_cast<uint16_t>(
+ statusEffects & 0xffffU));
+}
+
+void BeingNet::processBeingSpawn(Net::MessageIn &msg)
+{
+ if (!actorManager)
+ return;
+
+ msg.readInt16("len");
+ const BeingType::BeingType type = static_cast<BeingType::BeingType>(
+ msg.readUInt8("object type"));
+
+ // Information about a being in range
+ const BeingId id = msg.readBeingId("being id");
+ Ea::BeingNet::mSpawnId = id;
+ const BeingId spawnId = id;
+ int16_t speed = msg.readInt16("speed");
+// if (visible)
+// {
+ const uint16_t stunMode = msg.readInt16("opt1");
+ // probably wrong effect usage
+ const uint32_t statusEffects = msg.readInt16("opt2");
+// }
+// else
+// {
+// commented for now, probably it can be removed after testing
+// msg.readInt16("body state");
+// msg.readInt16("health state");
+// }
+ msg.readInt32("effect state");
+
+ const int16_t job = msg.readInt16("class");
+
+ Being *dstBeing = actorManager->findBeing(id);
+
+ if (dstBeing && dstBeing->getType() == ActorType::Monster
+ && !dstBeing->isAlive())
+ {
+ actorManager->destroy(dstBeing);
+ actorManager->erase(dstBeing);
+ dstBeing = nullptr;
+ }
+
+ if (!dstBeing)
+ {
+ if (actorManager->isBlocked(id) == true)
+ return;
+
+ dstBeing = createBeing2(msg, id, job, type);
+ if (!dstBeing)
+ return;
+ }
+ else
+ {
+ // undeleting marked for deletion being
+ if (dstBeing->getType() == ActorType::Npc)
+ actorManager->undelete(dstBeing);
+ }
+
+ if (dstBeing->getType() == ActorType::Player)
+ dstBeing->setMoveTime();
+
+ if (spawnId != BeingId_zero)
+ dstBeing->setAction(BeingAction::SPAWN, 0);
+
+ // Prevent division by 0 when calculating frame
+ if (speed == 0)
+ speed = 150;
+
+ dstBeing->setWalkSpeed(Vector(speed, speed, 0));
+ dstBeing->setSubtype(fromInt(job, BeingTypeId), 0);
+ if (dstBeing->getType() == ActorType::Monster && localPlayer)
+ localPlayer->checkNewName(dstBeing);
+
+ const int hairStyle = msg.readInt16("hair style");
+ const uint32_t weapon = static_cast<uint32_t>(msg.readInt32("weapon"));
+ const uint16_t headBottom = msg.readInt16("head bottom");
+
+ const uint16_t headTop = msg.readInt16("head top");
+ const uint16_t headMid = msg.readInt16("head mid");
+ const ItemColor hairColor = fromInt(
+ msg.readInt16("hair color"), ItemColor);
+ const uint16_t shoes = msg.readInt16("shoes or clothes color?");
+ const uint16_t gloves = msg.readInt16("head dir / gloves");
+ // may be use robe as gloves?
+ msg.readInt16("robe");
+ msg.readInt32("guild id");
+ msg.readInt16("guild emblem");
+ dstBeing->setManner(msg.readInt16("manner"));
+ dstBeing->setStatusEffectBlock(32, static_cast<uint16_t>(
+ msg.readInt32("opt3")));
+ dstBeing->setKarma(msg.readUInt8("karma"));
+ uint8_t gender = static_cast<uint8_t>(msg.readUInt8("gender") & 3);
+
+ if (dstBeing->getType() == ActorType::Player)
+ {
+ dstBeing->setGender(Being::intToGender(gender));
+ dstBeing->setHairColor(hairColor);
+ // Set these after the gender, as the sprites may be gender-specific
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_HAIR_COLOR, hairStyle * -1,
+ ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_WEAPON, headBottom);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_HEAD_BOTTOM, headMid);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_CLOTHES_COLOR, headTop);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_HAIR, shoes);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_SHOES, gloves);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_BODY, weapon, "",
+ ItemColor_one, true);
+// Ea::BeingNet::setSprite(dstBeing, SPRITE_FLOOR, shield);
+ }
+ else if (dstBeing->getType() == ActorType::Npc
+ && serverFeatures->haveNpcGender())
+ {
+ dstBeing->setGender(Being::intToGender(gender));
+ }
+
+ uint8_t dir;
+ uint16_t x, y;
+ msg.readCoordinates(x, y, dir, "position");
+ msg.readInt8("xs");
+ msg.readInt8("ys");
+ dstBeing->setTileCoords(x, y);
+
+ if (job == 45 && socialWindow && outfitWindow)
+ {
+ const int num = socialWindow->getPortalIndex(x, y);
+ if (num >= 0)
+ {
+ dstBeing->setName(keyboard.getKeyShortString(
+ outfitWindow->keyName(num)));
+ }
+ else
+ {
+ dstBeing->setName("");
+ }
+ }
+
+ dstBeing->setDirection(dir);
+
+ const int level = static_cast<int>(msg.readInt16("level"));
+ if (level)
+ dstBeing->setLevel(level);
+ msg.readInt16("font");
+
+ const int maxHP = msg.readInt32("max hp");
+ const int hp = msg.readInt32("hp");
+ dstBeing->setMaxHP(maxHP);
+ dstBeing->setHP(hp);
+
+ msg.readInt8("is boss");
+
+ dstBeing->setStunMode(stunMode);
+ dstBeing->setStatusEffectBlock(0, static_cast<uint16_t>(
+ (statusEffects >> 16) & 0xffffU));
+ dstBeing->setStatusEffectBlock(16, static_cast<uint16_t>(
+ statusEffects & 0xffffU));
+}
+
+void BeingNet::processMapTypeProperty(Net::MessageIn &msg)
+{
+ const int16_t type = msg.readInt16("type");
+ const int flags = msg.readInt32("flags");
+ if (type == 0x28)
+ {
+ // +++ need get other flags from here
+ MapTypeProperty2 props;
+ props.data = static_cast<uint32_t>(flags);
+ Game *const game = Game::instance();
+ if (!game)
+ return;
+ Map *const map = game->getCurrentMap();
+ if (!map)
+ return;
+ map->setPvpMode(props.bits.party | (props.bits.guild * 2));
+ }
+}
+
+void BeingNet::processMapType(Net::MessageIn &msg)
+{
+ const int16_t type = msg.readInt16("type");
+ if (type == 19)
+ NotifyManager::notify(NotifyTypes::MAP_TYPE_BATTLEFIELD);
+ else
+ UNIMPLIMENTEDPACKET;
+}
+
+void BeingNet::processSkillCasting(Net::MessageIn &msg)
+{
+ // +++ need use other parameters
+
+ const BeingId srcId = msg.readBeingId("src id");
+ const BeingId dstId = msg.readBeingId("dst id");
+ const int dstX = msg.readInt16("dst x");
+ const int dstY = msg.readInt16("dst y");
+ const int skillId = msg.readInt16("skill id");
+ msg.readInt32("property"); // can be used to trigger effect
+ msg.readInt32("cast time");
+ msg.readInt8("dispossable");
+
+ if (!effectManager)
+ return;
+
+ if (srcId == BeingId_zero)
+ {
+ UNIMPLIMENTEDPACKET;
+ return;
+ }
+ else if (dstId != BeingId_zero)
+ { // being to being
+ Being *const srcBeing = actorManager->findBeing(srcId);
+ Being *const dstBeing = actorManager->findBeing(dstId);
+ skillDialog->playCastingSrcEffect(skillId, srcBeing);
+ skillDialog->playCastingDstEffect(skillId, dstBeing);
+ }
+ else if (dstX != 0 || dstY != 0)
+ { // being to position
+ UNIMPLIMENTEDPACKET;
+ }
+}
+
+void BeingNet::processBeingStatusChange(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processBeingStatusChange")
+ if (!actorManager)
+ {
+ BLOCK_END("BeingNet::processBeingStatusChange")
+ return;
+ }
+
+ // Status change
+ const uint16_t status = msg.readInt16("status");
+ const BeingId id = msg.readBeingId("being id");
+ const Enable flag = fromBool(
+ msg.readUInt8("flag: 0: stop, 1: start"), Enable);
+ msg.readInt32("total");
+ msg.readInt32("left");
+ msg.readInt32("val1");
+ msg.readInt32("val2");
+ msg.readInt32("val3");
+
+ Being *const dstBeing = actorManager->findBeing(id);
+ if (dstBeing)
+ dstBeing->setStatusEffect(status, flag);
+ BLOCK_END("BeingNet::processBeingStatusChange")
+}
+
+void BeingNet::processBeingStatusChange2(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processBeingStatusChange")
+ if (!actorManager)
+ {
+ BLOCK_END("BeingNet::processBeingStatusChange")
+ return;
+ }
+
+ // Status change
+ const uint16_t status = msg.readInt16("status");
+ const BeingId id = msg.readBeingId("being id");
+ const Enable flag = fromBool(
+ msg.readUInt8("flag: 0: stop, 1: start"), Enable);
+ msg.readInt32("left");
+ msg.readInt32("val1");
+ msg.readInt32("val2");
+ msg.readInt32("val3");
+
+ Being *const dstBeing = actorManager->findBeing(id);
+ if (dstBeing)
+ dstBeing->setStatusEffect(status, flag);
+ BLOCK_END("BeingNet::processBeingStatusChange")
+}
+
+void BeingNet::processBeingMove2(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processBeingMove2")
+ if (!actorManager)
+ {
+ BLOCK_END("BeingNet::processBeingMove2")
+ return;
+ }
+
+ /*
+ * A simplified movement packet, used by the
+ * later versions of eAthena for both mobs and
+ * players
+ */
+ Being *const dstBeing = actorManager->findBeing(
+ msg.readBeingId("being id"));
+
+ uint16_t srcX, srcY, dstX, dstY;
+ msg.readCoordinatePair(srcX, srcY, dstX, dstY, "move path");
+ msg.readUInt8("(sx<<4) | (sy&0x0f)");
+ msg.readInt32("tick");
+
+ /*
+ * This packet doesn't have enough info to actually
+ * create a new being, so if the being isn't found,
+ * we'll just pretend the packet didn't happen
+ */
+
+ if (!dstBeing)
+ {
+ BLOCK_END("BeingNet::processBeingMove2")
+ return;
+ }
+
+ dstBeing->setTileCoords(srcX, srcY);
+ if (localPlayer)
+ localPlayer->followMoveTo(dstBeing, srcX, srcY, dstX, dstY);
+ if (!serverFeatures->haveMove3())
+ dstBeing->setDestination(dstX, dstY);
+ if (dstBeing->getType() == ActorType::Player)
+ dstBeing->setMoveTime();
+ BLOCK_END("BeingNet::processBeingMove2")
+}
+
+void BeingNet::processBeingAction2(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processBeingAction2")
+ if (!actorManager)
+ {
+ BLOCK_END("BeingNet::processBeingAction2")
+ return;
+ }
+
+ Being *const srcBeing = actorManager->findBeing(
+ msg.readBeingId("src being id"));
+ Being *const dstBeing = actorManager->findBeing(
+ msg.readBeingId("dst being id"));
+
+ msg.readInt32("tick");
+ const int srcSpeed = msg.readInt32("src speed");
+ msg.readInt32("dst speed");
+ const int param1 = msg.readInt32("damage");
+ msg.readInt16("count");
+ const AttackTypeT type = static_cast<AttackTypeT>(
+ msg.readUInt8("action"));
+ msg.readInt32("left damage");
+
+ switch (type)
+ {
+ case AttackType::HIT: // Damage
+ case AttackType::CRITICAL: // Critical Damage
+ case AttackType::MULTI: // Critical Damage
+ case AttackType::MULTI_REFLECT:
+ case AttackType::REFLECT: // Reflected Damage
+ case AttackType::FLEE: // Lucky Dodge
+ case AttackType::SPLASH:
+ case AttackType::SKILL:
+ case AttackType::REPEATE:
+ if (srcBeing)
+ {
+ if (srcSpeed && srcBeing->getType() == ActorType::Player)
+ srcBeing->setAttackDelay(srcSpeed);
+ // attackid=1, type
+ srcBeing->handleAttack(dstBeing, param1, 1);
+ if (srcBeing->getType() == ActorType::Player)
+ srcBeing->setAttackTime();
+ }
+ if (dstBeing)
+ {
+ // level not present, using 1
+ dstBeing->takeDamage(srcBeing, param1,
+ static_cast<AttackTypeT>(type), 1);
+ }
+ break;
+
+ case AttackType::PICKUP:
+ break;
+
+ case AttackType::TOUCH_SKILL:
+ break;
+
+ case AttackType::SIT:
+ if (srcBeing)
+ {
+ srcBeing->setAction(BeingAction::SIT, 0);
+ if (srcBeing->getType() == ActorType::Player)
+ {
+ srcBeing->setMoveTime();
+ if (localPlayer)
+ localPlayer->imitateAction(srcBeing, BeingAction::SIT);
+ }
+ }
+ break;
+
+ case AttackType::STAND:
+ if (srcBeing)
+ {
+ srcBeing->setAction(BeingAction::STAND, 0);
+ if (srcBeing->getType() == ActorType::Player)
+ {
+ srcBeing->setMoveTime();
+ if (localPlayer)
+ {
+ localPlayer->imitateAction(srcBeing,
+ BeingAction::STAND);
+ }
+ }
+ }
+ break;
+ default:
+ case AttackType::MISS:
+ case AttackType::SKILLMISS:
+ UNIMPLIMENTEDPACKET;
+ break;
+ }
+ BLOCK_END("BeingNet::processBeingAction2")
+}
+
+void BeingNet::processMonsterHp(Net::MessageIn &msg)
+{
+ Being *const dstBeing = actorManager->findBeing(
+ msg.readBeingId("monster id"));
+ const int hp = msg.readInt32("hp");
+ const int maxHP = msg.readInt32("max hp");
+ if (dstBeing)
+ {
+ dstBeing->setHP(hp);
+ dstBeing->setMaxHP(maxHP);
+ }
+}
+
+void BeingNet::processSkillAutoCast(Net::MessageIn &msg)
+{
+ const int id = msg.readInt16("skill id");
+ msg.readInt16("inf");
+ msg.readInt16("unused");
+ const int level = msg.readInt16("skill level");
+ msg.readInt16("sp");
+ msg.readInt16("range");
+ msg.readString(24, "skill name");
+ msg.readInt8("unused");
+
+ if (localPlayer)
+ {
+ localPlayer->handleSkill(localPlayer, 0, id, level);
+ localPlayer->takeDamage(localPlayer, 0, AttackType::SKILL, id, level);
+ }
+}
+
+void BeingNet::processRanksList(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+ // +++ here need window with rank tables.
+ msg.readInt16("rank type");
+ for (int f = 0; f < 10; f ++)
+ msg.readString(24, "name");
+ for (int f = 0; f < 10; f ++)
+ msg.readInt32("points");
+ msg.readInt32("my points");
+}
+
+void BeingNet::processBlacksmithRanksList(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+ // +++ here need window with rank tables.
+ for (int f = 0; f < 10; f ++)
+ msg.readString(24, "name");
+ for (int f = 0; f < 10; f ++)
+ msg.readInt32("points");
+}
+
+void BeingNet::processAlchemistRanksList(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+ // +++ here need window with rank tables.
+ for (int f = 0; f < 10; f ++)
+ msg.readString(24, "name");
+ for (int f = 0; f < 10; f ++)
+ msg.readInt32("points");
+}
+
+void BeingNet::processTaekwonRanksList(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+ // +++ here need window with rank tables.
+ for (int f = 0; f < 10; f ++)
+ msg.readString(24, "name");
+ for (int f = 0; f < 10; f ++)
+ msg.readInt32("points");
+}
+
+void BeingNet::processPkRanksList(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+ // +++ here need window with rank tables.
+ for (int f = 0; f < 10; f ++)
+ msg.readString(24, "name");
+ for (int f = 0; f < 10; f ++)
+ msg.readInt32("points");
+}
+
+void BeingNet::processBeingChangeDirection(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processBeingChangeDirection")
+ if (!actorManager)
+ {
+ BLOCK_END("BeingNet::processBeingChangeDirection")
+ return;
+ }
+
+ Being *const dstBeing = actorManager->findBeing(
+ msg.readBeingId("being id"));
+
+ msg.readInt16("head direction");
+
+ const uint8_t dir = Net::MessageIn::fromServerDirection(
+ static_cast<uint8_t>(msg.readUInt8("player direction") & 0x0FU));
+
+ if (!dstBeing)
+ {
+ BLOCK_END("BeingNet::processBeingChangeDirection")
+ return;
+ }
+
+ dstBeing->setDirection(dir);
+ if (localPlayer)
+ localPlayer->imitateDirection(dstBeing, dir);
+ BLOCK_END("BeingNet::processBeingChangeDirection")
+}
+
+void BeingNet::processBeingSpecialEffect(Net::MessageIn &msg)
+{
+ if (!effectManager || !actorManager)
+ return;
+
+ const BeingId id = msg.readBeingId("being id");
+ Being *const being = actorManager->findBeing(id);
+ if (!being)
+ return;
+
+ const int effectType = msg.readInt32("effect type");
+
+ if (Particle::enabled)
+ effectManager->trigger(effectType, being);
+
+ // +++ need dehard code effectType == 3
+ if (effectType == 3 && being->getType() == ActorType::Player
+ && socialWindow)
+ { // reset received damage
+ socialWindow->resetDamage(being->getName());
+ }
+}
+
+void BeingNet::processBeingSpecialEffectNum(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+ // +++ need somhow show this effects.
+ // type is not same with self/misc effect.
+ msg.readBeingId("account id");
+ msg.readInt32("effect type");
+ msg.readInt32("num"); // effect variable
+}
+
+void BeingNet::processBeingSoundEffect(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+ // +++ need play this effect.
+ msg.readString(24, "sound effect name");
+ msg.readUInt8("type");
+ msg.readInt32("unused");
+ msg.readInt32("source being id");
+}
+
+void BeingNet::processSkillGroundNoDamage(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+ msg.readInt16("skill id");
+ msg.readInt32("src id");
+ msg.readInt16("val");
+ msg.readInt16("x");
+ msg.readInt16("y");
+ msg.readInt32("tick");
+}
+
+void BeingNet::processSkillEntry(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+ msg.readInt16("len");
+ msg.readInt32("accound id");
+ msg.readInt32("creator accound id");
+ msg.readInt16("x");
+ msg.readInt16("y");
+ msg.readInt32("job");
+ msg.readUInt8("radius");
+ msg.readUInt8("visible");
+ msg.readUInt8("level");
+}
+
+void BeingNet::processPlaterStatusChange(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processPlayerStop")
+ if (!actorManager)
+ {
+ BLOCK_END("BeingNet::processPlayerStop")
+ return;
+ }
+
+ // Change in players' flags
+ const BeingId id = msg.readBeingId("account id");
+ Being *const dstBeing = actorManager->findBeing(id);
+ if (!dstBeing)
+ return;
+
+ const uint16_t stunMode = msg.readInt16("stun mode");
+ uint32_t statusEffects = msg.readInt16("status effect");
+ statusEffects |= (static_cast<uint32_t>(msg.readInt32("opt?"))) << 16;
+ dstBeing->setKarma(msg.readUInt8("karma"));
+
+ dstBeing->setStunMode(stunMode);
+ dstBeing->setStatusEffectBlock(0, static_cast<uint16_t>(
+ (statusEffects >> 16) & 0xffff));
+ dstBeing->setStatusEffectBlock(16, static_cast<uint16_t>(
+ statusEffects & 0xffff));
+ BLOCK_END("BeingNet::processPlayerStop")
+}
+
+void BeingNet::processPlaterStatusChange2(Net::MessageIn &msg)
+{
+ if (!actorManager)
+ return;
+
+ const BeingId id = msg.readBeingId("account id");
+ Being *const dstBeing = actorManager->findBeing(id);
+ if (!dstBeing)
+ return;
+
+ uint32_t statusEffects = msg.readInt32("status effect");
+ dstBeing->setLevel(msg.readInt32("level"));
+ msg.readInt32("showEFST");
+
+ dstBeing->setStatusEffectBlock(0, static_cast<uint16_t>(
+ (statusEffects >> 16) & 0xffff));
+ dstBeing->setStatusEffectBlock(16, static_cast<uint16_t>(
+ statusEffects & 0xffff));
+}
+
+void BeingNet::processPlaterStatusChangeNoTick(Net::MessageIn &msg)
+{
+ const uint16_t status = msg.readInt16("index");
+ const BeingId id = msg.readBeingId("account id");
+ const Enable flag = fromBool(msg.readUInt8("state")
+ ? true : false, Enable);
+
+ Being *const dstBeing = actorManager->findBeing(id);
+ if (!dstBeing)
+ return;
+
+ dstBeing->setStatusEffect(status, flag);
+}
+
+void BeingNet::processBeingResurrect(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processBeingResurrect")
+ if (!actorManager || !localPlayer)
+ {
+ BLOCK_END("BeingNet::processBeingResurrect")
+ return;
+ }
+
+ // A being changed mortality status
+
+ const BeingId id = msg.readBeingId("being id");
+ msg.readInt16("unused");
+ Being *const dstBeing = actorManager->findBeing(id);
+ if (!dstBeing)
+ {
+ BLOCK_END("BeingNet::processBeingResurrect")
+ return;
+ }
+
+ // If this is player's current target, clear it.
+ if (dstBeing == localPlayer->getTarget())
+ localPlayer->stopAttack();
+
+ dstBeing->setAction(BeingAction::STAND, 0);
+ BLOCK_END("BeingNet::processBeingResurrect")
+}
+
+void BeingNet::processPlayerGuilPartyInfo(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processPlayerGuilPartyInfo")
+ if (!actorManager)
+ {
+ BLOCK_END("BeingNet::processPlayerGuilPartyInfo")
+ return;
+ }
+
+ Being *const dstBeing = actorManager->findBeing(
+ msg.readBeingId("being id"));
+
+ if (dstBeing)
+ {
+ dstBeing->setName(msg.readString(24, "char name"));
+ dstBeing->setPartyName(msg.readString(24, "party name"));
+ dstBeing->setGuildName(msg.readString(24, "guild name"));
+ dstBeing->setGuildPos(msg.readString(24, "guild pos"));
+ dstBeing->addToCache();
+ }
+ BLOCK_END("BeingNet::processPlayerGuilPartyInfo")
+}
+
+void BeingNet::processBeingRemoveSkil(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+ // +++ if skill unit was added, here need remove it from actors
+ msg.readInt32("skill unit id");
+}
+
+void BeingNet::processBeingFakeName(Net::MessageIn &msg)
+{
+ const BeingType::BeingType type = static_cast<BeingType::BeingType>(
+ msg.readUInt8("object type"));
+ const BeingId id = msg.readBeingId("npc id");
+ msg.skip(8, "unused");
+ const uint16_t job = msg.readInt16("class?"); // 111
+ msg.skip(30, "unused");
+ uint16_t x, y;
+ uint8_t dir;
+ msg.readCoordinates(x, y, dir, "position");
+ msg.readUInt8("sx");
+ msg.readUInt8("sy");
+ msg.skip(4, "unsued");
+
+ Being *const dstBeing = createBeing2(msg, id, job, type);
+ if (!dstBeing)
+ return;
+ dstBeing->setSubtype(fromInt(job, BeingTypeId), 0);
+ dstBeing->setTileCoords(x, y);
+ dstBeing->setDirection(dir);
+}
+
+void BeingNet::processBeingStatUpdate1(Net::MessageIn &msg)
+{
+ const BeingId id = msg.readBeingId("account id");
+ const int type = msg.readInt16("type");
+ const int value = msg.readInt32("value");
+
+ Being *const dstBeing = actorManager->findBeing(id);
+ if (!dstBeing)
+ return;
+
+ if (type != Ea::MANNER)
+ {
+ UNIMPLIMENTEDPACKET;
+ return;
+ }
+ dstBeing->setManner(value);
+}
+
+void BeingNet::processBeingSelfEffect(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processBeingSelfEffect")
+ if (!effectManager || !actorManager)
+ {
+ BLOCK_END("BeingNet::processBeingSelfEffect")
+ return;
+ }
+
+ const BeingId id = msg.readBeingId("being id");
+ Being *const being = actorManager->findBeing(id);
+ if (!being)
+ {
+ BLOCK_END("BeingNet::processBeingSelfEffect")
+ return;
+ }
+
+ const int effectType = msg.readInt32("effect type");
+ if (Particle::enabled)
+ effectManager->trigger(effectType, being);
+
+ BLOCK_END("BeingNet::processBeingSelfEffect")
+}
+
+void BeingNet::processMobInfo(Net::MessageIn &msg)
+{
+ const int len = msg.readInt16("len");
+ if (len < 12)
+ return;
+ Being *const dstBeing = actorManager->findBeing(
+ msg.readBeingId("monster id"));
+ const int attackRange = msg.readInt32("range");
+ if (dstBeing)
+ dstBeing->setAttackRange(attackRange);
+}
+
+void BeingNet::processBeingAttrs(Net::MessageIn &msg)
+{
+ const int len = msg.readInt16("len");
+ if (len < 12)
+ return;
+ Being *const dstBeing = actorManager->findBeing(
+ msg.readBeingId("player id"));
+ const int gmLevel = msg.readInt32("gm level");
+ if (dstBeing && gmLevel)
+ {
+ if (dstBeing == localPlayer)
+ localPlayer->setGMLevel(gmLevel);
+ dstBeing->setGM(true);
+ }
+ else
+ {
+ if (dstBeing == localPlayer)
+ localPlayer->setGMLevel(0);
+ if (dstBeing)
+ dstBeing->setGM(false);
+ }
+}
+
+void BeingNet::processMonsterInfo(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+
+ msg.readInt16("class");
+ msg.readInt16("level");
+ msg.readInt16("size");
+ msg.readInt32("hp");
+ msg.readInt16("def");
+ msg.readInt16("race");
+ msg.readInt16("mdef");
+ msg.readInt16("ele");
+}
+
+void BeingNet::processClassChange(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+
+ msg.readBeingId("being id");
+ msg.readUInt8("type");
+ msg.readInt32("class");
+}
+
+void BeingNet::processSpiritBalls(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+
+ msg.readBeingId("being id");
+ msg.readInt16("spirits amount");
+}
+
+void BeingNet::processSpiritBallSingle(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+
+ msg.readBeingId("being id");
+ msg.readInt16("spirits amount");
+}
+
+void BeingNet::processBladeStop(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+
+ msg.readInt32("src being id");
+ msg.readInt32("dst being id");
+ msg.readInt32("flag");
+}
+
+void BeingNet::processComboDelay(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+
+ msg.readBeingId("being id");
+ msg.readInt32("wait");
+}
+
+void BeingNet::processWddingEffect(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+
+ msg.readBeingId("being id");
+}
+
+void BeingNet::processBeingSlide(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+
+ msg.readBeingId("being id");
+ msg.readInt16("x");
+ msg.readInt16("y");
+}
+
+void BeingNet::processStarsKill(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+
+ msg.readString(24, "map name");
+ msg.readInt32("monster id");
+ msg.readUInt8("start");
+ msg.readUInt8("result");
+}
+
+void BeingNet::processGladiatorFeelRequest(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+
+ msg.readUInt8("which");
+}
+
+void BeingNet::processBossMapInfo(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+
+ msg.readUInt8("info type");
+ msg.readInt32("x");
+ msg.readInt32("y");
+ msg.readInt16("min hours");
+ msg.readInt16("min minutes");
+ msg.readInt16("max hours");
+ msg.readInt16("max minutes");
+ msg.readString(24, "monster name"); // really can be used 51 byte?
+}
+
+void BeingNet::processBeingFont(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+
+ msg.readBeingId("account id");
+ msg.readInt16("font");
+}
+
+void BeingNet::processBeingMilleniumShield(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+
+ msg.readBeingId("account id");
+ msg.readInt16("shields");
+ msg.readInt16("unused");
+}
+
+void BeingNet::processBeingCharm(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+
+ msg.readBeingId("account id");
+ msg.readInt16("charm type");
+ msg.readInt16("charm count");
+}
+
+void BeingNet::processBeingViewEquipment(Net::MessageIn &msg)
+{
+ UNIMPLIMENTEDPACKET;
+
+ const int count = (msg.readInt16("len") - 45) / 31;
+ msg.readString(24, "name");
+ msg.readInt16("job");
+ msg.readInt16("head");
+ msg.readInt16("accessory");
+ msg.readInt16("accessory2");
+ msg.readInt16("accessory3");
+ msg.readInt16("robe");
+ msg.readInt16("hair color");
+ msg.readInt16("body color");
+ msg.readUInt8("gender");
+ for (int f = 0; f < count; f ++)
+ {
+ msg.readInt16("index");
+ msg.readInt16("item id");
+ msg.readUInt8("item type");
+ msg.readInt32("location");
+ msg.readInt32("wear state");
+ msg.readInt8("refine");
+ for (int d = 0; d < 4; d ++)
+ msg.readInt16("card");
+ msg.readInt32("hire expire date (?)");
+ msg.readInt16("equip type");
+ msg.readInt16("item sprite number");
+ msg.readUInt8("flags");
+ }
+}
+
+void BeingNet::processPvpSet(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processPvpSet")
+ const BeingId id = msg.readBeingId("being id");
+ const int rank = msg.readInt32("rank");
+ msg.readInt32("num");
+ if (actorManager)
+ {
+ Being *const dstBeing = actorManager->findBeing(id);
+ if (dstBeing)
+ dstBeing->setPvpRank(rank);
+ }
+ BLOCK_END("BeingNet::processPvpSet")
+}
+
+void BeingNet::processNameResponse2(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processNameResponse2")
+ if (!actorManager || !localPlayer)
+ {
+ BLOCK_END("BeingNet::processNameResponse2")
+ return;
+ }
+
+ const int len = msg.readInt16("len");
+ const BeingId beingId = msg.readBeingId("account ic");
+ const std::string str = msg.readString(len - 8, "name");
+ Being *const dstBeing = actorManager->findBeing(beingId);
+ if (dstBeing)
+ {
+ if (beingId == localPlayer->getId())
+ {
+ localPlayer->pingResponse();
+ }
+ else
+ {
+ dstBeing->setName(str);
+ dstBeing->updateGuild();
+ dstBeing->addToCache();
+
+ if (dstBeing->getType() == ActorType::Player)
+ dstBeing->updateColors();
+
+ if (localPlayer)
+ {
+ const Party *const party = localPlayer->getParty();
+ if (party && party->isMember(dstBeing->getId()))
+ {
+ PartyMember *const member = party->getMember(
+ dstBeing->getId());
+
+ if (member)
+ member->setName(dstBeing->getName());
+ }
+ localPlayer->checkNewName(dstBeing);
+ }
+ }
+ }
+ BLOCK_END("BeingNet::processNameResponse2")
+}
+
+Being *BeingNet::createBeing2(Net::MessageIn &msg,
+ const BeingId id,
+ const int16_t job,
+ const BeingType::BeingType beingType)
+{
+ if (!actorManager)
+ return nullptr;
+
+ ActorTypeT type = ActorType::Unknown;
+ switch (beingType)
+ {
+ case BeingType::PC:
+ type = ActorType::Player;
+ break;
+ case BeingType::NPC:
+ case BeingType::NPC_EVENT:
+ type = ActorType::Npc;
+ break;
+ case BeingType::MONSTER:
+ type = ActorType::Monster;
+ break;
+ case BeingType::MERSOL:
+ type = ActorType::Mercenary;
+ break;
+ case BeingType::PET:
+ type = ActorType::Pet;
+ break;
+ case BeingType::HOMUN:
+ type = ActorType::Homunculus;
+ break;
+ case BeingType::ITEM:
+ case BeingType::SKILL:
+ case BeingType::ELEMENTAL:
+ logger->log("not supported object type: %d, job: %d",
+ static_cast<int>(beingType), static_cast<int>(job));
+ break;
+ case BeingType::CHAT:
+ default:
+ UNIMPLIMENTEDPACKET;
+ type = ActorType::Monster;
+ logger->log("not supported object type: %d, job: %d",
+ static_cast<int>(beingType), static_cast<int>(job));
+ break;
+ }
+ if (job == 45 && beingType == BeingType::NPC_EVENT)
+ type = ActorType::Portal;
+
+ Being *const being = actorManager->createBeing(
+ id, type, fromInt(job, BeingTypeId));
+ if (beingType == BeingType::MERSOL)
+ {
+ MercenaryInfo *const info = PlayerInfo::getMercenary();
+ if (info && info->id == id)
+ PlayerInfo::setMercenaryBeing(being);
+ }
+ else if (beingType == BeingType::PET)
+ {
+ if (PlayerInfo::getPetBeingId() == id)
+ PlayerInfo::setPetBeing(being);
+ }
+ return being;
+}
+
+} // namespace EAthena
diff --git a/src/net/eathena/beingnet.h b/src/net/eathena/beingnet.h
new file mode 100644
index 000000000..0b3dd041f
--- /dev/null
+++ b/src/net/eathena/beingnet.h
@@ -0,0 +1,101 @@
+/*
+ * The ManaPlus Client
+ * Copyright (C) 2004-2009 The Mana World Development Team
+ * Copyright (C) 2009-2010 The Mana Developers
+ * Copyright (C) 2011-2015 The ManaPlus Developers
+ *
+ * This file is part of The ManaPlus Client.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NET_EATHENA_BEING_H
+#define NET_EATHENA_BEING_H
+
+#include "net/ea/beinghandler.h"
+
+#include "net/eathena/beingtype.h"
+#include "net/eathena/messagehandler.h"
+
+namespace EAthena
+{
+ namespace BeingNet
+ {
+ void processBeingChangeLook2(Net::MessageIn &msg);
+ void processBeingChangeLookCards(Net::MessageIn &msg);
+ void processBeingVisible(Net::MessageIn &msg);
+ void processBeingMove(Net::MessageIn &msg);
+ void processBeingSpawn(Net::MessageIn &msg);
+ void processMapTypeProperty(Net::MessageIn &msg);
+ void processMapType(Net::MessageIn &msg);
+ void processSkillCasting(Net::MessageIn &msg);
+ void processBeingStatusChange(Net::MessageIn &msg);
+ void processBeingStatusChange2(Net::MessageIn &msg);
+ void processBeingMove2(Net::MessageIn &msg);
+ void processBeingAction2(Net::MessageIn &msg);
+ void processMonsterHp(Net::MessageIn &msg);
+ void processSkillAutoCast(Net::MessageIn &msg);
+ void processRanksList(Net::MessageIn &msg);
+ void processBeingChangeDirection(Net::MessageIn &msg);
+ void processBeingChangeLookContinue(Net::MessageIn &msg,
+ Being *const dstBeing,
+ const uint8_t type,
+ const int id,
+ const int id2,
+ const int *cards) A_NONNULL(2);
+ void processBeingSpecialEffect(Net::MessageIn &msg);
+ void processBeingSpecialEffectNum(Net::MessageIn &msg);
+ void processBeingSoundEffect(Net::MessageIn &msg);
+ void processSkillGroundNoDamage(Net::MessageIn &msg);
+ void processSkillEntry(Net::MessageIn &msg);
+ void processPlaterStatusChange(Net::MessageIn &msg);
+ void processPlaterStatusChangeNoTick(Net::MessageIn &msg);
+ void processBeingResurrect(Net::MessageIn &msg);
+ void processPlayerGuilPartyInfo(Net::MessageIn &msg);
+ void processBeingRemoveSkil(Net::MessageIn &msg);
+ void processBeingFakeName(Net::MessageIn &msg);
+ void processBeingStatUpdate1(Net::MessageIn &msg);
+ void processPlaterStatusChange2(Net::MessageIn &msg);
+ void processBeingSelfEffect(Net::MessageIn &msg);
+ void processMobInfo(Net::MessageIn &msg);
+ void processBeingAttrs(Net::MessageIn &msg);
+ void processMonsterInfo(Net::MessageIn &msg);
+ void processClassChange(Net::MessageIn &msg);
+ void processSpiritBalls(Net::MessageIn &msg);
+ void processSpiritBallSingle(Net::MessageIn &msg);
+ void processBladeStop(Net::MessageIn &msg);
+ void processComboDelay(Net::MessageIn &msg);
+ void processWddingEffect(Net::MessageIn &msg);
+ void processBeingSlide(Net::MessageIn &msg);
+ void processStarsKill(Net::MessageIn &msg);
+ void processBlacksmithRanksList(Net::MessageIn &msg);
+ void processAlchemistRanksList(Net::MessageIn &msg);
+ void processTaekwonRanksList(Net::MessageIn &msg);
+ void processPkRanksList(Net::MessageIn &msg);
+ void processGladiatorFeelRequest(Net::MessageIn &msg);
+ void processBossMapInfo(Net::MessageIn &msg);
+ void processBeingFont(Net::MessageIn &msg);
+ void processBeingMilleniumShield(Net::MessageIn &msg);
+ void processBeingCharm(Net::MessageIn &msg);
+ void processBeingViewEquipment(Net::MessageIn &msg);
+ void processPvpSet(Net::MessageIn &msg);
+ void processNameResponse2(Net::MessageIn &msg);
+ Being *createBeing2(Net::MessageIn &msg,
+ const BeingId id,
+ const int16_t job,
+ const BeingType::BeingType beingType);
+ } // namespace Being
+} // namespace EAthena
+
+#endif // NET_EATHENA_BEING_H
diff --git a/src/net/tmwa/beinghandler.cpp b/src/net/tmwa/beinghandler.cpp
index d34594ee6..2ec3e62cb 100644
--- a/src/net/tmwa/beinghandler.cpp
+++ b/src/net/tmwa/beinghandler.cpp
@@ -38,6 +38,9 @@
#include "net/serverfeatures.h"
+#include "net/ea/beingnet.h"
+
+#include "net/tmwa/beingnet.h"
#include "net/tmwa/guildmanager.h"
#include "net/tmwa/messageout.h"
#include "net/tmwa/protocol.h"
@@ -112,122 +115,122 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
switch (msg.getId())
{
case SMSG_BEING_VISIBLE:
- processBeingVisible(msg);
+ BeingNet::processBeingVisible(msg);
break;
case SMSG_BEING_MOVE:
- processBeingMove(msg);
+ BeingNet::processBeingMove(msg);
break;
case SMSG_BEING_MOVE2:
- processBeingMove2(msg);
+ BeingNet::processBeingMove2(msg);
break;
case SMSG_BEING_MOVE3:
- processBeingMove3(msg);
+ Ea::BeingNet::processBeingMove3(msg);
break;
case SMSG_BEING_SPAWN:
- processBeingSpawn(msg);
+ BeingNet::processBeingSpawn(msg);
break;
case SMSG_BEING_REMOVE:
- processBeingRemove(msg);
+ Ea::BeingNet::processBeingRemove(msg);
break;
case SMSG_BEING_RESURRECT:
- processBeingResurrect(msg);
+ BeingNet::processBeingResurrect(msg);
break;
case SMSG_SKILL_DAMAGE:
- processSkillDamage(msg);
+ Ea::BeingNet::processSkillDamage(msg);
break;
case SMSG_BEING_ACTION:
- processBeingAction(msg);
+ Ea::BeingNet::processBeingAction(msg);
break;
case SMSG_BEING_SELFEFFECT:
- processBeingSelfEffect(msg);
+ BeingNet::processBeingSelfEffect(msg);
break;
case SMSG_BEING_EMOTION:
- processBeingEmotion(msg);
+ Ea::BeingNet::processBeingEmotion(msg);
break;
case SMSG_BEING_CHANGE_LOOKS:
- processBeingChangeLook(msg);
+ BeingNet::processBeingChangeLook(msg);
break;
case SMSG_BEING_CHANGE_LOOKS2:
- processBeingChangeLook2(msg);
+ BeingNet::processBeingChangeLook2(msg);
break;
case SMSG_BEING_NAME_RESPONSE:
- processNameResponse(msg);
+ Ea::BeingNet::processNameResponse(msg);
break;
case SMSG_BEING_IP_RESPONSE:
- processIpResponse(msg);
+ BeingNet::processIpResponse(msg);
break;
case SMSG_SOLVE_CHAR_NAME:
break;
case SMSG_PLAYER_GUILD_PARTY_INFO:
- processPlayerGuilPartyInfo(msg);
+ BeingNet::processPlayerGuilPartyInfo(msg);
break;
case SMSG_BEING_CHANGE_DIRECTION:
- processBeingChangeDirection(msg);
+ BeingNet::processBeingChangeDirection(msg);
break;
case SMSG_PLAYER_UPDATE_1:
- processPlayerUpdate1(msg);
+ BeingNet::processPlayerUpdate1(msg);
break;
case SMSG_PLAYER_UPDATE_2:
- processPlayerUpdate2(msg);
+ BeingNet::processPlayerUpdate2(msg);
break;
case SMSG_PLAYER_MOVE:
- processPlayerMove(msg);
+ BeingNet::processPlayerMove(msg);
break;
case SMSG_PLAYER_STOP:
- processPlayerStop(msg);
+ Ea::BeingNet::processPlayerStop(msg);
break;
case SMSG_PLAYER_MOVE_TO_ATTACK:
- processPlayerMoveToAttack(msg);
+ Ea::BeingNet::processPlayerMoveToAttack(msg);
break;
case SMSG_PLAYER_STATUS_CHANGE:
- processPlaterStatusChange(msg);
+ BeingNet::processPlaterStatusChange(msg);
break;
case SMSG_BEING_STATUS_CHANGE:
- processBeingStatusChange(msg);
+ BeingNet::processBeingStatusChange(msg);
break;
case SMSG_SKILL_CASTING:
- processSkillCasting(msg);
+ BeingNet::processSkillCasting(msg);
break;
case SMSG_SKILL_CAST_CANCEL:
- processSkillCastCancel(msg);
+ BeingNet::processSkillCastCancel(msg);
break;
case SMSG_SKILL_NO_DAMAGE:
- processSkillNoDamage(msg);
+ Ea::BeingNet::processSkillNoDamage(msg);
break;
case SMSG_PVP_MAP_MODE:
- processPvpMapMode(msg);
+ Ea::BeingNet::processPvpMapMode(msg);
break;
case SMSG_PVP_SET:
- processPvpSet(msg);
+ BeingNet::processPvpSet(msg);
break;
default:
@@ -254,1335 +257,8 @@ void BeingHandler::requestRanks(const RankT rank A_UNUSED) const
}
#endif
-void BeingHandler::processBeingChangeLook(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processBeingChangeLook")
- if (!actorManager)
- {
- BLOCK_END("BeingHandler::processBeingChangeLook")
- return;
- }
-
- Being *const dstBeing = actorManager->findBeing(
- msg.readBeingId("being id"));
-
- const uint8_t type = msg.readUInt8("type");
- const int16_t id = static_cast<int16_t>(msg.readUInt8("id"));
- const int id2 = 1;
-
- if (!localPlayer || !dstBeing)
- {
- BLOCK_END("BeingHandler::processBeingChangeLook")
- return;
- }
- processBeingChangeLookContinue(msg, dstBeing, type, id, id2);
- BLOCK_END("BeingHandler::processBeingChangeLook")
-}
-
-void BeingHandler::processBeingChangeLook2(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processBeingChangeLook")
- if (!actorManager)
- {
- BLOCK_END("BeingHandler::processBeingChangeLook")
- return;
- }
-
- Being *const dstBeing = actorManager->findBeing(
- msg.readBeingId("being id"));
-
- const uint8_t type = msg.readUInt8("type");
- int id2 = 0;
-
- const int16_t id = msg.readInt16("id1");
- if (type == 2)
- {
- id2 = msg.readInt16("id2");
- }
- else
- {
- msg.readInt16("id2");
- id2 = 1;
- }
-
- if (!localPlayer || !dstBeing)
- {
- BLOCK_END("BeingHandler::processBeingChangeLook")
- return;
- }
- processBeingChangeLookContinue(msg, dstBeing, type, id, id2);
- BLOCK_END("BeingHandler::processBeingChangeLook")
-}
-
-void BeingHandler::processBeingChangeLookContinue(Net::MessageIn &msg,
- Being *const dstBeing,
- const uint8_t type,
- const int id,
- const int id2)
-{
- if (dstBeing->getType() == ActorType::Player)
- dstBeing->setOtherTime();
-
- const std::string color;
- switch (type)
- {
- case 0: // change race
- dstBeing->setSubtype(fromInt(id, BeingTypeId),
- dstBeing->getLook());
- break;
- case 1: // eAthena LOOK_HAIR
- {
- const uint16_t look = static_cast<uint16_t>(id / 256);
- const int hair = id % 256;
- dstBeing->setHairStyle(SPRITE_HAIR_COLOR, hair * -1);
- dstBeing->setLook(look);
- break;
- }
- case 2: // Weapon ID in id, Shield ID in id2
- dstBeing->setSprite(SPRITE_BODY, id, "", ItemColor_one, true);
- dstBeing->setSprite(SPRITE_FLOOR, id2);
- localPlayer->imitateOutfit(dstBeing, SPRITE_FLOOR);
- break;
- case 3: // Change lower headgear for eAthena, pants for us
- dstBeing->setSprite(SPRITE_WEAPON, id, color,
- ItemColor_one);
- localPlayer->imitateOutfit(dstBeing, SPRITE_WEAPON);
- break;
- case 4: // Change upper headgear for eAthena, hat for us
- dstBeing->setSprite(SPRITE_CLOTHES_COLOR, id, color,
- ItemColor_one);
- localPlayer->imitateOutfit(dstBeing, SPRITE_CLOTHES_COLOR);
- break;
- case 5: // Change middle headgear for eathena, armor for us
- dstBeing->setSprite(SPRITE_HEAD_BOTTOM, id, color,
- ItemColor_one);
- localPlayer->imitateOutfit(dstBeing, SPRITE_HEAD_BOTTOM);
- break;
- case 6: // eAthena LOOK_HAIR_COLOR
- dstBeing->setHairColor(SPRITE_HAIR_COLOR,
- fromInt(id, ItemColor));
- break;
- case 7: // Clothes color
- // ignoring it
- break;
- case 8: // eAthena LOOK_SHIELD
- dstBeing->setSprite(SPRITE_FLOOR, id, color,
- ItemColor_one);
- localPlayer->imitateOutfit(dstBeing, SPRITE_FLOOR);
- break;
- case 9: // eAthena LOOK_SHOES
- dstBeing->setSprite(SPRITE_HAIR, id, color,
- ItemColor_one);
- localPlayer->imitateOutfit(dstBeing, SPRITE_HAIR);
- break;
- case 10: // LOOK_GLOVES
- dstBeing->setSprite(SPRITE_SHOES, id, color,
- ItemColor_one);
- localPlayer->imitateOutfit(dstBeing, SPRITE_SHOES);
- break;
- case 11: // LOOK_CAPE
- dstBeing->setSprite(SPRITE_SHIELD, id, color,
- ItemColor_one);
- localPlayer->imitateOutfit(dstBeing, SPRITE_SHIELD);
- break;
- case 12:
- dstBeing->setSprite(SPRITE_HEAD_TOP, id, color,
- ItemColor_one);
- localPlayer->imitateOutfit(dstBeing, SPRITE_HEAD_TOP);
- break;
- case 13:
- dstBeing->setSprite(SPRITE_HEAD_MID, id, color,
- ItemColor_one);
- localPlayer->imitateOutfit(dstBeing, SPRITE_HEAD_MID);
- break;
- case 14:
- dstBeing->setSprite(SPRITE_ROBE, id, color,
- ItemColor_one);
- localPlayer->imitateOutfit(dstBeing, SPRITE_ROBE);
- break;
- case 15:
- dstBeing->setSprite(SPRITE_EVOL2, id, color,
- ItemColor_one);
- localPlayer->imitateOutfit(dstBeing, SPRITE_EVOL2);
- break;
- case 16:
- dstBeing->setLook(static_cast<uint16_t>(id));
- break;
- default:
- UNIMPLIMENTEDPACKET;
- break;
- }
-}
-
-void BeingHandler::processPlayerUpdate1(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processPlayerMoveUpdate")
- if (!actorManager || !localPlayer)
- {
- BLOCK_END("BeingHandler::processPlayerMoveUpdate")
- return;
- }
-
- // An update about a player, potentially including movement.
- const BeingId id = msg.readBeingId("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 (toInt(id, int) < 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)
- beingHandler->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 uint16_t look = msg.readUInt8("look");
- dstBeing->setSubtype(fromInt(job, BeingTypeId), look);
- const uint16_t weapon = msg.readInt16("weapon");
- const uint16_t shield = msg.readInt16("shield");
- const uint16_t headBottom = msg.readInt16("head bottom");
-
- const uint16_t headTop = msg.readInt16("head top");
- const uint16_t headMid = msg.readInt16("head mid");
- const ItemColor hairColor = fromInt(
- msg.readUInt8("hair color"), ItemColor);
- msg.readUInt8("unused");
- msg.readInt32("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");
- dstBeing->setManner(msg.readInt16("manner"));
- dstBeing->setStatusEffectBlock(32, msg.readInt16("opt3"));
- dstBeing->setKarma(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_BODY, weapon, "", ItemColor_one, true);
- dstBeing->updateSprite(SPRITE_FLOOR, shield);
- dstBeing->updateSprite(SPRITE_WEAPON, headBottom);
- dstBeing->updateSprite(SPRITE_HEAD_BOTTOM, headMid);
- dstBeing->updateSprite(SPRITE_CLOTHES_COLOR, headTop);
- dstBeing->updateSprite(SPRITE_HAIR_COLOR, hairStyle * -1,
- ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
- dstBeing->setHairColor(hairColor);
- }
- localPlayer->imitateOutfit(dstBeing);
-
- 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);
-
- applyPlayerAction(msg, dstBeing, msg.readUInt8("action type"));
- const int level = static_cast<int>(msg.readUInt8("level"));
- if (level)
- dstBeing->setLevel(level);
-
- msg.readUInt8("unused");
-
- 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));
-
- BLOCK_END("BeingHandler::processPlayerMoveUpdate")
-}
-
-void BeingHandler::processPlayerUpdate2(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processPlayerMoveUpdate")
- if (!actorManager || !localPlayer)
- {
- BLOCK_END("BeingHandler::processPlayerMoveUpdate")
- return;
- }
-
- // An update about a player, potentially including movement.
- const BeingId id = msg.readBeingId("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 (toInt(id, int) < 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)
- beingHandler->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 uint16_t look = msg.readUInt8("look");
- dstBeing->setSubtype(fromInt(job, BeingTypeId), look);
- const uint16_t weapon = msg.readInt16("weapon");
- const uint16_t shield = msg.readInt16("shield");
- const uint16_t headBottom = msg.readInt16("head bottom");
- const uint16_t headTop = msg.readInt16("head top");
- const uint16_t headMid = msg.readInt16("head mid");
- const ItemColor hairColor = fromInt(
- msg.readUInt8("hair color"), ItemColor);
- msg.readUInt8("unused");
- msg.readInt32("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");
- dstBeing->setManner(msg.readInt16("manner"));
- dstBeing->setStatusEffectBlock(32, msg.readInt16("opt3"));
- dstBeing->setKarma(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_BODY, weapon, "", ItemColor_one, true);
- dstBeing->updateSprite(SPRITE_FLOOR, shield);
- dstBeing->updateSprite(SPRITE_WEAPON, headBottom);
- dstBeing->updateSprite(SPRITE_HEAD_BOTTOM, headMid);
- dstBeing->updateSprite(SPRITE_CLOTHES_COLOR, headTop);
- dstBeing->updateSprite(SPRITE_HAIR_COLOR, hairStyle * -1,
- ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
- dstBeing->setHairColor(hairColor);
- }
- localPlayer->imitateOutfit(dstBeing);
-
- 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);
-
- applyPlayerAction(msg, dstBeing, msg.readUInt8("action type"));
- const int level = static_cast<int>(msg.readUInt8("level"));
- if (level)
- dstBeing->setLevel(level);
-
- 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));
-
- BLOCK_END("BeingHandler::processPlayerMoveUpdate")
-}
-
-void BeingHandler::processPlayerMove(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processPlayerMoveUpdate")
- if (!actorManager || !localPlayer)
- {
- BLOCK_END("BeingHandler::processPlayerMoveUpdate")
- return;
- }
-
- // An update about a player, potentially including movement.
- const BeingId id = msg.readBeingId("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 (toInt(id, int) < 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)
- beingHandler->requestNameById(id);
- }
-
- const 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 uint16_t look = msg.readUInt8("look");
- dstBeing->setSubtype(fromInt(job, BeingTypeId), look);
- const uint16_t weapon = msg.readInt16("weapon");
- const uint16_t shield = msg.readInt16("shield");
- const uint16_t headBottom = msg.readInt16("head bottom");
-
- msg.readInt32("tick");
-
- const uint16_t headTop = msg.readInt16("head top");
- const uint16_t headMid = msg.readInt16("head mid");
- const ItemColor hairColor = fromInt(
- msg.readUInt8("hair color"), ItemColor);
- msg.readUInt8("unused");
- msg.readInt32("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");
- dstBeing->setManner(msg.readInt16("manner"));
- dstBeing->setStatusEffectBlock(32, msg.readInt16("opt3"));
- dstBeing->setKarma(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_BODY, weapon, "", ItemColor_one, true);
- dstBeing->updateSprite(SPRITE_FLOOR, shield);
- dstBeing->updateSprite(SPRITE_WEAPON, headBottom);
- dstBeing->updateSprite(SPRITE_HEAD_BOTTOM, headMid);
- dstBeing->updateSprite(SPRITE_CLOTHES_COLOR, headTop);
- dstBeing->updateSprite(SPRITE_HAIR_COLOR, hairStyle * -1,
- ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
- dstBeing->setHairColor(hairColor);
- }
- localPlayer->imitateOutfit(dstBeing);
-
- 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());
- }
-
- const uint16_t gmstatus = msg.readInt16("gm status");
-
- if (gmstatus & 0x80)
- dstBeing->setGM(true);
-
- msg.readUInt8("unused");
-
- const int level = static_cast<int>(msg.readUInt8("level"));
- if (level)
- dstBeing->setLevel(level);
-
- msg.readUInt8("unused");
-
- if (dstBeing->getType() != ActorType::Player)
- 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 (dstBeing->getType() == ActorType::Player)
- dstBeing->setMoveTime();
- BLOCK_END("BeingHandler::processPlayerMoveUpdate")
-}
-
-void BeingHandler::processBeingVisible(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processBeingVisibleOrMove")
- if (!actorManager)
- {
- BLOCK_END("BeingHandler::processBeingVisibleOrMove")
- return;
- }
-
- BeingId spawnId;
-
- // Information about a being in range
- const BeingId id = msg.readBeingId("being id");
- if (id == mSpawnId)
- spawnId = mSpawnId;
- else
- spawnId = BeingId_zero;
- mSpawnId = BeingId_zero;
- 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("option"))) << 16;
- const int16_t job = msg.readInt16("class");
- int disguiseId = 0;
- if (id == localPlayer->getId() && job >= 1000)
- disguiseId = job;
-
- Being *dstBeing = actorManager->findBeing(id);
-
- if (dstBeing && dstBeing->getType() == ActorType::Monster
- && !dstBeing->isAlive())
- {
- actorManager->destroy(dstBeing);
- actorManager->erase(dstBeing);
- dstBeing = nullptr;
- }
-
- if (!dstBeing)
- {
- // Being with id >= 110000000 and job 0 are better
- // known as ghosts, so don't create those.
- if (job == 0 && toInt(id, int) >= 110000000)
- {
- BLOCK_END("BeingHandler::processBeingVisibleOrMove")
- return;
- }
-
- if (actorManager->isBlocked(id) == true)
- {
- BLOCK_END("BeingHandler::processBeingVisibleOrMove")
- return;
- }
-
- dstBeing = createBeing(id, job);
-
- if (!dstBeing)
- {
- BLOCK_END("BeingHandler::processBeingVisibleOrMove")
- return;
- }
- }
- else
- {
- if (dstBeing->getType() == ActorType::Npc)
- {
- actorManager->undelete(dstBeing);
- if (serverVersion < 1)
- beingHandler->requestNameById(id);
- }
- }
-
- if (dstBeing->getType() == ActorType::Player)
- dstBeing->setMoveTime();
-
- if (spawnId != BeingId_zero)
- {
- dstBeing->setAction(BeingAction::SPAWN, 0);
- }
- else
- {
- dstBeing->clearPath();
- dstBeing->setActionTime(tick_time);
- dstBeing->setAction(BeingAction::STAND, 0);
- }
-
- // Prevent division by 0 when calculating frame
- if (speed == 0)
- speed = 150;
-
- const uint8_t hairStyle = msg.readUInt8("hair style");
- const uint16_t look = msg.readUInt8("look");
- dstBeing->setSubtype(fromInt(job, BeingTypeId), look);
- if (dstBeing->getType() == ActorType::Monster && localPlayer)
- localPlayer->checkNewName(dstBeing);
- dstBeing->setWalkSpeed(Vector(speed, speed, 0));
- const uint16_t weapon = msg.readInt16("weapon");
- const uint16_t headBottom = msg.readInt16("head bottom");
-
- const uint16_t shield = msg.readInt16("shield");
- const uint16_t headTop = msg.readInt16("head top");
- const uint16_t headMid = msg.readInt16("head mid");
- const ItemColor hairColor = fromInt(msg.readUInt8("hair color"), ItemColor);
- msg.readUInt8("unused");
- const uint16_t shoes = msg.readInt16("shoes / clothes color");
-
- uint16_t gloves;
- if (dstBeing->getType() == ActorType::Monster)
- {
- if (serverFeatures->haveServerHp())
- {
- const int hp = msg.readInt32("hp");
- const int maxHP = msg.readInt32("max hp");
- if (hp && maxHP)
- {
- dstBeing->setMaxHP(maxHP);
- const int oldHP = dstBeing->getHP();
- if (!oldHP || oldHP > hp)
- dstBeing->setHP(hp);
- }
- }
- else
- {
- msg.readInt32("unused");
- msg.readInt32("unused");
- }
- gloves = 0;
- }
- else
- {
- gloves = msg.readInt16("gloves / head dir");
- msg.readInt32("guild");
- msg.readInt16("guild emblem");
- }
-
- dstBeing->setManner(msg.readInt16("manner"));
- dstBeing->setStatusEffectBlock(32, msg.readInt16("opt3"));
- if (serverFeatures->haveMonsterAttackRange()
- && dstBeing->getType() == ActorType::Monster)
- {
- const int attackRange = static_cast<int>(
- msg.readUInt8("attack range (was karma)"));
- dstBeing->setAttackRange(attackRange);
- }
- else
- {
- dstBeing->setKarma(msg.readUInt8("karma"));
- }
- uint8_t gender = msg.readUInt8("gender");
-
- if (!disguiseId && dstBeing->getType() == ActorType::Player)
- {
- // reserving bits for future usage
- gender &= 3;
- dstBeing->setGender(Being::intToGender(gender));
- // Set these after the gender, as the sprites may be gender-specific
- setSprite(dstBeing, SPRITE_HAIR_COLOR, hairStyle * -1,
- ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
- dstBeing->setHairColor(hairColor);
- setSprite(dstBeing, SPRITE_WEAPON, headBottom);
- setSprite(dstBeing, SPRITE_HEAD_BOTTOM, headMid);
- setSprite(dstBeing, SPRITE_CLOTHES_COLOR, headTop);
- setSprite(dstBeing, SPRITE_HAIR, shoes);
- setSprite(dstBeing, SPRITE_SHOES, gloves);
- setSprite(dstBeing, SPRITE_BODY, weapon, "", ItemColor_one, true);
- setSprite(dstBeing, SPRITE_FLOOR, shield);
- }
- else if (dstBeing->getType() == ActorType::Npc
- && serverFeatures->haveNpcGender())
- {
- setServerGender(dstBeing, gender);
- }
-
- uint8_t dir;
- uint16_t x, y;
- msg.readCoordinates(x, y, dir, "position");
- dstBeing->setTileCoords(x, y);
-
- if (job == 45 && socialWindow && outfitWindow)
- {
- const int num = socialWindow->getPortalIndex(x, y);
- if (num >= 0)
- {
- dstBeing->setName(keyboard.getKeyShortString(
- outfitWindow->keyName(num)));
- }
- else
- {
- dstBeing->setName("");
- }
- }
-
- dstBeing->setDirection(dir);
-
- msg.readUInt8("unknown");
- msg.readUInt8("unknown");
- msg.readUInt8("unknown");
- msg.readUInt8("unknown");
- msg.readUInt8("unknown");
-
- dstBeing->setStunMode(stunMode);
- dstBeing->setStatusEffectBlock(0, static_cast<uint16_t>(
- (statusEffects >> 16) & 0xffff));
- dstBeing->setStatusEffectBlock(16, static_cast<uint16_t>(
- statusEffects & 0xffff));
- BLOCK_END("BeingHandler::processBeingVisibleOrMove")
-}
-
-void BeingHandler::processBeingMove(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processBeingVisibleOrMove")
- if (!actorManager)
- {
- BLOCK_END("BeingHandler::processBeingVisibleOrMove")
- return;
- }
-
- BeingId spawnId;
-
- // Information about a being in range
- const BeingId id = msg.readBeingId("being id");
- if (id == mSpawnId)
- spawnId = mSpawnId;
- else
- spawnId = BeingId_zero;
- mSpawnId = BeingId_zero;
- 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("option"))) << 16;
- const int16_t job = msg.readInt16("class");
- int disguiseId = 0;
- if (id == localPlayer->getId() && job >= 1000)
- disguiseId = job;
-
- Being *dstBeing = actorManager->findBeing(id);
-
- if (dstBeing && dstBeing->getType() == ActorType::Monster
- && !dstBeing->isAlive())
- {
- actorManager->destroy(dstBeing);
- actorManager->erase(dstBeing);
- dstBeing = nullptr;
- }
-
- if (!dstBeing)
- {
- // Being with id >= 110000000 and job 0 are better
- // known as ghosts, so don't create those.
- if (job == 0 && toInt(id, int) >= 110000000)
- {
- BLOCK_END("BeingHandler::processBeingVisibleOrMove")
- return;
- }
-
- if (actorManager->isBlocked(id) == true)
- {
- BLOCK_END("BeingHandler::processBeingVisibleOrMove")
- return;
- }
-
- dstBeing = createBeing(id, job);
-
- if (!dstBeing)
- {
- BLOCK_END("BeingHandler::processBeingVisibleOrMove")
- return;
- }
- }
- else
- {
- if (dstBeing->getType() == ActorType::Npc)
- {
- actorManager->undelete(dstBeing);
- if (serverVersion < 1)
- beingHandler->requestNameById(id);
- }
- }
-
- if (dstBeing->getType() == ActorType::Player)
- dstBeing->setMoveTime();
-
- if (spawnId != BeingId_zero)
- dstBeing->setAction(BeingAction::SPAWN, 0);
-
- // Prevent division by 0 when calculating frame
- if (speed == 0)
- speed = 150;
-
- const uint8_t hairStyle = msg.readUInt8("hair style");
- const uint16_t look = msg.readUInt8("look");
- dstBeing->setSubtype(fromInt(job, BeingTypeId), look);
- if (dstBeing->getType() == ActorType::Monster && localPlayer)
- localPlayer->checkNewName(dstBeing);
- dstBeing->setWalkSpeed(Vector(speed, speed, 0));
- const uint16_t weapon = msg.readInt16("weapon");
- const uint16_t headBottom = msg.readInt16("head bottom");
-
- msg.readInt32("tick");
-
- const uint16_t shield = msg.readInt16("shield");
- const uint16_t headTop = msg.readInt16("head top");
- const uint16_t headMid = msg.readInt16("head mid");
- const ItemColor hairColor = fromInt(
- msg.readUInt8("hair color"), ItemColor);
- msg.readUInt8("unused");
- const uint16_t shoes = msg.readInt16("shoes / clothes color");
-
- uint16_t gloves;
- if (dstBeing->getType() == ActorType::Monster)
- {
- if (serverFeatures->haveServerHp())
- {
- const int hp = msg.readInt32("hp");
- const int maxHP = msg.readInt32("max hp");
- if (hp && maxHP)
- {
- dstBeing->setMaxHP(maxHP);
- const int oldHP = dstBeing->getHP();
- if (!oldHP || oldHP > hp)
- dstBeing->setHP(hp);
- }
- }
- else
- {
- msg.readInt32("unused");
- msg.readInt32("unused");
- }
- gloves = 0;
- }
- else
- {
- gloves = msg.readInt16("gloves / head dir");
- msg.readInt32("guild");
- msg.readInt16("guild emblem");
- }
-
- dstBeing->setManner(msg.readInt16("manner"));
- dstBeing->setStatusEffectBlock(32, msg.readInt16("opt3"));
- if (serverFeatures->haveMonsterAttackRange()
- && dstBeing->getType() == ActorType::Monster)
- {
- const int attackRange = static_cast<int>(
- msg.readUInt8("attack range (was karma)"));
- dstBeing->setAttackRange(attackRange);
- }
- else
- {
- dstBeing->setKarma(msg.readUInt8("karma"));
- }
- uint8_t gender = msg.readUInt8("gender");
-
- if (!disguiseId && dstBeing->getType() == ActorType::Player)
- {
- // reserving bits for future usage
- gender &= 3;
- dstBeing->setGender(Being::intToGender(gender));
- // Set these after the gender, as the sprites may be gender-specific
- setSprite(dstBeing, SPRITE_HAIR_COLOR, hairStyle * -1,
- ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
- dstBeing->setHairColor(hairColor);
- setSprite(dstBeing, SPRITE_WEAPON, headBottom);
- setSprite(dstBeing, SPRITE_HEAD_BOTTOM, headMid);
- setSprite(dstBeing, SPRITE_CLOTHES_COLOR, headTop);
- setSprite(dstBeing, SPRITE_HAIR, shoes);
- setSprite(dstBeing, SPRITE_SHOES, gloves);
- setSprite(dstBeing, SPRITE_BODY, weapon, "", ItemColor_one, true);
- setSprite(dstBeing, SPRITE_FLOOR, shield);
- }
- else if (dstBeing->getType() == ActorType::Npc
- && serverFeatures->haveNpcGender())
- {
- setServerGender(dstBeing, gender);
- }
-
- uint16_t srcX, srcY, dstX, dstY;
- msg.readCoordinatePair(srcX, srcY, dstX, dstY, "move path");
- if (!disguiseId)
- {
- dstBeing->setAction(BeingAction::STAND, 0);
- dstBeing->setTileCoords(srcX, srcY);
- if (!serverFeatures->haveMove3())
- dstBeing->setDestination(dstX, dstY);
- }
-
- msg.readUInt8("unknown");
- msg.readUInt8("unknown");
- msg.readUInt8("unknown");
- msg.readUInt8("unknown");
- msg.readUInt8("unknown");
-
- dstBeing->setStunMode(stunMode);
- dstBeing->setStatusEffectBlock(0, static_cast<uint16_t>(
- (statusEffects >> 16) & 0xffff));
- dstBeing->setStatusEffectBlock(16, static_cast<uint16_t>(
- statusEffects & 0xffff));
- BLOCK_END("BeingHandler::processBeingVisibleOrMove")
-}
-
-void BeingHandler::processBeingSpawn(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processBeingSpawn")
- // skipping this packet
- mSpawnId = msg.readBeingId("being id");
- msg.readInt16("speed");
- msg.readInt16("opt1");
- msg.readInt16("opt2");
- msg.readInt16("option");
- msg.readInt16("disguise");
- msg.skip(25, "unused");
- BLOCK_END("BeingHandler::processBeingSpawn")
-}
-
-void BeingHandler::processSkillCasting(Net::MessageIn &msg)
-{
- msg.readInt32("src id");
- msg.readInt32("dst id");
- msg.readInt16("dst x");
- msg.readInt16("dst y");
- msg.readInt16("skill num");
- msg.readInt32("skill get p1");
- msg.readInt32("cast time");
-}
-
-void BeingHandler::processBeingStatusChange(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processBeingStatusChange")
- if (!actorManager)
- {
- BLOCK_END("BeingHandler::processBeingStatusChange")
- return;
- }
-
- // Status change
- const uint16_t status = msg.readInt16("status");
- const BeingId id = msg.readBeingId("being id");
- const Enable flag = fromBool(
- msg.readUInt8("flag: 0: stop, 1: start"), Enable);
-
- Being *const dstBeing = actorManager->findBeing(id);
- if (dstBeing)
- dstBeing->setStatusEffect(status, flag);
- BLOCK_END("BeingHandler::processBeingStatusChange")
-}
-
-void BeingHandler::processBeingMove2(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processBeingMove2")
- if (!actorManager)
- {
- BLOCK_END("BeingHandler::processBeingMove2")
- return;
- }
-
- /*
- * A simplified movement packet, used by the
- * later versions of eAthena for both mobs and
- * players
- */
- Being *const dstBeing = actorManager->findBeing(
- msg.readBeingId("being id"));
-
- /*
- * This packet doesn't have enough info to actually
- * create a new being, so if the being isn't found,
- * we'll just pretend the packet didn't happen
- */
-
- if (!dstBeing)
- {
- BLOCK_END("BeingHandler::processBeingMove2")
- return;
- }
-
- uint16_t srcX, srcY, dstX, dstY;
- msg.readCoordinatePair(srcX, srcY, dstX, dstY, "move path");
- msg.readInt32("tick");
-
- dstBeing->setAction(BeingAction::STAND, 0);
- dstBeing->setTileCoords(srcX, srcY);
- dstBeing->setDestination(dstX, dstY);
- if (dstBeing->getType() == ActorType::Player)
- dstBeing->setMoveTime();
- BLOCK_END("BeingHandler::processBeingMove2")
-}
-
-void BeingHandler::processBeingChangeDirection(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processBeingChangeDirection")
- if (!actorManager)
- {
- BLOCK_END("BeingHandler::processBeingChangeDirection")
- return;
- }
-
- Being *const dstBeing = actorManager->findBeing(
- msg.readBeingId("being id"));
-
- if (!dstBeing)
- {
- msg.readInt16("unused");
- msg.readUInt8("direction");
- BLOCK_END("BeingHandler::processBeingChangeDirection");
- return;
- }
-
- msg.readInt16("unused");
-
- const uint8_t dir = Net::MessageIn::fromServerDirection(
- static_cast<uint8_t>(msg.readUInt8("direction") & 0x0FU));
- dstBeing->setDirection(dir);
- if (localPlayer)
- localPlayer->imitateDirection(dstBeing, dir);
- BLOCK_END("BeingHandler::processBeingChangeDirection")
-}
-
-void BeingHandler::setServerGender(Being *const being, const uint8_t gender)
-{
- if (!being)
- return;
- switch (gender)
- {
- case 2:
- being->setGender(Gender::FEMALE);
- break;
- case 3:
- being->setGender(Gender::MALE);
- break;
- case 4:
- being->setGender(Gender::OTHER);
- break;
- default:
- being->setGender(Gender::UNSPECIFIED);
- break;
- }
-}
-
-void BeingHandler::applyPlayerAction(Net::MessageIn &msg,
- Being *const being,
- const uint8_t type)
-{
- if (!being)
- return;
- switch (type)
- {
- case 0:
- being->setAction(BeingAction::STAND, 0);
- localPlayer->imitateAction(being, BeingAction::STAND);
- break;
-
- case 1:
- if (being->getCurrentAction() != BeingAction::DEAD)
- {
- being->setAction(BeingAction::DEAD, 0);
- being->recalcSpritesOrder();
- }
- break;
-
- case 2:
- being->setAction(BeingAction::SIT, 0);
- localPlayer->imitateAction(being, BeingAction::SIT);
- break;
-
- default:
- UNIMPLIMENTEDPACKET;
- break;
- }
-}
-
void BeingHandler::viewPlayerEquipment(const Being *const being A_UNUSED)
{
}
-void BeingHandler::processPlaterStatusChange(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processPlayerStop")
- if (!actorManager)
- {
- BLOCK_END("BeingHandler::processPlayerStop")
- return;
- }
-
- // Change in players' flags
- const BeingId id = msg.readBeingId("account id");
- Being *const dstBeing = actorManager->findBeing(id);
- if (!dstBeing)
- return;
-
- const uint16_t stunMode = msg.readInt16("stun mode");
- uint32_t statusEffects = msg.readInt16("status effect");
- statusEffects |= (static_cast<uint32_t>(msg.readInt16("opt?"))) << 16;
- msg.readUInt8("Unused?");
-
- dstBeing->setStunMode(stunMode);
- dstBeing->setStatusEffectBlock(0, static_cast<uint16_t>(
- (statusEffects >> 16) & 0xffff));
- dstBeing->setStatusEffectBlock(16, static_cast<uint16_t>(
- statusEffects & 0xffff));
- BLOCK_END("BeingHandler::processPlayerStop")
-}
-
-void BeingHandler::processBeingResurrect(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processBeingResurrect")
- if (!actorManager || !localPlayer)
- {
- BLOCK_END("BeingHandler::processBeingResurrect")
- return;
- }
-
- // A being changed mortality status
-
- const BeingId id = msg.readBeingId("being id");
- Being *const dstBeing = actorManager->findBeing(id);
- if (!dstBeing)
- {
- BLOCK_END("BeingHandler::processBeingResurrect")
- return;
- }
-
- // If this is player's current target, clear it.
- if (dstBeing == localPlayer->getTarget())
- localPlayer->stopAttack();
-
- if (msg.readUInt8("flag?") == 1U)
- dstBeing->setAction(BeingAction::STAND, 0);
- BLOCK_END("BeingHandler::processBeingResurrect")
-}
-
-void BeingHandler::processPlayerGuilPartyInfo(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processPlayerGuilPartyInfo")
- if (!actorManager)
- {
- BLOCK_END("BeingHandler::processPlayerGuilPartyInfo")
- return;
- }
-
- Being *const dstBeing = actorManager->findBeing(
- msg.readBeingId("being id"));
-
- if (dstBeing)
- {
- dstBeing->setPartyName(msg.readString(24, "party name"));
- if (!guildManager || !GuildManager::getEnableGuildBot())
- {
- dstBeing->setGuildName(msg.readString(24, "guild name"));
- dstBeing->setGuildPos(msg.readString(24, "guild pos"));
- }
- else
- {
- msg.readString(24, "guild name");
- msg.readString(24, "guild pos");
- }
- dstBeing->addToCache();
- msg.readString(24, "?");
- }
- else
- {
- msg.readString(24, "party name");
- msg.readString(24, "guild name");
- msg.readString(24, "guild pos");
- msg.readString(24, "?");
- }
- BLOCK_END("BeingHandler::processPlayerGuilPartyInfo")
-}
-
-void BeingHandler::processBeingSelfEffect(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processBeingSelfEffect")
- if (!effectManager || !actorManager)
- {
- BLOCK_END("BeingHandler::processBeingSelfEffect")
- return;
- }
-
- const BeingId id = msg.readBeingId("being id");
- Being *const being = actorManager->findBeing(id);
- if (!being)
- {
- BLOCK_END("BeingHandler::processBeingSelfEffect")
- return;
- }
-
- const int effectType = msg.readInt32("effect type");
-
- if (Particle::enabled)
- effectManager->trigger(effectType, being);
-
- // +++ need dehard code effectType == 3
- if (effectType == 3 && being->getType() == ActorType::Player
- && socialWindow)
- { // reset received damage
- socialWindow->resetDamage(being->getName());
- }
- BLOCK_END("BeingHandler::processBeingSelfEffect")
-}
-
-void BeingHandler::processSkillCastCancel(Net::MessageIn &msg)
-{
- msg.readInt32("skill id");
-}
-
-void BeingHandler::processIpResponse(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processIpResponse")
- if (!actorManager)
- {
- BLOCK_END("BeingHandler::processIpResponse")
- return;
- }
-
- Being *const dstBeing = actorManager->findBeing(
- msg.readBeingId("being id"));
- if (dstBeing)
- dstBeing->setIp(ipToString(msg.readInt32("ip address")));
- BLOCK_END("BeingHandler::processIpResponse")
-}
-
-void BeingHandler::processPvpSet(Net::MessageIn &msg)
-{
- BLOCK_START("BeingHandler::processPvpSet")
- const BeingId id = msg.readBeingId("being id");
- const int rank = msg.readInt32("rank");
- int teamId = 0;
- if (serverFeatures->haveTeamId())
- teamId = msg.readInt32("team");
- else
- msg.readInt32("num");
- if (actorManager)
- {
- Being *const dstBeing = actorManager->findBeing(id);
- if (dstBeing)
- {
- dstBeing->setPvpRank(rank);
- dstBeing->setTeamId(static_cast<uint16_t>(teamId));
- dstBeing->addToCache();
- }
- }
- BLOCK_END("BeingHandler::processPvpSet")
-}
-
} // namespace TmwAthena
diff --git a/src/net/tmwa/beinghandler.h b/src/net/tmwa/beinghandler.h
index 1b722415d..a11415531 100644
--- a/src/net/tmwa/beinghandler.h
+++ b/src/net/tmwa/beinghandler.h
@@ -49,57 +49,6 @@ class BeingHandler final : public MessageHandler, public Ea::BeingHandler
protected:
void viewPlayerEquipment(const Being *const being);
-
- static void processBeingChangeLook(Net::MessageIn &msg);
-
- static void processBeingChangeLook2(Net::MessageIn &msg);
-
- static void processBeingVisible(Net::MessageIn &msg);
-
- static void processBeingMove(Net::MessageIn &msg);
-
- static void processPlayerUpdate1(Net::MessageIn &msg);
-
- static void processPlayerUpdate2(Net::MessageIn &msg);
-
- static void processPlayerMove(Net::MessageIn &msg);
-
- static void processBeingSpawn(Net::MessageIn &msg);
-
- static void processSkillCasting(Net::MessageIn &msg);
-
- static void processBeingStatusChange(Net::MessageIn &msg);
-
- static void processBeingMove2(Net::MessageIn &msg);
-
- static void processBeingChangeDirection(Net::MessageIn &msg);
-
- static void processBeingChangeLookContinue(Net::MessageIn &msg,
- Being *const dstBeing,
- const uint8_t type,
- const int id,
- const int id2) A_NONNULL(2);
-
- static void processPlaterStatusChange(Net::MessageIn &msg);
-
- static void processBeingResurrect(Net::MessageIn &msg);
-
- static void processPlayerGuilPartyInfo(Net::MessageIn &msg);
-
- static void setServerGender(Being *const being,
- const uint8_t gender);
-
- static void applyPlayerAction(Net::MessageIn &msg,
- Being *const being,
- const uint8_t type);
-
- static void processBeingSelfEffect(Net::MessageIn &msg);
-
- static void processSkillCastCancel(Net::MessageIn &msg);
-
- static void processIpResponse(Net::MessageIn &msg);
-
- static void processPvpSet(Net::MessageIn &msg);
};
} // namespace TmwAthena
diff --git a/src/net/tmwa/beingnet.cpp b/src/net/tmwa/beingnet.cpp
new file mode 100644
index 000000000..0230e053d
--- /dev/null
+++ b/src/net/tmwa/beingnet.cpp
@@ -0,0 +1,1391 @@
+/*
+ * The ManaPlus Client
+ * Copyright (C) 2004-2009 The Mana World Development Team
+ * Copyright (C) 2009-2010 The Mana Developers
+ * Copyright (C) 2011-2015 The ManaPlus Developers
+ *
+ * This file is part of The ManaPlus Client.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "net/tmwa/beingnet.h"
+
+#include "actormanager.h"
+#include "effectmanager.h"
+#include "guild.h"
+#include "party.h"
+
+#include "being/localplayer.h"
+
+#include "particle/particle.h"
+
+#include "input/keyboardconfig.h"
+
+#include "gui/windows/outfitwindow.h"
+#include "gui/windows/socialwindow.h"
+
+#include "net/serverfeatures.h"
+
+#include "net/ea/beingnet.h"
+
+#include "net/tmwa/guildmanager.h"
+#include "net/tmwa/messageout.h"
+#include "net/tmwa/protocol.h"
+#include "net/tmwa/sprite.h"
+
+#include "resources/iteminfo.h"
+
+#include "resources/db/itemdb.h"
+
+#include "utils/stringutils.h"
+#include "utils/timer.h"
+
+#include "debug.h"
+
+extern int serverVersion;
+
+namespace TmwAthena
+{
+
+void BeingNet::processBeingChangeLook(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processBeingChangeLook")
+ if (!actorManager)
+ {
+ BLOCK_END("BeingNet::processBeingChangeLook")
+ return;
+ }
+
+ Being *const dstBeing = actorManager->findBeing(
+ msg.readBeingId("being id"));
+
+ const uint8_t type = msg.readUInt8("type");
+ const int16_t id = static_cast<int16_t>(msg.readUInt8("id"));
+ const int id2 = 1;
+
+ if (!localPlayer || !dstBeing)
+ {
+ BLOCK_END("BeingNet::processBeingChangeLook")
+ return;
+ }
+ processBeingChangeLookContinue(msg, dstBeing, type, id, id2);
+ BLOCK_END("BeingNet::processBeingChangeLook")
+}
+
+void BeingNet::processBeingChangeLook2(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processBeingChangeLook")
+ if (!actorManager)
+ {
+ BLOCK_END("BeingNet::processBeingChangeLook")
+ return;
+ }
+
+ Being *const dstBeing = actorManager->findBeing(
+ msg.readBeingId("being id"));
+
+ const uint8_t type = msg.readUInt8("type");
+ int id2 = 0;
+
+ const int16_t id = msg.readInt16("id1");
+ if (type == 2)
+ {
+ id2 = msg.readInt16("id2");
+ }
+ else
+ {
+ msg.readInt16("id2");
+ id2 = 1;
+ }
+
+ if (!localPlayer || !dstBeing)
+ {
+ BLOCK_END("BeingNet::processBeingChangeLook")
+ return;
+ }
+ processBeingChangeLookContinue(msg, dstBeing, type, id, id2);
+ BLOCK_END("BeingNet::processBeingChangeLook")
+}
+
+void BeingNet::processBeingChangeLookContinue(Net::MessageIn &msg,
+ Being *const dstBeing,
+ const uint8_t type,
+ const int id,
+ const int id2)
+{
+ if (dstBeing->getType() == ActorType::Player)
+ dstBeing->setOtherTime();
+
+ const std::string color;
+ switch (type)
+ {
+ case 0: // change race
+ dstBeing->setSubtype(fromInt(id, BeingTypeId),
+ dstBeing->getLook());
+ break;
+ case 1: // eAthena LOOK_HAIR
+ {
+ const uint16_t look = static_cast<uint16_t>(id / 256);
+ const int hair = id % 256;
+ dstBeing->setHairStyle(SPRITE_HAIR_COLOR, hair * -1);
+ dstBeing->setLook(look);
+ break;
+ }
+ case 2: // Weapon ID in id, Shield ID in id2
+ dstBeing->setSprite(SPRITE_BODY, id, "", ItemColor_one, true);
+ dstBeing->setSprite(SPRITE_FLOOR, id2);
+ localPlayer->imitateOutfit(dstBeing, SPRITE_FLOOR);
+ break;
+ case 3: // Change lower headgear for eAthena, pants for us
+ dstBeing->setSprite(SPRITE_WEAPON, id, color,
+ ItemColor_one);
+ localPlayer->imitateOutfit(dstBeing, SPRITE_WEAPON);
+ break;
+ case 4: // Change upper headgear for eAthena, hat for us
+ dstBeing->setSprite(SPRITE_CLOTHES_COLOR, id, color,
+ ItemColor_one);
+ localPlayer->imitateOutfit(dstBeing, SPRITE_CLOTHES_COLOR);
+ break;
+ case 5: // Change middle headgear for eathena, armor for us
+ dstBeing->setSprite(SPRITE_HEAD_BOTTOM, id, color,
+ ItemColor_one);
+ localPlayer->imitateOutfit(dstBeing, SPRITE_HEAD_BOTTOM);
+ break;
+ case 6: // eAthena LOOK_HAIR_COLOR
+ dstBeing->setHairColor(SPRITE_HAIR_COLOR,
+ fromInt(id, ItemColor));
+ break;
+ case 7: // Clothes color
+ // ignoring it
+ break;
+ case 8: // eAthena LOOK_SHIELD
+ dstBeing->setSprite(SPRITE_FLOOR, id, color,
+ ItemColor_one);
+ localPlayer->imitateOutfit(dstBeing, SPRITE_FLOOR);
+ break;
+ case 9: // eAthena LOOK_SHOES
+ dstBeing->setSprite(SPRITE_HAIR, id, color,
+ ItemColor_one);
+ localPlayer->imitateOutfit(dstBeing, SPRITE_HAIR);
+ break;
+ case 10: // LOOK_GLOVES
+ dstBeing->setSprite(SPRITE_SHOES, id, color,
+ ItemColor_one);
+ localPlayer->imitateOutfit(dstBeing, SPRITE_SHOES);
+ break;
+ case 11: // LOOK_CAPE
+ dstBeing->setSprite(SPRITE_SHIELD, id, color,
+ ItemColor_one);
+ localPlayer->imitateOutfit(dstBeing, SPRITE_SHIELD);
+ break;
+ case 12:
+ dstBeing->setSprite(SPRITE_HEAD_TOP, id, color,
+ ItemColor_one);
+ localPlayer->imitateOutfit(dstBeing, SPRITE_HEAD_TOP);
+ break;
+ case 13:
+ dstBeing->setSprite(SPRITE_HEAD_MID, id, color,
+ ItemColor_one);
+ localPlayer->imitateOutfit(dstBeing, SPRITE_HEAD_MID);
+ break;
+ case 14:
+ dstBeing->setSprite(SPRITE_ROBE, id, color,
+ ItemColor_one);
+ localPlayer->imitateOutfit(dstBeing, SPRITE_ROBE);
+ break;
+ case 15:
+ dstBeing->setSprite(SPRITE_EVOL2, id, color,
+ ItemColor_one);
+ localPlayer->imitateOutfit(dstBeing, SPRITE_EVOL2);
+ break;
+ case 16:
+ dstBeing->setLook(static_cast<uint16_t>(id));
+ break;
+ default:
+ UNIMPLIMENTEDPACKET;
+ break;
+ }
+}
+
+void BeingNet::processPlayerUpdate1(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processPlayerMoveUpdate")
+ if (!actorManager || !localPlayer)
+ {
+ BLOCK_END("BeingNet::processPlayerMoveUpdate")
+ return;
+ }
+
+ // An update about a player, potentially including movement.
+ const BeingId id = msg.readBeingId("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 (toInt(id, int) < 110000000 && job >= 1000)
+ disguiseId = job;
+
+ Being *dstBeing = actorManager->findBeing(id);
+ if (!dstBeing)
+ {
+ if (actorManager->isBlocked(id) == true)
+ {
+ BLOCK_END("BeingNet::processPlayerMoveUpdate")
+ return;
+ }
+
+ dstBeing = Ea::BeingNet::createBeing(id, job);
+
+ if (!dstBeing)
+ {
+ BLOCK_END("BeingNet::processPlayerMoveUpdate")
+ return;
+ }
+ }
+ else if (disguiseId)
+ {
+ actorManager->undelete(dstBeing);
+ if (serverVersion < 1)
+ beingHandler->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 uint16_t look = msg.readUInt8("look");
+ dstBeing->setSubtype(fromInt(job, BeingTypeId), look);
+ const uint16_t weapon = msg.readInt16("weapon");
+ const uint16_t shield = msg.readInt16("shield");
+ const uint16_t headBottom = msg.readInt16("head bottom");
+
+ const uint16_t headTop = msg.readInt16("head top");
+ const uint16_t headMid = msg.readInt16("head mid");
+ const ItemColor hairColor = fromInt(
+ msg.readUInt8("hair color"), ItemColor);
+ msg.readUInt8("unused");
+ msg.readInt32("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");
+ dstBeing->setManner(msg.readInt16("manner"));
+ dstBeing->setStatusEffectBlock(32, msg.readInt16("opt3"));
+ dstBeing->setKarma(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_BODY, weapon, "", ItemColor_one, true);
+ dstBeing->updateSprite(SPRITE_FLOOR, shield);
+ dstBeing->updateSprite(SPRITE_WEAPON, headBottom);
+ dstBeing->updateSprite(SPRITE_HEAD_BOTTOM, headMid);
+ dstBeing->updateSprite(SPRITE_CLOTHES_COLOR, headTop);
+ dstBeing->updateSprite(SPRITE_HAIR_COLOR, hairStyle * -1,
+ ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
+ dstBeing->setHairColor(hairColor);
+ }
+ localPlayer->imitateOutfit(dstBeing);
+
+ 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);
+
+ applyPlayerAction(msg, dstBeing, msg.readUInt8("action type"));
+ const int level = static_cast<int>(msg.readUInt8("level"));
+ if (level)
+ dstBeing->setLevel(level);
+
+ msg.readUInt8("unused");
+
+ 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));
+
+ BLOCK_END("BeingNet::processPlayerMoveUpdate")
+}
+
+void BeingNet::processPlayerUpdate2(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processPlayerMoveUpdate")
+ if (!actorManager || !localPlayer)
+ {
+ BLOCK_END("BeingNet::processPlayerMoveUpdate")
+ return;
+ }
+
+ // An update about a player, potentially including movement.
+ const BeingId id = msg.readBeingId("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 (toInt(id, int) < 110000000 && job >= 1000)
+ disguiseId = job;
+
+ Being *dstBeing = actorManager->findBeing(id);
+ if (!dstBeing)
+ {
+ if (actorManager->isBlocked(id) == true)
+ {
+ BLOCK_END("BeingNet::processPlayerMoveUpdate")
+ return;
+ }
+
+ dstBeing = Ea::BeingNet::createBeing(id, job);
+
+ if (!dstBeing)
+ {
+ BLOCK_END("BeingNet::processPlayerMoveUpdate")
+ return;
+ }
+ }
+ else if (disguiseId)
+ {
+ actorManager->undelete(dstBeing);
+ if (serverVersion < 1)
+ beingHandler->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 uint16_t look = msg.readUInt8("look");
+ dstBeing->setSubtype(fromInt(job, BeingTypeId), look);
+ const uint16_t weapon = msg.readInt16("weapon");
+ const uint16_t shield = msg.readInt16("shield");
+ const uint16_t headBottom = msg.readInt16("head bottom");
+ const uint16_t headTop = msg.readInt16("head top");
+ const uint16_t headMid = msg.readInt16("head mid");
+ const ItemColor hairColor = fromInt(
+ msg.readUInt8("hair color"), ItemColor);
+ msg.readUInt8("unused");
+ msg.readInt32("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");
+ dstBeing->setManner(msg.readInt16("manner"));
+ dstBeing->setStatusEffectBlock(32, msg.readInt16("opt3"));
+ dstBeing->setKarma(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_BODY, weapon, "", ItemColor_one, true);
+ dstBeing->updateSprite(SPRITE_FLOOR, shield);
+ dstBeing->updateSprite(SPRITE_WEAPON, headBottom);
+ dstBeing->updateSprite(SPRITE_HEAD_BOTTOM, headMid);
+ dstBeing->updateSprite(SPRITE_CLOTHES_COLOR, headTop);
+ dstBeing->updateSprite(SPRITE_HAIR_COLOR, hairStyle * -1,
+ ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
+ dstBeing->setHairColor(hairColor);
+ }
+ localPlayer->imitateOutfit(dstBeing);
+
+ 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);
+
+ applyPlayerAction(msg, dstBeing, msg.readUInt8("action type"));
+ const int level = static_cast<int>(msg.readUInt8("level"));
+ if (level)
+ dstBeing->setLevel(level);
+
+ 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));
+
+ BLOCK_END("BeingNet::processPlayerMoveUpdate")
+}
+
+void BeingNet::processPlayerMove(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processPlayerMoveUpdate")
+ if (!actorManager || !localPlayer)
+ {
+ BLOCK_END("BeingNet::processPlayerMoveUpdate")
+ return;
+ }
+
+ // An update about a player, potentially including movement.
+ const BeingId id = msg.readBeingId("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 (toInt(id, int) < 110000000 && job >= 1000)
+ disguiseId = job;
+
+ Being *dstBeing = actorManager->findBeing(id);
+ if (!dstBeing)
+ {
+ if (actorManager->isBlocked(id) == true)
+ {
+ BLOCK_END("BeingNet::processPlayerMoveUpdate")
+ return;
+ }
+
+ dstBeing = Ea::BeingNet::createBeing(id, job);
+
+ if (!dstBeing)
+ {
+ BLOCK_END("BeingNet::processPlayerMoveUpdate")
+ return;
+ }
+ }
+ else if (disguiseId)
+ {
+ actorManager->undelete(dstBeing);
+ if (serverVersion < 1)
+ beingHandler->requestNameById(id);
+ }
+
+ const 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 uint16_t look = msg.readUInt8("look");
+ dstBeing->setSubtype(fromInt(job, BeingTypeId), look);
+ const uint16_t weapon = msg.readInt16("weapon");
+ const uint16_t shield = msg.readInt16("shield");
+ const uint16_t headBottom = msg.readInt16("head bottom");
+
+ msg.readInt32("tick");
+
+ const uint16_t headTop = msg.readInt16("head top");
+ const uint16_t headMid = msg.readInt16("head mid");
+ const ItemColor hairColor = fromInt(
+ msg.readUInt8("hair color"), ItemColor);
+ msg.readUInt8("unused");
+ msg.readInt32("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");
+ dstBeing->setManner(msg.readInt16("manner"));
+ dstBeing->setStatusEffectBlock(32, msg.readInt16("opt3"));
+ dstBeing->setKarma(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_BODY, weapon, "", ItemColor_one, true);
+ dstBeing->updateSprite(SPRITE_FLOOR, shield);
+ dstBeing->updateSprite(SPRITE_WEAPON, headBottom);
+ dstBeing->updateSprite(SPRITE_HEAD_BOTTOM, headMid);
+ dstBeing->updateSprite(SPRITE_CLOTHES_COLOR, headTop);
+ dstBeing->updateSprite(SPRITE_HAIR_COLOR, hairStyle * -1,
+ ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
+ dstBeing->setHairColor(hairColor);
+ }
+ localPlayer->imitateOutfit(dstBeing);
+
+ 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());
+ }
+
+ const uint16_t gmstatus = msg.readInt16("gm status");
+
+ if (gmstatus & 0x80)
+ dstBeing->setGM(true);
+
+ msg.readUInt8("unused");
+
+ const int level = static_cast<int>(msg.readUInt8("level"));
+ if (level)
+ dstBeing->setLevel(level);
+
+ msg.readUInt8("unused");
+
+ if (dstBeing->getType() != ActorType::Player)
+ 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 (dstBeing->getType() == ActorType::Player)
+ dstBeing->setMoveTime();
+ BLOCK_END("BeingNet::processPlayerMoveUpdate")
+}
+
+void BeingNet::processBeingVisible(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processBeingVisibleOrMove")
+ if (!actorManager)
+ {
+ BLOCK_END("BeingNet::processBeingVisibleOrMove")
+ return;
+ }
+
+ BeingId spawnId;
+
+ // Information about a being in range
+ const BeingId id = msg.readBeingId("being id");
+ if (id == Ea::BeingNet::mSpawnId)
+ spawnId = Ea::BeingNet::mSpawnId;
+ else
+ spawnId = BeingId_zero;
+ Ea::BeingNet::mSpawnId = BeingId_zero;
+ 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("option"))) << 16;
+ const int16_t job = msg.readInt16("class");
+ int disguiseId = 0;
+ if (id == localPlayer->getId() && job >= 1000)
+ disguiseId = job;
+
+ Being *dstBeing = actorManager->findBeing(id);
+
+ if (dstBeing && dstBeing->getType() == ActorType::Monster
+ && !dstBeing->isAlive())
+ {
+ actorManager->destroy(dstBeing);
+ actorManager->erase(dstBeing);
+ dstBeing = nullptr;
+ }
+
+ if (!dstBeing)
+ {
+ // Being with id >= 110000000 and job 0 are better
+ // known as ghosts, so don't create those.
+ if (job == 0 && toInt(id, int) >= 110000000)
+ {
+ BLOCK_END("BeingNet::processBeingVisibleOrMove")
+ return;
+ }
+
+ if (actorManager->isBlocked(id) == true)
+ {
+ BLOCK_END("BeingNet::processBeingVisibleOrMove")
+ return;
+ }
+
+ dstBeing = Ea::BeingNet::createBeing(id, job);
+
+ if (!dstBeing)
+ {
+ BLOCK_END("BeingNet::processBeingVisibleOrMove")
+ return;
+ }
+ }
+ else
+ {
+ if (dstBeing->getType() == ActorType::Npc)
+ {
+ actorManager->undelete(dstBeing);
+ if (serverVersion < 1)
+ beingHandler->requestNameById(id);
+ }
+ }
+
+ if (dstBeing->getType() == ActorType::Player)
+ dstBeing->setMoveTime();
+
+ if (spawnId != BeingId_zero)
+ {
+ dstBeing->setAction(BeingAction::SPAWN, 0);
+ }
+ else
+ {
+ dstBeing->clearPath();
+ dstBeing->setActionTime(tick_time);
+ dstBeing->setAction(BeingAction::STAND, 0);
+ }
+
+ // Prevent division by 0 when calculating frame
+ if (speed == 0)
+ speed = 150;
+
+ const uint8_t hairStyle = msg.readUInt8("hair style");
+ const uint16_t look = msg.readUInt8("look");
+ dstBeing->setSubtype(fromInt(job, BeingTypeId), look);
+ if (dstBeing->getType() == ActorType::Monster && localPlayer)
+ localPlayer->checkNewName(dstBeing);
+ dstBeing->setWalkSpeed(Vector(speed, speed, 0));
+ const uint16_t weapon = msg.readInt16("weapon");
+ const uint16_t headBottom = msg.readInt16("head bottom");
+
+ const uint16_t shield = msg.readInt16("shield");
+ const uint16_t headTop = msg.readInt16("head top");
+ const uint16_t headMid = msg.readInt16("head mid");
+ const ItemColor hairColor = fromInt(msg.readUInt8("hair color"), ItemColor);
+ msg.readUInt8("unused");
+ const uint16_t shoes = msg.readInt16("shoes / clothes color");
+
+ uint16_t gloves;
+ if (dstBeing->getType() == ActorType::Monster)
+ {
+ if (serverFeatures->haveServerHp())
+ {
+ const int hp = msg.readInt32("hp");
+ const int maxHP = msg.readInt32("max hp");
+ if (hp && maxHP)
+ {
+ dstBeing->setMaxHP(maxHP);
+ const int oldHP = dstBeing->getHP();
+ if (!oldHP || oldHP > hp)
+ dstBeing->setHP(hp);
+ }
+ }
+ else
+ {
+ msg.readInt32("unused");
+ msg.readInt32("unused");
+ }
+ gloves = 0;
+ }
+ else
+ {
+ gloves = msg.readInt16("gloves / head dir");
+ msg.readInt32("guild");
+ msg.readInt16("guild emblem");
+ }
+
+ dstBeing->setManner(msg.readInt16("manner"));
+ dstBeing->setStatusEffectBlock(32, msg.readInt16("opt3"));
+ if (serverFeatures->haveMonsterAttackRange()
+ && dstBeing->getType() == ActorType::Monster)
+ {
+ const int attackRange = static_cast<int>(
+ msg.readUInt8("attack range (was karma)"));
+ dstBeing->setAttackRange(attackRange);
+ }
+ else
+ {
+ dstBeing->setKarma(msg.readUInt8("karma"));
+ }
+ uint8_t gender = msg.readUInt8("gender");
+
+ if (!disguiseId && dstBeing->getType() == ActorType::Player)
+ {
+ // reserving bits for future usage
+ gender &= 3;
+ dstBeing->setGender(Being::intToGender(gender));
+ // Set these after the gender, as the sprites may be gender-specific
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_HAIR_COLOR, hairStyle * -1,
+ ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
+ dstBeing->setHairColor(hairColor);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_WEAPON, headBottom);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_HEAD_BOTTOM, headMid);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_CLOTHES_COLOR, headTop);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_HAIR, shoes);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_SHOES, gloves);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_BODY, weapon, "",
+ ItemColor_one, true);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_FLOOR, shield);
+ }
+ else if (dstBeing->getType() == ActorType::Npc
+ && serverFeatures->haveNpcGender())
+ {
+ setServerGender(dstBeing, gender);
+ }
+
+ uint8_t dir;
+ uint16_t x, y;
+ msg.readCoordinates(x, y, dir, "position");
+ dstBeing->setTileCoords(x, y);
+
+ if (job == 45 && socialWindow && outfitWindow)
+ {
+ const int num = socialWindow->getPortalIndex(x, y);
+ if (num >= 0)
+ {
+ dstBeing->setName(keyboard.getKeyShortString(
+ outfitWindow->keyName(num)));
+ }
+ else
+ {
+ dstBeing->setName("");
+ }
+ }
+
+ dstBeing->setDirection(dir);
+
+ msg.readUInt8("unknown");
+ msg.readUInt8("unknown");
+ msg.readUInt8("unknown");
+ msg.readUInt8("unknown");
+ msg.readUInt8("unknown");
+
+ dstBeing->setStunMode(stunMode);
+ dstBeing->setStatusEffectBlock(0, static_cast<uint16_t>(
+ (statusEffects >> 16) & 0xffff));
+ dstBeing->setStatusEffectBlock(16, static_cast<uint16_t>(
+ statusEffects & 0xffff));
+ BLOCK_END("BeingNet::processBeingVisibleOrMove")
+}
+
+void BeingNet::processBeingMove(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processBeingVisibleOrMove")
+ if (!actorManager)
+ {
+ BLOCK_END("BeingNet::processBeingVisibleOrMove")
+ return;
+ }
+
+ BeingId spawnId;
+
+ // Information about a being in range
+ const BeingId id = msg.readBeingId("being id");
+ if (id == Ea::BeingNet::mSpawnId)
+ spawnId = Ea::BeingNet::mSpawnId;
+ else
+ spawnId = BeingId_zero;
+ Ea::BeingNet::mSpawnId = BeingId_zero;
+ 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("option"))) << 16;
+ const int16_t job = msg.readInt16("class");
+ int disguiseId = 0;
+ if (id == localPlayer->getId() && job >= 1000)
+ disguiseId = job;
+
+ Being *dstBeing = actorManager->findBeing(id);
+
+ if (dstBeing && dstBeing->getType() == ActorType::Monster
+ && !dstBeing->isAlive())
+ {
+ actorManager->destroy(dstBeing);
+ actorManager->erase(dstBeing);
+ dstBeing = nullptr;
+ }
+
+ if (!dstBeing)
+ {
+ // Being with id >= 110000000 and job 0 are better
+ // known as ghosts, so don't create those.
+ if (job == 0 && toInt(id, int) >= 110000000)
+ {
+ BLOCK_END("BeingNet::processBeingVisibleOrMove")
+ return;
+ }
+
+ if (actorManager->isBlocked(id) == true)
+ {
+ BLOCK_END("BeingNet::processBeingVisibleOrMove")
+ return;
+ }
+
+ dstBeing = Ea::BeingNet::createBeing(id, job);
+
+ if (!dstBeing)
+ {
+ BLOCK_END("BeingNet::processBeingVisibleOrMove")
+ return;
+ }
+ }
+ else
+ {
+ if (dstBeing->getType() == ActorType::Npc)
+ {
+ actorManager->undelete(dstBeing);
+ if (serverVersion < 1)
+ beingHandler->requestNameById(id);
+ }
+ }
+
+ if (dstBeing->getType() == ActorType::Player)
+ dstBeing->setMoveTime();
+
+ if (spawnId != BeingId_zero)
+ dstBeing->setAction(BeingAction::SPAWN, 0);
+
+ // Prevent division by 0 when calculating frame
+ if (speed == 0)
+ speed = 150;
+
+ const uint8_t hairStyle = msg.readUInt8("hair style");
+ const uint16_t look = msg.readUInt8("look");
+ dstBeing->setSubtype(fromInt(job, BeingTypeId), look);
+ if (dstBeing->getType() == ActorType::Monster && localPlayer)
+ localPlayer->checkNewName(dstBeing);
+ dstBeing->setWalkSpeed(Vector(speed, speed, 0));
+ const uint16_t weapon = msg.readInt16("weapon");
+ const uint16_t headBottom = msg.readInt16("head bottom");
+
+ msg.readInt32("tick");
+
+ const uint16_t shield = msg.readInt16("shield");
+ const uint16_t headTop = msg.readInt16("head top");
+ const uint16_t headMid = msg.readInt16("head mid");
+ const ItemColor hairColor = fromInt(
+ msg.readUInt8("hair color"), ItemColor);
+ msg.readUInt8("unused");
+ const uint16_t shoes = msg.readInt16("shoes / clothes color");
+
+ uint16_t gloves;
+ if (dstBeing->getType() == ActorType::Monster)
+ {
+ if (serverFeatures->haveServerHp())
+ {
+ const int hp = msg.readInt32("hp");
+ const int maxHP = msg.readInt32("max hp");
+ if (hp && maxHP)
+ {
+ dstBeing->setMaxHP(maxHP);
+ const int oldHP = dstBeing->getHP();
+ if (!oldHP || oldHP > hp)
+ dstBeing->setHP(hp);
+ }
+ }
+ else
+ {
+ msg.readInt32("unused");
+ msg.readInt32("unused");
+ }
+ gloves = 0;
+ }
+ else
+ {
+ gloves = msg.readInt16("gloves / head dir");
+ msg.readInt32("guild");
+ msg.readInt16("guild emblem");
+ }
+
+ dstBeing->setManner(msg.readInt16("manner"));
+ dstBeing->setStatusEffectBlock(32, msg.readInt16("opt3"));
+ if (serverFeatures->haveMonsterAttackRange()
+ && dstBeing->getType() == ActorType::Monster)
+ {
+ const int attackRange = static_cast<int>(
+ msg.readUInt8("attack range (was karma)"));
+ dstBeing->setAttackRange(attackRange);
+ }
+ else
+ {
+ dstBeing->setKarma(msg.readUInt8("karma"));
+ }
+ uint8_t gender = msg.readUInt8("gender");
+
+ if (!disguiseId && dstBeing->getType() == ActorType::Player)
+ {
+ // reserving bits for future usage
+ gender &= 3;
+ dstBeing->setGender(Being::intToGender(gender));
+ // Set these after the gender, as the sprites may be gender-specific
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_HAIR_COLOR, hairStyle * -1,
+ ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
+ dstBeing->setHairColor(hairColor);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_WEAPON, headBottom);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_HEAD_BOTTOM, headMid);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_CLOTHES_COLOR, headTop);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_HAIR, shoes);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_SHOES, gloves);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_BODY, weapon, "",
+ ItemColor_one, true);
+ Ea::BeingNet::setSprite(dstBeing, SPRITE_FLOOR, shield);
+ }
+ else if (dstBeing->getType() == ActorType::Npc
+ && serverFeatures->haveNpcGender())
+ {
+ setServerGender(dstBeing, gender);
+ }
+
+ uint16_t srcX, srcY, dstX, dstY;
+ msg.readCoordinatePair(srcX, srcY, dstX, dstY, "move path");
+ if (!disguiseId)
+ {
+ dstBeing->setAction(BeingAction::STAND, 0);
+ dstBeing->setTileCoords(srcX, srcY);
+ if (!serverFeatures->haveMove3())
+ dstBeing->setDestination(dstX, dstY);
+ }
+
+ msg.readUInt8("unknown");
+ msg.readUInt8("unknown");
+ msg.readUInt8("unknown");
+ msg.readUInt8("unknown");
+ msg.readUInt8("unknown");
+
+ dstBeing->setStunMode(stunMode);
+ dstBeing->setStatusEffectBlock(0, static_cast<uint16_t>(
+ (statusEffects >> 16) & 0xffff));
+ dstBeing->setStatusEffectBlock(16, static_cast<uint16_t>(
+ statusEffects & 0xffff));
+ BLOCK_END("BeingNet::processBeingVisibleOrMove")
+}
+
+void BeingNet::processBeingSpawn(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processBeingSpawn")
+ // skipping this packet
+ Ea::BeingNet::mSpawnId = msg.readBeingId("being id");
+ msg.readInt16("speed");
+ msg.readInt16("opt1");
+ msg.readInt16("opt2");
+ msg.readInt16("option");
+ msg.readInt16("disguise");
+ msg.skip(25, "unused");
+ BLOCK_END("BeingNet::processBeingSpawn")
+}
+
+void BeingNet::processSkillCasting(Net::MessageIn &msg)
+{
+ msg.readInt32("src id");
+ msg.readInt32("dst id");
+ msg.readInt16("dst x");
+ msg.readInt16("dst y");
+ msg.readInt16("skill num");
+ msg.readInt32("skill get p1");
+ msg.readInt32("cast time");
+}
+
+void BeingNet::processBeingStatusChange(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processBeingStatusChange")
+ if (!actorManager)
+ {
+ BLOCK_END("BeingNet::processBeingStatusChange")
+ return;
+ }
+
+ // Status change
+ const uint16_t status = msg.readInt16("status");
+ const BeingId id = msg.readBeingId("being id");
+ const Enable flag = fromBool(
+ msg.readUInt8("flag: 0: stop, 1: start"), Enable);
+
+ Being *const dstBeing = actorManager->findBeing(id);
+ if (dstBeing)
+ dstBeing->setStatusEffect(status, flag);
+ BLOCK_END("BeingNet::processBeingStatusChange")
+}
+
+void BeingNet::processBeingMove2(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processBeingMove2")
+ if (!actorManager)
+ {
+ BLOCK_END("BeingNet::processBeingMove2")
+ return;
+ }
+
+ /*
+ * A simplified movement packet, used by the
+ * later versions of eAthena for both mobs and
+ * players
+ */
+ Being *const dstBeing = actorManager->findBeing(
+ msg.readBeingId("being id"));
+
+ /*
+ * This packet doesn't have enough info to actually
+ * create a new being, so if the being isn't found,
+ * we'll just pretend the packet didn't happen
+ */
+
+ if (!dstBeing)
+ {
+ BLOCK_END("BeingNet::processBeingMove2")
+ return;
+ }
+
+ uint16_t srcX, srcY, dstX, dstY;
+ msg.readCoordinatePair(srcX, srcY, dstX, dstY, "move path");
+ msg.readInt32("tick");
+
+ dstBeing->setAction(BeingAction::STAND, 0);
+ dstBeing->setTileCoords(srcX, srcY);
+ dstBeing->setDestination(dstX, dstY);
+ if (dstBeing->getType() == ActorType::Player)
+ dstBeing->setMoveTime();
+ BLOCK_END("BeingNet::processBeingMove2")
+}
+
+void BeingNet::processBeingChangeDirection(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processBeingChangeDirection")
+ if (!actorManager)
+ {
+ BLOCK_END("BeingNet::processBeingChangeDirection")
+ return;
+ }
+
+ Being *const dstBeing = actorManager->findBeing(
+ msg.readBeingId("being id"));
+
+ if (!dstBeing)
+ {
+ msg.readInt16("unused");
+ msg.readUInt8("direction");
+ BLOCK_END("BeingNet::processBeingChangeDirection");
+ return;
+ }
+
+ msg.readInt16("unused");
+
+ const uint8_t dir = Net::MessageIn::fromServerDirection(
+ static_cast<uint8_t>(msg.readUInt8("direction") & 0x0FU));
+ dstBeing->setDirection(dir);
+ if (localPlayer)
+ localPlayer->imitateDirection(dstBeing, dir);
+ BLOCK_END("BeingNet::processBeingChangeDirection")
+}
+
+void BeingNet::processPlaterStatusChange(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processPlayerStop")
+ if (!actorManager)
+ {
+ BLOCK_END("BeingNet::processPlayerStop")
+ return;
+ }
+
+ // Change in players' flags
+ const BeingId id = msg.readBeingId("account id");
+ Being *const dstBeing = actorManager->findBeing(id);
+ if (!dstBeing)
+ return;
+
+ const uint16_t stunMode = msg.readInt16("stun mode");
+ uint32_t statusEffects = msg.readInt16("status effect");
+ statusEffects |= (static_cast<uint32_t>(msg.readInt16("opt?"))) << 16;
+ msg.readUInt8("Unused?");
+
+ dstBeing->setStunMode(stunMode);
+ dstBeing->setStatusEffectBlock(0, static_cast<uint16_t>(
+ (statusEffects >> 16) & 0xffff));
+ dstBeing->setStatusEffectBlock(16, static_cast<uint16_t>(
+ statusEffects & 0xffff));
+ BLOCK_END("BeingNet::processPlayerStop")
+}
+
+void BeingNet::processBeingResurrect(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processBeingResurrect")
+ if (!actorManager || !localPlayer)
+ {
+ BLOCK_END("BeingNet::processBeingResurrect")
+ return;
+ }
+
+ // A being changed mortality status
+
+ const BeingId id = msg.readBeingId("being id");
+ Being *const dstBeing = actorManager->findBeing(id);
+ if (!dstBeing)
+ {
+ BLOCK_END("BeingNet::processBeingResurrect")
+ return;
+ }
+
+ // If this is player's current target, clear it.
+ if (dstBeing == localPlayer->getTarget())
+ localPlayer->stopAttack();
+
+ if (msg.readUInt8("flag?") == 1U)
+ dstBeing->setAction(BeingAction::STAND, 0);
+ BLOCK_END("BeingNet::processBeingResurrect")
+}
+
+void BeingNet::processPlayerGuilPartyInfo(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processPlayerGuilPartyInfo")
+ if (!actorManager)
+ {
+ BLOCK_END("BeingNet::processPlayerGuilPartyInfo")
+ return;
+ }
+
+ Being *const dstBeing = actorManager->findBeing(
+ msg.readBeingId("being id"));
+
+ if (dstBeing)
+ {
+ dstBeing->setPartyName(msg.readString(24, "party name"));
+ if (!guildManager || !GuildManager::getEnableGuildBot())
+ {
+ dstBeing->setGuildName(msg.readString(24, "guild name"));
+ dstBeing->setGuildPos(msg.readString(24, "guild pos"));
+ }
+ else
+ {
+ msg.readString(24, "guild name");
+ msg.readString(24, "guild pos");
+ }
+ dstBeing->addToCache();
+ msg.readString(24, "?");
+ }
+ else
+ {
+ msg.readString(24, "party name");
+ msg.readString(24, "guild name");
+ msg.readString(24, "guild pos");
+ msg.readString(24, "?");
+ }
+ BLOCK_END("BeingNet::processPlayerGuilPartyInfo")
+}
+
+void BeingNet::processBeingSelfEffect(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processBeingSelfEffect")
+ if (!effectManager || !actorManager)
+ {
+ BLOCK_END("BeingNet::processBeingSelfEffect")
+ return;
+ }
+
+ const BeingId id = msg.readBeingId("being id");
+ Being *const being = actorManager->findBeing(id);
+ if (!being)
+ {
+ BLOCK_END("BeingNet::processBeingSelfEffect")
+ return;
+ }
+
+ const int effectType = msg.readInt32("effect type");
+
+ if (Particle::enabled)
+ effectManager->trigger(effectType, being);
+
+ // +++ need dehard code effectType == 3
+ if (effectType == 3 && being->getType() == ActorType::Player
+ && socialWindow)
+ { // reset received damage
+ socialWindow->resetDamage(being->getName());
+ }
+ BLOCK_END("BeingNet::processBeingSelfEffect")
+}
+
+void BeingNet::processSkillCastCancel(Net::MessageIn &msg)
+{
+ msg.readInt32("skill id");
+}
+
+void BeingNet::processIpResponse(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processIpResponse")
+ if (!actorManager)
+ {
+ BLOCK_END("BeingNet::processIpResponse")
+ return;
+ }
+
+ Being *const dstBeing = actorManager->findBeing(
+ msg.readBeingId("being id"));
+ if (dstBeing)
+ dstBeing->setIp(ipToString(msg.readInt32("ip address")));
+ BLOCK_END("BeingNet::processIpResponse")
+}
+
+void BeingNet::processPvpSet(Net::MessageIn &msg)
+{
+ BLOCK_START("BeingNet::processPvpSet")
+ const BeingId id = msg.readBeingId("being id");
+ const int rank = msg.readInt32("rank");
+ int teamId = 0;
+ if (serverFeatures->haveTeamId())
+ teamId = msg.readInt32("team");
+ else
+ msg.readInt32("num");
+ if (actorManager)
+ {
+ Being *const dstBeing = actorManager->findBeing(id);
+ if (dstBeing)
+ {
+ dstBeing->setPvpRank(rank);
+ dstBeing->setTeamId(static_cast<uint16_t>(teamId));
+ dstBeing->addToCache();
+ }
+ }
+ BLOCK_END("BeingNet::processPvpSet")
+}
+
+void BeingNet::applyPlayerAction(Net::MessageIn &msg,
+ Being *const being,
+ const uint8_t type)
+{
+ if (!being)
+ return;
+ switch (type)
+ {
+ case 0:
+ being->setAction(BeingAction::STAND, 0);
+ localPlayer->imitateAction(being, BeingAction::STAND);
+ break;
+
+ case 1:
+ if (being->getCurrentAction() != BeingAction::DEAD)
+ {
+ being->setAction(BeingAction::DEAD, 0);
+ being->recalcSpritesOrder();
+ }
+ break;
+
+ case 2:
+ being->setAction(BeingAction::SIT, 0);
+ localPlayer->imitateAction(being, BeingAction::SIT);
+ break;
+
+ default:
+ UNIMPLIMENTEDPACKET;
+ break;
+ }
+}
+
+void BeingNet::setServerGender(Being *const being, const uint8_t gender)
+{
+ if (!being)
+ return;
+ switch (gender)
+ {
+ case 2:
+ being->setGender(Gender::FEMALE);
+ break;
+ case 3:
+ being->setGender(Gender::MALE);
+ break;
+ case 4:
+ being->setGender(Gender::OTHER);
+ break;
+ default:
+ being->setGender(Gender::UNSPECIFIED);
+ break;
+ }
+}
+
+} // namespace TmwAthena
diff --git a/src/net/tmwa/beingnet.h b/src/net/tmwa/beingnet.h
new file mode 100644
index 000000000..268cc0723
--- /dev/null
+++ b/src/net/tmwa/beingnet.h
@@ -0,0 +1,66 @@
+/*
+ * The ManaPlus Client
+ * Copyright (C) 2004-2009 The Mana World Development Team
+ * Copyright (C) 2009-2010 The Mana Developers
+ * Copyright (C) 2011-2015 The ManaPlus Developers
+ *
+ * This file is part of The ManaPlus Client.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NET_TMWA_BEING_H
+#define NET_TMWA_BEING_H
+
+#include "net/ea/beinghandler.h"
+
+#include "net/tmwa/messagehandler.h"
+
+namespace TmwAthena
+{
+ namespace BeingNet
+ {
+ void processBeingChangeLook(Net::MessageIn &msg);
+ void processBeingChangeLook2(Net::MessageIn &msg);
+ void processBeingVisible(Net::MessageIn &msg);
+ void processBeingMove(Net::MessageIn &msg);
+ void processPlayerUpdate1(Net::MessageIn &msg);
+ void processPlayerUpdate2(Net::MessageIn &msg);
+ void processPlayerMove(Net::MessageIn &msg);
+ void processBeingSpawn(Net::MessageIn &msg);
+ void processSkillCasting(Net::MessageIn &msg);
+ void processBeingStatusChange(Net::MessageIn &msg);
+ void processBeingMove2(Net::MessageIn &msg);
+ void processBeingChangeDirection(Net::MessageIn &msg);
+ void processBeingChangeLookContinue(Net::MessageIn &msg,
+ Being *const dstBeing,
+ const uint8_t type,
+ const int id,
+ const int id2) A_NONNULL(2);
+ void processPlaterStatusChange(Net::MessageIn &msg);
+ void processBeingResurrect(Net::MessageIn &msg);
+ void processPlayerGuilPartyInfo(Net::MessageIn &msg);
+ void processBeingSelfEffect(Net::MessageIn &msg);
+ void processSkillCastCancel(Net::MessageIn &msg);
+ void processIpResponse(Net::MessageIn &msg);
+ void processPvpSet(Net::MessageIn &msg);
+ void applyPlayerAction(Net::MessageIn &msg,
+ Being *const being,
+ const uint8_t type);
+ void setServerGender(Being *const being,
+ const uint8_t gender);
+ } // namespace Being
+} // namespace TmwAthena
+
+#endif // NET_TMWA_BEING_H