summaryrefslogtreecommitdiff
path: root/src/net
diff options
context:
space:
mode:
Diffstat (limited to 'src/net')
-rw-r--r--src/net/beinghandler.cpp356
-rw-r--r--src/net/beinghandler.h37
-rw-r--r--src/net/buysellhandler.cpp129
-rw-r--r--src/net/buysellhandler.h37
-rw-r--r--src/net/charserverhandler.cpp210
-rw-r--r--src/net/charserverhandler.h48
-rw-r--r--src/net/chathandler.cpp118
-rw-r--r--src/net/chathandler.h37
-rw-r--r--src/net/equipmenthandler.cpp210
-rw-r--r--src/net/equipmenthandler.h37
-rw-r--r--src/net/inventoryhandler.cpp128
-rw-r--r--src/net/inventoryhandler.h37
-rw-r--r--src/net/itemhandler.cpp67
-rw-r--r--src/net/itemhandler.h37
-rw-r--r--src/net/loginhandler.cpp114
-rw-r--r--src/net/loginhandler.h37
-rw-r--r--src/net/maploginhandler.cpp63
-rw-r--r--src/net/maploginhandler.h37
-rw-r--r--src/net/messagehandler.cpp45
-rw-r--r--src/net/messagehandler.h48
-rw-r--r--src/net/messageout.cpp49
-rw-r--r--src/net/messageout.h26
-rw-r--r--src/net/network.cpp505
-rw-r--r--src/net/network.h86
-rw-r--r--src/net/npchandler.cpp74
-rw-r--r--src/net/npchandler.h37
-rw-r--r--src/net/playerhandler.cpp301
-rw-r--r--src/net/playerhandler.h37
-rw-r--r--src/net/protocol.cpp106
-rw-r--r--src/net/protocol.h23
-rw-r--r--src/net/skillhandler.cpp93
-rw-r--r--src/net/skillhandler.h37
-rw-r--r--src/net/tradehandler.cpp179
-rw-r--r--src/net/tradehandler.h39
34 files changed, 2986 insertions, 438 deletions
diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp
new file mode 100644
index 00000000..9578f5c1
--- /dev/null
+++ b/src/net/beinghandler.cpp
@@ -0,0 +1,356 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "beinghandler.h"
+
+#include <SDL_types.h>
+
+#include "messagein.h"
+#include "protocol.h"
+
+#include "../being.h"
+#include "../beingmanager.h"
+#include "../game.h"
+#include "../localplayer.h"
+#include "../log.h"
+#include "../main.h"
+#include "../sound.h"
+
+const int EMOTION_TIME = 150; /**< Duration of emotion icon */
+
+BeingHandler::BeingHandler()
+{
+ static const Uint16 _messages[] = {
+ SMSG_BEING_VISIBLE,
+ SMSG_BEING_MOVE,
+ SMSG_BEING_REMOVE,
+ SMSG_BEING_ACTION,
+ SMSG_BEING_LEVELUP,
+ SMSG_BEING_EMOTION,
+ SMSG_BEING_CHANGE_LOOKS,
+ SMSG_BEING_NAME_RESPONSE,
+ SMSG_PLAYER_UPDATE_1,
+ SMSG_PLAYER_UPDATE_2,
+ SMSG_PLAYER_MOVE,
+ 0x0119,
+ 0
+ };
+ handledMessages = _messages;
+}
+
+void BeingHandler::handleMessage(MessageIn *msg)
+{
+ Uint32 id;
+ Uint16 job, speed;
+ Sint16 param1;
+ Sint8 type;
+ Being *srcBeing, *dstBeing;
+
+ switch (msg->getId())
+ {
+ case SMSG_BEING_VISIBLE:
+ case SMSG_BEING_MOVE:
+ // Information about a being in range
+ id = msg->readInt32();
+ speed = msg->readInt16();
+ msg->readInt16(); // unknown
+ msg->readInt16(); // unknown
+ msg->readInt16(); // option
+ job = msg->readInt16(); // class
+
+ dstBeing = beingManager->findBeing(id);
+
+ if (dstBeing == NULL)
+ {
+ // Being with id >= 110000000 and job 0 are better
+ // known as ghosts, so don't create those.
+ if (job == 0 && id >= 110000000)
+ {
+ break;
+ }
+
+ dstBeing = beingManager->createBeing(id, job);
+ }
+ else if (msg->getId() == 0x0078)
+ {
+ dstBeing->clearPath();
+ dstBeing->mFrame = 0;
+ dstBeing->walk_time = tick_time;
+ dstBeing->action = Being::STAND;
+ }
+
+ // Prevent division by 0 when calculating frame
+ if (speed == 0) { speed = 150; }
+
+ dstBeing->setWalkSpeed(speed);
+ dstBeing->job = job;
+ dstBeing->setHairStyle(msg->readInt16());
+ dstBeing->setWeapon(msg->readInt16());
+ msg->readInt16(); // head option bottom
+
+ if (msg->getId() == SMSG_BEING_MOVE)
+ {
+ msg->readInt32(); // server tick
+ }
+
+ msg->readInt16(); // shield
+ msg->readInt16(); // head option top
+ msg->readInt16(); // head option mid
+ dstBeing->setHairColor(msg->readInt16());
+ msg->readInt16(); // unknown
+ msg->readInt16(); // head dir
+ msg->readInt16(); // guild
+ msg->readInt16(); // unknown
+ msg->readInt16(); // unknown
+ msg->readInt16(); // manner
+ msg->readInt16(); // karma
+ msg->readInt8(); // unknown
+ msg->readInt8(); // sex
+
+ if (msg->getId() == SMSG_BEING_MOVE)
+ {
+ Uint16 srcX, srcY, dstX, dstY;
+ msg->readCoordinatePair(srcX, srcY, dstX, dstY);
+ dstBeing->action = Being::STAND;
+ dstBeing->x = srcX;
+ dstBeing->y = srcY;
+ dstBeing->setDestination(dstX, dstY);
+ }
+ else
+ {
+ msg->readCoordinates(dstBeing->x, dstBeing->y,
+ dstBeing->direction);
+ }
+
+ msg->readInt8(); // unknown
+ msg->readInt8(); // unknown
+ msg->readInt8(); // unknown / sit
+ break;
+
+ case SMSG_BEING_REMOVE:
+ // A being should be removed or has died
+ dstBeing = beingManager->findBeing(msg->readInt32());
+
+ if (!dstBeing)
+ break;
+
+ if (msg->readInt8() == 1)
+ {
+ // Death
+ switch (dstBeing->getType())
+ {
+ case Being::MONSTER:
+ dstBeing->action = Being::MONSTER_DEAD;
+ dstBeing->mFrame = 0;
+ dstBeing->walk_time = tick_time;
+ break;
+
+ default:
+ dstBeing->action = Being::DEAD;
+ break;
+ }
+ }
+ else
+ {
+ beingManager->destroyBeing(dstBeing);
+ }
+
+ if (dstBeing == player_node->getTarget())
+ {
+ player_node->stopAttack();
+ }
+ break;
+
+ case SMSG_BEING_ACTION:
+ srcBeing = beingManager->findBeing(msg->readInt32());
+ dstBeing = beingManager->findBeing(msg->readInt32());
+ msg->readInt32(); // server tick
+ 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 0: // Damage
+ if (dstBeing == NULL) break;
+
+ dstBeing->setDamage(param1, SPEECH_TIME);
+
+ if (srcBeing != NULL &&
+ srcBeing != player_node)
+ {
+ // buggy
+ srcBeing->action = Being::ATTACK;
+ srcBeing->mFrame = 0;
+ srcBeing->walk_time = tick_time;
+ }
+ break;
+
+ case 2: // Sit
+ if (srcBeing == NULL) break;
+ srcBeing->mFrame = 0;
+ srcBeing->action = Being::SIT;
+ break;
+
+ case 3: // Stand up
+ if (srcBeing == NULL) break;
+ srcBeing->mFrame = 0;
+ srcBeing->action = Being::STAND;
+ break;
+ }
+ break;
+
+ case SMSG_BEING_LEVELUP:
+ if ((Uint32)msg->readInt32() == player_node->getId()) {
+ logger->log("Level up");
+ sound.playSfx("sfx/levelup.ogg");
+ } else {
+ logger->log("Someone else went level up");
+ }
+ msg->readInt32(); // type
+ break;
+
+ case SMSG_BEING_EMOTION:
+ if (!(dstBeing = beingManager->findBeing(msg->readInt32())))
+ {
+ break;
+ }
+
+ dstBeing->emotion = msg->readInt8();
+ dstBeing->emotion_time = EMOTION_TIME;
+ break;
+
+ case SMSG_BEING_CHANGE_LOOKS:
+ if (!(dstBeing = beingManager->findBeing(msg->readInt32())))
+ {
+ break;
+ }
+
+ switch (msg->readInt8()) {
+ case 1:
+ dstBeing->setHairStyle(msg->readInt8());
+ break;
+ case 2:
+ dstBeing->setWeapon(msg->readInt8());
+ break;
+ case 6:
+ dstBeing->setHairColor(msg->readInt8());
+ break;
+ default:
+ msg->readInt8(); // unsupported
+ break;
+ }
+ break;
+
+ case SMSG_BEING_NAME_RESPONSE:
+ if ((dstBeing = beingManager->findBeing(msg->readInt32())))
+ {
+ dstBeing->setName(msg->readString(24));
+ }
+ break;
+
+ case SMSG_PLAYER_UPDATE_1:
+ case SMSG_PLAYER_UPDATE_2:
+ case SMSG_PLAYER_MOVE:
+ // An update about a player, potentially including movement.
+ id = msg->readInt32();
+ speed = msg->readInt16();
+ msg->readInt16(); // option 1
+ msg->readInt16(); // option 2
+ msg->readInt16(); // option
+ job = msg->readInt16();
+
+ dstBeing = beingManager->findBeing(id);
+
+ if (dstBeing == NULL)
+ {
+ dstBeing = beingManager->createBeing(id, job);
+ }
+
+ dstBeing->setWalkSpeed(speed);
+ dstBeing->job = job;
+ dstBeing->setHairStyle(msg->readInt16());
+ dstBeing->setWeaponById(msg->readInt16()); // item id 1
+ msg->readInt16(); // item id 2
+ msg->readInt16(); // head option bottom
+
+ if (msg->getId() == SMSG_PLAYER_MOVE)
+ {
+ msg->readInt32(); // server tick
+ }
+
+ msg->readInt16(); // head option top
+ msg->readInt16(); // head option mid
+ dstBeing->setHairColor(msg->readInt16());
+ msg->readInt16(); // unknown
+ msg->readInt16(); // head dir
+ msg->readInt32(); // guild
+ msg->readInt32(); // emblem
+ msg->readInt16(); // manner
+ msg->readInt8(); // karma
+ msg->readInt8(); // sex
+
+ if (msg->getId() == SMSG_PLAYER_MOVE)
+ {
+ Uint16 srcX, srcY, dstX, dstY;
+ msg->readCoordinatePair(srcX, srcY, dstX, dstY);
+ dstBeing->x = srcX;
+ dstBeing->y = srcY;
+ dstBeing->setDestination(dstX, dstY);
+ }
+ else
+ {
+ msg->readCoordinates(dstBeing->x, dstBeing->y,
+ dstBeing->direction);
+ }
+
+ msg->readInt8(); // unknown
+ msg->readInt8(); // unknown
+
+ if (msg->getId() == SMSG_PLAYER_UPDATE_1)
+ {
+ if (msg->readInt8() == 2)
+ {
+ dstBeing->action = Being::SIT;
+ }
+ }
+ else if (msg->getId() == SMSG_PLAYER_MOVE)
+ {
+ msg->readInt8(); // unknown
+ }
+
+ msg->readInt8(); // Lv
+ msg->readInt8(); // unknown
+
+ dstBeing->walk_time = tick_time;
+ dstBeing->mFrame = 0;
+ break;
+
+ case 0x0119:
+ // Change in players look
+ break;
+ }
+}
diff --git a/src/net/beinghandler.h b/src/net/beinghandler.h
new file mode 100644
index 00000000..03012f39
--- /dev/null
+++ b/src/net/beinghandler.h
@@ -0,0 +1,37 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_NET_BEINGHANDLER_H
+#define _TMW_NET_BEINGHANDLER_H
+
+#include "messagehandler.h"
+
+class BeingHandler : public MessageHandler
+{
+ public:
+ BeingHandler();
+
+ void handleMessage(MessageIn *msg);
+};
+
+#endif
diff --git a/src/net/buysellhandler.cpp b/src/net/buysellhandler.cpp
new file mode 100644
index 00000000..501762ad
--- /dev/null
+++ b/src/net/buysellhandler.cpp
@@ -0,0 +1,129 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "buysellhandler.h"
+
+#include <SDL_types.h>
+
+#include "messagein.h"
+#include "protocol.h"
+
+#include "../beingmanager.h"
+#include "../item.h"
+#include "../localplayer.h"
+#include "../npc.h"
+
+#include "../gui/buy.h"
+#include "../gui/chat.h"
+#include "../gui/sell.h"
+
+extern BuyDialog *buyDialog;
+extern SellDialog *sellDialog;
+extern Window *buySellDialog;
+
+BuySellHandler::BuySellHandler()
+{
+ static const Uint16 _messages[] = {
+ SMSG_NPC_BUY_SELL_CHOICE,
+ SMSG_NPC_BUY,
+ SMSG_NPC_SELL,
+ SMSG_NPC_BUY_RESPONSE,
+ SMSG_NPC_SELL_RESPONSE,
+ 0
+ };
+ handledMessages = _messages;
+}
+
+void BuySellHandler::handleMessage(MessageIn *msg)
+{
+ int n_items;
+ switch (msg->getId())
+ {
+ case SMSG_NPC_BUY_SELL_CHOICE:
+ buyDialog->setVisible(false);
+ buyDialog->reset();
+ sellDialog->setVisible(false);
+ sellDialog->reset();
+ buySellDialog->setVisible(true);
+ current_npc = dynamic_cast<NPC*>(beingManager->findBeing(msg->readInt32()));
+ break;
+
+ case SMSG_NPC_BUY:
+ msg->readInt16(); // length
+ n_items = (msg->getLength() - 4) / 11;
+ buyDialog->reset();
+ buyDialog->setMoney(player_node->gp);
+ buyDialog->setVisible(true);
+
+ for (int k = 0; k < n_items; k++)
+ {
+ Sint32 value = msg->readInt32();
+ msg->readInt32(); // DCvalue
+ msg->readInt8(); // type
+ Sint16 itemId = msg->readInt16();
+ buyDialog->addItem(itemId, value);
+ }
+ break;
+
+ case SMSG_NPC_SELL:
+ msg->readInt16(); // length
+ n_items = (msg->getLength() - 4) / 10;
+ if (n_items > 0) {
+ sellDialog->reset();
+ sellDialog->setVisible(true);
+
+ for (int k = 0; k < n_items; k++)
+ {
+ Sint16 index = msg->readInt16();
+ Sint32 value = msg->readInt32();
+ msg->readInt32(); // OCvalue
+
+ Item *item = player_node->getInvItem(index);
+ if (item && !(item->isEquipped())) {
+ sellDialog->addItem(item, value);
+ }
+ }
+ }
+ else {
+ chatWindow->chatLog("Nothing to sell", BY_SERVER);
+ current_npc = 0;
+ }
+ break;
+
+ case SMSG_NPC_BUY_RESPONSE:
+ if (msg->readInt8() == 0) {
+ chatWindow->chatLog("Thanks for buying", BY_SERVER);
+ } else {
+ chatWindow->chatLog("Unable to buy", BY_SERVER);
+ }
+ break;
+
+ case SMSG_NPC_SELL_RESPONSE:
+ if (msg->readInt8() == 0) {
+ chatWindow->chatLog("Thanks for selling", BY_SERVER);
+ } else {
+ chatWindow->chatLog("Unable to sell", BY_SERVER);
+ }
+ break;
+ }
+}
diff --git a/src/net/buysellhandler.h b/src/net/buysellhandler.h
new file mode 100644
index 00000000..673aaac1
--- /dev/null
+++ b/src/net/buysellhandler.h
@@ -0,0 +1,37 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_NET_BUYSELLHANDLER_H
+#define _TMW_NET_BUYSELLHANDLER_H
+
+#include "messagehandler.h"
+
+class BuySellHandler : public MessageHandler
+{
+ public:
+ BuySellHandler();
+
+ void handleMessage(MessageIn *msg);
+};
+
+#endif
diff --git a/src/net/charserverhandler.cpp b/src/net/charserverhandler.cpp
new file mode 100644
index 00000000..a60e39b0
--- /dev/null
+++ b/src/net/charserverhandler.cpp
@@ -0,0 +1,210 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "charserverhandler.h"
+
+#include "messagein.h"
+#include "network.h"
+#include "protocol.h"
+
+#include "../game.h"
+#include "../localplayer.h"
+#include "../log.h"
+#include "../main.h"
+
+#include "../gui/ok_dialog.h"
+
+CharServerHandler::CharServerHandler()
+{
+ static const Uint16 _messages[] = {
+ 0x006b,
+ 0x006c,
+ 0x006d,
+ 0x006e,
+ 0x006f,
+ 0x0070,
+ 0x0071,
+ 0x0081,
+ 0
+ };
+ handledMessages = _messages;
+}
+
+void CharServerHandler::handleMessage(MessageIn *msg)
+{
+ int slot;
+ LocalPlayer *tempPlayer;
+
+ logger->log("CharServerHandler: Packet ID: %x, Length: %d",
+ msg->getId(), msg->getLength());
+ switch (msg->getId())
+ {
+ case 0x006b:
+ // Skip length word and an additional mysterious 20 bytes
+ msg->skip(2 + 20);
+
+ // Derive number of characters from message length
+ n_character = (msg->getLength() - 24) / 106;
+
+ for (int i = 0; i < n_character; i++)
+ {
+ tempPlayer = readPlayerData(msg, slot);
+ mCharInfo->select(slot);
+ mCharInfo->setEntry(tempPlayer);
+ logger->log("CharServer: Player: %s (%d)",
+ tempPlayer->getName().c_str(), slot);
+ }
+
+ state = CHAR_SELECT_STATE;
+ break;
+
+ case 0x006c:
+ switch (msg->readInt8()) {
+ case 0:
+ errorMessage = "Access denied";
+ break;
+ case 1:
+ errorMessage = "Cannot use this ID";
+ break;
+ default:
+ errorMessage = "Unknown failure to select character";
+ break;
+ }
+ mCharInfo->unlock();
+ break;
+
+ case 0x006d:
+ tempPlayer = readPlayerData(msg, slot);
+ mCharInfo->unlock();
+ mCharInfo->select(slot);
+ mCharInfo->setEntry(tempPlayer);
+ n_character++;
+ break;
+
+ case 0x006e:
+ new OkDialog(NULL, "Error", "Failed to create character");
+ break;
+
+ case 0x006f:
+ delete mCharInfo->getEntry();
+ mCharInfo->setEntry(0);
+ mCharInfo->unlock();
+ n_character--;
+ new OkDialog(NULL, "Info", "Player deleted");
+ break;
+
+ case 0x0070:
+ mCharInfo->unlock();
+ new OkDialog(NULL, "Error", "Failed to delete character.");
+ break;
+
+ case 0x0071:
+ char_ID = msg->readInt32();
+ map_path = msg->readString(16);
+ map_address = msg->readInt32();
+ map_port = msg->readInt16();
+ player_node = mCharInfo->getEntry();
+ mCharInfo->unlock();
+ mCharInfo->select(0);
+ // Clear unselected players infos
+ do
+ {
+ LocalPlayer *tmp = mCharInfo->getEntry();
+ if (tmp != player_node)
+ delete tmp;
+ mCharInfo->next();
+ } while (mCharInfo->getPos());
+
+ state = CONNECTING_STATE;
+
+ logger->log("CharSelect: Map: %s", map_path.c_str());
+ logger->log("CharSelect: Server: %s:%i", iptostring(map_address),
+ map_port);
+ break;
+
+ case 0x0081:
+ switch (msg->readInt8()) {
+ case 1:
+ errorMessage = "Map server offline";
+ break;
+ case 3:
+ errorMessage = "Speed hack detected";
+ break;
+ case 8:
+ errorMessage = "Duplicated login";
+ break;
+ default:
+ errorMessage = "Unkown error with 0x0081";
+ break;
+ }
+ mCharInfo->unlock();
+ state = ERROR_STATE;
+ break;
+ }
+}
+
+LocalPlayer* CharServerHandler::readPlayerData(MessageIn *msg, int &slot)
+{
+ LocalPlayer *tempPlayer = new LocalPlayer(account_ID, 0, NULL);
+
+ tempPlayer->mLoginId = msg->readInt32();
+ tempPlayer->totalWeight = 0;
+ tempPlayer->maxWeight = 0;
+ tempPlayer->lastAttackTime = 0;
+ tempPlayer->xp = msg->readInt32();
+ tempPlayer->gp = msg->readInt32();
+ tempPlayer->jobXp = msg->readInt32();
+ tempPlayer->jobLvl = msg->readInt32();
+ msg->skip(8); // unknown
+ msg->readInt32(); // option
+ msg->readInt32(); // karma
+ msg->readInt32(); // manner
+ msg->skip(2); // unknown
+ tempPlayer->hp = msg->readInt16();
+ tempPlayer->maxHp = msg->readInt16();
+ tempPlayer->mp = msg->readInt16();
+ tempPlayer->maxMp = msg->readInt16();
+ msg->readInt16(); // speed
+ msg->readInt16(); // class
+ tempPlayer->setHairStyle(msg->readInt16());
+ Uint16 weapon = msg->readInt16();
+ if (weapon == 11)
+ weapon = 2;
+ tempPlayer->setWeapon(weapon);
+ tempPlayer->lvl = msg->readInt16();
+ msg->readInt16(); // skill point
+ msg->readInt16(); // head bottom
+ msg->readInt16(); // shield
+ msg->readInt16(); // head option top
+ msg->readInt16(); // head option mid
+ tempPlayer->setHairColor(msg->readInt16());
+ msg->readInt16(); // unknown
+ tempPlayer->setName(msg->readString(24));
+ for (int i = 0; i < 6; i++) {
+ tempPlayer->ATTR[i] = msg->readInt8();
+ }
+ slot = msg->readInt8(); // character slot
+ msg->readInt8(); // unknown
+
+ return tempPlayer;
+}
diff --git a/src/net/charserverhandler.h b/src/net/charserverhandler.h
new file mode 100644
index 00000000..21178377
--- /dev/null
+++ b/src/net/charserverhandler.h
@@ -0,0 +1,48 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_NET_CHARSERVERHANDLER_H
+#define _TMW_NET_CHARSERVERHANDLER_H
+
+#include "messagehandler.h"
+
+#include "../lockedarray.h"
+
+class LocalPlayer;
+
+class CharServerHandler : public MessageHandler
+{
+ public:
+ CharServerHandler();
+
+ void handleMessage(MessageIn *msg);
+
+ void setCharInfo(LockedArray<LocalPlayer*> *charInfo) { mCharInfo = charInfo; };
+
+ protected:
+ LockedArray<LocalPlayer*> *mCharInfo;
+
+ LocalPlayer* readPlayerData(MessageIn *msg, int &slot);
+};
+
+#endif
diff --git a/src/net/chathandler.cpp b/src/net/chathandler.cpp
new file mode 100644
index 00000000..97e8186d
--- /dev/null
+++ b/src/net/chathandler.cpp
@@ -0,0 +1,118 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "chathandler.h"
+
+#include <SDL_types.h>
+#include <string>
+#include <sstream>
+
+#include "messagein.h"
+#include "protocol.h"
+
+#include "../being.h"
+#include "../beingmanager.h"
+#include "../game.h"
+
+#include "../gui/chat.h"
+
+extern Being *player_node;
+
+ChatHandler::ChatHandler()
+{
+ static const Uint16 _messages[] = {
+ SMSG_BEING_CHAT,
+ SMSG_PLAYER_CHAT,
+ SMSG_GM_CHAT,
+ SMSG_WHO_ANSWER,
+ 0x10c, // MVP
+ 0
+ };
+ handledMessages = _messages;
+}
+
+void ChatHandler::handleMessage(MessageIn *msg)
+{
+ Being *being;
+ std::string chatMsg;
+ std::stringstream ss;
+ Sint16 chatMsgLength;
+
+ switch (msg->getId())
+ {
+ // Received speech from being
+ case SMSG_BEING_CHAT:
+ chatMsgLength = msg->readInt16() - 8;
+ being = beingManager->findBeing(msg->readInt32());
+
+ if (!being || chatMsgLength <= 0)
+ {
+ break;
+ }
+
+ chatMsg = msg->readString(chatMsgLength);
+ chatWindow->chatLog(chatMsg, BY_OTHER);
+ chatMsg.erase(0, chatMsg.find(" : ", 0) + 3);
+ being->setSpeech(chatMsg, SPEECH_TIME);
+ break;
+
+ case SMSG_PLAYER_CHAT:
+ case SMSG_GM_CHAT:
+ chatMsgLength = msg->readInt16() - 4;
+
+ if (chatMsgLength <= 0)
+ {
+ break;
+ }
+
+ chatMsg = msg->readString(chatMsgLength);
+
+ if (msg->getId() == SMSG_PLAYER_CHAT)
+ {
+ chatWindow->chatLog(chatMsg, BY_PLAYER);
+
+ std::string::size_type pos = chatMsg.find(" : ", 0);
+ if (pos != std::string::npos)
+ {
+ chatMsg.erase(0, pos + 3);
+ }
+ player_node->setSpeech(chatMsg, SPEECH_TIME);
+ }
+ else
+ {
+ chatWindow->chatLog(chatMsg, BY_GM);
+ }
+ break;
+
+ case SMSG_WHO_ANSWER:
+ ss << "Online users: " << msg->readInt32();
+ chatWindow->chatLog(ss.str(), BY_SERVER);
+ break;
+
+ case 0x010c:
+ // Display MVP player
+ msg->readInt32(); // id
+ chatWindow->chatLog("MVP player", BY_SERVER);
+ break;
+ }
+}
diff --git a/src/net/chathandler.h b/src/net/chathandler.h
new file mode 100644
index 00000000..eed19206
--- /dev/null
+++ b/src/net/chathandler.h
@@ -0,0 +1,37 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_NET_CHATHANDLER_H
+#define _TMW_NET_CHATHANDLER_H
+
+#include "messagehandler.h"
+
+class ChatHandler : public MessageHandler
+{
+ public:
+ ChatHandler();
+
+ void handleMessage(MessageIn *msg);
+};
+
+#endif
diff --git a/src/net/equipmenthandler.cpp b/src/net/equipmenthandler.cpp
new file mode 100644
index 00000000..437b5f3e
--- /dev/null
+++ b/src/net/equipmenthandler.cpp
@@ -0,0 +1,210 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "equipmenthandler.h"
+
+#include "messagein.h"
+#include "protocol.h"
+
+#include "../being.h"
+#include "../beingmanager.h"
+#include "../equipment.h"
+#include "../item.h"
+#include "../localplayer.h"
+#include "../log.h"
+
+#include "../gui/chat.h"
+
+EquipmentHandler::EquipmentHandler()
+{
+ static const Uint16 _messages[] = {
+ SMSG_PLAYER_EQUIPMENT,
+ SMSG_PLAYER_EQUIP,
+ 0x01d7,
+ SMSG_PLAYER_UNEQUIP,
+ SMSG_PLAYER_ARROW_EQUIP,
+ 0
+ };
+ handledMessages = _messages;
+}
+
+void EquipmentHandler::handleMessage(MessageIn *msg)
+{
+ Sint32 itemCount;
+ Sint16 index, equipPoint, itemId;
+ Sint8 type;
+ int mask, position;
+ Being *being;
+ Item *item;
+
+ switch (msg->getId())
+ {
+ case SMSG_PLAYER_EQUIPMENT:
+ msg->readInt16(); // length
+ itemCount = (msg->getLength() - 4) / 20;
+
+ for (int loop = 0; loop < itemCount; loop++)
+ {
+ index = msg->readInt16();
+ itemId = msg->readInt16();
+ msg->readInt8(); // type
+ msg->readInt8(); // identify flag
+ msg->readInt16(); // equip type
+ equipPoint = msg->readInt16();
+ msg->readInt8(); // attribute
+ msg->readInt8(); // refine
+ msg->skip(8); // card
+
+ player_node->addInvItem(index, itemId, 1, true);
+
+ if (equipPoint)
+ {
+ mask = 1;
+ position = 0;
+ while (!(equipPoint & mask))
+ {
+ mask <<= 1;
+ position++;
+ }
+ item = player_node->getInvItem(index);
+ player_node->mEquipment->setEquipment(position - 1, item);
+ }
+ }
+ break;
+
+ case SMSG_PLAYER_EQUIP:
+ index = msg->readInt16();
+ equipPoint = msg->readInt16();
+ type = msg->readInt8();
+
+ logger->log("Equipping: %i %i %i", index, equipPoint, type);
+
+ if (!type) {
+ chatWindow->chatLog("Unable to equip.", BY_SERVER);
+ break;
+ }
+
+ if (!equipPoint) {
+ // No point given, no point in searching
+ break;
+ }
+
+ // Unequip any existing equipped item in this position
+ mask = 1;
+ position = 0;
+ while (!(equipPoint & mask)) {
+ mask <<= 1;
+ position++;
+ }
+ logger->log("Position %i", position - 1);
+ item = player_node->mEquipment->getEquipment(position - 1);
+ if (item) {
+ item->setEquipped(false);
+ }
+
+ item = player_node->getInvItem(index);
+ player_node->mEquipment->setEquipment(position - 1, item);
+ player_node->setWeaponById(item->getId());
+ break;
+
+ case 0x01d7:
+ // Equipment related
+ being = beingManager->findBeing(msg->readInt32());
+ msg->readInt8(); // equip point
+ itemId = msg->readInt16();
+ msg->readInt16(); // item id 2
+
+ if (!being)
+ break;
+
+ being->setWeaponById(itemId);
+ break;
+
+ case SMSG_PLAYER_UNEQUIP:
+ index = msg->readInt16();
+ equipPoint = msg->readInt16();
+ type = msg->readInt8();
+
+ if (!type) {
+ chatWindow->chatLog("Unable to unequip.", BY_SERVER);
+ break;
+ }
+
+ if (!equipPoint) {
+ // No point given, no point in searching
+ break;
+ }
+
+ mask = 1;
+ position = 0;
+ while (!(equipPoint & mask)) {
+ mask <<= 1;
+ position++;
+ }
+
+ item = player_node->getInvItem(index);
+
+ if (!item)
+ break;
+
+ item->setEquipped(false);
+
+ switch (item->getId()) {
+ case 529:
+ case 1199:
+ player_node->mEquipment->setArrows(NULL);
+ break;
+ case 521:
+ case 522:
+ case 530:
+ case 536:
+ case 1200:
+ case 1201:
+ player_node->setWeapon(0);
+ // TODO: Why this break? Shouldn't a weapon be
+ // unequipped in inventory too?
+ break;
+ default:
+ player_node->mEquipment->removeEquipment(position - 1);
+ break;
+ }
+ logger->log("Unequipping: %i %i(%i) %i",
+ index, equipPoint, type, position - 1);
+ break;
+
+ case SMSG_PLAYER_ARROW_EQUIP:
+ itemId = msg->readInt16();
+
+ if (itemId <= 1)
+ break;
+
+ item = player_node->getInvItem(itemId);
+ if (!item)
+ break;
+
+ item->setEquipped(true);
+ player_node->mEquipment->setArrows(item);
+ logger->log("Arrows equipped: %i", itemId);
+ break;
+ }
+}
diff --git a/src/net/equipmenthandler.h b/src/net/equipmenthandler.h
new file mode 100644
index 00000000..656f7a73
--- /dev/null
+++ b/src/net/equipmenthandler.h
@@ -0,0 +1,37 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_NET_EQUIPMENTHANDLER_H
+#define _TMW_NET_EQUIPMENTHANDLER_H
+
+#include "messagehandler.h"
+
+class EquipmentHandler : public MessageHandler
+{
+ public:
+ EquipmentHandler();
+
+ void handleMessage(MessageIn *msg);
+};
+
+#endif
diff --git a/src/net/inventoryhandler.cpp b/src/net/inventoryhandler.cpp
new file mode 100644
index 00000000..3742d327
--- /dev/null
+++ b/src/net/inventoryhandler.cpp
@@ -0,0 +1,128 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "inventoryhandler.h"
+
+#include <SDL_types.h>
+
+#include "messagein.h"
+#include "protocol.h"
+
+#include "../item.h"
+#include "../localplayer.h"
+
+#include "../gui/chat.h"
+
+InventoryHandler::InventoryHandler()
+{
+ static const Uint16 _messages[] = {
+ SMSG_PLAYER_INVENTORY,
+ SMSG_PLAYER_INVENTORY_ADD,
+ SMSG_PLAYER_INVENTORY_REMOVE,
+ SMSG_PLAYER_INVENTORY_USE,
+ SMSG_ITEM_USE_RESPONSE,
+ 0
+ };
+ handledMessages = _messages;
+}
+
+void InventoryHandler::handleMessage(MessageIn *msg)
+{
+ Sint32 number;
+ Sint16 index, amount, itemId, equipType;
+
+ switch (msg->getId())
+ {
+ case SMSG_PLAYER_INVENTORY:
+ // Only called on map load / warp. First reset all items
+ // to not load them twice on map change.
+ player_node->clearInventory();
+ msg->readInt16(); // length
+ number = (msg->getLength() - 4) / 18;
+
+ for (int loop = 0; loop < number; loop++)
+ {
+ index = msg->readInt16();
+ itemId = msg->readInt16();
+ msg->readInt8(); // type
+ msg->readInt8(); // identify flag
+ amount = msg->readInt16();
+ msg->skip(2); // unknown
+ msg->skip(8); // card (4 shorts)
+
+ player_node->addInvItem(index, itemId, amount, false);
+
+ // Trick because arrows are not considered equipment
+ if (itemId == 1199 || itemId == 529)
+ {
+ player_node->getInvItem(index)->setEquipment(true);
+ }
+ }
+ break;
+
+ case SMSG_PLAYER_INVENTORY_ADD:
+ index = msg->readInt16();
+ amount = msg->readInt16();
+ itemId = msg->readInt16();
+ msg->readInt8(); // identify flag
+ msg->readInt8(); // attribute
+ msg->readInt8(); // refine
+ msg->skip(8); // card
+ equipType = msg->readInt16();
+ msg->readInt8(); // type
+
+ if (msg->readInt8()> 0) {
+ chatWindow->chatLog("Unable to pick up item", BY_SERVER);
+ } else {
+ player_node->addInvItem(index, itemId, amount, equipType != 0);
+ }
+ break;
+
+ case SMSG_PLAYER_INVENTORY_REMOVE:
+ index = msg->readInt16();
+ amount = msg->readInt16();
+ player_node->getInvItem(index)->increaseQuantity(-amount);
+ break;
+
+ case SMSG_PLAYER_INVENTORY_USE:
+ index = msg->readInt16();
+ msg->readInt16(); // item id
+ msg->readInt32(); // id
+ amount = msg->readInt16();
+ msg->readInt8(); // type
+
+ player_node->getInvItem(index)->setQuantity(amount);
+ break;
+
+ case SMSG_ITEM_USE_RESPONSE:
+ index = msg->readInt16();
+ amount = msg->readInt16();
+
+ if (msg->readInt8() == 0) {
+ chatWindow->chatLog("Failed to use item", BY_SERVER);
+ } else {
+ player_node->getInvItem(index)->setQuantity(amount);
+ }
+ break;
+ }
+}
diff --git a/src/net/inventoryhandler.h b/src/net/inventoryhandler.h
new file mode 100644
index 00000000..aedbc3a1
--- /dev/null
+++ b/src/net/inventoryhandler.h
@@ -0,0 +1,37 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_NET_INVENTORYHANDLER_H
+#define _TMW_NET_INVENTORYHANDLER_H
+
+#include "messagehandler.h"
+
+class InventoryHandler : public MessageHandler
+{
+ public:
+ InventoryHandler();
+
+ void handleMessage(MessageIn *msg);
+};
+
+#endif
diff --git a/src/net/itemhandler.cpp b/src/net/itemhandler.cpp
new file mode 100644
index 00000000..d2a938fd
--- /dev/null
+++ b/src/net/itemhandler.cpp
@@ -0,0 +1,67 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "itemhandler.h"
+
+#include "messagein.h"
+#include "protocol.h"
+
+#include "../engine.h"
+#include "../floor_item.h"
+
+ItemHandler::ItemHandler()
+{
+ static const Uint16 _messages[] = {
+ SMSG_ITEM_VISIBLE,
+ SMSG_ITEM_DROPPED,
+ SMSG_ITEM_REMOVE,
+ 0
+ };
+ handledMessages = _messages;
+}
+
+void ItemHandler::handleMessage(MessageIn *msg)
+{
+ Uint32 id;
+ Uint16 x, y;
+ Sint16 itemId;
+
+ switch (msg->getId())
+ {
+ case SMSG_ITEM_VISIBLE:
+ case SMSG_ITEM_DROPPED:
+ id = msg->readInt32();
+ itemId = msg->readInt16();
+ msg->readInt8(); // identify flag
+ x = msg->readInt16();
+ y = msg->readInt16();
+ msg->skip(4); // amount,subX,subY / subX,subY,amount
+
+ add_floor_item(new FloorItem(id, itemId, x, y, engine->getCurrentMap()));
+ break;
+
+ case SMSG_ITEM_REMOVE:
+ remove_floor_item(msg->readInt32());
+ break;
+ }
+}
diff --git a/src/net/itemhandler.h b/src/net/itemhandler.h
new file mode 100644
index 00000000..b2104722
--- /dev/null
+++ b/src/net/itemhandler.h
@@ -0,0 +1,37 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_NET_ITEMHANDLER_H
+#define _TMW_NET_ITEMHANDLER_H
+
+#include "messagehandler.h"
+
+class ItemHandler : public MessageHandler
+{
+ public:
+ ItemHandler();
+
+ void handleMessage(MessageIn *msg);
+};
+
+#endif
diff --git a/src/net/loginhandler.cpp b/src/net/loginhandler.cpp
new file mode 100644
index 00000000..fd525d99
--- /dev/null
+++ b/src/net/loginhandler.cpp
@@ -0,0 +1,114 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "loginhandler.h"
+
+#include "messagein.h"
+#include "network.h"
+#include "protocol.h"
+
+#include "../log.h"
+#include "../main.h"
+#include "../serverinfo.h"
+
+extern SERVER_INFO **server_info;
+
+LoginHandler::LoginHandler()
+{
+ static const Uint16 _messages[] = {
+ 0x0069,
+ 0x006a,
+ 0
+ };
+ handledMessages = _messages;
+}
+
+void LoginHandler::handleMessage(MessageIn *msg)
+{
+ switch (msg->getId())
+ {
+ case 0x0069:
+ // Skip the length word
+ msg->skip(2);
+
+ n_server = (msg->getLength() - 47) / 32;
+ server_info = (SERVER_INFO**)malloc(sizeof(SERVER_INFO*) * n_server);
+
+ session_ID1 = msg->readInt32();
+ account_ID = msg->readInt32();
+ session_ID2 = msg->readInt32();
+ msg->skip(30); // unknown
+ sex = msg->readInt8();
+
+ for (int i = 0; i < n_server; i++)
+ {
+ server_info[i] = new SERVER_INFO;
+
+ server_info[i]->address = msg->readInt32();
+ server_info[i]->port = msg->readInt16();
+ server_info[i]->name = msg->readString(20);
+ server_info[i]->online_users = msg->readInt32();
+ msg->skip(2); // unknown
+
+ logger->log("Network: Server: %s (%s:%d)",
+ server_info[i]->name.c_str(),
+ iptostring(server_info[i]->address),
+ server_info[i]->port);
+ }
+ state = CHAR_SERVER_STATE;
+ break;
+
+ case 0x006a:
+ int loginError = msg->readInt8();
+ logger->log("Login::error code: %i", loginError);
+
+ switch (loginError) {
+ case 0:
+ errorMessage = "Unregistered ID";
+ break;
+ case 1:
+ errorMessage = "Wrong password";
+ break;
+ case 2:
+ errorMessage = "Account expired";
+ break;
+ case 3:
+ errorMessage = "Rejected from server";
+ break;
+ case 4:
+ errorMessage = "You have been blocked by the GM Team";
+ break;
+ case 6:
+ errorMessage = "You have been banned for 5 minutes";
+ break;
+ case 9:
+ errorMessage = "This account is already logged in";
+ break;
+ default:
+ errorMessage = "Unknown error";
+ break;
+ }
+ state = ERROR_STATE;
+ break;
+ }
+}
diff --git a/src/net/loginhandler.h b/src/net/loginhandler.h
new file mode 100644
index 00000000..99ade7f1
--- /dev/null
+++ b/src/net/loginhandler.h
@@ -0,0 +1,37 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_NET_LOGINHANDLER_H
+#define _TMW_NET_LOGINHANDLER_H
+
+#include "messagehandler.h"
+
+class LoginHandler : public MessageHandler
+{
+ public:
+ LoginHandler();
+
+ void handleMessage(MessageIn *msg);
+};
+
+#endif
diff --git a/src/net/maploginhandler.cpp b/src/net/maploginhandler.cpp
new file mode 100644
index 00000000..27a7b4c6
--- /dev/null
+++ b/src/net/maploginhandler.cpp
@@ -0,0 +1,63 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "maploginhandler.h"
+
+#include "messagein.h"
+#include "protocol.h"
+
+#include "../localplayer.h"
+#include "../log.h"
+#include "../main.h"
+
+MapLoginHandler::MapLoginHandler()
+{
+ static const Uint16 _messages[] = {
+ SMSG_LOGIN_SUCCESS,
+ 0x0081,
+ 0
+ };
+ handledMessages = _messages;
+}
+
+void MapLoginHandler::handleMessage(MessageIn *msg)
+{
+ unsigned char direction;
+
+ switch (msg->getId())
+ {
+ case SMSG_LOGIN_SUCCESS:
+ msg->readInt32(); // server tick
+ msg->readCoordinates(player_node->x, player_node->y, direction);
+ msg->skip(2); // unknown
+ logger->log("Protocol: Player start position: (%d, %d), Direction: %d",
+ player_node->x, player_node->y, direction);
+ state = GAME_STATE;
+ break;
+
+ case 0x0081:
+ logger->log("Warning: Map server D/C");
+ state = ERROR_STATE;
+ break;
+ }
+}
diff --git a/src/net/maploginhandler.h b/src/net/maploginhandler.h
new file mode 100644
index 00000000..fe597549
--- /dev/null
+++ b/src/net/maploginhandler.h
@@ -0,0 +1,37 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_NET_MAPLOGINHANDLER_H
+#define _TMW_NET_MAPLOGINHANDLER_H
+
+#include "messagehandler.h"
+
+class MapLoginHandler : public MessageHandler
+{
+ public:
+ MapLoginHandler();
+
+ void handleMessage(MessageIn *msg);
+};
+
+#endif
diff --git a/src/net/messagehandler.cpp b/src/net/messagehandler.cpp
new file mode 100644
index 00000000..849b6716
--- /dev/null
+++ b/src/net/messagehandler.cpp
@@ -0,0 +1,45 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "messagehandler.h"
+
+#include <cassert>
+
+#include "network.h"
+
+MessageHandler::MessageHandler():
+ mNetwork(0)
+{
+}
+
+MessageHandler::~MessageHandler()
+{
+ if (mNetwork)
+ mNetwork->unregisterHandler(this);
+}
+
+void MessageHandler::setNetwork(Network *network)
+{
+ assert(!(network && mNetwork));
+ mNetwork = network;
+}
diff --git a/src/net/messagehandler.h b/src/net/messagehandler.h
new file mode 100644
index 00000000..c09037f6
--- /dev/null
+++ b/src/net/messagehandler.h
@@ -0,0 +1,48 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_NET_MESSAGEHANDLER_H
+#define _TMW_NET_MESSAGEHANDLER_H
+
+#include <SDL_types.h>
+
+class MessageIn;
+class Network;
+
+class MessageHandler
+{
+ public:
+ const Uint16 *handledMessages;
+
+ MessageHandler();
+ virtual ~MessageHandler();
+
+ virtual void handleMessage(MessageIn *msg) =0;
+
+ void setNetwork(Network *network);
+
+ protected:
+ Network *mNetwork;
+};
+
+#endif
diff --git a/src/net/messageout.cpp b/src/net/messageout.cpp
index 9b27a6a5..f6ed5de6 100644
--- a/src/net/messageout.cpp
+++ b/src/net/messageout.cpp
@@ -30,63 +30,42 @@
#include "network.h"
#include "packet.h"
-MessageOut::MessageOut():
- mPacket(0),
+MessageOut::MessageOut(Network *network):
+ mNetwork(network),
mData(0),
mDataSize(0),
mPos(0)
{
- mData = out + out_size;
-}
-
-MessageOut::~MessageOut()
-{
- if (mPacket) {
- delete mPacket;
- }
-
- // Don't free this data for now, see above.
- //if (mData) {
- // free(mData);
- //}
-}
-
-void MessageOut::expand(size_t bytes)
-{
- /*mData = (char*)realloc(mData, bytes);
- mDataSize = bytes;*/
+ mData = mNetwork->mOutBuffer + mNetwork->mOutSize;
}
void MessageOut::writeInt8(Sint8 value)
{
- expand(mPos + sizeof(Sint8));
mData[mPos] = value;
mPos += sizeof(Sint8);
- out_size += sizeof(Sint8);
+ mNetwork->mOutSize+= sizeof(Sint8);
}
void MessageOut::writeInt16(Sint16 value)
{
- expand(mPos + sizeof(Sint16));
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
(*(Sint16 *)(mData + mPos)) = SDL_Swap16(value);
#else
(*(Sint16 *)(mData + mPos)) = value;
#endif
mPos += sizeof(Sint16);
- out_size += sizeof(Sint16);
+ mNetwork->mOutSize += sizeof(Sint16);
}
void MessageOut::writeInt32(Sint32 value)
{
- expand(mPos + sizeof(Sint32));
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
(*(Sint32 *)(mData + mPos)) = SDL_Swap32(value);
#else
(*(Sint32 *)(mData + mPos)) = value;
#endif
mPos += sizeof(Sint32);
- out_size += sizeof(Sint32);
+ mNetwork->mOutSize += sizeof(Sint32);
}
void MessageOut::writeString(const std::string &string, int length)
@@ -97,39 +76,27 @@ void MessageOut::writeString(const std::string &string, int length)
{
// Write the length at the start if not fixed
writeInt16(string.length());
- expand(mPos + string.length());
}
else
{
// Make sure the length of the string is no longer than specified
toWrite = string.substr(0, length);
- expand(mPos + length);
}
// Write the actual string
memcpy(&mData[mPos], (void*)toWrite.c_str(), toWrite.length());
mPos += toWrite.length();
- out_size += toWrite.length();
+ mNetwork->mOutSize += toWrite.length();
// Pad remaining space with zeros
if (length > (int)toWrite.length())
{
memset(&mData[mPos], '\0', length - toWrite.length());
mPos += length - toWrite.length();
- out_size += length - toWrite.length();
+ mNetwork->mOutSize += length - toWrite.length();
}
}
-const Packet *MessageOut::getPacket()
-{
- if (!mPacket)
- {
- mPacket = new Packet(mData, mDataSize);
- }
-
- return mPacket;
-}
-
MessageOut& operator<<(MessageOut &msg, const Sint8 &rhs)
{
msg.writeInt8(rhs);
diff --git a/src/net/messageout.h b/src/net/messageout.h
index b2ee506e..f6468adb 100644
--- a/src/net/messageout.h
+++ b/src/net/messageout.h
@@ -27,7 +27,7 @@
#include <iosfwd>
#include <SDL_types.h>
-class Packet;
+class Network;
/**
* Used for building an outgoing message.
@@ -42,12 +42,7 @@ class MessageOut
/**
* Constructor.
*/
- MessageOut();
-
- /**
- * Destructor.
- */
- ~MessageOut();
+ MessageOut(Network *network);
void writeInt8(Sint8 value); /**< Writes a byte. */
void writeInt16(Sint16 value); /**< Writes a short. */
@@ -59,24 +54,9 @@ class MessageOut
*/
void writeString(const std::string &string, int length = -1);
- /**
- * Returns an instance of Packet derived from the written data. Use for
- * sending the packet. No more writing to the packet may be done after
- * a call to this method.
- */
- const Packet *getPacket();
-
private:
- /**
- * Expand the packet data to be able to hold more data.
- *
- * NOTE: For performance enhancements this method could allocate extra
- * memory in advance instead of expanding size every time more data is
- * added.
- */
- void expand(size_t size);
+ Network *mNetwork;
- Packet *mPacket; /**< Created packet. */
char *mData; /**< Data building up. */
unsigned int mDataSize; /**< Size of data. */
unsigned int mPos; /**< Position in the data. */
diff --git a/src/net/network.cpp b/src/net/network.cpp
index fbcf199b..3b0652e2 100644
--- a/src/net/network.cpp
+++ b/src/net/network.cpp
@@ -23,15 +23,10 @@
#include "network.h"
-#include <cassert>
-#include <sstream>
-#include <SDL_net.h>
-#include <SDL_thread.h>
-
+#include "messagehandler.h"
#include "messagein.h"
#include "../log.h"
-#include "../main.h"
/** Warning: buffers and other variables are shared,
so there can be only one connection active at a time */
@@ -81,309 +76,379 @@ short packet_lengths[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
-unsigned int buffer_size = 65536;
-char *in = NULL;
-char *out = NULL;
-unsigned int in_size = 0;
-unsigned int out_size = 0;
-int connectionOpen = NET_IDLE;
+const unsigned int BUFFER_SIZE = 65536;
-TCPsocket sock;
-SDLNet_SocketSet set;
-SDL_Thread *mThread = NULL;
-SDL_mutex *mMutex = NULL;
-IPaddress *ip = NULL;
+int networkThread(void *data)
+{
+ Network *network = static_cast<Network*>(data);
-char *iptostring(int address)
+ if (!network->realConnect())
+ return -1;
+
+ network->receive();
+
+ return 0;
+}
+
+Network::Network():
+ mAddress(0), mPort(0),
+ mInBuffer(new char[BUFFER_SIZE]),
+ mOutBuffer(new char[BUFFER_SIZE]),
+ mInSize(0), mOutSize(0),
+ mToSkip(0),
+ mState(IDLE),
+ mWorkerThread(0)
{
- static char asciiIP[16];
+ mMutex = SDL_CreateMutex();
+}
- sprintf(asciiIP, "%i.%i.%i.%i",
- (unsigned char)(address),
- (unsigned char)(address >> 8),
- (unsigned char)(address >> 16),
- (unsigned char)(address >> 24));
+Network::~Network()
+{
+ clearHandlers();
- return asciiIP;
+ if (mAddress)
+ free(mAddress);
+
+ if (mState != IDLE && mState != ERROR)
+ disconnect();
+
+ SDL_DestroyMutex(mMutex);
+
+ delete mInBuffer;
+ delete mOutBuffer;
}
-int connectionThread(void *ptr)
+bool Network::connect(const char *address, short port)
{
- // Create the socket for the current session
- sock = SDLNet_TCP_Open((IPaddress *)ptr);
- if (!sock)
+ if (mState != IDLE && mState != ERROR)
{
- logger->log("Error in SDLNet_TCP_Open(): %s", SDLNet_GetError());
- connectionOpen = NET_ERROR;
- return NET_ERROR;
+ logger->log("Tried to connect an already connected socket!");
+ return false;
}
- // Create a socket set to listen to socket
- set = SDLNet_AllocSocketSet(1);
- if (!set)
+ if (!address)
{
- logger->log("Error in SDLNet_AllocSocketSet(): %s", SDLNet_GetError());
- connectionOpen = NET_ERROR;
- return NET_ERROR;
+ logger->log("Empty address given to Network::connect()!");
+ mState = ERROR;
+ return false;
}
- // Add the socket to the set
- int ret = SDLNet_TCP_AddSocket(set, sock);
- if (ret == -1)
+ if (mAddress)
+ free(mAddress);
+
+ mAddress = strdup(address);
+ mPort = port;
+
+ // Reset to sane values
+ mOutSize = 0;
+ mInSize = 0;
+ mToSkip = 0;
+
+ mState = CONNECTING;
+ mWorkerThread = SDL_CreateThread(networkThread, this);
+ if (!mWorkerThread)
{
- logger->log("Error in SDLNet_AddSocket(): %s", SDLNet_GetError());
- connectionOpen = NET_ERROR;
- return NET_ERROR;
+ logger->log("Unable to create network worker thread");
+ mState = ERROR;
+ return false;
}
- // Init buffers
- in = (char*)malloc(buffer_size);
- out = (char*)malloc(buffer_size);
- memset(in, '\0', buffer_size);
- memset(out, '\0', buffer_size);
- in_size = 0;
- out_size = 0;
-
- SDL_mutexP(mMutex);
- logger->log("Network::Started session with %s:%i",
- iptostring(((IPaddress *)ptr)->host),
- ((IPaddress *)ptr)->port);
- connectionOpen = NET_CONNECTED;
- SDL_mutexV(mMutex);
- return NET_CONNECTED;
+ return true;
}
-void openConnection(const char* address, short port)
+void Network::disconnect()
{
- //assert(connectionOpen <= NET_IDLE);
+ if (mState != CONNECTED && mState != CONNECTING)
+ return;
- // Initialize SDL_net
- if (SDLNet_Init() == -1)
+ mState = IDLE;
+
+ if (mWorkerThread)
{
- logger->log("Error in SDLNet_Init(): %s", SDLNet_GetError());
- connectionOpen = NET_ERROR;
+ SDL_WaitThread(mWorkerThread, NULL);
+ mWorkerThread = NULL;
}
+ SDLNet_TCP_Close(mSocket);
+}
- ip = new IPaddress();
+void Network::registerHandler(MessageHandler *handler)
+{
+ const Uint16 *i = handler->handledMessages;
- // Resolve host name
- if (SDLNet_ResolveHost(ip, address, port) == -1)
+ while(*i)
{
- logger->log("Error in SDLNet_ResolveHost(): %s", SDLNet_GetError());
- connectionOpen = NET_ERROR;
+ mMessageHandlers[*i] = handler;
+ i++;
}
- connectionOpen = NET_CONNECTING;
- // Create the synchronization lock
- mMutex = SDL_CreateMutex();
- // Create the connection thread
- mThread = SDL_CreateThread(connectionThread, ip);
- if (mThread == NULL) {
- logger->log("Unable to create connection thread");
- connectionOpen = NET_ERROR;
- }
+ handler->setNetwork(this);
}
-int pollConnection()
+void Network::unregisterHandler(MessageHandler *handler)
{
- if (mMutex)
- {
- SDL_mutexP(mMutex);
- }
+ const Uint16 *i = handler->handledMessages;
- switch (connectionOpen)
+ while(*i)
{
- case NET_IDLE:
- case NET_CONNECTING:
- break;
- case NET_CONNECTED:
- case NET_ERROR:
- SDL_WaitThread(mThread, NULL);
- mThread = NULL;
- SDL_DestroyMutex(mMutex);
- mMutex = NULL;
- break;
+ std::map<Uint16, MessageHandler*>::iterator iter;
+ iter = mMessageHandlers.find(*i);
+ if (iter != mMessageHandlers.end())
+ {
+ mMessageHandlers.erase(iter);
+ }
+ i++;
}
- if (mMutex)
+ handler->setNetwork(0);
+}
+
+void Network::clearHandlers()
+{
+ std::map<Uint16, MessageHandler*>::iterator i;
+ for (i = mMessageHandlers.begin(); i != mMessageHandlers.end(); i++)
{
- SDL_mutexV(mMutex);
+ i->second->setNetwork(0);
}
- return connectionOpen;
+ mMessageHandlers.clear();
+}
+
+void Network::dispatchMessages()
+{
+ if (!messageReady())
+ return;
+
+ MessageIn msg = getNextMessage();
+
+ std::map<Uint16, MessageHandler*>::iterator iter;
+ iter = mMessageHandlers.find(msg.getId());
+
+ if (iter != mMessageHandlers.end())
+ iter->second->handleMessage(&msg);
+ else
+ logger->log("Unhandled packet: %x", msg.getId());
+
+ skip(msg.getLength());
}
-void closeConnection()
+void Network::flush()
{
- //assert(connectionOpen > );
+ if (!mOutSize || mState != CONNECTED)
+ return;
+
+ int ret;
- if (connectionOpen == NET_ERROR)return;
- if (mThread)
+ SDL_mutexP(mMutex);
+ ret = SDLNet_TCP_Send(mSocket, mOutBuffer, mOutSize);
+ if (ret < (int)mOutSize)
{
- SDL_WaitThread(mThread, NULL);
- mThread = NULL;
+ logger->log("Error in SDLNet_TCP_Send(): %s", SDLNet_GetError());
+ mState = ERROR;
}
+ mOutSize = 0;
+ SDL_mutexV(mMutex);
+}
- if (mMutex)
+void Network::skip(int len)
+{
+ SDL_mutexP(mMutex);
+ mToSkip += len;
+ if (!mInSize)
{
- SDL_DestroyMutex(mMutex);
- mMutex = NULL;
+ SDL_mutexV(mMutex);
+ return;
}
- if (ip)
+ if (mInSize >= mToSkip)
{
- delete ip;
- ip = NULL;
+ mInSize -= mToSkip;
+ memmove(mInBuffer, mInBuffer + mToSkip, mInSize);
+ mToSkip = 0;
}
-
- // Remove the socket from the socket set
- int ret = SDLNet_TCP_DelSocket(set, sock);
- if (ret == -1)
+ else
{
- logger->log("Error in SDLNet_DelSocket(): %s", SDLNet_GetError());
+ mToSkip -= mInSize;
+ mInSize = 0;
}
+ SDL_mutexV(mMutex);
+}
- // Close the TCP connection
- SDLNet_TCP_Close(sock);
-
- // Free the socket set
- SDLNet_FreeSocketSet(set);
- set = NULL;
+bool Network::messageReady()
+{
+ int len = -1;
- // Clear buffers
- if (in != NULL)
+ SDL_mutexP(mMutex);
+ if (mInSize >= 2)
{
- free(in);
- in = NULL;
+ len = packet_lengths[readWord(0)];
+
+ if (len == -1 && mInSize > 4)
+ len = readWord(2);
+
}
- if (out != NULL)
+ bool ret = (mInSize >= static_cast<unsigned int>(len));
+ SDL_mutexV(mMutex);
+
+ return ret;
+}
+
+MessageIn Network::getNextMessage()
+{
+ while (!messageReady())
{
- free(out);
- out = NULL;
+ if (mState == ERROR)
+ break;
}
- in_size = 0;
- out_size = 0;
+ SDL_mutexP(mMutex);
+ int msgId = readWord(0);
+ int len = packet_lengths[msgId];
- // Shutdown the network API
- SDLNet_Quit();
+ if (len == -1)
+ len = readWord(2);
- logger->log("Network::Closed session");
- connectionOpen = NET_IDLE;
+#ifdef DEBUG
+ printf("Received packet 0x%x of length %d\n", msgId, length);
+#endif
+
+ MessageIn msg(mInBuffer, len);
+ SDL_mutexV(mMutex);
+
+ return msg;
}
-void flush()
+bool Network::realConnect()
{
- // Send all available data, waits if not all data can be sent immediately
- if (out_size > 0)
+ IPaddress ipAddress;
+
+ if (SDLNet_ResolveHost(&ipAddress, mAddress, mPort) == -1)
{
- int ret = SDLNet_TCP_Send(sock, (char*)out, out_size);
- if (ret < (int)out_size)
- {
- logger->log("Error in SDLNet_TCP_Send(): %s", SDLNet_GetError());
- errorMessage = "You got disconnected from server";
- state = ERROR_STATE;
- return;
- }
- out_size -= ret;
+ logger->log("Error in SDLNet_ResolveHost(): %s", SDLNet_GetError());
+ mState = ERROR;
+ return false;
}
- int numReady = SDLNet_CheckSockets(set, 0);
- if (numReady == -1)
+ mState = CONNECTING;
+
+ mSocket = SDLNet_TCP_Open(&ipAddress);
+ if (!mSocket)
{
- logger->log("Error: SDLNet_CheckSockets");
- return;
+ logger->log("Error in SDLNet_TCP_Open(): %s", SDLNet_GetError());
+ mState = ERROR;
+ return false;
}
- else if (numReady == 0) // any socket ready
+
+ logger->log("Network::Started session with %s:%i",
+ iptostring(ipAddress.host), ipAddress.port);
+
+ mState = CONNECTED;
+
+ return true;
+}
+
+void Network::receive()
+{
+ SDLNet_SocketSet set;
+
+ if (!(set = SDLNet_AllocSocketSet(1)))
{
+ logger->log("Error in SDLNet_AllocSocketSet(): %s", SDLNet_GetError());
+ mState = ERROR;
return;
}
- else if (numReady == 1) // one socket is ready
- {
- // Receive data from the socket
- int ret = SDLNet_TCP_Recv(sock, in + in_size, buffer_size - in_size);
- if (ret <= 0)
- {
- logger->log("Error in SDLNet_TCP_Recv(): %s", SDLNet_GetError());
- errorMessage = "You got disconnected from server";
- state = ERROR_STATE;
- return;
- }
- else {
- in_size += ret;
- }
- }
- else // more than one socket is ready.. this should not happen since we only listen once socket.
+
+ if (SDLNet_TCP_AddSocket(set, mSocket) == -1)
{
- logger->log("Error in SDLNet_TCP_Recv(), %d sockets are ready : %s", numReady, SDLNet_GetError());
- errorMessage = "You got disconnected from server";
- state = ERROR_STATE;
- return;
+ logger->log("Error in SDLNet_AddSocket(): %s", SDLNet_GetError());
+ mState = ERROR;
}
-}
-unsigned short readWord(int pos)
-{
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
- return SDL_Swap16((*(unsigned short*)(in+(pos))));
-#else
- return (*(unsigned short *)(in+(pos)));
-#endif
-}
-
-bool packetReady()
-{
- bool ret = false;
- if (in_size >= 2)
+ while (mState == CONNECTED)
{
- int length = packet_lengths[readWord(0)];
- if (length == -1)
+ // TODO Try to get this to block all the time while still being able
+ // to escape the loop
+ int numReady = SDLNet_CheckSockets(set, ((Uint32)500));
+ int ret;
+ switch (numReady)
{
- if (in_size >= 4)
- {
- length = readWord(2);
- if (in_size >= (unsigned int)length)
+ case -1:
+ logger->log("Error: SDLNet_CheckSockets");
+ // FALLTHROUGH
+ case 0:
+ break;
+
+ case 1:
+ // Receive data from the socket
+ SDL_mutexP(mMutex);
+ ret = SDLNet_TCP_Recv(mSocket, mInBuffer + mInSize, BUFFER_SIZE - mInSize);
+
+ if (!ret)
{
- ret = true;
+ // We got disconnected
+ mState = IDLE;
+ logger->log("Disconnected.");
}
- }
- }
- else if (in_size >= (unsigned int)length)
- {
- ret = true;
+ else if (ret < 0)
+ {
+ logger->log("Error in SDLNet_TCP_Recv(): %s", SDLNet_GetError());
+ mState = ERROR;
+ }
+ else {
+ mInSize += ret;
+ if (mToSkip)
+ {
+ if (mInSize >= mToSkip)
+ {
+ mInSize -= mToSkip;
+ memmove(mInBuffer, mInBuffer + mToSkip, mInSize);
+ mToSkip = 0;
+ }
+ else
+ {
+ mToSkip -= mInSize;
+ mInSize = 0;
+ }
+ }
+ }
+ SDL_mutexV(mMutex);
+ break;
+
+ default:
+ // more than one socket is ready..
+ // this should not happen since we only listen once socket.
+ logger->log("Error in SDLNet_TCP_Recv(), %d sockets are ready : %s", numReady, SDLNet_GetError());
+ mState = ERROR;
+ break;
}
}
- return ret;
-}
-
-MessageIn
-get_next_message()
-{
- // At least 2 bytes should be received for the message ID
- while (in_size < 2 && state != ERROR_STATE) flush();
-
- int length = packet_lengths[readWord(0)];
- if (length == -1)
+ if (SDLNet_TCP_DelSocket(set, mSocket) == -1)
{
- // Another 2 bytes should be received for the length
- while (in_size < 4) flush();
- length = readWord(2);
+ logger->log("Error in SDLNet_DelSocket(): %s", SDLNet_GetError());
}
-#ifdef DEBUG
- printf("Received packet 0x%x of length %d\n", readWord(0), length);
-#endif
+ SDLNet_FreeSocketSet(set);
+}
+
+char *iptostring(int address)
+{
+ static char asciiIP[16];
- // Make sure the whole packet is received
- while (in_size < static_cast<unsigned int>(length) && state != ERROR_STATE) flush();
+ sprintf(asciiIP, "%i.%i.%i.%i",
+ (unsigned char)(address),
+ (unsigned char)(address >> 8),
+ (unsigned char)(address >> 16),
+ (unsigned char)(address >> 24));
- return MessageIn(in, length);
+ return asciiIP;
}
-void skip(int len)
+Uint16 Network::readWord(int pos)
{
- memcpy(in, in + len, in_size - len);
- in_size -= len;
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+ return SDL_Swap16((*(Uint16*)(mInBuffer+(pos))));
+#else
+ return (*(Uint16*)(mInBuffer+(pos)));
+#endif
}
diff --git a/src/net/network.h b/src/net/network.h
index db95d7c3..75bde584 100644
--- a/src/net/network.h
+++ b/src/net/network.h
@@ -24,41 +24,77 @@
#ifndef _TMW_NETWORK_
#define _TMW_NETWORK_
-#define NET_ERROR -1
-#define NET_CONNECTED 0
-#define NET_IDLE 1
-#define NET_CONNECTING 2
-#define NET_DATA 3
+#include <map>
+#include <SDL_net.h>
+#include <SDL_thread.h>
+class MessageHandler;
class MessageIn;
-/** Convert an address from int format to string */
-char *iptostring(int address);
+class Network;
-/** Open a session with a server */
-void openConnection(const char* address, short port);
+class Network
+{
+ public:
+ friend int networkThread(void *data);
+ friend class MessageOut;
-/** Returns the status of the current connection attempt. */
-int pollConnection();
+ Network();
+ ~Network();
-/** Close a session */
-void closeConnection();
+ bool connect(const char *address, short port);
+ void disconnect();
-/** Send and receive data waiting in the buffers */
-void flush();
+ void registerHandler(MessageHandler *handler);
+ void unregisterHandler(MessageHandler *handler);
+ void clearHandlers();
-/** Check if a packet is complete */
-bool packetReady();
+ int getState() const { return mState; }
+ bool isConnected() const { return mState == CONNECTED; }
-/**
- * Returns the next arriving message, waiting for it if necessary.
- */
-MessageIn get_next_message();
-extern char *out;
+ int getInSize() const { return mInSize; }
+
+ void skip(int len);
+
+ bool messageReady();
+ MessageIn getNextMessage();
+
+ void dispatchMessages();
+ void flush();
+
+ enum {
+ IDLE,
+ CONNECTED,
+ CONNECTING,
+ DATA,
+ ERROR
+ };
+
+ protected:
+ Uint16 readWord(int pos);
+
+ TCPsocket mSocket;
-void skip(int len);
+ char *mAddress;
+ short mPort;
-extern unsigned int in_size; /**< Amount of data in input buffer. */
-extern unsigned int out_size; /**< Amount of data in output buffer. */
+ char *mInBuffer, *mOutBuffer;
+ unsigned int mInSize, mOutSize;
+
+ unsigned int mToSkip;
+
+ int mState;
+
+ SDL_Thread *mWorkerThread;
+ SDL_mutex *mMutex;
+
+ std::map<Uint16, MessageHandler*> mMessageHandlers;
+
+ bool realConnect();
+ void receive();
+};
+
+/** Convert an address from int format to string */
+char *iptostring(int address);
#endif
diff --git a/src/net/npchandler.cpp b/src/net/npchandler.cpp
new file mode 100644
index 00000000..a803710e
--- /dev/null
+++ b/src/net/npchandler.cpp
@@ -0,0 +1,74 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "npchandler.h"
+
+#include "messagein.h"
+#include "protocol.h"
+
+#include "../beingmanager.h"
+#include "../npc.h"
+
+#include "../gui/npclistdialog.h"
+#include "../gui/npc_text.h"
+
+extern NpcListDialog *npcListDialog;
+extern NpcTextDialog *npcTextDialog;
+
+NPCHandler::NPCHandler()
+{
+ static const Uint16 _messages[] = {
+ SMSG_NPC_CHOICE,
+ SMSG_NPC_MESSAGE,
+ SMSG_NPC_NEXT,
+ SMSG_NPC_CLOSE,
+ 0
+ };
+ handledMessages = _messages;
+}
+
+void NPCHandler::handleMessage(MessageIn *msg)
+{
+ switch (msg->getId())
+ {
+ case SMSG_NPC_CHOICE:
+ msg->readInt16(); // length
+ current_npc = dynamic_cast<NPC*>(beingManager->findBeing(msg->readInt32()));
+ npcListDialog->parseItems(msg->readString(msg->getLength() - 8));
+ npcListDialog->setVisible(true);
+ break;
+
+ case SMSG_NPC_MESSAGE:
+ msg->readInt16(); // length
+ current_npc = dynamic_cast<NPC*>(beingManager->findBeing(msg->readInt32()));
+ npcTextDialog->addText(msg->readString(msg->getLength() - 8));
+ npcListDialog->setVisible(false);
+ npcTextDialog->setVisible(true);
+ break;
+
+ case SMSG_NPC_NEXT:
+ case SMSG_NPC_CLOSE:
+ // Next/Close button in NPC dialog, currently unused
+ break;
+ }
+}
diff --git a/src/net/npchandler.h b/src/net/npchandler.h
new file mode 100644
index 00000000..903ecd10
--- /dev/null
+++ b/src/net/npchandler.h
@@ -0,0 +1,37 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_NET_NPCHANDLER_H
+#define _TMW_NET_NPCHANDLER_H
+
+#include "messagehandler.h"
+
+class NPCHandler : public MessageHandler
+{
+ public:
+ NPCHandler();
+
+ void handleMessage(MessageIn *msg);
+};
+
+#endif
diff --git a/src/net/playerhandler.cpp b/src/net/playerhandler.cpp
new file mode 100644
index 00000000..1a255e0b
--- /dev/null
+++ b/src/net/playerhandler.cpp
@@ -0,0 +1,301 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "playerhandler.h"
+
+#include "messagein.h"
+#include "protocol.h"
+
+#include "../engine.h"
+#include "../localplayer.h"
+#include "../log.h"
+#include "../npc.h"
+
+#include "../gui/chat.h"
+#include "../gui/ok_dialog.h"
+#include "../gui/skill.h"
+
+// TODO Move somewhere else
+OkDialog *weightNotice = NULL;
+OkDialog *deathNotice = NULL;
+
+/**
+ * Listener used for handling the overweigth message.
+ */
+// TODO Move somewhere else
+class WeightNoticeListener : public gcn::ActionListener
+{
+ public:
+ void action(const std::string &eventId)
+ {
+ weightNotice = NULL;
+ }
+} weightNoticeListener;
+
+
+/**
+ * Listener used for handling death message.
+ */
+// TODO Move somewhere else
+class DeathNoticeListener : public gcn::ActionListener {
+ public:
+ void action(const std::string &eventId) {
+ player_node->revive();
+ deathNotice = NULL;
+ }
+} deathNoticeListener;
+
+PlayerHandler::PlayerHandler()
+{
+ static const Uint16 _messages[] = {
+ SMSG_WALK_RESPONSE,
+ SMSG_PLAYER_WARP,
+ SMSG_PLAYER_STAT_UPDATE_1,
+ SMSG_PLAYER_STAT_UPDATE_2,
+ SMSG_PLAYER_STAT_UPDATE_3,
+ SMSG_PLAYER_STAT_UPDATE_4,
+ SMSG_PLAYER_STAT_UPDATE_5,
+ SMSG_PLAYER_STAT_UPDATE_6,
+ SMSG_PLAYER_ARROW_MESSAGE,
+ 0
+ };
+ handledMessages = _messages;
+}
+
+void PlayerHandler::handleMessage(MessageIn *msg)
+{
+ switch (msg->getId())
+ {
+ case SMSG_WALK_RESPONSE:
+ // It is assumed by the client any request to walk actually
+ // succeeds on the server. The plan is to have a correction
+ // message when the server senses the client has the wrong
+ // idea.
+ break;
+
+ case SMSG_PLAYER_WARP:
+ {
+ std::string mapPath = msg->readString(16);
+ Uint16 x = msg->readInt16();
+ Uint16 y = msg->readInt16();
+
+ logger->log("Warping to %s (%d, %d)", mapPath.c_str(), x, y);
+
+ // Switch the actual map, deleting the previous one
+ engine->changeMap(mapPath);
+
+ current_npc = 0;
+
+ player_node->action = Being::STAND;
+ player_node->stopAttack();
+ player_node->mFrame = 0;
+ player_node->x = x;
+ player_node->y = y;
+ }
+ break;
+
+ case SMSG_PLAYER_STAT_UPDATE_1:
+ {
+ Sint16 type = msg->readInt16();
+ Uint32 value = msg->readInt32();
+
+ switch (type)
+ {
+ //case 0x0000:
+ // player_node->setWalkSpeed(msg->readInt32());
+ // break;
+ case 0x0005: player_node->hp = value; break;
+ case 0x0006: player_node->maxHp = value; break;
+ case 0x0007: player_node->mp = value; break;
+ case 0x0008: player_node->maxMp = value; break;
+ case 0x000b: player_node->lvl = value; break;
+ case 0x000c:
+ player_node->skillPoint = value;
+ skillDialog->update();
+ break;
+ case 0x0018:
+ if (value >= player_node->maxWeight / 2 &&
+ player_node->totalWeight <
+ player_node->maxWeight / 2)
+ {
+ weightNotice = new OkDialog("Message",
+ "You are carrying more then half your "
+ "weight. You are unable to regain "
+ "health.",
+ &weightNoticeListener);
+ }
+ player_node->totalWeight = value;
+ break;
+ case 0x0019: player_node->maxWeight = value; break;
+ case 0x0037: player_node->jobLvl = value; break;
+ case 0x0009:
+ player_node->statsPointsToAttribute = value;
+ break;
+ case 0x0029: player_node->ATK = value; break;
+ case 0x002b: player_node->MATK = value; break;
+ case 0x002d: player_node->DEF = value; break;
+ case 0x002f: player_node->MDEF = value; break;
+ case 0x0031: player_node->HIT = value; break;
+ case 0x0032: player_node->FLEE = value; break;
+ case 0x0035: player_node->aspd = value; break;
+ }
+
+ if (player_node->hp == 0 && deathNotice == NULL)
+ {
+ deathNotice = new OkDialog("Message",
+ "You're now dead, press ok to restart",
+ &deathNoticeListener);
+ player_node->action = Being::DEAD;
+ }
+ }
+ break;
+
+ case SMSG_PLAYER_STAT_UPDATE_2:
+ switch (msg->readInt16()) {
+ case 0x0001:
+ player_node->xp = msg->readInt32();
+ break;
+ case 0x0002:
+ player_node->jobXp = msg->readInt32();
+ break;
+ case 0x0014:
+ player_node->gp = msg->readInt32();
+ break;
+ case 0x0016:
+ player_node->xpForNextLevel = msg->readInt32();
+ break;
+ case 0x0017:
+ player_node->jobXpForNextLevel = msg->readInt32();
+ break;
+ }
+ break;
+
+ case SMSG_PLAYER_STAT_UPDATE_3:
+ {
+ Sint32 type = msg->readInt32();
+ Sint32 base = msg->readInt32();
+ Sint32 bonus = msg->readInt32();
+ Sint32 total = base + bonus;
+
+ switch (type) {
+ case 0x000d: player_node->ATTR[LocalPlayer::STR] = total; break;
+ case 0x000e: player_node->ATTR[LocalPlayer::AGI] = total; break;
+ case 0x000f: player_node->ATTR[LocalPlayer::VIT] = total; break;
+ case 0x0010: player_node->ATTR[LocalPlayer::INT] = total; break;
+ case 0x0011: player_node->ATTR[LocalPlayer::DEX] = total; break;
+ case 0x0012: player_node->ATTR[LocalPlayer::LUK] = total; break;
+ }
+ }
+ break;
+
+ case SMSG_PLAYER_STAT_UPDATE_4:
+ {
+ Sint16 type = msg->readInt16();
+ Sint8 fail = msg->readInt8();
+ Sint8 value = msg->readInt8();
+
+ if (fail == 1)
+ {
+ switch (type) {
+ case 0x000d: player_node->ATTR[LocalPlayer::STR] = value; break;
+ case 0x000e: player_node->ATTR[LocalPlayer::AGI] = value; break;
+ case 0x000f: player_node->ATTR[LocalPlayer::VIT] = value; break;
+ case 0x0010: player_node->ATTR[LocalPlayer::INT] = value; break;
+ case 0x0011: player_node->ATTR[LocalPlayer::DEX] = value; break;
+ case 0x0012: player_node->ATTR[LocalPlayer::LUK] = value; break;
+ }
+ }
+ }
+ break;
+
+ // Updates stats and status points
+ case SMSG_PLAYER_STAT_UPDATE_5:
+ player_node->statsPointsToAttribute = msg->readInt16();
+ player_node->ATTR[LocalPlayer::STR] = msg->readInt8();
+ player_node->ATTR_UP[LocalPlayer::STR] = msg->readInt8();
+ player_node->ATTR[LocalPlayer::AGI] = msg->readInt8();
+ player_node->ATTR_UP[LocalPlayer::AGI] = msg->readInt8();
+ player_node->ATTR[LocalPlayer::VIT] = msg->readInt8();
+ player_node->ATTR_UP[LocalPlayer::VIT] = msg->readInt8();
+ player_node->ATTR[LocalPlayer::INT] = msg->readInt8();
+ player_node->ATTR_UP[LocalPlayer::INT] = msg->readInt8();
+ player_node->ATTR[LocalPlayer::DEX] = msg->readInt8();
+ player_node->ATTR_UP[LocalPlayer::DEX] = msg->readInt8();
+ player_node->ATTR[LocalPlayer::LUK] = msg->readInt8();
+ player_node->ATTR_UP[LocalPlayer::LUK] = msg->readInt8();
+ player_node->ATK = msg->readInt16(); // ATK
+ player_node->ATK_BONUS = msg->readInt16(); // ATK bonus
+ player_node->MATK = msg->readInt16(); // MATK max
+ player_node->MATK_BONUS = msg->readInt16(); // MATK min
+ player_node->DEF = msg->readInt16(); // DEF
+ player_node->DEF_BONUS = msg->readInt16(); // DEF bonus
+ player_node->MDEF = msg->readInt16(); // MDEF
+ player_node->MDEF_BONUS = msg->readInt16(); // MDEF bonus
+ player_node->HIT = msg->readInt16(); // HIT
+ player_node->FLEE = msg->readInt16(); // FLEE
+ player_node->FLEE_BONUS = msg->readInt16(); // FLEE bonus
+ msg->readInt16(); // critical
+ msg->readInt16(); // unknown
+ break;
+
+ case SMSG_PLAYER_STAT_UPDATE_6:
+ switch (msg->readInt16()) {
+ case 0x0020: player_node->ATTR_UP[LocalPlayer::STR] = msg->readInt8(); break;
+ case 0x0021: player_node->ATTR_UP[LocalPlayer::AGI] = msg->readInt8(); break;
+ case 0x0022: player_node->ATTR_UP[LocalPlayer::VIT] = msg->readInt8(); break;
+ case 0x0023: player_node->ATTR_UP[LocalPlayer::INT] = msg->readInt8(); break;
+ case 0x0024: player_node->ATTR_UP[LocalPlayer::DEX] = msg->readInt8(); break;
+ case 0x0025: player_node->ATTR_UP[LocalPlayer::LUK] = msg->readInt8(); break;
+ }
+ break;
+
+ case SMSG_PLAYER_ARROW_MESSAGE:
+ {
+ Sint16 type = msg->readInt16();
+
+ switch (type) {
+ case 0:
+ chatWindow->chatLog("Equip arrows first",
+ BY_SERVER);
+ break;
+ default:
+ logger->log("0x013b: Unhandled message %i", type);
+ break;
+ }
+ }
+ break;
+
+ //Stop walking
+ //case 0x0088: // Disabled because giving some problems
+ //if (being = beingManager->findBeing(readInt32(2))) {
+ // if (being->getId() != player_node->getId()) {
+ // being->action = STAND;
+ // being->mFrame = 0;
+ // set_coordinates(being->coordinates,
+ // readWord(6), readWord(8),
+ // get_direction(being->coordinates));
+ // }
+ //}
+ //break;
+ }
+}
diff --git a/src/net/playerhandler.h b/src/net/playerhandler.h
new file mode 100644
index 00000000..b28a23f5
--- /dev/null
+++ b/src/net/playerhandler.h
@@ -0,0 +1,37 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_NET_PLAYERHANDLER_H
+#define _TMW_NET_PLAYERHANDLER_H
+
+#include "messagehandler.h"
+
+class PlayerHandler : public MessageHandler
+{
+ public:
+ PlayerHandler();
+
+ void handleMessage(MessageIn *msg);
+};
+
+#endif
diff --git a/src/net/protocol.cpp b/src/net/protocol.cpp
index 28663827..5de1b0cf 100644
--- a/src/net/protocol.cpp
+++ b/src/net/protocol.cpp
@@ -23,14 +23,6 @@
#include "protocol.h"
-#include "messageout.h"
-
-#include "../being.h"
-#include "../game.h"
-#include "../main.h"
-#include "../playerinfo.h"
-#include "../sound.h"
-
#define LOBYTE(w) ((unsigned char)(w))
#define HIBYTE(w) ((unsigned char)(((unsigned short)(w)) >> 8))
@@ -64,101 +56,3 @@ void set_coordinates(char *data,
data[2] = LOBYTE(temp);
data[2] |= direction;
}
-
-void walk(unsigned short x, unsigned short y, unsigned char direction)
-{
- char temp[3];
- MessageOut outMsg;
- set_coordinates(temp, x, y, direction);
- outMsg.writeInt16(0x0085);
- outMsg.writeString(temp, 3);
-}
-
-void action(char type, int id)
-{
- MessageOut outMsg;
- outMsg.writeInt16(0x0089);
- outMsg.writeInt32(id);
- outMsg.writeInt8(type);
-}
-
-void talk(Being *being)
-{
- MessageOut outMsg;
- outMsg.writeInt16(CMSG_NPC_TALK);
- outMsg.writeInt32(being->getId());
- outMsg.writeInt8(0);
-}
-
-void pickUp(Uint32 floorItemId)
-{
- MessageOut outMsg;
- outMsg.writeInt16(CMSG_ITEM_PICKUP);
- outMsg.writeInt32(floorItemId);
-}
-
-Being* attack(unsigned short x, unsigned short y, unsigned char direction)
-{
- Being *target = NULL;
-
- switch (direction)
- {
- case Being::SOUTH:
- target = findNode(x, y + 1, Being::MONSTER);
- if (!target) target = findNode(x, y + 1, Being::PLAYER);
- break;
-
- case Being::WEST:
- target = findNode(x - 1, y, Being::MONSTER);
- if (!target) target = findNode(x - 1, y, Being::PLAYER);
- break;
-
- case Being::NORTH:
- target = findNode(x, y - 1, Being::MONSTER);
- if (!target) target = findNode(x, y - 1, Being::PLAYER);
- break;
-
- case Being::EAST:
- target = findNode(x + 1, y, Being::MONSTER);
- if (!target) target = findNode(x + 1, y, Being::PLAYER);
- break;
- }
-
- if (target) {
- attack(target);
- }
-
- return target;
-}
-
-void attack(Being *target)
-{
- int dist_x = target->x - player_node->x;
- int dist_y = target->y - player_node->y;
-
- if (abs(dist_y) >= abs(dist_x))
- {
- if (dist_y > 0)
- player_node->direction = Being::SOUTH;
- else
- player_node->direction = Being::NORTH;
- }
- else
- {
- if (dist_x > 0)
- player_node->direction = Being::EAST;
- else
- player_node->direction = Being::WEST;
- }
-
- // Implement charging attacks here
- player_info->lastAttackTime = 0;
-
- player_node->action = Being::ATTACK;
- action(0, target->getId());
- player_node->walk_time = tick_time;
- if (player_node->getWeapon() == 2)
- sound.playSfx("sfx/bow_shoot_1.ogg");
- else
- sound.playSfx("sfx/fist-swish.ogg");
-}
diff --git a/src/net/protocol.h b/src/net/protocol.h
index e7d6f286..716aa0f9 100644
--- a/src/net/protocol.h
+++ b/src/net/protocol.h
@@ -24,10 +24,6 @@
#ifndef _TMW_PROTOCOL_
#define _TMW_PROTOCOL_
-#include <SDL_types.h>
-
-class Being;
-
// Packets from server to client
#define SMSG_LOGIN_SUCCESS 0x0073 /**< Contains starting location */
#define SMSG_PLAYER_UPDATE_1 0x01d8
@@ -108,7 +104,6 @@ class Being;
#define CMSG_PLAYER_EQUIP 0x00a9
#define CMSG_PLAYER_UNEQUIP 0x00ab
-
/** Decodes src direction */
unsigned char get_src_direction(char data);
@@ -118,22 +113,4 @@ unsigned char get_dest_direction(char data);
/** Encodes coords and direction in 3 bytes data */
void set_coordinates(char *data, unsigned short x, unsigned short y, unsigned char direction);
-/** Requests to walk */
-void walk(unsigned short x, unsigned short y, unsigned char direction);
-
-/** Request to attack */
-Being* attack(unsigned short x, unsigned short y, unsigned char direction);
-
-/** Request to attack */
-void attack(Being *target);
-
-/** Request action */
-void action(char type, int id);
-
-/** Talk to a being */
-void talk(Being *being);
-
-/** Pick up an item */
-void pickUp(Uint32 floorItemId);
-
#endif
diff --git a/src/net/skillhandler.cpp b/src/net/skillhandler.cpp
new file mode 100644
index 00000000..e9dc9c19
--- /dev/null
+++ b/src/net/skillhandler.cpp
@@ -0,0 +1,93 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "skillhandler.h"
+
+#include "messagein.h"
+#include "protocol.h"
+
+#include "../gui/chat.h"
+#include "../gui/skill.h"
+
+SkillHandler::SkillHandler()
+{
+ static const Uint16 _messages[] = {
+ SMSG_PLAYER_SKILLS,
+ SMSG_SKILL_FAILED,
+ 0
+ };
+ handledMessages = _messages;
+}
+
+void SkillHandler::handleMessage(MessageIn *msg)
+{
+ int skillCount;
+
+ switch (msg->getId())
+ {
+ case SMSG_PLAYER_SKILLS:
+ msg->readInt16(); // length
+ skillCount = (msg->getLength() - 4) / 37;
+ skillDialog->cleanList();
+
+ for (int k = 0; k < skillCount; k++)
+ {
+ Sint16 skillId = msg->readInt16();
+ msg->readInt16(); // target type
+ msg->readInt16(); // unknown
+ Sint16 level = msg->readInt16();
+ Sint16 sp = msg->readInt16();
+ msg->readInt16(); // range
+ std::string skillName = msg->readString(24);
+ Sint8 up = msg->readInt8();
+
+ if (level != 0 || up != 0)
+ {
+ if (skillDialog->hasSkill(skillId)) {
+ skillDialog->setSkill(skillId, level, sp);
+ }
+ else {
+ skillDialog->addSkill(skillId, level, sp);
+ }
+ }
+ }
+ break;
+
+ case SMSG_SKILL_FAILED:
+ // Action failed (ex. sit because you have not reached the
+ // right level)
+ CHATSKILL action;
+ action.skill = msg->readInt16();
+ action.bskill = msg->readInt16();
+ action.unused = msg->readInt16(); // unknown
+ action.success = msg->readInt8();
+ action.reason = msg->readInt8();
+ if (action.success != SKILL_FAILED &&
+ action.bskill == BSKILL_EMOTE)
+ {
+ printf("Action: %d/%d", action.bskill, action.success);
+ }
+ chatWindow->chatLog(action);
+ break;
+ }
+}
diff --git a/src/net/skillhandler.h b/src/net/skillhandler.h
new file mode 100644
index 00000000..820a7b6a
--- /dev/null
+++ b/src/net/skillhandler.h
@@ -0,0 +1,37 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_NET_SKILLHANDLER_H
+#define _TMW_NET_SKILLHANDLER_H
+
+#include "messagehandler.h"
+
+class SkillHandler : public MessageHandler
+{
+ public:
+ SkillHandler();
+
+ void handleMessage(MessageIn *msg);
+};
+
+#endif
diff --git a/src/net/tradehandler.cpp b/src/net/tradehandler.cpp
new file mode 100644
index 00000000..6ed3bab2
--- /dev/null
+++ b/src/net/tradehandler.cpp
@@ -0,0 +1,179 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "tradehandler.h"
+
+#include "messagein.h"
+#include "protocol.h"
+
+#include "../item.h"
+#include "../localplayer.h"
+
+#include "../gui/chat.h"
+#include "../gui/requesttrade.h"
+#include "../gui/trade.h"
+
+std::string tradePartnerName;
+
+TradeHandler::TradeHandler()
+{
+ static const Uint16 _messages[] = {
+ SMSG_TRADE_REQUEST,
+ SMSG_TRADE_RESPONSE,
+ SMSG_TRADE_ITEM_ADD,
+ SMSG_TRADE_ITEM_ADD_RESPONSE,
+ SMSG_TRADE_OK,
+ SMSG_TRADE_CANCEL,
+ SMSG_TRADE_COMPLETE,
+ 0
+ };
+ handledMessages = _messages;
+}
+
+void TradeHandler::handleMessage(MessageIn *msg)
+{
+ switch (msg->getId())
+ {
+ case SMSG_TRADE_REQUEST:
+ // If a trade window or request window is already open, send a
+ // trade cancel to any other trade request.
+ //
+ // Note that it would be nice if the server would prevent this
+ // situation, and that the requesting player would get a
+ // special message about the player being occupied.
+ if (!player_node->tradeRequestOk())
+ {
+ player_node->tradeReply(false);
+ break;
+ }
+
+ player_node->setTrading(true);
+ tradePartnerName = msg->readString(24);
+ new RequestTradeDialog(tradePartnerName);
+ break;
+
+ case SMSG_TRADE_RESPONSE:
+ switch (msg->readInt8())
+ {
+ case 0: // Too far away
+ chatWindow->chatLog("Trading isn't possible. "
+ "Trade partner is too far away.",
+ BY_SERVER);
+ break;
+ case 1: // Character doesn't exist
+ chatWindow->chatLog("Trading isn't possible. "
+ "Character doesn't exist.",
+ BY_SERVER);
+ break;
+ case 2: // Invite request check failed...
+ chatWindow->chatLog("Trade cancelled due to an "
+ "unknown reason.", BY_SERVER);
+ break;
+ case 3: // Trade accepted
+ tradeWindow->reset();
+ tradeWindow->setCaption(
+ "Trade: You and " + tradePartnerName);
+ tradeWindow->setVisible(true);
+ break;
+ case 4: // Trade cancelled
+ chatWindow->chatLog("Trade cancelled.", BY_SERVER);
+ tradeWindow->setVisible(false);
+ player_node->setTrading(false);
+ break;
+ default: // Shouldn't happen as well, but to be sure
+ chatWindow->chatLog("Unhandled trade cancel packet",
+ BY_SERVER);
+ break;
+ }
+ break;
+
+ case SMSG_TRADE_ITEM_ADD:
+ {
+ Sint32 amount = msg->readInt32();
+ Sint16 type = msg->readInt16();
+ msg->readInt8(); // identified flag
+ msg->readInt8(); // attribute
+ msg->readInt8(); // refine
+ msg->skip(8); // card (4 shorts)
+
+ // TODO: handle also identified, etc
+ if (type == 0) {
+ tradeWindow->addMoney(amount);
+ } else {
+ tradeWindow->addItem(type, false, amount, false);
+ }
+ }
+ break;
+
+ case SMSG_TRADE_ITEM_ADD_RESPONSE:
+ // Trade: New Item add response (was 0x00ea, now 01b1)
+ {
+ Item *item = player_node->getInvItem(msg->readInt16());
+ Sint16 quantity = msg->readInt16();
+
+ switch (msg->readInt8())
+ {
+ case 0:
+ // Successfully added item
+ if (item->isEquipment() && item->isEquipped())
+ {
+ player_node->unequipItem(item);
+ }
+ tradeWindow->addItem(item->getId(), true, quantity,
+ item->isEquipment());
+ item->increaseQuantity(-quantity);
+ break;
+ case 1:
+ // Add item failed - player overweighted
+ chatWindow->chatLog("Failed adding item. Trade "
+ "partner is over weighted.",
+ BY_SERVER);
+ break;
+ default:
+ chatWindow->chatLog("Failed adding item for "
+ "unknown reason.", BY_SERVER);
+ break;
+ }
+ }
+ break;
+
+ case SMSG_TRADE_OK:
+ // 0 means ok from myself, 1 means ok from other;
+ tradeWindow->receivedOk(msg->readInt8() == 0);
+ break;
+
+ case SMSG_TRADE_CANCEL:
+ chatWindow->chatLog("Trade canceled.", BY_SERVER);
+ tradeWindow->setVisible(false);
+ tradeWindow->reset();
+ player_node->setTrading(false);
+ break;
+
+ case SMSG_TRADE_COMPLETE:
+ chatWindow->chatLog("Trade completed.", BY_SERVER);
+ tradeWindow->setVisible(false);
+ tradeWindow->reset();
+ player_node->setTrading(false);
+ break;
+ }
+}
diff --git a/src/net/tradehandler.h b/src/net/tradehandler.h
new file mode 100644
index 00000000..a1971004
--- /dev/null
+++ b/src/net/tradehandler.h
@@ -0,0 +1,39 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_NET_TRADEHANDLER_H
+#define _TMW_NET_TRADEHANDLER_H
+
+#include "messagehandler.h"
+
+class Network;
+
+class TradeHandler : public MessageHandler
+{
+ public:
+ TradeHandler();
+
+ void handleMessage(MessageIn *msg);
+};
+
+#endif