summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrei Karas <akaras@inbox.ru>2011-05-19 23:41:05 +0300
committerAndrei Karas <akaras@inbox.ru>2011-05-20 20:50:00 +0300
commit78ab801cc5dfe687718ec7e027c3050bed62a1e9 (patch)
tree064fc82cf6aed1dbcd0a5650b146e74cf23a20a0
parent2a2155ae3c601fe1f813f9214b1421e4ac634148 (diff)
downloadplus-78ab801cc5dfe687718ec7e027c3050bed62a1e9.tar.gz
plus-78ab801cc5dfe687718ec7e027c3050bed62a1e9.tar.bz2
plus-78ab801cc5dfe687718ec7e027c3050bed62a1e9.tar.xz
plus-78ab801cc5dfe687718ec7e027c3050bed62a1e9.zip
Start separating netcode to functions and moving some code to ea name space
for future usage for different server types. Processed classes: adminhandler, beinghandler, buysellhandler.
-rw-r--r--src/CMakeLists.txt14
-rw-r--r--src/Makefile.am7
-rw-r--r--src/net/ea/adminhandler.cpp64
-rw-r--r--src/net/ea/adminhandler.h58
-rw-r--r--src/net/ea/beinghandler.cpp820
-rw-r--r--src/net/ea/beinghandler.h111
-rw-r--r--src/net/ea/buysellhandler.cpp180
-rw-r--r--src/net/ea/buysellhandler.h66
-rw-r--r--src/net/ea/eaprotocol.h42
-rw-r--r--src/net/tmwa/adminhandler.cpp40
-rw-r--r--src/net/tmwa/adminhandler.h16
-rw-r--r--src/net/tmwa/beinghandler.cpp1424
-rw-r--r--src/net/tmwa/beinghandler.h14
-rw-r--r--src/net/tmwa/buysellhandler.cpp187
-rw-r--r--src/net/tmwa/buysellhandler.h17
15 files changed, 1847 insertions, 1213 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 825cecd01..4cbc8154c 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -575,6 +575,16 @@ SET(SRCS
mumblemanager.h
)
+SET(SRCS_EVOL
+ net/ea/adminhandler.cpp
+ net/ea/adminhandler.h
+ net/ea/beinghandler.cpp
+ net/ea/beinghandler.h
+ net/ea/buysellhandler.cpp
+ net/ea/buysellhandler.h
+ net/ea/eaprotocol.h
+ )
+
SET(SRCS_TMWA
net/tmwa/gui/guildtab.cpp
net/tmwa/gui/guildtab.h
@@ -707,9 +717,9 @@ ENDIF ()
SET (PROGRAMS manaplus)
IF (ENABLE_MANASERV)
- ADD_EXECUTABLE(manaplus WIN32 ${SRCS} ${SRCS_MANASERV} ${SRCS_TMWA})
+ ADD_EXECUTABLE(manaplus WIN32 ${SRCS} ${SRCS_MANASERV} ${SRCS_TMWA} ${SRCS_EVOL})
ELSE(ENABLE_MANASERV)
- ADD_EXECUTABLE(manaplus WIN32 ${SRCS} ${SRCS_TMWA})
+ ADD_EXECUTABLE(manaplus WIN32 ${SRCS} ${SRCS_TMWA} ${SRCS_EVOL})
ENDIF(ENABLE_MANASERV)
TARGET_LINK_LIBRARIES(manaplus
diff --git a/src/Makefile.am b/src/Makefile.am
index 956595304..31674723d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -543,6 +543,13 @@ manaplus_SOURCES += enet/callbacks.c \
endif
manaplus_SOURCES += \
+ net/ea/adminhandler.cpp \
+ net/ea/adminhandler.h \
+ net/ea/beinghandler.cpp \
+ net/ea/beinghandler.h \
+ net/ea/buysellhandler.cpp \
+ net/ea/buysellhandler.h \
+ net/ea/eaprotocol.h \
net/tmwa/gui/guildtab.cpp \
net/tmwa/gui/guildtab.h \
net/tmwa/gui/partytab.cpp \
diff --git a/src/net/ea/adminhandler.cpp b/src/net/ea/adminhandler.cpp
new file mode 100644
index 000000000..9dd525ae9
--- /dev/null
+++ b/src/net/ea/adminhandler.cpp
@@ -0,0 +1,64 @@
+/*
+ * The ManaPlus Client
+ * Copyright (C) 2004-2009 The Mana World Development Team
+ * Copyright (C) 2009-2010 The Mana Developers
+ * Copyright (C) 2011 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/adminhandler.h"
+
+#include "net/chathandler.h"
+#include "net/net.h"
+
+#include <string>
+
+namespace Ea
+{
+
+void AdminHandler::kick(const std::string &name)
+{
+ Net::getChatHandler()->talk("@kick " + name);
+}
+
+void AdminHandler::ban(int playerId _UNUSED_)
+{
+ // Not supported
+}
+
+void AdminHandler::ban(const std::string &name)
+{
+ Net::getChatHandler()->talk("@ban " + name);
+}
+
+void AdminHandler::unban(int playerId _UNUSED_)
+{
+ // Not supported
+}
+
+void AdminHandler::unban(const std::string &name)
+{
+ Net::getChatHandler()->talk("@unban " + name);
+}
+
+void AdminHandler::mute(int playerId _UNUSED_, int type _UNUSED_,
+ int limit _UNUSED_)
+{
+ return; // Still looking into this
+}
+
+} // namespace Ea
diff --git a/src/net/ea/adminhandler.h b/src/net/ea/adminhandler.h
new file mode 100644
index 000000000..67b5cdc11
--- /dev/null
+++ b/src/net/ea/adminhandler.h
@@ -0,0 +1,58 @@
+/*
+ * The ManaPlus Client
+ * Copyright (C) 2004-2009 The Mana World Development Team
+ * Copyright (C) 2009-2010 The Mana Developers
+ * Copyright (C) 2011 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_ADMINHANDLER_H
+#define NET_EA_ADMINHANDLER_H
+
+#include "net/adminhandler.h"
+#include "net/net.h"
+
+#ifdef __GNUC__
+#define _UNUSED_ __attribute__ ((unused))
+#else
+#define _UNUSED_
+#endif
+
+namespace Ea
+{
+
+class AdminHandler : public Net::AdminHandler
+{
+ public:
+ virtual ~AdminHandler() { }
+
+ virtual void kick(const std::string &name);
+
+ virtual void ban(int playerId);
+
+ virtual void ban(const std::string &name);
+
+ virtual void unban(int playerId);
+
+ virtual void unban(const std::string &name);
+
+ virtual void mute(int playerId, int type, int limit);
+};
+
+} // namespace Ea
+
+#endif // NET_EA_ADMINHANDLER_H
diff --git a/src/net/ea/beinghandler.cpp b/src/net/ea/beinghandler.cpp
new file mode 100644
index 000000000..91c83a4e9
--- /dev/null
+++ b/src/net/ea/beinghandler.cpp
@@ -0,0 +1,820 @@
+/*
+ * The ManaPlus Client
+ * Copyright (C) 2004-2009 The Mana World Development Team
+ * Copyright (C) 2009-2010 The Mana Developers
+ * Copyright (C) 2011 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/beinghandler.h"
+
+#include "net/ea/eaprotocol.h"
+
+#include "actorspritemanager.h"
+#include "being.h"
+#include "client.h"
+#include "effectmanager.h"
+#include "guild.h"
+#include "keyboardconfig.h"
+#include "localplayer.h"
+#include "log.h"
+#include "party.h"
+#include "playerrelations.h"
+#include "configuration.h"
+
+#include "gui/botcheckerwindow.h"
+#include "gui/outfitwindow.h"
+#include "gui/socialwindow.h"
+#include "gui/killstats.h"
+
+#include "utils/gettext.h"
+#include "utils/stringutils.h"
+
+#include "net/playerhandler.h"
+#include "net/net.h"
+
+#include "resources/colordb.h"
+
+#include <iostream>
+
+namespace Ea
+{
+const int EMOTION_TIME = 500; /**< Duration of emotion icon */
+
+BeingHandler::BeingHandler(bool enableSync):
+ mSync(enableSync),
+ mSpawnId(0)
+{
+}
+
+Being *BeingHandler::createBeing(int id, short job)
+{
+ if (!actorSpriteManager)
+ return 0;
+
+ ActorSprite::Type type = ActorSprite::UNKNOWN;
+ if (job <= 25 || (job >= 4001 && job <= 4049))
+ type = ActorSprite::PLAYER;
+ else if (job >= 46 && job <= 1000)
+ type = ActorSprite::NPC;
+ else if (job > 1000 && job <= 2000)
+ type = ActorSprite::MONSTER;
+ else if (job == 45)
+ type = ActorSprite::PORTAL;
+
+ Being *being = actorSpriteManager->createBeing(id, type, job);
+
+ if (type == ActorSprite::PLAYER || type == ActorSprite::NPC)
+ {
+ if (!being->updateFromCache())
+ {
+ requestNameById(id);
+ }
+ else
+ {
+ if (player_node)
+ player_node->checkNewName(being);
+ }
+ }
+ if (type == Being::PLAYER)
+ {
+ if (botCheckerWindow)
+ botCheckerWindow->updateList();
+ if (socialWindow)
+ socialWindow->updateActiveList();
+ }
+ return being;
+}
+
+void BeingHandler::setSprite(Being *being, unsigned int slot, int id,
+ std::string color, unsigned char colorId,
+ bool isWeapon, bool isTempSprite)
+{
+ if (!being)
+ return;
+ being->setSprite(slot, id, color, colorId, isWeapon, isTempSprite);
+}
+
+void BeingHandler::processBeingVisibleOrMove(Net::MessageIn &msg, bool visible)
+{
+ if (!actorSpriteManager)
+ return;
+
+ int id;
+ short job, speed, gender;
+ Uint16 headTop, headMid, headBottom;
+ Uint16 shoes, gloves;
+ Uint16 weapon, shield;
+ Uint16 stunMode;
+ Uint32 statusEffects;
+ int guild;
+ Being *dstBeing;
+ int hairStyle, hairColor;
+ int hp, maxHP, oldHP;
+ int spawnId;
+
+ // Information about a being in range
+ id = msg.readInt32();
+ if (id == mSpawnId)
+ spawnId = mSpawnId;
+ else
+ spawnId = 0;
+ mSpawnId = 0;
+ speed = msg.readInt16();
+ stunMode = msg.readInt16(); // opt1
+ statusEffects = msg.readInt16(); // opt2
+ statusEffects |= (static_cast<Uint32>(
+ msg.readInt16())) << 16; // option
+ job = msg.readInt16(); // class
+
+ dstBeing = actorSpriteManager->findBeing(id);
+
+ if (dstBeing && dstBeing->getType() == Being::MONSTER
+ && !dstBeing->isAlive())
+ {
+ actorSpriteManager->destroy(dstBeing);
+ actorSpriteManager->erase(dstBeing);
+ dstBeing = 0;
+ }
+
+ if (!dstBeing)
+ {
+ // Being with id >= 110000000 and job 0 are better
+ // known as ghosts, so don't create those.
+ if (job == 0 && id >= 110000000)
+ return;
+
+ if (actorSpriteManager->isBlocked(id) == true)
+ return;
+
+ dstBeing = createBeing(id, job);
+
+ if (!dstBeing)
+ return;
+
+ if (job == 1022 && killStats)
+ killStats->jackoAlive(dstBeing->getId());
+ }
+ else
+ {
+ // undeleting marked for deletion being
+ if (dstBeing->getType() == Being::NPC)
+ actorSpriteManager->undelete(dstBeing);
+ }
+
+ if (dstBeing->getType() == Being::PLAYER)
+ dstBeing->setMoveTime();
+
+ if (spawnId)
+ {
+ dstBeing->setAction(Being::SPAWN);
+ }
+ else if (visible)
+ {
+ dstBeing->clearPath();
+ dstBeing->setActionTime(tick_time);
+ dstBeing->setAction(Being::STAND);
+ }
+
+ // Prevent division by 0 when calculating frame
+ if (speed == 0)
+ speed = 150;
+
+ dstBeing->setWalkSpeed(Vector(speed, speed, 0));
+ dstBeing->setSubtype(job);
+ if (dstBeing->getType() == ActorSprite::MONSTER && player_node)
+ player_node->checkNewName(dstBeing);
+
+ hairStyle = msg.readInt16();
+ weapon = msg.readInt16();
+ headBottom = msg.readInt16();
+
+ if (!visible)
+ msg.readInt32(); // server tick
+
+ shield = msg.readInt16();
+ headTop = msg.readInt16();
+ headMid = msg.readInt16();
+ hairColor = msg.readInt16();
+ shoes = msg.readInt16(); // clothes color - "abused" as shoes
+
+ if (dstBeing->getType() == ActorSprite::MONSTER)
+ {
+ hp = msg.readInt32();
+ maxHP = msg.readInt32();
+ if (hp && maxHP)
+ {
+ oldHP = dstBeing->getHP();
+ if (!oldHP || oldHP > hp)
+ dstBeing->setHP(hp);
+ dstBeing->setMaxHP(maxHP);
+ }
+ gloves = 0;
+ guild = 0;
+ }
+ else
+ {
+ gloves = msg.readInt16(); // head dir - "abused" as gloves
+ guild = msg.readInt32(); // guild
+ msg.readInt16(); // guild emblem
+ }
+// logger->log("being guild: " + toString(guild));
+/*
+ if (guild == 0)
+ dstBeing->clearGuilds();
+ else
+ dstBeing->setGuild(Guild::getGuild(static_cast<short>(guild)));
+*/
+
+ msg.readInt16(); // manner
+ dstBeing->setStatusEffectBlock(32, msg.readInt16()); // opt3
+ msg.readInt8(); // karma
+ gender = msg.readInt8();
+
+ if (dstBeing->getType() == ActorSprite::PLAYER)
+ {
+ dstBeing->setGender((gender == 0)
+ ? GENDER_FEMALE : GENDER_MALE);
+ // Set these after the gender, as the sprites may be gender-specific
+ setSprite(dstBeing, EA_SPRITE_HAIR, hairStyle * -1,
+ ColorDB::getHairColor(hairColor));
+ setSprite(dstBeing, EA_SPRITE_BOTTOMCLOTHES, headBottom);
+ setSprite(dstBeing, EA_SPRITE_TOPCLOTHES, headMid);
+ setSprite(dstBeing, EA_SPRITE_HAT, headTop);
+ setSprite(dstBeing, EA_SPRITE_SHOE, shoes);
+ setSprite(dstBeing, EA_SPRITE_GLOVES, gloves);
+ setSprite(dstBeing, EA_SPRITE_WEAPON, weapon, "", true);
+ if (!config.getBoolValue("hideShield"))
+ setSprite(dstBeing, EA_SPRITE_SHIELD, shield);
+ }
+ else if (dstBeing->getType() == ActorSprite::NPC)
+ {
+ switch (gender)
+ {
+ case 2:
+ dstBeing->setGender(GENDER_FEMALE);
+ break;
+ case 3:
+ dstBeing->setGender(GENDER_MALE);
+ break;
+ default:
+ dstBeing->setGender(GENDER_UNSPECIFIED);
+ break;
+ }
+ }
+
+
+ if (!visible)
+ {
+ Uint16 srcX, srcY, dstX, dstY;
+ msg.readCoordinatePair(srcX, srcY, dstX, dstY);
+ dstBeing->setAction(Being::STAND);
+ dstBeing->setTileCoords(srcX, srcY);
+ dstBeing->setDestination(dstX, dstY);
+// if (player_node && player_node->getTarget() == dstBeing)
+// player_node->targetMoved();
+ }
+ else
+ {
+ Uint8 dir;
+ Uint16 x, y;
+ msg.readCoordinates(x, y, dir);
+ dstBeing->setTileCoords(x, y);
+
+
+ if (job == 45 && socialWindow && outfitWindow)
+ {
+ int num = socialWindow->getPortalIndex(x, y);
+ if (num >= 0)
+ {
+ dstBeing->setName(keyboard.getKeyShortString(
+ outfitWindow->keyName(num)));
+ }
+ else
+ {
+ dstBeing->setName("");
+ }
+ }
+
+ dstBeing->setDirection(dir);
+ }
+
+ msg.readInt8(); // unknown
+ msg.readInt8(); // unknown
+// msg.readInt8(); // unknown / sit
+ msg.readInt16();
+
+ dstBeing->setStunMode(stunMode);
+ dstBeing->setStatusEffectBlock(0, static_cast<Uint16>(
+ (statusEffects >> 16) & 0xffff));
+ dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff);
+
+}
+
+void BeingHandler::processBeingMove2(Net::MessageIn &msg)
+{
+ if (!actorSpriteManager)
+ return;
+
+ /*
+ * A simplified movement packet, used by the
+ * later versions of eAthena for both mobs and
+ * players
+ */
+ Being *dstBeing = actorSpriteManager->findBeing(msg.readInt32());
+
+ /*
+ * 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)
+ return;
+
+ Uint16 srcX, srcY, dstX, dstY;
+ msg.readCoordinatePair(srcX, srcY, dstX, dstY);
+ msg.readInt32(); // Server tick
+
+ dstBeing->setAction(Being::STAND);
+ dstBeing->setTileCoords(srcX, srcY);
+ dstBeing->setDestination(dstX, dstY);
+ if (dstBeing->getType() == Being::PLAYER)
+ dstBeing->setMoveTime();
+}
+
+void BeingHandler::processBeingSpawn(Net::MessageIn &msg)
+{
+ // skipping this packet
+ mSpawnId = msg.readInt32(); // id
+ msg.readInt16(); // speed
+ msg.readInt16(); // opt1
+ msg.readInt16(); // opt2
+ msg.readInt16(); // option
+ msg.readInt16(); // disguise
+}
+
+void BeingHandler::processBeingRemove(Net::MessageIn &msg)
+{
+ if (!actorSpriteManager || !player_node)
+ return;
+
+ // A being should be removed or has died
+
+ int id = msg.readInt32();
+ Being *dstBeing = actorSpriteManager->findBeing(id);
+ if (!dstBeing)
+ return;
+
+ player_node->followMoveTo(dstBeing, player_node->getNextDestX(),
+ player_node->getNextDestY());
+
+ // If this is player's current target, clear it.
+ if (dstBeing == player_node->getTarget())
+ player_node->stopAttack();
+
+ if (msg.readInt8() == 1)
+ {
+ dstBeing->setAction(Being::DEAD);
+ if (dstBeing->getName() == "Jack O" && killStats)
+ killStats->jackoDead(id);
+ }
+ else
+ {
+ if (dstBeing->getType() == Being::PLAYER)
+ {
+ if (botCheckerWindow)
+ botCheckerWindow->updateList();
+ if (socialWindow)
+ socialWindow->updateActiveList();
+ }
+ actorSpriteManager->destroy(dstBeing);
+ }
+}
+
+void BeingHandler::processBeingResurrect(Net::MessageIn &msg)
+{
+ if (!actorSpriteManager || !player_node)
+ return;
+
+ // A being changed mortality status
+
+ int id = msg.readInt32();
+ Being *dstBeing = actorSpriteManager->findBeing(id);
+ if (!dstBeing)
+ return;
+
+ // If this is player's current target, clear it.
+ if (dstBeing == player_node->getTarget())
+ player_node->stopAttack();
+
+ if (msg.readInt8() == 1)
+ dstBeing->setAction(Being::STAND);
+}
+
+
+void BeingHandler::processSkillDamage(Net::MessageIn &msg)
+{
+ if (!actorSpriteManager)
+ return;
+
+ Being *srcBeing;
+ Being *dstBeing;
+ int param1;
+
+ msg.readInt16(); // Skill Id
+ srcBeing = actorSpriteManager->findBeing(msg.readInt32());
+ dstBeing = actorSpriteManager->findBeing(msg.readInt32());
+ msg.readInt32(); // Server tick
+ msg.readInt32(); // src speed
+ msg.readInt32(); // dst speed
+ param1 = msg.readInt32(); // Damage
+ msg.readInt16(); // Skill level
+ msg.readInt16(); // Div
+ msg.readInt8(); // Skill hit/type (?)
+ if (dstBeing)
+ {
+ // Perhaps a new skill attack type should be created and used?
+// if (dstSpeed)
+// dstBeing->setAttackDelay(dstSpeed);
+ dstBeing->takeDamage(srcBeing, param1, Being::HIT);
+ }
+ if (srcBeing)
+ {
+// if (srcSpeed)
+// srcBeing->setAttackDelay(srcSpeed);
+ srcBeing->handleAttack(dstBeing, param1, Being::HIT);
+ }
+}
+
+void BeingHandler::processBeingAction(Net::MessageIn &msg)
+{
+ if (!actorSpriteManager)
+ return;
+
+ Being *srcBeing;
+ Being *dstBeing;
+ int param1;
+ int type;
+
+ srcBeing = actorSpriteManager->findBeing(msg.readInt32());
+ dstBeing = actorSpriteManager->findBeing(msg.readInt32());
+
+ msg.readInt32(); // server tick
+ int srcSpeed = msg.readInt32(); // src speed
+ msg.readInt32(); // dst speed
+ param1 = msg.readInt16();
+ msg.readInt16(); // param 2
+ type = msg.readInt8();
+ msg.readInt16(); // param 3
+
+ switch (type)
+ {
+ case Being::HIT: // Damage
+ case Being::CRITICAL: // Critical Damage
+ case Being::MULTI: // Critical Damage
+ case Being::REFLECT: // Reflected Damage
+ case Being::FLEE: // Lucky Dodge
+ if (dstBeing)
+ {
+// if (dstSpeed)
+// dstBeing->setAttackDelay(dstSpeed);
+ dstBeing->takeDamage(srcBeing, param1,
+ static_cast<Being::AttackType>(type));
+ }
+ if (srcBeing)
+ {
+ if (srcSpeed && srcBeing->getType() == Being::PLAYER)
+ srcBeing->setAttackDelay(srcSpeed);
+ srcBeing->handleAttack(dstBeing, param1,
+ static_cast<Being::AttackType>(type));
+ if (srcBeing->getType() == Being::PLAYER)
+ srcBeing->setAttackTime();
+ }
+ break;
+
+ case 0x02: // Sit
+ if (srcBeing)
+ {
+ srcBeing->setAction(Being::SIT);
+ if (srcBeing->getType() == Being::PLAYER)
+ {
+ srcBeing->setMoveTime();
+ if (player_node)
+ {
+ player_node->imitateAction(
+ srcBeing, Being::SIT);
+ }
+ }
+ }
+ break;
+
+ case 0x03: // Stand up
+ if (srcBeing)
+ {
+ srcBeing->setAction(Being::STAND);
+ if (srcBeing->getType() == Being::PLAYER)
+ {
+ srcBeing->setMoveTime();
+ if (player_node)
+ {
+ player_node->imitateAction(
+ srcBeing, Being::STAND);
+ }
+ }
+ }
+ break;
+ default:
+ break;
+/*
+ logger->log("QQQ1 SMSG_BEING_ACTION:");
+ if (srcBeing)
+ logger->log("srcBeing:" + toString(srcBeing->getId()));
+ if (dstBeing)
+ logger->log("dstBeing:" + toString(dstBeing->getId()));
+ logger->log("type: " + toString(type));
+*/
+ }
+}
+
+void BeingHandler::processBeingSelfEffect(Net::MessageIn &msg)
+{
+ if (!effectManager || !actorSpriteManager)
+ return;
+
+ int id;
+
+ id = static_cast<Uint32>(msg.readInt32());
+ Being* being = actorSpriteManager->findBeing(id);
+ if (!being)
+ return;
+
+ int effectType = msg.readInt32();
+
+ effectManager->trigger(effectType, being);
+
+ //+++ need dehard code effectType == 3
+ if (being && effectType == 3
+ && being->getType() == Being::PLAYER
+ && socialWindow)
+ { //reset received damage
+ socialWindow->resetDamage(being->getName());
+ }
+}
+
+void BeingHandler::processBeingEmotion(Net::MessageIn &msg)
+{
+ if (!player_node || !actorSpriteManager)
+ return;
+
+ Being *dstBeing;
+
+ if (!(dstBeing = actorSpriteManager->findBeing(msg.readInt32())))
+ return;
+
+ if (player_relations.hasPermission(dstBeing,
+ PlayerRelation::EMOTE))
+ {
+ unsigned char emote = msg.readInt8();
+ if (emote)
+ {
+ dstBeing->setEmote(emote, EMOTION_TIME);
+ player_node->imitateEmote(dstBeing, emote);
+ }
+ }
+ if (dstBeing->getType() == Being::PLAYER)
+ dstBeing->setOtherTime();
+}
+
+void BeingHandler::processNameResponse(Net::MessageIn &msg)
+{
+ if (!player_node || !actorSpriteManager)
+ return;
+
+ Being *dstBeing;
+
+ int beingId = msg.readInt32();
+ if ((dstBeing = actorSpriteManager->findBeing(beingId)))
+ {
+ if (beingId == player_node->getId())
+ {
+ player_node->pingResponse();
+ }
+ else
+ {
+ dstBeing->setName(msg.readString(24));
+ dstBeing->updateGuild();
+ dstBeing->addToCache();
+
+ if (dstBeing->getType() == Being::PLAYER)
+ dstBeing->updateColors();
+
+ if (player_node)
+ {
+ Party *party = player_node->getParty();
+ if (party && party->isMember(dstBeing->getId()))
+ {
+ PartyMember *member = party->getMember(
+ dstBeing->getId());
+
+ if (member)
+ member->setName(dstBeing->getName());
+ }
+ player_node->checkNewName(dstBeing);
+ }
+ }
+ }
+}
+
+void BeingHandler::processIpResponse(Net::MessageIn &msg)
+{
+ if (!actorSpriteManager)
+ return;
+
+ Being *dstBeing;
+
+ if ((dstBeing = actorSpriteManager->findBeing(
+ msg.readInt32())))
+ {
+ dstBeing->setIp(ipToString(msg.readInt32()));
+ }
+}
+
+void BeingHandler::processPlayerGuilPartyInfo(Net::MessageIn &msg)
+{
+ if (!actorSpriteManager)
+ return;
+
+ Being *dstBeing;
+
+ if ((dstBeing = actorSpriteManager->findBeing(msg.readInt32())))
+ {
+ dstBeing->setPartyName(msg.readString(24));
+ dstBeing->setGuildName(msg.readString(24));
+ dstBeing->setGuildPos(msg.readString(24));
+ dstBeing->addToCache();
+ msg.readString(24); // Discard this
+ }
+}
+
+void BeingHandler::processBeingChangeDirection(Net::MessageIn &msg)
+{
+ if (!actorSpriteManager)
+ return;
+
+ Being *dstBeing;
+
+ if (!(dstBeing = actorSpriteManager->findBeing(msg.readInt32())))
+ return;
+
+ msg.readInt16(); // unused
+
+ unsigned char dir = msg.readInt8();
+ dstBeing->setDirection(dir);
+ if (player_node)
+ player_node->imitateDirection(dstBeing, dir);
+}
+
+void BeingHandler::processPlayerStop(Net::MessageIn &msg)
+{
+ if (!actorSpriteManager || !player_node)
+ return;
+
+ /*
+ * Instruction from server to stop walking at x, y.
+ *
+ * Some people like having this enabled. Others absolutely
+ * despise it. So I'm setting to so that it only affects the
+ * local player if the person has set a key "EnableSync" to "1"
+ * in their config.xml file.
+ *
+ * This packet will be honored for all other beings, regardless
+ * of the config setting.
+ */
+
+ int id = msg.readInt32();
+
+ if (mSync || id != player_node->getId())
+ {
+ Being *dstBeing = actorSpriteManager->findBeing(id);
+ if (dstBeing)
+ {
+ Uint16 x, y;
+ x = msg.readInt16();
+ y = msg.readInt16();
+ dstBeing->setTileCoords(x, y);
+ if (dstBeing->getCurrentAction() == Being::MOVE)
+ dstBeing->setAction(Being::STAND);
+ }
+ }
+}
+
+void BeingHandler::processPlayerMoveToAttack(Net::MessageIn &msg _UNUSED_)
+{
+ /*
+ * This is an *advisory* message, telling the client that
+ * it needs to move the character before attacking
+ * a target (out of range, obstruction in line of fire).
+ * We can safely ignore this...
+ */
+ if (player_node)
+ player_node->fixAttackTarget();
+}
+
+void BeingHandler::processPlaterStatusChange(Net::MessageIn &msg)
+{
+ if (!actorSpriteManager)
+ return;
+
+ // Change in players' flags
+
+ int id = msg.readInt32();
+ Being *dstBeing = actorSpriteManager->findBeing(id);
+ if (!dstBeing)
+ return;
+
+ Uint16 stunMode = msg.readInt16();
+ Uint32 statusEffects = msg.readInt16();
+ statusEffects |= (static_cast<Uint32>(msg.readInt16())) << 16;
+ msg.readInt8(); // Unused?
+
+ dstBeing->setStunMode(stunMode);
+ dstBeing->setStatusEffectBlock(0, static_cast<Uint16>(
+ (statusEffects >> 16) & 0xffff));
+ dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff);
+}
+
+void BeingHandler::processBeingStatusChange(Net::MessageIn &msg)
+{
+ if (!actorSpriteManager)
+ return;
+
+ // Status change
+ Uint16 status = msg.readInt16();
+ int id = msg.readInt32();
+ int flag = msg.readInt8(); // 0: stop, 1: start
+
+ Being *dstBeing = actorSpriteManager->findBeing(id);
+ if (dstBeing)
+ dstBeing->setStatusEffect(status, flag);
+}
+
+void BeingHandler::processSkilCasting(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 pl
+ msg.readInt32(); // cast time
+}
+
+void BeingHandler::processSkillNoDamage(Net::MessageIn &msg)
+{
+ msg.readInt16(); // skill id
+ msg.readInt16(); // heal
+ msg.readInt32(); // dst id
+ msg.readInt32(); // src id
+ msg.readInt8(); // fail
+}
+
+void BeingHandler::processPvpMapMode(Net::MessageIn &msg)
+{
+ Game *game = Game::instance();
+ if (!game)
+ return;
+
+ Map *map = game->getCurrentMap();
+ if (map)
+ map->setPvpMode(msg.readInt16());
+}
+
+void BeingHandler::processPvpSet(Net::MessageIn &msg)
+{
+ int id = msg.readInt32(); // id
+ int rank = msg.readInt32(); // rank
+ msg.readInt32(); // num
+ if (actorSpriteManager)
+ {
+ Being *dstBeing = actorSpriteManager->findBeing(id);
+ if (dstBeing)
+ dstBeing->setPvpRank(rank);
+ }
+}
+
+} // namespace Ea
diff --git a/src/net/ea/beinghandler.h b/src/net/ea/beinghandler.h
new file mode 100644
index 000000000..e76cf7840
--- /dev/null
+++ b/src/net/ea/beinghandler.h
@@ -0,0 +1,111 @@
+/*
+ * The ManaPlus Client
+ * Copyright (C) 2004-2009 The Mana World Development Team
+ * Copyright (C) 2009-2010 The Mana Developers
+ * Copyright (C) 2011 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_BEINGHANDLER_H
+#define NET_EA_BEINGHANDLER_H
+
+#include "net/beinghandler.h"
+#include "net/net.h"
+
+#ifdef __GNUC__
+#define _UNUSED_ __attribute__ ((unused))
+#else
+#define _UNUSED_
+#endif
+
+namespace Ea
+{
+
+class BeingHandler : public Net::BeingHandler
+{
+ public:
+ BeingHandler(bool enableSync);
+
+ protected:
+ virtual void requestNameById(int id) = 0;
+
+ virtual Being *createBeing(int id, short job);
+
+ virtual void setSprite(Being *being, unsigned int slot, int id,
+ std::string color = "",
+ unsigned char colorId = 1,
+ bool isWeapon = false,
+ bool isTempSprite = false);
+
+ virtual void processBeingVisibleOrMove(Net::MessageIn &msg,
+ bool visible);
+
+ virtual void processBeingMove2(Net::MessageIn &msg);
+
+ virtual void processBeingSpawn(Net::MessageIn &msg);
+
+ virtual void processBeingRemove(Net::MessageIn &msg);
+
+ virtual void processBeingResurrect(Net::MessageIn &msg);
+
+ virtual void processSkillDamage(Net::MessageIn &msg);
+
+ virtual void processBeingAction(Net::MessageIn &msg);
+
+ virtual void processBeingSelfEffect(Net::MessageIn &msg);
+
+ virtual void processBeingEmotion(Net::MessageIn &msg);
+
+ virtual void processBeingChangeLook(Net::MessageIn &msg,
+ bool look2) = 0;
+
+ virtual void processNameResponse(Net::MessageIn &msg);
+
+ virtual void processIpResponse(Net::MessageIn &msg);
+
+ virtual void processPlayerGuilPartyInfo(Net::MessageIn &msg);
+
+ virtual void processBeingChangeDirection(Net::MessageIn &msg);
+
+ virtual void processPlayerMoveUpdate(Net::MessageIn &msg,
+ int type) = 0;
+
+ virtual void processPlayerStop(Net::MessageIn &msg);
+
+ virtual void processPlayerMoveToAttack(Net::MessageIn &msg);
+
+ virtual void processPlaterStatusChange(Net::MessageIn &msg);
+
+ virtual void processBeingStatusChange(Net::MessageIn &msg);
+
+ virtual void processSkilCasting(Net::MessageIn &msg);
+
+ virtual void processSkillNoDamage(Net::MessageIn &msg);
+
+ virtual void processPvpMapMode(Net::MessageIn &msg);
+
+ virtual void processPvpSet(Net::MessageIn &msg);
+
+ protected:
+ // Should we honor server "Stop Walking" packets
+ bool mSync;
+ int mSpawnId;
+};
+
+} // namespace Ea
+
+#endif // NET_EA_BEINGHANDLER_H
diff --git a/src/net/ea/buysellhandler.cpp b/src/net/ea/buysellhandler.cpp
new file mode 100644
index 000000000..35180c10f
--- /dev/null
+++ b/src/net/ea/buysellhandler.cpp
@@ -0,0 +1,180 @@
+/*
+ * The ManaPlus Client
+ * Copyright (C) 2004-2009 The Mana World Development Team
+ * Copyright (C) 2009-2010 The Mana Developers
+ * Copyright (C) 2011 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/buysellhandler.h"
+
+#include "actorspritemanager.h"
+#include "configuration.h"
+#include "event.h"
+#include "inventory.h"
+#include "item.h"
+#include "localplayer.h"
+#include "playerinfo.h"
+#include "shopitem.h"
+
+#include "gui/buydialog.h"
+#include "gui/buyselldialog.h"
+#include "gui/selldialog.h"
+#include "gui/shopwindow.h"
+
+#include "gui/widgets/chattab.h"
+
+#include "net/chathandler.h"
+#include "net/messagein.h"
+#include "net/net.h"
+
+#include "utils/gettext.h"
+
+namespace Ea
+{
+
+BuySellHandler::BuySellHandler()
+{
+ mNpcId = 0;
+}
+
+void BuySellHandler::requestSellList(std::string nick)
+{
+ if (nick.empty() != 0 || !shopWindow)
+ return;
+
+ std::string data = "!selllist " + toString(tick_time);
+ shopWindow->setAcceptPlayer(nick);
+
+ if (config.getBoolValue("hideShopMessages"))
+ {
+ Net::getChatHandler()->privateMessage(nick, data);
+ }
+ else
+ {
+ if (chatWindow)
+ chatWindow->whisper(nick, data, BY_PLAYER);
+ }
+}
+
+void BuySellHandler::requestBuyList(std::string nick)
+{
+ if (nick.empty() || !shopWindow)
+ return;
+
+ std::string data = "!buylist " + toString(tick_time);
+ shopWindow->setAcceptPlayer(nick);
+
+ if (config.getBoolValue("hideShopMessages"))
+ {
+ Net::getChatHandler()->privateMessage(nick, data);
+ }
+ else
+ {
+ if (chatWindow)
+ chatWindow->whisper(nick, data, BY_PLAYER);
+ }
+}
+
+void BuySellHandler::sendBuyRequest(std::string nick, ShopItem* item,
+ int amount)
+{
+ if (!chatWindow || nick.empty() || !item ||
+ amount < 1 || amount > item->getQuantity())
+ {
+ return;
+ }
+ std::string data = strprintf("!buyitem %d %d %d",
+ item->getId(), item->getPrice(), amount);
+
+ if (config.getBoolValue("hideShopMessages"))
+ Net::getChatHandler()->privateMessage(nick, data);
+ else
+ chatWindow->whisper(nick, data, BY_PLAYER);
+}
+
+void BuySellHandler::sendSellRequest(std::string nick, ShopItem* item,
+ int amount)
+{
+ if (!chatWindow || nick.empty() || !item ||
+ amount < 1 || amount > item->getQuantity())
+ {
+ return;
+ }
+
+ std::string data = strprintf("!sellitem %d %d %d",
+ item->getId(), item->getPrice(), amount);
+
+ if (config.getBoolValue("hideShopMessages"))
+ Net::getChatHandler()->privateMessage(nick, data);
+ else
+ chatWindow->whisper(nick, data, BY_PLAYER);
+}
+
+void BuySellHandler::processNpcBuySellChoice(Net::MessageIn &msg)
+{
+ if (!BuySellDialog::isActive())
+ {
+ mNpcId = msg.readInt32();
+ new BuySellDialog(mNpcId);
+ }
+}
+
+void BuySellHandler::processNpcSell(Net::MessageIn &msg, int offset)
+{
+ msg.readInt16(); // length
+ int n_items = (msg.getLength() - 4) / 10;
+ if (n_items > 0)
+ {
+ SellDialog *dialog = new SellDialog(mNpcId);
+ dialog->setMoney(PlayerInfo::getAttribute(MONEY));
+
+ for (int k = 0; k < n_items; k++)
+ {
+ int index = msg.readInt16() - offset;
+ int value = msg.readInt32();
+ msg.readInt32(); // OCvalue
+
+ Item *item = PlayerInfo::getInventory()->getItem(index);
+
+ if (item && !(item->isEquipped()))
+ dialog->addItem(item, value);
+ }
+ }
+ else
+ {
+ SERVER_NOTICE(_("Nothing to sell."))
+ }
+}
+
+void BuySellHandler::processNpcBuyResponse(Net::MessageIn &msg)
+{
+ if (msg.readInt8() == 0)
+ {
+ SERVER_NOTICE(_("Thanks for buying."))
+ }
+ else
+ {
+ // Reset player money since buy dialog already assumed purchase
+ // would go fine
+ if (mBuyDialog)
+ mBuyDialog->setMoney(PlayerInfo::getAttribute(MONEY));
+ SERVER_NOTICE(_("Unable to buy."))
+ }
+}
+
+} // namespace Ea
diff --git a/src/net/ea/buysellhandler.h b/src/net/ea/buysellhandler.h
new file mode 100644
index 000000000..60931ef9b
--- /dev/null
+++ b/src/net/ea/buysellhandler.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 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_BUYSELLHANDLER_H
+#define NET_EA_BUYSELLHANDLER_H
+
+#include "net/buysellhandler.h"
+
+#include "being.h"
+
+#include "net/net.h"
+
+class BuyDialog;
+
+namespace Ea
+{
+
+class BuySellHandler : public Net::BuySellHandler
+{
+ public:
+ BuySellHandler();
+
+ virtual void requestSellList(std::string nick);
+ virtual void requestBuyList(std::string nick);
+ virtual void sendBuyRequest(std::string nick, ShopItem* item,
+ int amount);
+ virtual void sendSellRequest(std::string nick, ShopItem* item,
+ int amount);
+
+ virtual void processNpcBuySellChoice(Net::MessageIn &msg);
+
+ virtual void processNpcBuy(Net::MessageIn &msg) = 0;
+
+ virtual void processNpcSell(Net::MessageIn &msg, int offset);
+
+ virtual void processNpcBuyResponse(Net::MessageIn &msg);
+
+ virtual void processNpcSellResponse(Net::MessageIn &msg) = 0;
+
+ protected:
+ int mNpcId;
+ BuyDialog *mBuyDialog;
+};
+
+} // namespace Ea
+
+#endif // NET_EA_BUYSELLHANDLER_H
diff --git a/src/net/ea/eaprotocol.h b/src/net/ea/eaprotocol.h
new file mode 100644
index 000000000..d72ca3515
--- /dev/null
+++ b/src/net/ea/eaprotocol.h
@@ -0,0 +1,42 @@
+/*
+ * The ManaPlus Client
+ * Copyright (C) 2004-2009 The Mana World Development Team
+ * Copyright (C) 2009-2010 The Mana Developers
+ * Copyright (C) 2011 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 EA_EA_PROTOCOL_H
+#define EA_EA_PROTOCOL_H
+
+enum
+{
+ EA_SPRITE_BASE = 0,
+ EA_SPRITE_SHOE,
+ EA_SPRITE_BOTTOMCLOTHES,
+ EA_SPRITE_TOPCLOTHES,
+ EA_SPRITE_MISC1,
+ EA_SPRITE_MISC2,
+ EA_SPRITE_HAIR,
+ EA_SPRITE_HAT,
+ EA_SPRITE_CAPE,
+ EA_SPRITE_GLOVES,
+ EA_SPRITE_WEAPON,
+ EA_SPRITE_SHIELD
+};
+
+#endif
diff --git a/src/net/tmwa/adminhandler.cpp b/src/net/tmwa/adminhandler.cpp
index f33bf295b..45a285d02 100644
--- a/src/net/tmwa/adminhandler.cpp
+++ b/src/net/tmwa/adminhandler.cpp
@@ -22,10 +22,13 @@
#include "net/tmwa/adminhandler.h"
+#include "net/ea/adminhandler.h"
+
#include "actorspritemanager.h"
#include "being.h"
#include "event.h"
#include "game.h"
+#include "log.h"
#include "playerrelations.h"
#include "net/chathandler.h"
@@ -96,41 +99,4 @@ void AdminHandler::kick(int playerId)
outMsg.writeInt32(playerId);
}
-void AdminHandler::kick(const std::string &name)
-{
- Net::getChatHandler()->talk("@kick " + name);
-}
-
-void AdminHandler::ban(int playerId _UNUSED_)
-{
- // Not supported
-}
-
-void AdminHandler::ban(const std::string &name)
-{
- Net::getChatHandler()->talk("@ban " + name);
-}
-
-void AdminHandler::unban(int playerId _UNUSED_)
-{
- // Not supported
-}
-
-void AdminHandler::unban(const std::string &name)
-{
- Net::getChatHandler()->talk("@unban " + name);
-}
-
-void AdminHandler::mute(int playerId _UNUSED_, int type _UNUSED_,
- int limit _UNUSED_)
-{
- return; // Still looking into this
-/*
- MessageOut outMsg(CMSG_ADMIN_MUTE);
- outMsg.writeInt32(playerId);
- outMsg.writeInt8(type);
- outMsg.writeInt16(limit);
-*/
-}
-
} // namespace TmwAthena
diff --git a/src/net/tmwa/adminhandler.h b/src/net/tmwa/adminhandler.h
index 60934be77..6c60398fc 100644
--- a/src/net/tmwa/adminhandler.h
+++ b/src/net/tmwa/adminhandler.h
@@ -26,6 +26,8 @@
#include "net/adminhandler.h"
#include "net/net.h"
+#include "net/ea/adminhandler.h"
+
#include "net/tmwa/messagehandler.h"
#ifdef __GNUC__
@@ -37,7 +39,7 @@
namespace TmwAthena
{
-class AdminHandler : public MessageHandler, public Net::AdminHandler
+class AdminHandler : public MessageHandler, public Ea::AdminHandler
{
public:
AdminHandler();
@@ -51,18 +53,6 @@ class AdminHandler : public MessageHandler, public Net::AdminHandler
void hide(bool hide);
void kick(int playerId);
-
- void kick(const std::string &name);
-
- void ban(int playerId);
-
- void ban(const std::string &name);
-
- void unban(int playerId);
-
- void unban(const std::string &name);
-
- void mute(int playerId, int type, int limit);
};
} // namespace TmwAthena
diff --git a/src/net/tmwa/beinghandler.cpp b/src/net/tmwa/beinghandler.cpp
index 582f755f1..ff458b31b 100644
--- a/src/net/tmwa/beinghandler.cpp
+++ b/src/net/tmwa/beinghandler.cpp
@@ -56,13 +56,8 @@ extern Net::BeingHandler *beingHandler;
namespace TmwAthena
{
-const int EMOTION_TIME = 500; /**< Duration of emotion icon */
-
-Being *createBeing(int id, short job);
-
BeingHandler::BeingHandler(bool enableSync):
- mSync(enableSync),
- mSpawnId(0)
+ Ea::BeingHandler(enableSync)
{
static const Uint16 _messages[] =
{
@@ -102,46 +97,6 @@ BeingHandler::BeingHandler(bool enableSync):
beingHandler = this;
}
-Being *createBeing(int id, short job)
-{
- if (!actorSpriteManager)
- return 0;
-
- ActorSprite::Type type = ActorSprite::UNKNOWN;
- if (job <= 25 || (job >= 4001 && job <= 4049))
- type = ActorSprite::PLAYER;
- else if (job >= 46 && job <= 1000)
- type = ActorSprite::NPC;
- else if (job > 1000 && job <= 2000)
- type = ActorSprite::MONSTER;
- else if (job == 45)
- type = ActorSprite::PORTAL;
-
- Being *being = actorSpriteManager->createBeing(id, type, job);
-
- if (type == ActorSprite::PLAYER || type == ActorSprite::NPC)
- {
- if (!being->updateFromCache())
- {
- MessageOut outMsg(0x0094);
- outMsg.writeInt32(id); //readLong(2));
- }
- else
- {
- if (player_node)
- player_node->checkNewName(being);
- }
- }
- if (type == Being::PLAYER)
- {
- if (botCheckerWindow)
- botCheckerWindow->updateList();
- if (socialWindow)
- socialWindow->updateActiveList();
- }
- return being;
-}
-
void BeingHandler::requestNameById(int id)
{
MessageOut outMsg(0x0094);
@@ -150,1071 +105,546 @@ void BeingHandler::requestNameById(int id)
void BeingHandler::handleMessage(Net::MessageIn &msg)
{
- if (!actorSpriteManager)
- return;
-
- int id;
- short job, speed, gender;
- Uint16 headTop, headMid, headBottom;
- Uint16 shoes, gloves;
- Uint16 weapon, shield;
- Uint16 gmstatus;
- int param1;
- Uint16 stunMode;
- int level;
- Uint32 statusEffects;
- int type, guild;
- Uint16 status;
- Being *srcBeing, *dstBeing;
- int hairStyle, hairColor, flag;
- int hp, maxHP, oldHP;
- unsigned char colors[9];
- Uint8 dir;
- int spawnId;
-
switch (msg.getId())
{
case SMSG_BEING_VISIBLE:
case SMSG_BEING_MOVE:
- // Information about a being in range
- id = msg.readInt32();
- if (id == mSpawnId)
- spawnId = mSpawnId;
- else
- spawnId = 0;
- mSpawnId = 0;
- speed = msg.readInt16();
- stunMode = msg.readInt16(); // opt1
- statusEffects = msg.readInt16(); // opt2
- statusEffects |= (static_cast<Uint32>(
- msg.readInt16())) << 16; // option
- job = msg.readInt16(); // class
-
- dstBeing = actorSpriteManager->findBeing(id);
-
- if (dstBeing && dstBeing->getType() == Being::MONSTER
- && !dstBeing->isAlive())
- {
- actorSpriteManager->destroy(dstBeing);
- actorSpriteManager->erase(dstBeing);
- dstBeing = 0;
- }
-
- if (!dstBeing)
- {
- // Being with id >= 110000000 and job 0 are better
- // known as ghosts, so don't create those.
- if (job == 0 && id >= 110000000)
- break;
-
- if (actorSpriteManager->isBlocked(id) == true)
- break;
-
- dstBeing = createBeing(id, job);
-
- if (!dstBeing)
- break;
-
-
- if (job == 1022 && killStats)
- killStats->jackoAlive(dstBeing->getId());
- }
- else
- {
- // undeleting marked for deletion being
- if (dstBeing->getType() == Being::NPC)
- {
- actorSpriteManager->undelete(dstBeing);
- }
- }
-
- if (dstBeing->getType() == Being::PLAYER)
- dstBeing->setMoveTime();
-
- if (spawnId)
- {
- dstBeing->setAction(Being::SPAWN);
- }
- else if (msg.getId() == SMSG_BEING_VISIBLE)
- {
- dstBeing->clearPath();
- dstBeing->setActionTime(tick_time);
- dstBeing->setAction(Being::STAND);
- }
-
- // Prevent division by 0 when calculating frame
- if (speed == 0)
- speed = 150;
-
- dstBeing->setWalkSpeed(Vector(speed, speed, 0));
- dstBeing->setSubtype(job);
- if (dstBeing->getType() == ActorSprite::MONSTER && player_node)
- player_node->checkNewName(dstBeing);
-
- hairStyle = msg.readInt16();
- weapon = msg.readInt16();
- headBottom = msg.readInt16();
-
- if (msg.getId() == SMSG_BEING_MOVE)
- msg.readInt32(); // server tick
-
- shield = msg.readInt16();
- headTop = msg.readInt16();
- headMid = msg.readInt16();
- hairColor = msg.readInt16();
- shoes = msg.readInt16(); // clothes color - "abused" as shoes
-
- if (dstBeing->getType() == ActorSprite::MONSTER)
- {
- hp = msg.readInt32();
- maxHP = msg.readInt32();
- if (hp && maxHP)
- {
- oldHP = dstBeing->getHP();
- if (!oldHP || oldHP > hp)
- dstBeing->setHP(hp);
- dstBeing->setMaxHP(maxHP);
- }
- gloves = 0;
- guild = 0;
- }
- else
- {
- gloves = msg.readInt16(); // head dir - "abused" as gloves
- guild = msg.readInt32(); // guild
- msg.readInt16(); // guild emblem
- }
-// logger->log("being guild: " + toString(guild));
-/*
- if (guild == 0)
- dstBeing->clearGuilds();
- else
- dstBeing->setGuild(Guild::getGuild(static_cast<short>(guild)));
-*/
-
- msg.readInt16(); // manner
- dstBeing->setStatusEffectBlock(32, msg.readInt16()); // opt3
- msg.readInt8(); // karma
- gender = msg.readInt8();
-
- if (dstBeing->getType() == ActorSprite::PLAYER)
- {
- dstBeing->setGender((gender == 0)
- ? GENDER_FEMALE : GENDER_MALE);
- // Set these after the gender, as the sprites may be gender-specific
- dstBeing->setSprite(SPRITE_HAIR, hairStyle * -1,
- ColorDB::getHairColor(hairColor));
- dstBeing->setSprite(SPRITE_BOTTOMCLOTHES, headBottom);
- dstBeing->setSprite(SPRITE_TOPCLOTHES, headMid);
- dstBeing->setSprite(SPRITE_HAT, headTop);
- dstBeing->setSprite(SPRITE_SHOE, shoes);
- dstBeing->setSprite(SPRITE_GLOVES, gloves);
- dstBeing->setSprite(SPRITE_WEAPON, weapon, "", true);
- if (!config.getBoolValue("hideShield"))
- dstBeing->setSprite(SPRITE_SHIELD, shield);
- }
- else if (dstBeing->getType() == ActorSprite::NPC)
- {
- switch (gender)
- {
- case 2:
- dstBeing->setGender(GENDER_FEMALE);
- break;
- case 3:
- dstBeing->setGender(GENDER_MALE);
- break;
- default:
- dstBeing->setGender(GENDER_UNSPECIFIED);
- break;
- }
- }
-
- if (msg.getId() == SMSG_BEING_MOVE)
- {
- Uint16 srcX, srcY, dstX, dstY;
- msg.readCoordinatePair(srcX, srcY, dstX, dstY);
- dstBeing->setAction(Being::STAND);
- dstBeing->setTileCoords(srcX, srcY);
- dstBeing->setDestination(dstX, dstY);
-
-// if (player_node && player_node->getTarget() == dstBeing)
-// player_node->targetMoved();
- }
- else
- {
- Uint8 dir;
- Uint16 x, y;
- msg.readCoordinates(x, y, dir);
- dstBeing->setTileCoords(x, y);
-
- if (job == 45 && socialWindow && outfitWindow)
- {
- int num = socialWindow->getPortalIndex(x, y);
- if (num >= 0)
- {
- dstBeing->setName(keyboard.getKeyShortString(
- outfitWindow->keyName(num)));
- }
- else
- {
- dstBeing->setName("");
- }
- }
-
- dstBeing->setDirection(dir);
- }
-
- msg.readInt8(); // unknown
- msg.readInt8(); // unknown
-// msg.readInt8(); // unknown / sit
- msg.readInt16();
-
- dstBeing->setStunMode(stunMode);
- dstBeing->setStatusEffectBlock(0, static_cast<Uint16>(
- (statusEffects >> 16) & 0xffff));
- dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff);
+ processBeingVisibleOrMove(msg, msg.getId() == SMSG_BEING_VISIBLE);
break;
case SMSG_BEING_MOVE2:
- /*
- * A simplified movement packet, used by the
- * later versions of eAthena for both mobs and
- * players
- */
- dstBeing = actorSpriteManager->findBeing(msg.readInt32());
-
- /*
- * 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)
- break;
-
- Uint16 srcX, srcY, dstX, dstY;
- msg.readCoordinatePair(srcX, srcY, dstX, dstY);
- msg.readInt32(); // Server tick
-
- dstBeing->setAction(Being::STAND);
- dstBeing->setTileCoords(srcX, srcY);
- dstBeing->setDestination(dstX, dstY);
- if (dstBeing->getType() == Being::PLAYER)
- dstBeing->setMoveTime();
-
-// if (player_node && player_node->getTarget() == dstBeing)
-// {
-// logger->log("SMSG_BEING_MOVE2");
-// player_node->targetMoved();
-// }
-
+ processBeingMove2(msg);
break;
case SMSG_BEING_SPAWN:
- // skipping this packet
- mSpawnId = msg.readInt32(); // id
- msg.readInt16(); // speed
- msg.readInt16(); // opt1
- msg.readInt16(); // opt2
- msg.readInt16(); // option
- msg.readInt16(); // disguise
+ processBeingSpawn(msg);
break;
case SMSG_BEING_REMOVE:
- // A being should be removed or has died
-
- id = msg.readInt32();
- dstBeing = actorSpriteManager->findBeing(id);
- if (!dstBeing)
- break;
-
- player_node->followMoveTo(dstBeing, player_node->getNextDestX(),
- player_node->getNextDestY());
-
- // If this is player's current target, clear it.
- if (dstBeing == player_node->getTarget())
- player_node->stopAttack();
-
- if (msg.readInt8() == 1)
- {
- dstBeing->setAction(Being::DEAD);
- if (dstBeing->getName() == "Jack O" && killStats)
- killStats->jackoDead(id);
- }
- else
- {
- if (dstBeing->getType() == Being::PLAYER)
- {
- if (botCheckerWindow)
- botCheckerWindow->updateList();
- if (socialWindow)
- socialWindow->updateActiveList();
- }
- actorSpriteManager->destroy(dstBeing);
- }
+ processBeingRemove(msg);
break;
case SMSG_BEING_RESURRECT:
- // A being changed mortality status
-
- id = msg.readInt32();
- dstBeing = actorSpriteManager->findBeing(id);
- if (!dstBeing)
- break;
-
- // If this is player's current target, clear it.
- if (dstBeing == player_node->getTarget())
- player_node->stopAttack();
-
- if (msg.readInt8() == 1)
- dstBeing->setAction(Being::STAND);
-
+ processBeingResurrect(msg);
break;
case SMSG_SKILL_DAMAGE:
{
- msg.readInt16(); // Skill Id
- srcBeing = actorSpriteManager->findBeing(msg.readInt32());
- dstBeing = actorSpriteManager->findBeing(msg.readInt32());
- msg.readInt32(); // Server tick
- msg.readInt32(); // src speed
- msg.readInt32(); // dst speed
- param1 = msg.readInt32(); // Damage
- msg.readInt16(); // Skill level
- msg.readInt16(); // Div
- msg.readInt8(); // Skill hit/type (?)
- if (dstBeing)
- {
- // Perhaps a new skill attack type should be created and used?
-// if (dstSpeed)
-// dstBeing->setAttackDelay(dstSpeed);
- dstBeing->takeDamage(srcBeing, param1, Being::HIT);
- }
- if (srcBeing)
- {
-// if (srcSpeed)
-// srcBeing->setAttackDelay(srcSpeed);
- srcBeing->handleAttack(dstBeing, param1, Being::HIT);
- }
+ processSkillDamage(msg);
break;
}
case SMSG_BEING_ACTION:
{
- srcBeing = actorSpriteManager->findBeing(msg.readInt32());
- dstBeing = actorSpriteManager->findBeing(msg.readInt32());
-
- msg.readInt32(); // server tick
- int srcSpeed = msg.readInt32(); // src speed
- msg.readInt32(); // dst speed
- param1 = msg.readInt16();
- msg.readInt16(); // param 2
- type = msg.readInt8();
- msg.readInt16(); // param 3
-
- switch (type)
- {
- case Being::HIT: // Damage
- case Being::CRITICAL: // Critical Damage
- case Being::MULTI: // Critical Damage
- case Being::REFLECT: // Reflected Damage
- case Being::FLEE: // Lucky Dodge
- if (dstBeing)
- {
-// if (dstSpeed)
-// dstBeing->setAttackDelay(dstSpeed);
- dstBeing->takeDamage(srcBeing, param1,
- static_cast<Being::AttackType>(type));
- }
- if (srcBeing)
- {
- if (srcSpeed && srcBeing->getType() == Being::PLAYER)
- srcBeing->setAttackDelay(srcSpeed);
- srcBeing->handleAttack(dstBeing, param1,
- static_cast<Being::AttackType>(type));
- if (srcBeing->getType() == Being::PLAYER)
- srcBeing->setAttackTime();
- }
- break;
-
- case 0x02: // Sit
- if (srcBeing)
- {
- srcBeing->setAction(Being::SIT);
- if (srcBeing->getType() == Being::PLAYER)
- {
- srcBeing->setMoveTime();
- if (player_node)
- {
- player_node->imitateAction(
- srcBeing, Being::SIT);
- }
- }
- }
- break;
-
- case 0x03: // Stand up
- if (srcBeing)
- {
- srcBeing->setAction(Being::STAND);
- if (srcBeing->getType() == Being::PLAYER)
- {
- srcBeing->setMoveTime();
- if (player_node)
- {
- player_node->imitateAction(
- srcBeing, Being::STAND);
- }
- }
- }
- break;
- default:
- break;
-/*
- logger->log("QQQ1 SMSG_BEING_ACTION:");
- if (srcBeing)
- logger->log("srcBeing:" + toString(srcBeing->getId()));
- if (dstBeing)
- logger->log("dstBeing:" + toString(dstBeing->getId()));
- logger->log("type: " + toString(type));
-*/
- }
+ processBeingAction(msg);
break;
}
case SMSG_BEING_SELFEFFECT:
{
- if (!effectManager)
- return;
-
- id = static_cast<Uint32>(msg.readInt32());
- Being* being = actorSpriteManager->findBeing(id);
- if (!being)
- break;
-
- int effectType = msg.readInt32();
-
- effectManager->trigger(effectType, being);
-
- if (being && effectType == 3
- && being->getType() == Being::PLAYER
- && socialWindow)
- { //reset received damage
- socialWindow->resetDamage(being->getName());
- }
-
+ processBeingSelfEffect(msg);
break;
}
case SMSG_BEING_EMOTION:
- if (!player_node)
- break;
-
- if (!(dstBeing = actorSpriteManager->findBeing(msg.readInt32())))
- break;
-
- if (player_relations.hasPermission(dstBeing,
- PlayerRelation::EMOTE))
- {
- unsigned char emote = msg.readInt8();
- if (emote)
- {
- dstBeing->setEmote(emote, EMOTION_TIME);
- player_node->imitateEmote(dstBeing, emote);
- }
- }
- if (dstBeing->getType() == Being::PLAYER)
- dstBeing->setOtherTime();
-
+ processBeingEmotion(msg);
break;
case SMSG_BEING_CHANGE_LOOKS:
case SMSG_BEING_CHANGE_LOOKS2:
- {
- /*
- * SMSG_BEING_CHANGE_LOOKS (0x00c3) and
- * SMSG_BEING_CHANGE_LOOKS2 (0x01d7) do basically the same
- * thing. The difference is that ...LOOKS carries a single
- * 8 bit value, where ...LOOKS2 carries two 16 bit values.
- *
- * If type = 2, then the first 16 bit value is the weapon ID,
- * and the second 16 bit value is the shield ID. If no
- * shield is equipped, or type is not 2, then the second
- * 16 bit value will be 0.
- */
-
- if (!(dstBeing = actorSpriteManager->findBeing(msg.readInt32())))
- break;
-
- int type = msg.readInt8();
- int id = 0;
- int id2 = 0;
- std::string color;
-
- if (msg.getId() == SMSG_BEING_CHANGE_LOOKS)
- {
- id = msg.readInt8();
- id2 = 1; // default color
- }
- else
- { // SMSG_BEING_CHANGE_LOOKS2
- id = msg.readInt16();
- if (type == 2 || serverVersion > 0)
- id2 = msg.readInt16();
- else
- id2 = 1;
- color = "";
- }
-
- if (dstBeing->getType() == Being::PLAYER)
- dstBeing->setOtherTime();
-
- if (!player_node)
- break;
-
- switch (type)
- {
- case 0: // change race
- dstBeing->setSubtype(static_cast<Uint16>(id));
- break;
- case 1: // eAthena LOOK_HAIR
- dstBeing->setSpriteID(SPRITE_HAIR, id *-1);
- break;
- case 2: // Weapon ID in id, Shield ID in id2
- dstBeing->setSprite(SPRITE_WEAPON, id, "", 1, true);
- if (!config.getBoolValue("hideShield"))
- dstBeing->setSprite(SPRITE_SHIELD, id2);
- player_node->imitateOutfit(dstBeing, SPRITE_SHIELD);
- break;
- case 3: // Change lower headgear for eAthena, pants for us
- dstBeing->setSprite(SPRITE_BOTTOMCLOTHES, id, color,
- static_cast<unsigned char>(id2));
- player_node->imitateOutfit(dstBeing, SPRITE_BOTTOMCLOTHES);
- break;
- case 4: // Change upper headgear for eAthena, hat for us
- dstBeing->setSprite(SPRITE_HAT, id, color,
- static_cast<unsigned char>(id2));
- player_node->imitateOutfit(dstBeing, SPRITE_HAT);
- break;
- case 5: // Change middle headgear for eathena, armor for us
- dstBeing->setSprite(SPRITE_TOPCLOTHES, id, color,
- static_cast<unsigned char>(id2));
- player_node->imitateOutfit(dstBeing, SPRITE_TOPCLOTHES);
- break;
- case 6: // eAthena LOOK_HAIR_COLOR
- dstBeing->setSpriteColor(SPRITE_HAIR,
- ColorDB::getHairColor(id));
- break;
- case 8: // eAthena LOOK_SHIELD
- if (!config.getBoolValue("hideShield"))
- {
- dstBeing->setSprite(SPRITE_SHIELD, id, color,
- static_cast<unsigned char>(id2));
- }
- player_node->imitateOutfit(dstBeing, SPRITE_SHIELD);
- break;
- case 9: // eAthena LOOK_SHOES
- dstBeing->setSprite(SPRITE_SHOE, id, color,
- static_cast<unsigned char>(id2));
- player_node->imitateOutfit(dstBeing, SPRITE_SHOE);
- break;
- case 10: // LOOK_GLOVES
- dstBeing->setSprite(SPRITE_GLOVES, id, color,
- static_cast<unsigned char>(id2));
- player_node->imitateOutfit(dstBeing, SPRITE_GLOVES);
- break;
- case 11: // LOOK_CAPE
- dstBeing->setSprite(SPRITE_CAPE, id, color,
- static_cast<unsigned char>(id2));
- player_node->imitateOutfit(dstBeing, SPRITE_CAPE);
- break;
- case 12:
- dstBeing->setSprite(SPRITE_MISC1, id, color,
- static_cast<unsigned char>(id2));
- player_node->imitateOutfit(dstBeing, SPRITE_MISC1);
- break;
- case 13:
- dstBeing->setSprite(SPRITE_MISC2, id, color,
- static_cast<unsigned char>(id2));
- player_node->imitateOutfit(dstBeing, SPRITE_MISC2);
- break;
- case 14:
- dstBeing->setSprite(SPRITE_EVOL1, id, color,
- static_cast<unsigned char>(id2));
- player_node->imitateOutfit(dstBeing, SPRITE_EVOL1);
- break;
- case 15:
- dstBeing->setSprite(SPRITE_EVOL2, id, color,
- static_cast<unsigned char>(id2));
- player_node->imitateOutfit(dstBeing, SPRITE_EVOL2);
- break;
- default:
- logger->log("QQQ3 CHANGE_LOOKS: unsupported type: "
- "%d, id: %d", type, id);
- if (dstBeing)
- {
- logger->log("ID: " + toString(dstBeing->getId()));
- logger->log("name: " + toString(dstBeing->getName()));
- }
- break;
- }
- }
+ processBeingChangeLook(msg,
+ msg.getId() == SMSG_BEING_CHANGE_LOOKS2);
break;
case SMSG_BEING_NAME_RESPONSE:
- {
- int beingId = msg.readInt32();
- if ((dstBeing = actorSpriteManager->findBeing(beingId)))
- {
- if (beingId == player_node->getId())
- {
- player_node->pingResponse();
- }
- else
- {
- dstBeing->setName(msg.readString(24));
- dstBeing->updateGuild();
- dstBeing->addToCache();
-
- if (dstBeing->getType() == Being::PLAYER)
- dstBeing->updateColors();
-
- if (player_node)
- {
- Party *party = player_node->getParty();
- if (party && party->isMember(dstBeing->getId()))
- {
- PartyMember *member = party->getMember(
- dstBeing->getId());
-
- if (member)
- member->setName(dstBeing->getName());
- }
- player_node->checkNewName(dstBeing);
- }
- }
- }
- }
+ processNameResponse(msg);
break;
+
case SMSG_BEING_NAME_RESPONSE2:
- {
- int len = msg.readInt16();
- int beingId = msg.readInt32();
- std::string str = msg.readString(len - 8);
- if ((dstBeing = actorSpriteManager->findBeing(beingId)))
- {
- if (beingId == player_node->getId())
- {
- player_node->pingResponse();
- }
- else
- {
- dstBeing->setName(str);
- dstBeing->updateGuild();
- dstBeing->addToCache();
-
- if (dstBeing->getType() == Being::PLAYER)
- dstBeing->updateColors();
-
- if (player_node)
- {
- Party *party = player_node->getParty();
- if (party && party->isMember(dstBeing->getId()))
- {
- PartyMember *member = party->getMember(
- dstBeing->getId());
-
- if (member)
- member->setName(dstBeing->getName());
- }
- player_node->checkNewName(dstBeing);
- }
- }
- }
- }
+ processNameResponse2(msg);
break;
+
case SMSG_BEING_IP_RESPONSE:
- {
- if ((dstBeing = actorSpriteManager->findBeing(
- msg.readInt32())))
- {
- dstBeing->setIp(ipToString(msg.readInt32()));
- }
- }
+ processIpResponse(msg);
break;
+
case SMSG_SOLVE_CHAR_NAME:
- {
- logger->log1("SMSG_SOLVE_CHAR_NAME");
- logger->log(toString(msg.readInt32()));
- logger->log(msg.readString(24));
- }
break;
+
case SMSG_PLAYER_GUILD_PARTY_INFO:
- if ((dstBeing = actorSpriteManager->findBeing(msg.readInt32())))
- {
- dstBeing->setPartyName(msg.readString(24));
- dstBeing->setGuildName(msg.readString(24));
- dstBeing->setGuildPos(msg.readString(24));
- dstBeing->addToCache();
- msg.readString(24); // Discard this
- }
+ processPlayerGuilPartyInfo(msg);
break;
- case SMSG_BEING_CHANGE_DIRECTION:
- {
- if (!(dstBeing = actorSpriteManager->findBeing(msg.readInt32())))
- break;
-
- msg.readInt16(); // unused
- unsigned char dir = msg.readInt8();
- dstBeing->setDirection(dir);
- if (player_node)
- player_node->imitateDirection(dstBeing, dir);
+ case SMSG_BEING_CHANGE_DIRECTION:
+ processBeingChangeDirection(msg);
break;
- }
+
case SMSG_PLAYER_UPDATE_1:
case SMSG_PLAYER_UPDATE_2:
case SMSG_PLAYER_MOVE:
- if (!actorSpriteManager || !player_node)
- break;
+ int type;
+ switch (msg.getId())
+ {
+ case SMSG_PLAYER_UPDATE_1:
+ type = 1;
+ break;
+ case SMSG_PLAYER_UPDATE_2:
+ type = 2;
+ break;
+ case SMSG_PLAYER_MOVE:
+ type = 3;
+ break;
+ default:
+ return;
+ }
+ processPlayerMoveUpdate(msg, type);
- // An update about a player, potentially including movement.
- id = msg.readInt32();
- speed = msg.readInt16();
- stunMode = msg.readInt16(); // opt1; Aethyra use this as cape
- statusEffects = msg.readInt16(); // opt2; Aethyra use this as misc1
- statusEffects |= (static_cast<Uint32>(msg.readInt16()))
- << 16; // status.options; Aethyra uses this as misc2
- job = msg.readInt16();
+ break;
+ case SMSG_PLAYER_STOP:
+ processPlayerStop(msg);
+ break;
- dstBeing = actorSpriteManager->findBeing(id);
+ case SMSG_PLAYER_MOVE_TO_ATTACK:
+ processPlayerMoveToAttack(msg);
+ break;
- if (!dstBeing)
- {
- if (actorSpriteManager->isBlocked(id) == true)
- break;
+ case SMSG_PLAYER_STATUS_CHANGE:
+ processPlaterStatusChange(msg);
+ break;
- dstBeing = createBeing(id, job);
+ case SMSG_BEING_STATUS_CHANGE:
+ processBeingStatusChange(msg);
+ break;
- if (!dstBeing)
- break;
- }
+ case SMSG_SKILL_CASTING:
+ processSkilCasting(msg);
+ break;
- dir = dstBeing->getDirectionDelayed();
- if (dir)
- {
- if (dir != dstBeing->getDirection())
- dstBeing->setDirection(dir);
- }
+ case SMSG_SKILL_CAST_CANCEL:
+ msg.readInt32(); // id
+ break;
- if (Party *party = player_node->getParty())
- {
- if (party->isMember(id))
- dstBeing->setParty(party);
- }
+ case SMSG_SKILL_NO_DAMAGE:
+ processSkillNoDamage(msg);
+ break;
- dstBeing->setWalkSpeed(Vector(speed, speed, 0));
- dstBeing->setSubtype(job);
- hairStyle = msg.readInt16();
- weapon = msg.readInt16();
- shield = msg.readInt16();
- headBottom = msg.readInt16();
+ case SMSG_PVP_MAP_MODE:
+ processPvpMapMode(msg);
+ break;
- if (msg.getId() == SMSG_PLAYER_MOVE)
- msg.readInt32(); // server tick
+ case SMSG_PVP_SET:
+ processPvpSet(msg);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void BeingHandler::undress(Being *being)
+{
+ being->setSprite(SPRITE_BOTTOMCLOTHES, 0);
+ being->setSprite(SPRITE_TOPCLOTHES, 0);
+ being->setSprite(SPRITE_HAT, 0);
+ being->setSprite(SPRITE_SHOE, 0);
+ being->setSprite(SPRITE_GLOVES, 0);
+// being->setSprite(SPRITE_WEAPON, 0, "", true);
+}
- headTop = msg.readInt16();
- headMid = msg.readInt16();
- hairColor = msg.readInt16();
+void BeingHandler::processBeingChangeLook(Net::MessageIn &msg, bool look2)
+{
+ if (!actorSpriteManager)
+ return;
- colors[0] = msg.readInt8();
- colors[1] = msg.readInt8();
- colors[2] = msg.readInt8();
+ Being *dstBeing;
+ /*
+ * SMSG_BEING_CHANGE_LOOKS (0x00c3) and
+ * SMSG_BEING_CHANGE_LOOKS2 (0x01d7) do basically the same
+ * thing. The difference is that ...LOOKS carries a single
+ * 8 bit value, where ...LOOKS2 carries two 16 bit values.
+ *
+ * If type = 2, then the first 16 bit value is the weapon ID,
+ * and the second 16 bit value is the shield ID. If no
+ * shield is equipped, or type is not 2, then the second
+ * 16 bit value will be 0.
+ */
+
+ if (!(dstBeing = actorSpriteManager->findBeing(msg.readInt32())))
+ return;
- msg.readInt8(); //unused
-// shoes = msg.readInt16();
-// gloves = msg.readInt16(); //sd->head_dir
+ int type = msg.readInt8();
+ int id = 0;
+ int id2 = 0;
+ std::string color;
- guild = msg.readInt32(); // guild
+ if (!look2)
+ {
+ id = msg.readInt8();
+ id2 = 1; // default color
+ }
+ else
+ { // SMSG_BEING_CHANGE_LOOKS2
+ id = msg.readInt16();
+ if (type == 2 || serverVersion > 0)
+ id2 = msg.readInt16();
+ else
+ id2 = 1;
+ color = "";
+ }
- if (guild == 0)
- dstBeing->clearGuilds();
- else
- dstBeing->setGuild(Guild::getGuild(static_cast<short>(guild)));
+ if (dstBeing->getType() == Being::PLAYER)
+ dstBeing->setOtherTime();
- msg.readInt16(); // emblem
- msg.readInt16(); // manner
- dstBeing->setStatusEffectBlock(32, msg.readInt16()); // opt3
- msg.readInt8(); // karma
- dstBeing->setGender((msg.readInt8() == 0)
- ? GENDER_FEMALE : GENDER_MALE);
+ if (!player_node)
+ return;
- // Set these after the gender, as the sprites may be gender-specific
- dstBeing->setSprite(SPRITE_WEAPON, weapon, "", 1, true);
+ switch (type)
+ {
+ case 0: // change race
+ dstBeing->setSubtype(static_cast<Uint16>(id));
+ break;
+ case 1: // eAthena LOOK_HAIR
+ dstBeing->setSpriteID(SPRITE_HAIR, id *-1);
+ break;
+ case 2: // Weapon ID in id, Shield ID in id2
+ dstBeing->setSprite(SPRITE_WEAPON, id, "", 1, true);
+ if (!config.getBoolValue("hideShield"))
+ dstBeing->setSprite(SPRITE_SHIELD, id2);
+ player_node->imitateOutfit(dstBeing, SPRITE_SHIELD);
+ break;
+ case 3: // Change lower headgear for eAthena, pants for us
+ dstBeing->setSprite(SPRITE_BOTTOMCLOTHES, id, color,
+ static_cast<unsigned char>(id2));
+ player_node->imitateOutfit(dstBeing, SPRITE_BOTTOMCLOTHES);
+ break;
+ case 4: // Change upper headgear for eAthena, hat for us
+ dstBeing->setSprite(SPRITE_HAT, id, color,
+ static_cast<unsigned char>(id2));
+ player_node->imitateOutfit(dstBeing, SPRITE_HAT);
+ break;
+ case 5: // Change middle headgear for eathena, armor for us
+ dstBeing->setSprite(SPRITE_TOPCLOTHES, id, color,
+ static_cast<unsigned char>(id2));
+ player_node->imitateOutfit(dstBeing, SPRITE_TOPCLOTHES);
+ break;
+ case 6: // eAthena LOOK_HAIR_COLOR
+ dstBeing->setSpriteColor(SPRITE_HAIR,
+ ColorDB::getHairColor(id));
+ break;
+ case 8: // eAthena LOOK_SHIELD
if (!config.getBoolValue("hideShield"))
- dstBeing->setSprite(SPRITE_SHIELD, shield);
- //dstBeing->setSprite(SPRITE_SHOE, shoes);
- if (serverVersion > 0)
{
- dstBeing->setSprite(SPRITE_BOTTOMCLOTHES, headBottom,
- "", colors[0]);
- dstBeing->setSprite(SPRITE_TOPCLOTHES, headMid, "", colors[2]);
- dstBeing->setSprite(SPRITE_HAT, headTop, "", colors[1]);
+ dstBeing->setSprite(SPRITE_SHIELD, id, color,
+ static_cast<unsigned char>(id2));
}
- else
+ player_node->imitateOutfit(dstBeing, SPRITE_SHIELD);
+ break;
+ case 9: // eAthena LOOK_SHOES
+ dstBeing->setSprite(SPRITE_SHOE, id, color,
+ static_cast<unsigned char>(id2));
+ player_node->imitateOutfit(dstBeing, SPRITE_SHOE);
+ break;
+ case 10: // LOOK_GLOVES
+ dstBeing->setSprite(SPRITE_GLOVES, id, color,
+ static_cast<unsigned char>(id2));
+ player_node->imitateOutfit(dstBeing, SPRITE_GLOVES);
+ break;
+ case 11: // LOOK_CAPE
+ dstBeing->setSprite(SPRITE_CAPE, id, color,
+ static_cast<unsigned char>(id2));
+ player_node->imitateOutfit(dstBeing, SPRITE_CAPE);
+ break;
+ case 12:
+ dstBeing->setSprite(SPRITE_MISC1, id, color,
+ static_cast<unsigned char>(id2));
+ player_node->imitateOutfit(dstBeing, SPRITE_MISC1);
+ break;
+ case 13:
+ dstBeing->setSprite(SPRITE_MISC2, id, color,
+ static_cast<unsigned char>(id2));
+ player_node->imitateOutfit(dstBeing, SPRITE_MISC2);
+ break;
+ case 14:
+ dstBeing->setSprite(SPRITE_EVOL1, id, color,
+ static_cast<unsigned char>(id2));
+ player_node->imitateOutfit(dstBeing, SPRITE_EVOL1);
+ break;
+ case 15:
+ dstBeing->setSprite(SPRITE_EVOL2, id, color,
+ static_cast<unsigned char>(id2));
+ player_node->imitateOutfit(dstBeing, SPRITE_EVOL2);
+ break;
+ default:
+ logger->log("QQQ3 CHANGE_LOOKS: unsupported type: "
+ "%d, id: %d", type, id);
+ if (dstBeing)
{
- dstBeing->setSprite(SPRITE_BOTTOMCLOTHES, headBottom);
- dstBeing->setSprite(SPRITE_TOPCLOTHES, headMid);
- dstBeing->setSprite(SPRITE_HAT, headTop);
+ logger->log("ID: " + toString(dstBeing->getId()));
+ logger->log("name: " + toString(dstBeing->getName()));
}
- //dstBeing->setSprite(SPRITE_GLOVES, gloves);
- //dstBeing->setSprite(SPRITE_CAPE, cape);
- //dstBeing->setSprite(SPRITE_MISC1, misc1);
- //dstBeing->setSprite(SPRITE_MISC2, misc2);
- dstBeing->setSprite(SPRITE_HAIR, hairStyle * -1,
- ColorDB::getHairColor(hairColor));
-
- player_node->imitateOutfit(dstBeing);
+ break;
+ }
+}
- if (msg.getId() == SMSG_PLAYER_MOVE)
- {
- Uint16 srcX, srcY, dstX, dstY;
- msg.readCoordinatePair(srcX, srcY, dstX, dstY);
+void BeingHandler::processNameResponse2(Net::MessageIn &msg)
+{
+ if (!actorSpriteManager || !player_node)
+ return;
- player_node->followMoveTo(dstBeing, srcX, srcY, dstX, dstY);
+ Being *dstBeing;
- dstBeing->setTileCoords(srcX, srcY);
- dstBeing->setDestination(dstX, dstY);
+ int len = msg.readInt16();
+ int beingId = msg.readInt32();
+ std::string str = msg.readString(len - 8);
+ if ((dstBeing = actorSpriteManager->findBeing(beingId)))
+ {
+ if (beingId == player_node->getId())
+ {
+ player_node->pingResponse();
+ }
+ else
+ {
+ dstBeing->setName(str);
+ dstBeing->updateGuild();
+ dstBeing->addToCache();
- // because server dont send direction in move packet,
- // we fixing it
+ if (dstBeing->getType() == Being::PLAYER)
+ dstBeing->updateColors();
- if (srcX != dstX || srcY != dstY)
+ if (player_node)
+ {
+ Party *party = player_node->getParty();
+ if (party && party->isMember(dstBeing->getId()))
{
- int dir = dstBeing->calcDirection(dstX, dstY);
+ PartyMember *member = party->getMember(
+ dstBeing->getId());
- if (dir && dstBeing->getDirection() != dir)
- dstBeing->setDirectionDelayed(static_cast<Uint8>(dir));
+ if (member)
+ member->setName(dstBeing->getName());
}
-
- if (player_node->getCurrentAction() != Being::STAND)
- player_node->imitateAction(dstBeing, Being::STAND);
- if (player_node->getDirection() != dstBeing->getDirection())
- {
- player_node->imitateDirection(dstBeing,
- dstBeing->getDirection());
- }
- }
- else
- {
- Uint8 dir;
- Uint16 x, y;
- msg.readCoordinates(x, y, dir);
- dstBeing->setTileCoords(x, y);
- dstBeing->setDirection(dir);
-
- player_node->imitateDirection(dstBeing, dir);
+ player_node->checkNewName(dstBeing);
}
+ }
+ }
+}
- gmstatus = msg.readInt16();
+void BeingHandler::processPlayerMoveUpdate(Net::MessageIn &msg, int msgType)
+{
+ if (!actorSpriteManager || !player_node)
+ return;
- if (gmstatus & 0x80)
- dstBeing->setGM(true);
+ Uint16 headTop, headMid, headBottom;
+ Uint16 weapon, shield;
+ Uint16 gmstatus;
+ int level;
+ int guild;
+ Being *dstBeing;
+ int hairStyle, hairColor;
+ unsigned char colors[9];
+ Uint8 dir;
- if (msg.getId() == SMSG_PLAYER_UPDATE_1)
- {
- int type = msg.readInt8();
- switch (type)
- {
- case 0:
- dstBeing->setAction(Being::STAND);
- player_node->imitateAction(dstBeing, Being::STAND);
- break;
-
- case 1:
- dstBeing->setAction(Being::DEAD);
- break;
-
- case 2:
- dstBeing->setAction(Being::SIT);
- player_node->imitateAction(dstBeing, Being::SIT);
- break;
-
- default:
- //need set stay state?
- logger->log("QQQ2 SMSG_PLAYER_UPDATE_1:"
- + toString(id) + " " + toString(type));
- if (dstBeing)
- {
- logger->log("dstBeing id:"
- + toString(dstBeing->getId()));
- logger->log("dstBeing name:"
- + dstBeing->getName());
- }
- break;
+ // An update about a player, potentially including movement.
+ int id = msg.readInt32();
+ short speed = msg.readInt16();
+ Uint16 stunMode = msg.readInt16(); // opt1; Aethyra use this as cape
+ Uint32 statusEffects = msg.readInt16(); // opt2; Aethyra use this as misc1
+ statusEffects |= (static_cast<Uint32>(msg.readInt16()))
+ << 16; // status.options; Aethyra uses this as misc2
+ short job = msg.readInt16();
- }
- }
- else if (msg.getId() == SMSG_PLAYER_MOVE)
- {
- msg.readInt8(); // unknown
- }
+ dstBeing = actorSpriteManager->findBeing(id);
- level = msg.readInt8(); // Lv
- if (level)
- dstBeing->setLevel(level);
+ if (!dstBeing)
+ {
+ if (actorSpriteManager->isBlocked(id) == true)
+ return;
- msg.readInt8(); // unknown
+ dstBeing = createBeing(id, job);
- if (dstBeing->getType() != Being::PLAYER
- || msg.getId() != SMSG_PLAYER_MOVE)
- {
- dstBeing->setActionTime(tick_time);
-// dstBeing->reset();
- }
+ if (!dstBeing)
+ return;
+ }
- dstBeing->setStunMode(stunMode);
- dstBeing->setStatusEffectBlock(0, static_cast<Uint16>(
- (statusEffects >> 16) & 0xffff));
- dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff);
+ dir = dstBeing->getDirectionDelayed();
+ if (dir)
+ {
+ if (dir != dstBeing->getDirection())
+ dstBeing->setDirection(dir);
+ }
- if (msg.getId() == SMSG_PLAYER_MOVE
- && dstBeing->getType() == Being::PLAYER)
- {
- dstBeing->setMoveTime();
- }
+ if (Party *party = player_node->getParty())
+ {
+ if (party->isMember(id))
+ dstBeing->setParty(party);
+ }
- break;
- case SMSG_PLAYER_STOP:
- /*
- * Instruction from server to stop walking at x, y.
- *
- * Some people like having this enabled. Others absolutely
- * despise it. So I'm setting to so that it only affects the
- * local player if the person has set a key "EnableSync" to "1"
- * in their config.xml file.
- *
- * This packet will be honored for all other beings, regardless
- * of the config setting.
- */
-
- id = msg.readInt32();
-
- if (mSync || id != player_node->getId())
- {
- dstBeing = actorSpriteManager->findBeing(id);
- if (dstBeing)
- {
- Uint16 x, y;
- x = msg.readInt16();
- y = msg.readInt16();
- dstBeing->setTileCoords(x, y);
- if (dstBeing->getCurrentAction() == Being::MOVE)
- dstBeing->setAction(Being::STAND);
- }
- }
- break;
+ dstBeing->setWalkSpeed(Vector(speed, speed, 0));
+ dstBeing->setSubtype(job);
+ hairStyle = msg.readInt16();
+ weapon = msg.readInt16();
+ shield = msg.readInt16();
+ headBottom = msg.readInt16();
- case SMSG_PLAYER_MOVE_TO_ATTACK:
- /*
- * This is an *advisory* message, telling the client that
- * it needs to move the character before attacking
- * a target (out of range, obstruction in line of fire).
- * We can safely ignore this...
- */
- if (player_node)
- player_node->fixAttackTarget();
- break;
+ if (msgType == 3)
+ msg.readInt32(); // server tick
- case SMSG_PLAYER_STATUS_CHANGE:
- // Change in players' flags
+ headTop = msg.readInt16();
+ headMid = msg.readInt16();
+ hairColor = msg.readInt16();
- id = msg.readInt32();
- dstBeing = actorSpriteManager->findBeing(id);
- if (!dstBeing)
- break;
+ colors[0] = msg.readInt8();
+ colors[1] = msg.readInt8();
+ colors[2] = msg.readInt8();
- stunMode = msg.readInt16();
- statusEffects = msg.readInt16();
- statusEffects |= (static_cast<Uint32>(msg.readInt16())) << 16;
- msg.readInt8(); // Unused?
+ msg.readInt8(); //unused
+// shoes = msg.readInt16();
+// gloves = msg.readInt16(); //sd->head_dir
- dstBeing->setStunMode(stunMode);
- dstBeing->setStatusEffectBlock(0, static_cast<Uint16>(
- (statusEffects >> 16) & 0xffff));
- dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff);
- break;
+ guild = msg.readInt32(); // guild
+
+ if (guild == 0)
+ dstBeing->clearGuilds();
+ else
+ dstBeing->setGuild(Guild::getGuild(static_cast<short>(guild)));
+
+ msg.readInt16(); // emblem
+ msg.readInt16(); // manner
+ dstBeing->setStatusEffectBlock(32, msg.readInt16()); // opt3
+ msg.readInt8(); // karma
+ dstBeing->setGender((msg.readInt8() == 0)
+ ? GENDER_FEMALE : GENDER_MALE);
+
+ // Set these after the gender, as the sprites may be gender-specific
+ dstBeing->setSprite(SPRITE_WEAPON, weapon, "", 1, true);
+ if (!config.getBoolValue("hideShield"))
+ dstBeing->setSprite(SPRITE_SHIELD, shield);
+ //dstBeing->setSprite(SPRITE_SHOE, shoes);
+ if (serverVersion > 0)
+ {
+ dstBeing->setSprite(SPRITE_BOTTOMCLOTHES, headBottom,
+ "", colors[0]);
+ dstBeing->setSprite(SPRITE_TOPCLOTHES, headMid, "", colors[2]);
+ dstBeing->setSprite(SPRITE_HAT, headTop, "", colors[1]);
+ }
+ else
+ {
+ dstBeing->setSprite(SPRITE_BOTTOMCLOTHES, headBottom);
+ dstBeing->setSprite(SPRITE_TOPCLOTHES, headMid);
+ dstBeing->setSprite(SPRITE_HAT, headTop);
+ }
+ //dstBeing->setSprite(SPRITE_GLOVES, gloves);
+ //dstBeing->setSprite(SPRITE_CAPE, cape);
+ //dstBeing->setSprite(SPRITE_MISC1, misc1);
+ //dstBeing->setSprite(SPRITE_MISC2, misc2);
+ dstBeing->setSprite(SPRITE_HAIR, hairStyle * -1,
+ ColorDB::getHairColor(hairColor));
- case SMSG_BEING_STATUS_CHANGE:
- // Status change
- status = msg.readInt16();
- id = msg.readInt32();
- flag = msg.readInt8(); // 0: stop, 1: start
+ player_node->imitateOutfit(dstBeing);
- dstBeing = actorSpriteManager->findBeing(id);
- if (dstBeing)
- dstBeing->setStatusEffect(status, flag);
- break;
+ if (msgType == 3)
+ {
+ Uint16 srcX, srcY, dstX, dstY;
+ msg.readCoordinatePair(srcX, srcY, dstX, dstY);
- case SMSG_SKILL_CASTING:
- msg.readInt32(); // src id
- msg.readInt32(); // dst id
- msg.readInt16(); // dst x
- msg.readInt16(); // dst y
- msg.readInt16(); // skill num
- msg.readInt32(); // skill get pl
- msg.readInt32(); // cast time
- break;
+ player_node->followMoveTo(dstBeing, srcX, srcY, dstX, dstY);
- case SMSG_SKILL_CAST_CANCEL:
- msg.readInt32(); // id
- break;
+ dstBeing->setTileCoords(srcX, srcY);
+ dstBeing->setDestination(dstX, dstY);
- case SMSG_SKILL_NO_DAMAGE:
- msg.readInt16(); // skill id
- msg.readInt16(); // heal
- msg.readInt32(); // dst id
- msg.readInt32(); // src id
- msg.readInt8(); // fail
- break;
+ // because server dont send direction in move packet,
+ // we fixing it
- case SMSG_PVP_MAP_MODE:
+ if (srcX != dstX || srcY != dstY)
{
- Game *game = Game::instance();
- if (!game)
- break;
+ int dir = dstBeing->calcDirection(dstX, dstY);
- Map *map = game->getCurrentMap();
- if (map)
- map->setPvpMode(msg.readInt16());
- break;
+ if (dir && dstBeing->getDirection() != dir)
+ dstBeing->setDirectionDelayed(static_cast<Uint8>(dir));
}
- case SMSG_PVP_SET:
+ if (player_node->getCurrentAction() != Being::STAND)
+ player_node->imitateAction(dstBeing, Being::STAND);
+ if (player_node->getDirection() != dstBeing->getDirection())
{
- int id = msg.readInt32(); // id
- int rank = msg.readInt32(); // rank
- msg.readInt32(); // num
- if (actorSpriteManager)
- {
- dstBeing = actorSpriteManager->findBeing(id);
+ player_node->imitateDirection(dstBeing,
+ dstBeing->getDirection());
+ }
+ }
+ else
+ {
+ Uint8 dir;
+ Uint16 x, y;
+ msg.readCoordinates(x, y, dir);
+ dstBeing->setTileCoords(x, y);
+ dstBeing->setDirection(dir);
+
+ player_node->imitateDirection(dstBeing, dir);
+ }
+
+ gmstatus = msg.readInt16();
+
+ if (gmstatus & 0x80)
+ dstBeing->setGM(true);
+
+ if (msgType == 1)
+ {
+ int type = msg.readInt8();
+ switch (type)
+ {
+ case 0:
+ dstBeing->setAction(Being::STAND);
+ player_node->imitateAction(dstBeing, Being::STAND);
+ break;
+
+ case 1:
+ dstBeing->setAction(Being::DEAD);
+ break;
+
+ case 2:
+ dstBeing->setAction(Being::SIT);
+ player_node->imitateAction(dstBeing, Being::SIT);
+ break;
+
+ default:
+ //need set stay state?
+ logger->log("QQQ2 SMSG_PLAYER_UPDATE_1:"
+ + toString(id) + " " + toString(type));
if (dstBeing)
- dstBeing->setPvpRank(rank);
- }
- break;
+ {
+ logger->log("dstBeing id:"
+ + toString(dstBeing->getId()));
+ logger->log("dstBeing name:"
+ + dstBeing->getName());
+ }
+ break;
+
}
+ }
+ else if (msgType == 3)
+ {
+ msg.readInt8(); // unknown
+ }
- default:
- break;
+ level = msg.readInt8(); // Lv
+ if (level)
+ dstBeing->setLevel(level);
+
+ msg.readInt8(); // unknown
+
+ if (dstBeing->getType() != Being::PLAYER
+ || msgType != 3)
+ {
+ dstBeing->setActionTime(tick_time);
+// dstBeing->reset();
}
-}
-void BeingHandler::undress(Being *being)
-{
- being->setSprite(SPRITE_BOTTOMCLOTHES, 0);
- being->setSprite(SPRITE_TOPCLOTHES, 0);
- being->setSprite(SPRITE_HAT, 0);
- being->setSprite(SPRITE_SHOE, 0);
- being->setSprite(SPRITE_GLOVES, 0);
-// being->setSprite(SPRITE_WEAPON, 0, "", true);
+ dstBeing->setStunMode(stunMode);
+ dstBeing->setStatusEffectBlock(0, static_cast<Uint16>(
+ (statusEffects >> 16) & 0xffff));
+ dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff);
+
+ if (msgType == 3 && dstBeing->getType() == Being::PLAYER)
+ dstBeing->setMoveTime();
}
+
+
} // namespace TmwAthena
diff --git a/src/net/tmwa/beinghandler.h b/src/net/tmwa/beinghandler.h
index aa278b1d6..5e741aaa8 100644
--- a/src/net/tmwa/beinghandler.h
+++ b/src/net/tmwa/beinghandler.h
@@ -26,12 +26,14 @@
#include "net/beinghandler.h"
#include "net/net.h"
+#include "net/ea/beinghandler.h"
+
#include "net/tmwa/messagehandler.h"
namespace TmwAthena
{
-class BeingHandler : public MessageHandler, public Net::BeingHandler
+class BeingHandler : public MessageHandler, public Ea::BeingHandler
{
public:
BeingHandler(bool enableSync);
@@ -42,10 +44,12 @@ class BeingHandler : public MessageHandler, public Net::BeingHandler
virtual void undress(Being *being);
- private:
- // Should we honor server "Stop Walking" packets
- bool mSync;
- int mSpawnId;
+ protected:
+ virtual void processBeingChangeLook(Net::MessageIn &msg, bool look2);
+
+ void processNameResponse2(Net::MessageIn &msg);
+
+ virtual void processPlayerMoveUpdate(Net::MessageIn &msg, int type);
};
} // namespace TmwAthena
diff --git a/src/net/tmwa/buysellhandler.cpp b/src/net/tmwa/buysellhandler.cpp
index 5113f0303..0b839a3f5 100644
--- a/src/net/tmwa/buysellhandler.cpp
+++ b/src/net/tmwa/buysellhandler.cpp
@@ -63,7 +63,6 @@ BuySellHandler::BuySellHandler()
SMSG_NPC_SELL_RESPONSE,
0
};
- mNpcId = 0;
handledMessages = _messages;
buySellHandler = this;
mBuyDialog = 0;
@@ -71,181 +70,75 @@ BuySellHandler::BuySellHandler()
void BuySellHandler::handleMessage(Net::MessageIn &msg)
{
- int n_items;
-
switch (msg.getId())
{
case SMSG_NPC_BUY_SELL_CHOICE:
- if (!BuySellDialog::isActive())
- {
- mNpcId = msg.readInt32();
- new BuySellDialog(mNpcId);
- }
+ processNpcBuySellChoice(msg);
break;
case SMSG_NPC_BUY:
- {
- msg.readInt16(); // length
- int sz = 11;
- if (serverVersion > 0)
- sz += 1;
- n_items = (msg.getLength() - 4) / sz;
- mBuyDialog = new BuyDialog(mNpcId);
- mBuyDialog->setMoney(PlayerInfo::getAttribute(MONEY));
-
- for (int k = 0; k < n_items; k++)
- {
- int value = msg.readInt32();
- msg.readInt32(); // DCvalue
- msg.readInt8(); // type
- int itemId = msg.readInt16();
- unsigned char color = 1;
- if (serverVersion > 0)
- color = msg.readInt8();
- mBuyDialog->addItem(itemId, color, 0, value);
- }
+ processNpcBuy(msg);
break;
- }
case SMSG_NPC_SELL:
- msg.readInt16(); // length
- n_items = (msg.getLength() - 4) / 10;
- if (n_items > 0)
- {
- SellDialog *dialog = new SellDialog(mNpcId);
- dialog->setMoney(PlayerInfo::getAttribute(MONEY));
-
- for (int k = 0; k < n_items; k++)
- {
- int index = msg.readInt16() - INVENTORY_OFFSET;
- int value = msg.readInt32();
- msg.readInt32(); // OCvalue
-
- Item *item = PlayerInfo::getInventory()->getItem(index);
-
- if (item && !(item->isEquipped()))
- dialog->addItem(item, value);
- }
- }
- else
- {
- SERVER_NOTICE(_("Nothing to sell."))
- }
+ processNpcSell(msg, INVENTORY_OFFSET);
break;
case SMSG_NPC_BUY_RESPONSE:
- if (msg.readInt8() == 0)
- {
- SERVER_NOTICE(_("Thanks for buying."))
- }
- else
- {
- // Reset player money since buy dialog already assumed purchase
- // would go fine
- if (mBuyDialog)
- mBuyDialog->setMoney(PlayerInfo::getAttribute(MONEY));
- SERVER_NOTICE(_("Unable to buy."))
- }
+ processNpcBuyResponse(msg);
break;
case SMSG_NPC_SELL_RESPONSE:
- switch (msg.readInt8())
- {
- case 0:
- SERVER_NOTICE(_("Thanks for selling."))
- break;
- case 1:
- default:
- SERVER_NOTICE(_("Unable to sell."))
- break;
- case 2:
- SERVER_NOTICE(_("Unable to sell while trading."))
- break;
- case 3:
- SERVER_NOTICE(_("Unable to sell unsellable item."))
- break;
- }
- default:
+ processNpcSellResponse(msg);
break;
- }
-
-}
-
-void BuySellHandler::requestSellList(std::string nick)
-{
- if (nick.empty() != 0 || !shopWindow)
- return;
- std::string data = "!selllist " + toString(tick_time);
- shopWindow->setAcceptPlayer(nick);
-
- if (config.getBoolValue("hideShopMessages"))
- {
- Net::getChatHandler()->privateMessage(nick, data);
- }
- else
- {
- if (chatWindow)
- chatWindow->whisper(nick, data, BY_PLAYER);
+ default:
+ break;
}
-//was true
-}
-void BuySellHandler::requestBuyList(std::string nick)
-{
- if (nick.empty() || !shopWindow)
- return;
-
- std::string data = "!buylist " + toString(tick_time);
- shopWindow->setAcceptPlayer(nick);
-
- if (config.getBoolValue("hideShopMessages"))
- {
- Net::getChatHandler()->privateMessage(nick, data);
- }
- else
- {
- if (chatWindow)
- chatWindow->whisper(nick, data, BY_PLAYER);
- }
-//was true
}
-void BuySellHandler::sendBuyRequest(std::string nick, ShopItem* item,
- int amount)
+void BuySellHandler::processNpcBuy(Net::MessageIn &msg)
{
- if (!chatWindow || nick.empty() || !item ||
- amount < 1 || amount > item->getQuantity())
+ msg.readInt16(); // length
+ int sz = 11;
+ if (serverVersion > 0)
+ sz += 1;
+ int n_items = (msg.getLength() - 4) / sz;
+ mBuyDialog = new BuyDialog(mNpcId);
+ mBuyDialog->setMoney(PlayerInfo::getAttribute(MONEY));
+
+ for (int k = 0; k < n_items; k++)
{
- return;
+ int value = msg.readInt32();
+ msg.readInt32(); // DCvalue
+ msg.readInt8(); // type
+ int itemId = msg.readInt16();
+ unsigned char color = 1;
+ if (serverVersion > 0)
+ color = msg.readInt8();
+ mBuyDialog->addItem(itemId, color, 0, value);
}
- std::string data = strprintf("!buyitem %d %d %d",
- item->getId(), item->getPrice(), amount);
-
- if (config.getBoolValue("hideShopMessages"))
- Net::getChatHandler()->privateMessage(nick, data);
- else
- chatWindow->whisper(nick, data, BY_PLAYER);
-//was true
}
-void BuySellHandler::sendSellRequest(std::string nick, ShopItem* item,
- int amount)
+void BuySellHandler::processNpcSellResponse(Net::MessageIn &msg)
{
- if (!chatWindow || nick.empty() || !item ||
- amount < 1 || amount > item->getQuantity())
+ switch (msg.readInt8())
{
- return;
+ case 0:
+ SERVER_NOTICE(_("Thanks for selling."))
+ break;
+ case 1:
+ default:
+ SERVER_NOTICE(_("Unable to sell."))
+ break;
+ case 2:
+ SERVER_NOTICE(_("Unable to sell while trading."))
+ break;
+ case 3:
+ SERVER_NOTICE(_("Unable to sell unsellable item."))
+ break;
}
-
- std::string data = strprintf("!sellitem %d %d %d",
- item->getId(), item->getPrice(), amount);
-
- if (config.getBoolValue("hideShopMessages"))
- Net::getChatHandler()->privateMessage(nick, data);
- else
- chatWindow->whisper(nick, data, BY_PLAYER);
-//was true
}
} // namespace TmwAthena
diff --git a/src/net/tmwa/buysellhandler.h b/src/net/tmwa/buysellhandler.h
index 09aad0ec2..65067f7e0 100644
--- a/src/net/tmwa/buysellhandler.h
+++ b/src/net/tmwa/buysellhandler.h
@@ -25,34 +25,27 @@
#include "net/buysellhandler.h"
+#include "net/ea/buysellhandler.h"
+
#include "being.h"
#include "net/net.h"
#include "net/tmwa/messagehandler.h"
-class BuyDialog;
-
namespace TmwAthena
{
-class BuySellHandler : public MessageHandler, public Net::BuySellHandler
+class BuySellHandler : public MessageHandler, public Ea::BuySellHandler
{
public:
BuySellHandler();
virtual void handleMessage(Net::MessageIn &msg);
- virtual void requestSellList(std::string nick);
- virtual void requestBuyList(std::string nick);
- virtual void sendBuyRequest(std::string nick, ShopItem* item,
- int amount);
- virtual void sendSellRequest(std::string nick, ShopItem* item,
- int amount);
+ virtual void processNpcBuy(Net::MessageIn &msg);
- private:
- int mNpcId;
- BuyDialog *mBuyDialog;
+ virtual void processNpcSellResponse(Net::MessageIn &msg);
};
} // namespace TmwAthena