summaryrefslogtreecommitdiff
path: root/src/net
diff options
context:
space:
mode:
Diffstat (limited to 'src/net')
-rw-r--r--src/net/adminhandler.h4
-rw-r--r--src/net/charhandler.h16
-rw-r--r--src/net/chathandler.h4
-rw-r--r--src/net/download.cpp6
-rw-r--r--src/net/download.h6
-rw-r--r--src/net/gamehandler.h15
-rw-r--r--src/net/generalhandler.h9
-rw-r--r--src/net/guildhandler.h5
-rw-r--r--src/net/inventoryhandler.h23
-rw-r--r--src/net/logindata.h24
-rw-r--r--src/net/manaserv/adminhandler.cpp2
-rw-r--r--src/net/manaserv/attributes.cpp408
-rw-r--r--src/net/manaserv/attributes.h (renamed from src/net/manaserv/stats.h)41
-rw-r--r--src/net/manaserv/beinghandler.cpp171
-rw-r--r--src/net/manaserv/beinghandler.h8
-rw-r--r--src/net/manaserv/buysellhandler.cpp16
-rw-r--r--src/net/manaserv/charhandler.cpp79
-rw-r--r--src/net/manaserv/charhandler.h18
-rw-r--r--src/net/manaserv/chathandler.cpp55
-rw-r--r--src/net/manaserv/connection.cpp4
-rw-r--r--src/net/manaserv/defines.h76
-rw-r--r--src/net/manaserv/effecthandler.cpp50
-rw-r--r--src/net/manaserv/effecthandler.h1
-rw-r--r--src/net/manaserv/gamehandler.cpp20
-rw-r--r--src/net/manaserv/gamehandler.h9
-rw-r--r--src/net/manaserv/generalhandler.cpp64
-rw-r--r--src/net/manaserv/generalhandler.h10
-rw-r--r--src/net/manaserv/guildhandler.cpp21
-rw-r--r--src/net/manaserv/guildhandler.h2
-rw-r--r--src/net/manaserv/inventoryhandler.cpp331
-rw-r--r--src/net/manaserv/inventoryhandler.h71
-rw-r--r--src/net/manaserv/itemhandler.cpp29
-rw-r--r--src/net/manaserv/loginhandler.cpp47
-rw-r--r--src/net/manaserv/loginhandler.h6
-rw-r--r--src/net/manaserv/manaserv_protocol.h (renamed from src/net/manaserv/protocol.h)135
-rw-r--r--src/net/manaserv/messagein.cpp9
-rw-r--r--src/net/manaserv/messagein.h7
-rw-r--r--src/net/manaserv/messageout.cpp7
-rw-r--r--src/net/manaserv/messageout.h12
-rw-r--r--src/net/manaserv/network.cpp8
-rw-r--r--src/net/manaserv/npchandler.cpp248
-rw-r--r--src/net/manaserv/npchandler.h40
-rw-r--r--src/net/manaserv/partyhandler.cpp97
-rw-r--r--src/net/manaserv/partyhandler.h4
-rw-r--r--src/net/manaserv/playerhandler.cpp149
-rw-r--r--src/net/manaserv/playerhandler.h7
-rw-r--r--src/net/manaserv/specialhandler.cpp2
-rw-r--r--src/net/manaserv/stats.cpp217
-rw-r--r--src/net/manaserv/tradehandler.cpp29
-rw-r--r--src/net/messagehandler.h4
-rw-r--r--src/net/messagein.cpp24
-rw-r--r--src/net/messagein.h35
-rw-r--r--src/net/messageout.cpp7
-rw-r--r--src/net/messageout.h27
-rw-r--r--src/net/net.cpp10
-rw-r--r--src/net/npchandler.h29
-rw-r--r--src/net/partyhandler.h10
-rw-r--r--src/net/playerhandler.h25
-rw-r--r--src/net/specialhandler.h4
-rw-r--r--src/net/tmwa/adminhandler.cpp16
-rw-r--r--src/net/tmwa/beinghandler.cpp326
-rw-r--r--src/net/tmwa/buysellhandler.cpp33
-rw-r--r--src/net/tmwa/charserverhandler.cpp65
-rw-r--r--src/net/tmwa/charserverhandler.h8
-rw-r--r--src/net/tmwa/chathandler.cpp122
-rw-r--r--src/net/tmwa/chathandler.h6
-rw-r--r--src/net/tmwa/gamehandler.cpp58
-rw-r--r--src/net/tmwa/gamehandler.h23
-rw-r--r--src/net/tmwa/generalhandler.cpp103
-rw-r--r--src/net/tmwa/generalhandler.h14
-rw-r--r--src/net/tmwa/gui/guildtab.cpp10
-rw-r--r--src/net/tmwa/gui/guildtab.h2
-rw-r--r--src/net/tmwa/gui/partytab.cpp10
-rw-r--r--src/net/tmwa/gui/partytab.h2
-rw-r--r--src/net/tmwa/guildhandler.cpp10
-rw-r--r--src/net/tmwa/guildhandler.h2
-rw-r--r--src/net/tmwa/inventoryhandler.cpp240
-rw-r--r--src/net/tmwa/inventoryhandler.h51
-rw-r--r--src/net/tmwa/itemhandler.cpp20
-rw-r--r--src/net/tmwa/loginhandler.cpp2
-rw-r--r--src/net/tmwa/messagehandler.h2
-rw-r--r--src/net/tmwa/messagein.cpp24
-rw-r--r--src/net/tmwa/messagein.h8
-rw-r--r--src/net/tmwa/messageout.cpp41
-rw-r--r--src/net/tmwa/messageout.h16
-rw-r--r--src/net/tmwa/npchandler.cpp250
-rw-r--r--src/net/tmwa/npchandler.h39
-rw-r--r--src/net/tmwa/partyhandler.cpp48
-rw-r--r--src/net/tmwa/partyhandler.h4
-rw-r--r--src/net/tmwa/playerhandler.cpp306
-rw-r--r--src/net/tmwa/playerhandler.h7
-rw-r--r--src/net/tmwa/protocol.h14
-rw-r--r--src/net/tmwa/specialhandler.cpp13
-rw-r--r--src/net/tmwa/token.h2
-rw-r--r--src/net/tmwa/tradehandler.cpp66
-rw-r--r--src/net/tradehandler.h4
96 files changed, 2752 insertions, 2012 deletions
diff --git a/src/net/adminhandler.h b/src/net/adminhandler.h
index 23e9abc0..3ed96dbd 100644
--- a/src/net/adminhandler.h
+++ b/src/net/adminhandler.h
@@ -29,6 +29,8 @@ namespace Net {
class AdminHandler
{
public:
+ virtual ~AdminHandler() {}
+
virtual void announce(const std::string &text) = 0;
virtual void localAnnounce(const std::string &text) = 0;
@@ -49,8 +51,6 @@ class AdminHandler
virtual void mute(int playerId, int type, int limit) = 0;
- virtual ~AdminHandler() {}
-
// TODO
};
diff --git a/src/net/charhandler.h b/src/net/charhandler.h
index 4a813e21..0694e39e 100644
--- a/src/net/charhandler.h
+++ b/src/net/charhandler.h
@@ -23,14 +23,13 @@
#define CHARHANDLER_H
#include "localplayer.h"
-#include "logindata.h"
+#include "playerinfo.h"
#include <iosfwd>
#include <vector>
class CharCreateDialog;
class CharSelectDialog;
-class LocalPlayer;
namespace Net {
@@ -41,7 +40,7 @@ struct Character
{
Character() :
slot(0),
- dummy(new LocalPlayer)
+ dummy(0)
{
}
@@ -52,6 +51,7 @@ struct Character
int slot; /**< The index in the list of characters */
LocalPlayer *dummy; /**< A dummy representing this character */
+ PlayerInfoBackend data;
};
typedef std::list<Character*> Characters;
@@ -59,6 +59,8 @@ typedef std::list<Character*> Characters;
class CharHandler
{
public:
+ virtual ~CharHandler() {}
+
virtual void setCharSelectDialog(CharSelectDialog *window) = 0;
virtual void setCharCreateDialog(CharCreateDialog *window) = 0;
@@ -75,13 +77,11 @@ class CharHandler
virtual void switchCharacter() = 0;
- virtual int baseSprite() const = 0;
+ virtual unsigned int baseSprite() const = 0;
- virtual int hairSprite() const = 0;
+ virtual unsigned int hairSprite() const = 0;
- virtual int maxSprite() const = 0;
-
- virtual ~CharHandler() {}
+ virtual unsigned int maxSprite() const = 0;
protected:
CharHandler():
diff --git a/src/net/chathandler.h b/src/net/chathandler.h
index d1449698..fbaa8dba 100644
--- a/src/net/chathandler.h
+++ b/src/net/chathandler.h
@@ -28,6 +28,8 @@ namespace Net {
class ChatHandler
{
public:
+ virtual ~ChatHandler() {}
+
virtual void talk(const std::string &text) = 0;
virtual void me(const std::string &text) = 0;
@@ -53,8 +55,6 @@ class ChatHandler
virtual void kickUser(int channelId, const std::string &name) = 0;
virtual void who() = 0;
-
- virtual ~ChatHandler() {}
};
}
diff --git a/src/net/download.cpp b/src/net/download.cpp
index a2cd4910..b6d75b71 100644
--- a/src/net/download.cpp
+++ b/src/net/download.cpp
@@ -100,7 +100,7 @@ void Download::noCache()
addHeader("Cache-Control: no-cache");
}
-void Download::setFile(const std::string &filename, Sint64 adler32)
+void Download::setFile(const std::string &filename, int64_t adler32)
{
mOptions.memoryWrite = false;
mFileName = filename;
@@ -221,8 +221,8 @@ int Download::downloadThread(void *ptr)
}
curl_easy_setopt(d->mCurl, CURLOPT_USERAGENT,
- strprintf(PACKAGE_EXTENDED_VERSION, branding
- .getValue("appShort", "mana").c_str()).c_str());
+ strprintf(PACKAGE_EXTENDED_VERSION,
+ branding.getStringValue("appShort").c_str()).c_str());
curl_easy_setopt(d->mCurl, CURLOPT_ERRORBUFFER, d->mError);
curl_easy_setopt(d->mCurl, CURLOPT_URL, d->mUrl.c_str());
curl_easy_setopt(d->mCurl, CURLOPT_NOPROGRESS, 0);
diff --git a/src/net/download.h b/src/net/download.h
index 216f6ff2..62110918 100644
--- a/src/net/download.h
+++ b/src/net/download.h
@@ -18,9 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <SDL_types.h>
-
-#include <stdio.h>
+#include <cstdio>
#include <string>
#ifndef NET_DOWNLOAD_H
@@ -62,7 +60,7 @@ class Download
*/
void noCache();
- void setFile(const std::string &filename, Sint64 adler32 = -1);
+ void setFile(const std::string &filename, int64_t adler32 = -1);
void setWriteFunction(WriteFunction write);
diff --git a/src/net/gamehandler.h b/src/net/gamehandler.h
index 774de16c..2c430033 100644
--- a/src/net/gamehandler.h
+++ b/src/net/gamehandler.h
@@ -22,8 +22,6 @@
#ifndef MAPHANDLER_H
#define MAPHANDLER_H
-#include "logindata.h"
-
#include <iosfwd>
namespace Net {
@@ -31,25 +29,24 @@ namespace Net {
class GameHandler
{
public:
+ virtual ~GameHandler() {}
+
virtual void connect() = 0;
virtual bool isConnected() = 0;
virtual void disconnect() = 0;
- virtual void inGame() = 0;
-
- virtual void mapLoaded(const std::string &mapName) = 0;
-
virtual void who() = 0;
virtual void quit() = 0;
- virtual void ping(int tick) = 0;
-
virtual bool removeDeadBeings() const = 0;
- virtual ~GameHandler() {}
+ /**
+ * Tells whether the protocol is using the MP status bar
+ */
+ virtual bool canUseMagicBar() const = 0;
};
} // namespace Net
diff --git a/src/net/generalhandler.h b/src/net/generalhandler.h
index 222b430a..4b8474dd 100644
--- a/src/net/generalhandler.h
+++ b/src/net/generalhandler.h
@@ -19,9 +19,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "client.h"
-#include "main.h"
-
#ifndef GENERALHANDLER_H
#define GENERALHANDLER_H
@@ -40,13 +37,7 @@ class GeneralHandler
virtual void flushNetwork() = 0;
- virtual void guiWindowsLoaded() = 0;
-
- virtual void guiWindowsUnloaded() = 0;
-
virtual void clearHandlers() = 0;
-
- virtual void stateChanged(State oldState, State newState) = 0;
};
} // namespace Net
diff --git a/src/net/guildhandler.h b/src/net/guildhandler.h
index 1696b2d5..e4513cbb 100644
--- a/src/net/guildhandler.h
+++ b/src/net/guildhandler.h
@@ -23,10 +23,11 @@
#define GUILDHANDLER_H
#include "guild.h"
-#include "player.h"
#include <iosfwd>
+class Being;
+
namespace Net {
class GuildHandler
@@ -40,7 +41,7 @@ class GuildHandler
virtual void invite(int guildId, const std::string &name) = 0;
- virtual void invite(int guildId, Player *player) = 0;
+ virtual void invite(int guildId, Being *being) = 0;
virtual void inviteResponse(int guildId, bool response) = 0;
diff --git a/src/net/inventoryhandler.h b/src/net/inventoryhandler.h
index e48043a7..93b56a40 100644
--- a/src/net/inventoryhandler.h
+++ b/src/net/inventoryhandler.h
@@ -32,33 +32,12 @@ namespace Net {
class InventoryHandler
{
public:
- virtual void equipItem(const Item *item) = 0;
-
- virtual void unequipItem(const Item *item) = 0;
-
- virtual void useItem(const Item *item) = 0;
-
- virtual void dropItem(const Item *item, int amount) = 0;
+ virtual ~InventoryHandler() {}
virtual bool canSplit(const Item *item) = 0;
- virtual void splitItem(const Item *item, int amount) = 0;
-
- virtual void moveItem(int oldIndex, int newIndex) = 0;
-
- virtual void openStorage(int type) = 0;
-
- virtual void closeStorage(int type) = 0;
-
- //void changeCart() = 0;
-
- virtual void moveItem(int source, int slot, int amount,
- int destination) = 0;
-
// TODO: fix/remove me
virtual size_t getSize(int type) const = 0;
-
- virtual ~InventoryHandler() {}
};
} // namespace Net
diff --git a/src/net/logindata.h b/src/net/logindata.h
index 9bbeed4f..b842bdfd 100644
--- a/src/net/logindata.h
+++ b/src/net/logindata.h
@@ -1,7 +1,7 @@
/*
* The Mana Client
* Copyright (C) 2004-2009 The Mana World Development Team
- * Copyright (C) 2009-2010 The Mana Developers
+ * Copyright (C) 2009-2011 The Mana Developers
*
* This file is part of The Mana Client.
*
@@ -22,17 +22,21 @@
#ifndef LOGINDATA_H
#define LOGINDATA_H
-#include "player.h"
-
-#include "net/serverinfo.h"
+#include "being.h"
#include <string>
class LoginData
{
public:
+ LoginData()
+ {
+ characterSlots = 3;
+ }
+
std::string username;
std::string password;
+ std::string randomSeed;
std::string newPassword;
std::string updateHost;
@@ -44,15 +48,27 @@ public:
bool remember; /**< Whether to store the username. */
bool registerLogin; /**< Whether an account is being registered. */
+ unsigned short characterSlots; /**< The number of character slots */
+
+ /**
+ * Initialize character slots to 3 for backwards compatibility
+ */
+ void resetCharacterSlots()
+ {
+ characterSlots = 3;
+ }
+
void clear()
{
username.clear();
password.clear();
+ randomSeed.clear();
newPassword.clear();
updateHost.clear();
email.clear();
captchaResponse.clear();
gender = GENDER_UNSPECIFIED;
+ resetCharacterSlots();
}
};
diff --git a/src/net/manaserv/adminhandler.cpp b/src/net/manaserv/adminhandler.cpp
index 8a30e01b..db6c22ed 100644
--- a/src/net/manaserv/adminhandler.cpp
+++ b/src/net/manaserv/adminhandler.cpp
@@ -23,7 +23,7 @@
#include "net/manaserv/connection.h"
#include "net/manaserv/messageout.h"
-#include "net/manaserv/protocol.h"
+#include "net/manaserv/manaserv_protocol.h"
extern Net::AdminHandler *adminHandler;
diff --git a/src/net/manaserv/attributes.cpp b/src/net/manaserv/attributes.cpp
new file mode 100644
index 00000000..e57c6278
--- /dev/null
+++ b/src/net/manaserv/attributes.cpp
@@ -0,0 +1,408 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "net/manaserv/attributes.h"
+
+#include "log.h"
+#include "playerinfo.h"
+
+#include "gui/statuswindow.h"
+
+#include "resources/itemdb.h"
+
+#include "utils/gettext.h"
+#include "utils/stringutils.h"
+#include "utils/xml.h"
+
+#include <list>
+#include <map>
+
+#define DEFAULT_ATTRIBUTESDB_FILE "attributes.xml"
+#define DEFAULT_POINTS 60
+#define DEFAULT_MIN_PTS 1
+#define DEFAULT_MAX_PTS 20
+
+namespace ManaServ {
+namespace Attributes {
+
+ typedef struct
+ {
+ unsigned int id;
+ std::string name;
+ std::string description;
+ /** Whether the attribute value can be modified by the player */
+ bool modifiable;
+ /**< Attribute scope. */
+ std::string scope;
+ /** The playerInfo core Id the attribute is linked with or -1 if not */
+ int playerInfoId;
+ } Attribute;
+
+ /** Map for attributes. */
+ typedef std::map<unsigned int, Attribute> AttributeMap;
+ static AttributeMap attributes;
+
+ /** tags = effects on attributes. */
+ typedef std::map< std::string, std::string > TagMap;
+ static TagMap tags;
+
+ /** List of modifiable attribute names used at character's creation. */
+ static std::vector<std::string> attributeLabels;
+
+ /** Characters creation points. */
+ static unsigned int creationPoints = 0;
+ static unsigned int attributeMinimum = 0;
+ static unsigned int attributeMaximum = 0;
+
+ unsigned int getCreationPoints()
+ {
+ return creationPoints;
+ }
+
+ unsigned int getAttributeMinimum()
+ {
+ return attributeMinimum;
+ }
+
+ unsigned int getAttributeMaximum()
+ {
+ return attributeMaximum;
+ }
+
+ std::vector<std::string>& getLabels()
+ {
+ return attributeLabels;
+ }
+
+ /**
+ * Fills the list of base attribute labels.
+ */
+ static void fillLabels()
+ {
+ // Fill up the modifiable attribute label list.
+ attributeLabels.clear();
+ AttributeMap::const_iterator it, it_end;
+ for (it = attributes.begin(), it_end = attributes.end(); it != it_end;
+ it++)
+ {
+ if (it->second.modifiable &&
+ (it->second.scope == "character" || it->second.scope == "being"))
+ attributeLabels.push_back(it->second.name + ":");
+ }
+ }
+
+ /**
+ * Fills the list of base attribute labels.
+ */
+ static int getPlayerInfoIdFromAttrType(std::string attrType)
+ {
+ toLower(attrType);
+ if (attrType == "level")
+ return ::LEVEL;
+ else if (attrType == "hp")
+ return ::HP;
+ else if (attrType == "max-hp")
+ return ::MAX_HP;
+ else if (attrType == "mp")
+ return ::MP;
+ else if (attrType == "max-mp")
+ return ::MAX_MP;
+ else if (attrType == "exp")
+ return ::EXP;
+ else if (attrType == "exp-needed")
+ return ::EXP_NEEDED;
+ else if (attrType == "money")
+ return ::MONEY;
+ else if (attrType == "total-weight")
+ return ::TOTAL_WEIGHT;
+ else if (attrType == "max-weight")
+ return ::MAX_WEIGHT;
+ else if (attrType == "skill-points")
+ return ::SKILL_POINTS;
+ else if (attrType == "char-points")
+ return ::CHAR_POINTS;
+ else if (attrType == "corr-points")
+ return ::CORR_POINTS;
+ else if (attrType == "none")
+ return -2; // Used to hide the attribute display.
+
+ return -1; // Not linked to a playerinfo stat.
+ }
+
+ int getPlayerInfoIdFromAttrId(int attrId)
+ {
+ AttributeMap::const_iterator it = attributes.find(attrId);
+
+ if (it != attributes.end())
+ {
+ return it->second.playerInfoId;
+ }
+
+ return -1;
+ }
+
+ static void loadBuiltins()
+ {
+ {
+ Attribute a;
+ a.id = 16;
+ a.name = _("Strength");
+ a.description = "";
+ a.modifiable = true;
+ a.scope = "character";
+ a.playerInfoId = -1;
+
+ attributes[a.id] = a;
+ tags.insert(std::make_pair("str", _("Strength %+.1f")));
+ }
+
+ {
+ Attribute a;
+ a.id = 17;
+ a.name = _("Agility");
+ a.description = "";
+ a.modifiable = true;
+ a.scope = "character";
+ a.playerInfoId = -1;
+
+ attributes[a.id] = a;
+ tags.insert(std::make_pair("agi", _("Agility %+.1f")));
+ }
+
+ {
+ Attribute a;
+ a.id = 18;
+ a.name = _("Dexterity");
+ a.description = "";
+ a.modifiable = true;
+ a.scope = "character";
+ a.playerInfoId = -1;
+
+ attributes[a.id] = a;
+ tags.insert(std::make_pair("dex", _("Dexterity %+.1f")));
+ }
+
+ {
+ Attribute a;
+ a.id = 19;
+ a.name = _("Vitality");
+ a.description = "";
+ a.modifiable = true;
+ a.scope = "character";
+ a.playerInfoId = -1;
+
+ attributes[a.id] = a;
+ tags.insert(std::make_pair("vit", _("Vitality %+.1f")));
+ }
+
+ {
+ Attribute a;
+ a.id = 20;
+ a.name = _("Intelligence");
+ a.description = "";
+ a.modifiable = true;
+ a.scope = "character";
+ a.playerInfoId = -1;
+
+ attributes[a.id] = a;
+ tags.insert(std::make_pair("int", _("Intelligence %+.1f")));
+ }
+
+ {
+ Attribute a;
+ a.id = 21;
+ a.name = _("Willpower");
+ a.description = "";
+ a.modifiable = true;
+ a.scope = "character";
+ a.playerInfoId = -1;
+
+ attributes[a.id] = a;
+ tags.insert(std::make_pair("wil", _("Willpower %+.1f")));
+ }
+ }
+
+ void load()
+ {
+ logger->log("Initializing attributes database...");
+
+ XML::Document doc(DEFAULT_ATTRIBUTESDB_FILE);
+ xmlNodePtr rootNode = doc.rootNode();
+
+ if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "attributes"))
+ {
+ logger->log("Attributes: Error while loading "
+ DEFAULT_ATTRIBUTESDB_FILE ". Using Built-ins.");
+ loadBuiltins();
+ fillLabels();
+ return;
+ }
+
+ for_each_xml_child_node(node, rootNode)
+ {
+ if (xmlStrEqual(node->name, BAD_CAST "attribute"))
+ {
+ int id = XML::getProperty(node, "id", 0);
+
+ if (!id)
+ {
+ logger->log("Attributes: Invalid or missing stat ID in "
+ DEFAULT_ATTRIBUTESDB_FILE "!");
+ continue;
+ }
+ else if (attributes.find(id) != attributes.end())
+ {
+ logger->log("Attributes: Redefinition of stat ID %d", id);
+ }
+
+ std::string name = XML::getProperty(node, "name", "");
+
+ if (name.empty())
+ {
+ logger->log("Attributes: Invalid or missing stat name in "
+ DEFAULT_ATTRIBUTESDB_FILE "!");
+ continue;
+ }
+
+ // Create the attribute.
+ Attribute a;
+ a.id = id;
+ a.name = name;
+ a.description = XML::getProperty(node, "desc", "");
+ a.modifiable = XML::getBoolProperty(node, "modifiable", false);
+ a.scope = XML::getProperty(node, "scope", "none");
+ a.playerInfoId = getPlayerInfoIdFromAttrType(
+ XML::getProperty(node, "player-info", ""));
+
+ attributes[id] = a;
+
+ unsigned int count = 0;
+ for_each_xml_child_node(effectNode, node)
+ {
+ if (!xmlStrEqual(effectNode->name, BAD_CAST "modifier"))
+ continue;
+ ++count;
+ std::string tag = XML::getProperty(effectNode, "tag", "");
+ if (tag.empty())
+ {
+ if (name.empty())
+ {
+ logger->log("Attribute modifier in attribute %u:%s: "
+ "Empty name definition "
+ "on empty tag definition, skipping.",
+ a.id, a.name.c_str());
+ --count;
+ continue;
+ }
+ tag = name.substr(0, name.size() > 3 ? 3 : name.size());
+ tag = toLower(tag) + toString(count);
+ }
+
+ std::string effect = XML::getProperty(effectNode, "effect", "");
+ if (effect.empty())
+ {
+ if (name.empty())
+ {
+ logger->log("Attribute modifier in attribute %u:%s: "
+ "Empty name definition "
+ "on empty effect definition, skipping.",
+ a.id, a.name.c_str());
+ --count;
+ continue;
+ }
+ else
+ effect = name + " %+f";
+ }
+ tags.insert(std::make_pair(tag, effect));
+ }
+ logger->log("Found %d tags for attribute %d.", count, id);
+
+ }// End attribute
+ else if (xmlStrEqual(node->name, BAD_CAST "points"))
+ {
+ creationPoints = XML::getProperty(node, "start",DEFAULT_POINTS);
+ attributeMinimum = XML::getProperty(node, "minimum",
+ DEFAULT_MIN_PTS);
+ attributeMaximum = XML::getProperty(node, "maximum",
+ DEFAULT_MAX_PTS);
+ logger->log("Loaded points: start: %i, min: %i, max: %i.",
+ creationPoints, attributeMinimum, attributeMaximum);
+ }
+ else
+ {
+ continue;
+ }
+ }
+ logger->log("Found %d tags for %d attributes.", int(tags.size()),
+ int(attributes.size()));
+
+ fillLabels();
+
+ // Sanity checks on starting points
+ float modifiableAttributeCount = (float) attributeLabels.size();
+ float averageValue = ((float) creationPoints) / modifiableAttributeCount;
+ if (averageValue > attributeMaximum || averageValue < attributeMinimum
+ || creationPoints < 1)
+ {
+ logger->log("Attributes: Character's point values make "
+ "the character's creation impossible. "
+ "Switch back to defaults.");
+ creationPoints = DEFAULT_POINTS;
+ attributeMinimum = DEFAULT_MIN_PTS;
+ attributeMaximum = DEFAULT_MAX_PTS;
+ }
+ }
+
+ void unload()
+ {
+ attributes.clear();
+ }
+
+ void informItemDB()
+ {
+ std::list<ItemStat> dbStats;
+
+ TagMap::const_iterator it, it_end;
+ for (it = tags.begin(), it_end = tags.end(); it != it_end; ++it)
+ dbStats.push_back(ItemStat(it->first,
+ it->second));
+
+ setStatsList(dbStats);
+ }
+
+ void informStatusWindow()
+ {
+ AttributeMap::const_iterator it, it_end;
+ for (it = attributes.begin(), it_end = attributes.end(); it != it_end;
+ it++)
+ {
+ if (it->second.playerInfoId == -1 &&
+ (it->second.scope == "character" || it->second.scope == "being"))
+ {
+ statusWindow->addAttribute(it->second.id,
+ it->second.name,
+ it->second.modifiable,
+ it->second.description);
+ }
+ }
+ }
+
+} // namespace Attributes
+} // namespace ManaServ
diff --git a/src/net/manaserv/stats.h b/src/net/manaserv/attributes.h
index 63349095..aced85ec 100644
--- a/src/net/manaserv/stats.h
+++ b/src/net/manaserv/attributes.h
@@ -18,14 +18,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef NET_MANASERV_STATS_H
-#define NET_MANASERV_STATS_H
+#ifndef NET_MANASERV_ATTRIBUTES_H
+#define NET_MANASERV_ATTRIBUTES_H
#include <string>
#include <vector>
namespace ManaServ {
-namespace Stats {
+namespace Attributes {
+
void load();
void unload();
@@ -34,8 +35,36 @@ namespace Stats {
void informStatusWindow();
- std::vector<std::string> getLabelVector();
-} // namespace Stats
+ /**
+ * Returns the list of base attribute labels.
+ */
+ std::vector<std::string>& getLabels();
+
+ /**
+ * Give back the corresponding playerinfo Id from the attribute id
+ * defined in the xml file.
+ */
+ int getPlayerInfoIdFromAttrId(int attrId);
+
+ /**
+ * Give the attribute points given to a character
+ * at its creation.
+ */
+ unsigned int getCreationPoints();
+
+ /**
+ * Give the minimum attribute point possible
+ * at character's creation.
+ */
+ unsigned int getAttributeMinimum();
+
+ /**
+ * Give the maximum attribute point possible
+ * at character's creation.
+ */
+ unsigned int getAttributeMaximum();
+
+} // namespace Attributes
} // namespace ManaServ
-#endif // NET_MANASERV_STATS_H
+#endif // NET_MANASERV_ATTRIBUTES_H
diff --git a/src/net/manaserv/beinghandler.cpp b/src/net/manaserv/beinghandler.cpp
index 8df9a8ab..4d45da8a 100644
--- a/src/net/manaserv/beinghandler.cpp
+++ b/src/net/manaserv/beinghandler.cpp
@@ -21,13 +21,12 @@
#include "net/manaserv/beinghandler.h"
+#include "actorspritemanager.h"
#include "being.h"
-#include "beingmanager.h"
#include "client.h"
#include "game.h"
#include "localplayer.h"
#include "log.h"
-#include "npc.h"
#include "particle.h"
#include "gui/okdialog.h"
@@ -35,12 +34,14 @@
#include "net/messagein.h"
#include "net/manaserv/playerhandler.h"
-#include "net/manaserv/protocol.h"
+#include "net/manaserv/manaserv_protocol.h"
#include "resources/colordb.h"
#include "utils/gettext.h"
+#define POSITION_DIFF_TOLERANCE 48
+
namespace ManaServ {
BeingHandler::BeingHandler()
@@ -90,38 +91,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
}
}
-Vector BeingHandler::giveSpeedInPixelsPerTicks(float speedInTilesPerSeconds)
-{
- Vector speedInTicks;
- Game *game = Game::instance();
- Map *map = 0;
- if (game)
- {
- map = game->getCurrentMap();
- if (map)
- {
- speedInTicks.x = speedInTilesPerSeconds
- * (float)map->getTileWidth()
- / 1000 * (float) MILLISECONDS_IN_A_TICK;
- speedInTicks.y = speedInTilesPerSeconds
- * (float)map->getTileHeight()
- / 1000 * (float) MILLISECONDS_IN_A_TICK;
- }
- }
-
- if (!game || !map)
- {
- speedInTicks.x = speedInTicks.y = 0;
- logger->log("Manaserv::BeingHandler: Speed wasn't given back"
- " because game/Map not initialized.");
- }
- // We don't use z for now.
- speedInTicks.z = 0;
-
- return speedInTicks;
-}
-
-static void handleLooks(Player *being, Net::MessageIn &msg)
+static void handleLooks(Being *being, Net::MessageIn &msg)
{
// Order of sent slots. Has to be in sync with the server code.
static int const nb_slots = 4;
@@ -145,7 +115,7 @@ static void handleLooks(Player *being, Net::MessageIn &msg)
{
if (!(mask & (1 << i))) continue;
int id = msg.readInt16();
- being->setSprite(slots[i], id);
+ being->setSprite(slots[i], id,"", (slots[i] == SPRITE_WEAPON));
}
}
@@ -156,8 +126,17 @@ void BeingHandler::handleBeingEnterMessage(Net::MessageIn &msg)
Being::Action action = (Being::Action)msg.readInt8();
int px = msg.readInt16();
int py = msg.readInt16();
+ BeingDirection direction = (BeingDirection)msg.readInt8();
Being *being;
+ if (!Game::instance()->getCurrentMap()->containsPixel(px, py))
+ {
+ logger->log("Warning: Received GPMSG_BEING_ENTER for being id %i "
+ "with position outside the map boundaries "
+ "(x = %i, y = %i)", id, px, py);
+ return;
+ }
+
switch (type)
{
case OBJECT_CHARACTER:
@@ -170,23 +149,23 @@ void BeingHandler::handleBeingEnterMessage(Net::MessageIn &msg)
}
else
{
- being = beingManager->createBeing(id, Being::PLAYER, 0);
+ being = actorSpriteManager->createBeing(id,
+ ActorSprite::PLAYER, 0);
being->setName(name);
}
- Player *p = static_cast< Player * >(being);
int hs = msg.readInt8(), hc = msg.readInt8();
- p->setSprite(SPRITE_HAIR, hs * -1, ColorDB::get(hc));
- p->setGender(msg.readInt8() == GENDER_MALE ?
- GENDER_MALE : GENDER_FEMALE);
- handleLooks(p, msg);
+ being->setSprite(SPRITE_HAIR, hs * -1, ColorDB::get(hc));
+ being->setGender(msg.readInt8() == GENDER_MALE ?
+ GENDER_MALE : GENDER_FEMALE);
+ handleLooks(being, msg);
} break;
case OBJECT_MONSTER:
case OBJECT_NPC:
{
int subtype = msg.readInt16();
- being = beingManager->createBeing(id, type == OBJECT_MONSTER ?
- Being::MONSTER : Being::NPC, subtype);
+ being = actorSpriteManager->createBeing(id, type == OBJECT_MONSTER
+ ? ActorSprite::MONSTER : ActorSprite::NPC, subtype);
std::string name = msg.readString();
if (name.length() > 0) being->setName(name);
} break;
@@ -197,16 +176,17 @@ void BeingHandler::handleBeingEnterMessage(Net::MessageIn &msg)
being->setPosition(px, py);
being->setDestination(px, py);
+ being->setDirection(direction);
being->setAction(action);
}
void BeingHandler::handleBeingLeaveMessage(Net::MessageIn &msg)
{
- Being *being = beingManager->findBeing(msg.readInt16());
+ Being *being = actorSpriteManager->findBeing(msg.readInt16());
if (!being)
return;
- beingManager->destroyBeing(being);
+ actorSpriteManager->destroy(being);
}
void BeingHandler::handleBeingsMoveMessage(Net::MessageIn &msg)
@@ -215,71 +195,96 @@ void BeingHandler::handleBeingsMoveMessage(Net::MessageIn &msg)
{
int id = msg.readInt16();
int flags = msg.readInt8();
- Being *being = beingManager->findBeing(id);
- int sx = 0;
- int sy = 0;
- int speed = 0;
+ Being *being = actorSpriteManager->findBeing(id);
+ int sx = 0, sy = 0, dx = 0, dy = 0, speed = 0;
+
+ if ((!flags & (MOVING_POSITION | MOVING_DESTINATION)))
+ continue;
if (flags & MOVING_POSITION)
{
sx = msg.readInt16();
sy = msg.readInt16();
- speed = msg.readInt8();
}
- if (!being || !(flags & (MOVING_POSITION | MOVING_DESTINATION)))
+
+ if (flags & MOVING_DESTINATION)
{
- continue;
+ dx = msg.readInt16();
+ dy = msg.readInt16();
+ speed = msg.readInt8();
}
+
+ if (!being)
+ continue;
+
if (speed)
{
/*
* The being's speed is transfered in tiles per second * 10
* to keep it transferable in a Byte.
* We set it back to tiles per second and in a float.
- * Then, we translate it in pixels per ticks, to correspond
- * with the Being::logic() function calls
- * @see MILLISECONDS_IN_A_TICK
*/
- being->setWalkSpeed(
- giveSpeedInPixelsPerTicks((float) speed / 10));
+ float speedTilesSeconds = (float) speed / 10;
+ being->setMoveSpeed(Vector(speedTilesSeconds, speedTilesSeconds,
+ 0));
}
// Ignore messages from the server for the local player
if (being == player_node)
continue;
+ // If the position differs too much from the actual one, we resync
+ // the being position
if (flags & MOVING_POSITION)
{
- being->setDestination(sx, sy);
+ if (!being->getMap()->containsPixel(sx, sy))
+ {
+ logger->log("Warning: Received GPMSG_BEINGS_MOVE for being id "
+ "%i with position outside the map boundaries "
+ "(x = %i, y = %i)", id, sx, sy);
+ continue;
+ }
+
+ Vector serverPos(sx, sy);
+ if (serverPos.length()
+ - being->getPosition().length() > POSITION_DIFF_TOLERANCE)
+ being->setPosition(serverPos);
+ }
+
+ if (flags & MOVING_DESTINATION)
+ {
+ if (!being->getMap()->containsPixel(dx, dy))
+ {
+ logger->log("Warning: Received GPMSG_BEINGS_MOVE for being id "
+ "%i with destination outside the map boundaries "
+ "(x = %i, y = %i)", id, dx, dy);
+ continue;
+ }
+
+ being->setDestination(dx, dy);
}
}
}
void BeingHandler::handleBeingAttackMessage(Net::MessageIn &msg)
{
- Being *being = beingManager->findBeing(msg.readInt16());
- const int direction = msg.readInt8();
- const int attackType = msg.readInt8();
+ Being *being = actorSpriteManager->findBeing(msg.readInt16());
+ const BeingDirection direction = (BeingDirection) msg.readInt8();
+ const int attackId = msg.readInt8();
if (!being)
return;
- switch (direction)
- {
- case DIRECTION_UP: being->setDirection(Being::UP); break;
- case DIRECTION_DOWN: being->setDirection(Being::DOWN); break;
- case DIRECTION_LEFT: being->setDirection(Being::LEFT); break;
- case DIRECTION_RIGHT: being->setDirection(Being::RIGHT); break;
- }
+ being->setDirection(direction);
- being->setAction(Being::ATTACK, attackType);
+ being->setAction(Being::ATTACK, attackId);
}
void BeingHandler::handleBeingsDamageMessage(Net::MessageIn &msg)
{
while (msg.getUnreadLength())
{
- Being *being = beingManager->findBeing(msg.readInt16());
+ Being *being = actorSpriteManager->findBeing(msg.readInt16());
int damage = msg.readInt16();
if (being)
{
@@ -290,7 +295,7 @@ void BeingHandler::handleBeingsDamageMessage(Net::MessageIn &msg)
void BeingHandler::handleBeingActionChangeMessage(Net::MessageIn &msg)
{
- Being *being = beingManager->findBeing(msg.readInt16());
+ Being *being = actorSpriteManager->findBeing(msg.readInt16());
Being::Action action = (Being::Action) msg.readInt8();
if (!being)
return;
@@ -329,38 +334,28 @@ void BeingHandler::handleBeingActionChangeMessage(Net::MessageIn &msg)
void BeingHandler::handleBeingLooksChangeMessage(Net::MessageIn &msg)
{
- Being *being = beingManager->findBeing(msg.readInt16());
- if (!being || being->getType() != Being::PLAYER)
+ Being *being = actorSpriteManager->findBeing(msg.readInt16());
+ if (!being || being->getType() != ActorSprite::PLAYER)
return;
- Player *player = static_cast<Player *>(being);
- handleLooks(player, msg);
+ handleLooks(being, msg);
if (msg.getUnreadLength())
{
int style = msg.readInt16();
int color = msg.readInt16();
- player->setSprite(SPRITE_HAIR, style * -1, ColorDB::get(color));
+ being->setSprite(SPRITE_HAIR, style * -1, ColorDB::get(color));
}
}
void BeingHandler::handleBeingDirChangeMessage(Net::MessageIn &msg)
{
- Being *being = beingManager->findBeing(msg.readInt16());
+ Being *being = actorSpriteManager->findBeing(msg.readInt16());
if (!being)
return;
int data = msg.readInt8();
// The direction for the player's character is handled on client side.
if (being != player_node)
- {
- switch (data)
- {
- case DIRECTION_UP: being->setDirection(Being::UP); break;
- case DIRECTION_DOWN: being->setDirection(Being::DOWN); break;
- case DIRECTION_LEFT: being->setDirection(Being::LEFT); break;
- case DIRECTION_RIGHT: being->setDirection(Being::RIGHT); break;
- default: break;
- }
- }
+ being->setDirection((BeingDirection) data);
}
} // namespace ManaServ
diff --git a/src/net/manaserv/beinghandler.h b/src/net/manaserv/beinghandler.h
index 2e9eb333..04c766d9 100644
--- a/src/net/manaserv/beinghandler.h
+++ b/src/net/manaserv/beinghandler.h
@@ -35,14 +35,6 @@ class BeingHandler : public MessageHandler
void handleMessage(Net::MessageIn &msg);
- /**
- * Translate a given speed in tiles per seconds
- * into pixels per ticks.
- * Used to optimize Being::logic() calls.
- * @see MILLISECONDS_IN_A_TICKS
- */
- static Vector giveSpeedInPixelsPerTicks(float speedInTilesPerSeconds);
-
private:
void handleBeingAttackMessage(Net::MessageIn &msg);
void handleBeingEnterMessage(Net::MessageIn &msg);
diff --git a/src/net/manaserv/buysellhandler.cpp b/src/net/manaserv/buysellhandler.cpp
index a4ce6aa0..c375ed75 100644
--- a/src/net/manaserv/buysellhandler.cpp
+++ b/src/net/manaserv/buysellhandler.cpp
@@ -21,18 +21,16 @@
#include "net/manaserv/buysellhandler.h"
-#include "beingmanager.h"
+#include "actorspritemanager.h"
#include "item.h"
-#include "localplayer.h"
-#include "npc.h"
+#include "playerinfo.h"
#include "gui/buy.h"
-#include "gui/chat.h"
#include "gui/sell.h"
#include "net/messagein.h"
-#include "net/manaserv/protocol.h"
+#include "net/manaserv/manaserv_protocol.h"
namespace ManaServ {
@@ -49,8 +47,8 @@ BuySellHandler::BuySellHandler()
void BuySellHandler::handleMessage(Net::MessageIn &msg)
{
- Being *being = beingManager->findBeing(msg.readInt16());
- if (!being || being->getType() != Being::NPC)
+ Being *being = actorSpriteManager->findBeing(msg.readInt16());
+ if (!being || being->getType() != ActorSprite::NPC)
{
return;
}
@@ -64,7 +62,7 @@ void BuySellHandler::handleMessage(Net::MessageIn &msg)
BuyDialog* dialog = new BuyDialog(npcId);
dialog->reset();
- dialog->setMoney(player_node->getMoney());
+ dialog->setMoney(PlayerInfo::getAttribute(MONEY));
while (msg.getUnreadLength())
{
@@ -81,7 +79,7 @@ void BuySellHandler::handleMessage(Net::MessageIn &msg)
SellDialog* dialog = new SellDialog(npcId);
dialog->reset();
- dialog->setMoney(player_node->getMoney());
+ dialog->setMoney(PlayerInfo::getAttribute(MONEY));
while (msg.getUnreadLength())
{
diff --git a/src/net/manaserv/charhandler.cpp b/src/net/manaserv/charhandler.cpp
index e6723226..79f3b35a 100644
--- a/src/net/manaserv/charhandler.cpp
+++ b/src/net/manaserv/charhandler.cpp
@@ -36,8 +36,8 @@
#include "net/manaserv/gamehandler.h"
#include "net/manaserv/messagein.h"
#include "net/manaserv/messageout.h"
-#include "net/manaserv/protocol.h"
-#include "net/manaserv/stats.h"
+#include "net/manaserv/manaserv_protocol.h"
+#include "net/manaserv/attributes.h"
#include "resources/colordb.h"
@@ -108,11 +108,15 @@ void CharHandler::handleCharacterInfo(Net::MessageIn &msg)
info.level = msg.readInt16();
info.characterPoints = msg.readInt16();
info.correctionPoints = msg.readInt16();
- info.money = msg.readInt32();
- for (int i = 0; i < 7; i++)
+ while (msg.getUnreadLength() > 0)
{
- info.attribute[i] = msg.readInt8();
+ int id = msg.readInt32();
+ CachedAttrbiute attr;
+ attr.base = msg.readInt32() / 256.0;
+ attr.mod = msg.readInt32() / 256.0;
+
+ info.attribute[id] = attr;
}
mCachedCharacterInfos.push_back(info);
@@ -157,8 +161,14 @@ void CharHandler::handleCharacterCreateResponse(Net::MessageIn &msg)
case CREATE_ATTRIBUTES_TOO_LOW:
errorMessage = _("Character's stats are too low.");
break;
- case CREATE_ATTRIBUTES_EQUAL_TO_ZERO:
- errorMessage = _("One stat is zero.");
+ case CREATE_ATTRIBUTES_OUT_OF_RANGE:
+ errorMessage = strprintf( _("At least one stat"
+ "is out of the permitted range: (%u - %u)."),
+ Attributes::getAttributeMinimum(),
+ Attributes::getAttributeMaximum());
+ break;
+ case CREATE_INVALID_SLOT:
+ errorMessage = _("Invalid slot number.");
break;
default:
errorMessage = _("Unknown error.");
@@ -186,10 +196,17 @@ void CharHandler::handleCharacterDeleteResponse(Net::MessageIn &msg)
if (errMsg == ERRMSG_OK)
{
// Character deletion successful
+ for (unsigned i = 0; i < mCachedCharacterInfos.size(); ++i)
+ {
+ if (mCachedCharacterInfos[i].slot == mSelectedCharacter->slot)
+ {
+ mCachedCharacterInfos.erase(mCachedCharacterInfos.begin() + i);
+ break;
+ }
+ }
delete mSelectedCharacter;
mCharacters.remove(mSelectedCharacter);
updateCharSelectDialog();
- unlockCharSelectDialog();
new OkDialog(_("Info"), _("Player deleted."));
}
else
@@ -210,6 +227,7 @@ void CharHandler::handleCharacterDeleteResponse(Net::MessageIn &msg)
new OkDialog(_("Error"), errorMessage);
}
mSelectedCharacter = 0;
+ unlockCharSelectDialog();
}
void CharHandler::handleCharacterSelectResponse(Net::MessageIn &msg)
@@ -233,13 +251,25 @@ void CharHandler::handleCharacterSelectResponse(Net::MessageIn &msg)
// Prevent the selected local player from being deleted
player_node = mSelectedCharacter->dummy;
+ PlayerInfo::setBackend(mSelectedCharacter->data);
mSelectedCharacter->dummy = 0;
Client::setState(STATE_CONNECT_GAME);
}
- else if (errMsg == ERRMSG_FAILURE)
+ else
{
- errorMessage = _("No gameservers are available.");
+ switch (errMsg)
+ {
+ case ERRMSG_FAILURE:
+ errorMessage = _("No gameservers are available.");
+ break;
+ case ERRMSG_INVALID_ARGUMENT:
+ errorMessage = _("Invalid character slot selected.");
+ break;
+ default:
+ errorMessage = strprintf(_("Unhandled character select "
+ "error message %i."), errMsg);
+ }
delete_all(mCharacters);
mCharacters.clear();
Client::setState(STATE_ERROR);
@@ -259,7 +289,10 @@ void CharHandler::setCharCreateDialog(CharCreateDialog *window)
if (!mCharCreateDialog)
return;
- mCharCreateDialog->setAttributes(Stats::getLabelVector(), 60, 1, 20);
+ mCharCreateDialog->setAttributes(Attributes::getLabels(),
+ Attributes::getCreationPoints(),
+ Attributes::getAttributeMinimum(),
+ Attributes::getAttributeMaximum());
}
void CharHandler::requestCharacters()
@@ -285,7 +318,7 @@ void CharHandler::chooseCharacter(Net::Character *character)
}
void CharHandler::newCharacter(const std::string &name,
- int /* slot */,
+ int slot,
bool gender,
int hairstyle,
int hairColor,
@@ -297,6 +330,7 @@ void CharHandler::newCharacter(const std::string &name,
msg.writeInt8(hairstyle);
msg.writeInt8(hairColor);
msg.writeInt8(gender);
+ msg.writeInt8(slot);
std::vector<int>::const_iterator it, it_end;
for (it = stats.begin(), it_end = stats.end(); it != it_end; it++)
@@ -319,17 +353,17 @@ void CharHandler::switchCharacter()
gameHandler->quit(true);
}
-int CharHandler::baseSprite() const
+unsigned int CharHandler::baseSprite() const
{
return SPRITE_BASE;
}
-int CharHandler::hairSprite() const
+unsigned int CharHandler::hairSprite() const
{
return SPRITE_HAIR;
}
-int CharHandler::maxSprite() const
+unsigned int CharHandler::maxSprite() const
{
return SPRITE_VECTOREND;
}
@@ -350,19 +384,20 @@ void CharHandler::updateCharacters()
Net::Character *character = new Net::Character;
character->slot = info.slot;
- LocalPlayer *player = character->dummy;
+ LocalPlayer *player = character->dummy = new LocalPlayer;
player->setName(info.name);
player->setGender(info.gender);
player->setSprite(SPRITE_HAIR, info.hairStyle * -1,
ColorDB::get(info.hairColor));
- player->setLevel(info.level);
- player->setCharacterPoints(info.characterPoints);
- player->setCorrectionPoints(info.correctionPoints);
- player->setMoney(info.money);
+ character->data.mAttributes[LEVEL] = info.level;
+ character->data.mAttributes[CHAR_POINTS] = info.characterPoints;
+ character->data.mAttributes[CORR_POINTS] = info.correctionPoints;
- for (int i = 0; i < 7; i++)
+ for (CachedAttributes::const_iterator it = info.attribute.begin(),
+ it_end = info.attribute.end(); it != it_end; it++)
{
- player->setAttributeBase(i, info.attribute[i], false);
+ character->data.mStats[i].base = it->second.base;
+ character->data.mStats[i].mod = it->second.mod;
}
mCharacters.push_back(character);
diff --git a/src/net/manaserv/charhandler.h b/src/net/manaserv/charhandler.h
index 26a7bf4e..2f335688 100644
--- a/src/net/manaserv/charhandler.h
+++ b/src/net/manaserv/charhandler.h
@@ -28,6 +28,8 @@
#include "net/manaserv/messagehandler.h"
+#include <map.h>
+
class LoginData;
namespace ManaServ {
@@ -65,11 +67,11 @@ class CharHandler : public MessageHandler, public Net::CharHandler
void switchCharacter();
- int baseSprite() const;
+ unsigned int baseSprite() const;
- int hairSprite() const;
+ unsigned int hairSprite() const;
- int maxSprite() const;
+ unsigned int maxSprite() const;
void clear();
@@ -79,6 +81,13 @@ class CharHandler : public MessageHandler, public Net::CharHandler
* we have loaded the dynamic data, so we can't resolve load any
* sprites yet.
*/
+ struct CachedAttrbiute {
+ double base;
+ double mod;
+ };
+
+ typedef std::map<int, CachedAttrbiute> CachedAttributes;
+
struct CachedCharacterInfo {
int slot;
std::string name;
@@ -88,8 +97,7 @@ class CharHandler : public MessageHandler, public Net::CharHandler
int level;
int characterPoints;
int correctionPoints;
- int money;
- int attribute[7];
+ CachedAttributes attribute;
};
void handleCharacterInfo(Net::MessageIn &msg);
diff --git a/src/net/manaserv/chathandler.cpp b/src/net/manaserv/chathandler.cpp
index a452281f..6c97fae3 100644
--- a/src/net/manaserv/chathandler.cpp
+++ b/src/net/manaserv/chathandler.cpp
@@ -21,20 +21,21 @@
#include "net/manaserv/chathandler.h"
+#include "actorspritemanager.h"
#include "being.h"
-#include "beingmanager.h"
#include "client.h"
#include "channel.h"
#include "channelmanager.h"
-
-#include "gui/chat.h"
+#include "event.h"
+#include "log.h"
+#include "playerrelations.h"
#include "gui/widgets/channeltab.h"
#include "net/manaserv/connection.h"
#include "net/manaserv/messagein.h"
#include "net/manaserv/messageout.h"
-#include "net/manaserv/protocol.h"
+#include "net/manaserv/manaserv_protocol.h"
#include "utils/gettext.h"
#include "utils/stringutils.h"
@@ -149,22 +150,31 @@ void ChatHandler::handleGameChatMessage(Net::MessageIn &msg)
if (id == 0)
{
- localChatTab->chatLog(chatMsg, BY_SERVER);
+ SERVER_NOTICE(chatMsg)
return;
}
- Being *being = beingManager->findBeing(id);
+ Being *being = actorSpriteManager->findBeing(id);
- std::string mes;
- if (being)
+ if (!being)
{
- mes = being->getName() + " : " + chatMsg;
- being->setSpeech(chatMsg, SPEECH_TIME);
+ logger->log("Warning: Received GPMSG_SAY for unknown being with id %i."
+ " (Message is: %s)", id, chatMsg.c_str());
+ return;
}
- else
- mes = "Unknown : " + chatMsg;
- localChatTab->chatLog(mes, being == player_node ? BY_PLAYER : BY_OTHER);
+ std::string mes = being->getName() + " : " + chatMsg;
+
+ Event event(being == player_node ? Event::Player
+ : Event::Being);
+ event.setString("message", mes);
+ event.setString("text", chatMsg);
+ event.setString("nick", being->getName());
+ event.setInt("beingId", id);
+ event.setInt("permissions", player_relations
+ .checkPermissionSilently(being->getName(),
+ PlayerRelation::SPEECH_LOG | PlayerRelation::SPEECH_FLOAT));
+ event.trigger(Event::ChatChannel);
}
void ChatHandler::handleEnterChannelResponse(Net::MessageIn &msg)
@@ -198,13 +208,13 @@ void ChatHandler::handleEnterChannelResponse(Net::MessageIn &msg)
}
else
{
- localChatTab->chatLog(_("Error joining channel."), BY_SERVER);
+ SERVER_NOTICE(_("Error joining channel."))
}
}
void ChatHandler::handleListChannelsResponse(Net::MessageIn &msg)
{
- localChatTab->chatLog(_("Listing channels."), BY_SERVER);
+ SERVER_NOTICE(_("Listing channels."))
while (msg.getUnreadLength())
{
std::string channelName = msg.readString();
@@ -214,9 +224,9 @@ void ChatHandler::handleListChannelsResponse(Net::MessageIn &msg)
numUsers << msg.readInt16();
channelName += " - ";
channelName += numUsers.str();
- localChatTab->chatLog(channelName, BY_SERVER);
+ SERVER_NOTICE(channelName)
}
- localChatTab->chatLog(_("End of channel list."), BY_SERVER);
+ SERVER_NOTICE(_("End of channel list."))
}
void ChatHandler::handlePrivateMessage(Net::MessageIn &msg)
@@ -224,13 +234,18 @@ void ChatHandler::handlePrivateMessage(Net::MessageIn &msg)
std::string userNick = msg.readString();
std::string chatMsg = msg.readString();
- chatWindow->whisper(userNick, chatMsg);
+ Event event(Event::Whisper);
+ event.setString("nick", userNick);
+ event.setString("message", chatMsg);
+ event.trigger(Event::ChatChannel);
}
void ChatHandler::handleAnnouncement(Net::MessageIn &msg)
{
std::string chatMsg = msg.readString();
- localChatTab->chatLog(chatMsg, BY_GM);
+ Event event(Event::Announcement);
+ event.setString("message", chatMsg);
+ event.trigger(Event::ChatChannel);
}
void ChatHandler::handleChatMessage(Net::MessageIn &msg)
@@ -341,7 +356,7 @@ void ChatHandler::handleWhoResponse(Net::MessageIn &msg)
{
break;
}
- localChatTab->chatLog(userNick, BY_SERVER);
+ SERVER_NOTICE(userNick)
}
}
diff --git a/src/net/manaserv/connection.cpp b/src/net/manaserv/connection.cpp
index fbd2ed22..4b421a04 100644
--- a/src/net/manaserv/connection.cpp
+++ b/src/net/manaserv/connection.cpp
@@ -60,11 +60,7 @@ bool Connection::connect(const std::string &address, short port)
enetAddress.port = port;
// Initiate the connection, allocating channel 0.
-#ifdef ENET_VERSION_MAJOR
mConnection = enet_host_connect(mClient, &enetAddress, 1, 0);
-#else
- mConnection = enet_host_connect(mClient, &enetAddress, 1);
-#endif
if (!mConnection)
{
diff --git a/src/net/manaserv/defines.h b/src/net/manaserv/defines.h
new file mode 100644
index 00000000..e97866df
--- /dev/null
+++ b/src/net/manaserv/defines.h
@@ -0,0 +1,76 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2004-2009 The Mana World Development Team
+ * Copyright (C) 2009-2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MANASERV_DEFINES_H
+#define MANASERV_DEFINES_H
+
+/**
+ * Attributes used during combat. Available to all the beings.
+ */
+enum
+{
+BASE_ATTR_BEGIN = 0,
+ BASE_ATTR_PHY_ATK_MIN = BASE_ATTR_BEGIN,
+ BASE_ATTR_PHY_ATK_DELTA,
+ /**< Physical attack power. */
+ BASE_ATTR_MAG_ATK, /**< Magical attack power. */
+ BASE_ATTR_PHY_RES, /**< Resistance to physical damage. */
+ BASE_ATTR_MAG_RES, /**< Resistance to magical damage. */
+ BASE_ATTR_EVADE, /**< Ability to avoid hits. */
+ BASE_ATTR_HIT, /**< Ability to hit stuff. */
+ BASE_ATTR_HP, /**< Hit Points (Base value: maximum, Modded value: current) */
+ BASE_ATTR_HP_REGEN,/**< number of HP regenerated every 10 game ticks */
+ BASE_ATTR_END,
+ BASE_ATTR_NB = BASE_ATTR_END - BASE_ATTR_BEGIN,
+
+ BASE_ELEM_BEGIN = BASE_ATTR_END,
+ BASE_ELEM_NEUTRAL = BASE_ELEM_BEGIN,
+ BASE_ELEM_FIRE,
+ BASE_ELEM_WATER,
+ BASE_ELEM_EARTH,
+ BASE_ELEM_AIR,
+ BASE_ELEM_SACRED,
+ BASE_ELEM_DEATH,
+ BASE_ELEM_END,
+ BASE_ELEM_NB = BASE_ELEM_END - BASE_ELEM_BEGIN,
+
+ NB_BEING_ATTRIBUTES = BASE_ELEM_END
+};
+
+/**
+ * Attributes of characters. Used to derive being attributes.
+ */
+enum
+{
+ CHAR_ATTR_BEGIN = NB_BEING_ATTRIBUTES,
+ CHAR_ATTR_STRENGTH = CHAR_ATTR_BEGIN,
+ CHAR_ATTR_AGILITY,
+ CHAR_ATTR_DEXTERITY,
+ CHAR_ATTR_VITALITY,
+ CHAR_ATTR_INTELLIGENCE,
+ CHAR_ATTR_WILLPOWER,
+ CHAR_ATTR_END,
+ CHAR_ATTR_NB = CHAR_ATTR_END - CHAR_ATTR_BEGIN,
+
+ NB_CHARACTER_ATTRIBUTES = CHAR_ATTR_END
+};
+
+#endif // MANASERV_DEFINES_H
diff --git a/src/net/manaserv/effecthandler.cpp b/src/net/manaserv/effecthandler.cpp
index 27db9b59..cc732794 100644
--- a/src/net/manaserv/effecthandler.cpp
+++ b/src/net/manaserv/effecthandler.cpp
@@ -21,21 +21,24 @@
#include "net/manaserv/effecthandler.h"
-#include "beingmanager.h"
+#include "actorspritemanager.h"
#include "effectmanager.h"
#include "log.h"
+#include "gui/viewport.h"
+
#include "net/messagein.h"
-#include "net/manaserv/protocol.h"
+#include "net/manaserv/manaserv_protocol.h"
namespace ManaServ {
EffectHandler::EffectHandler()
{
- static const Uint16 _messages[] = {
+ static const uint16_t _messages[] = {
GPMSG_CREATE_EFFECT_POS,
GPMSG_CREATE_EFFECT_BEING,
+ GPMSG_SHAKE,
0
};
handledMessages = _messages;
@@ -51,6 +54,9 @@ void EffectHandler::handleMessage(Net::MessageIn &msg)
case GPMSG_CREATE_EFFECT_BEING:
handleCreateEffectBeing(msg);
break;
+ case GPMSG_SHAKE:
+ handleShake(msg);
+ break;
default:
break;
}
@@ -59,8 +65,8 @@ void EffectHandler::handleMessage(Net::MessageIn &msg)
void EffectHandler::handleCreateEffectPos(Net::MessageIn &msg)
{
int id = msg.readInt16();
- Uint16 x = msg.readInt16();
- Uint16 y = msg.readInt16();
+ uint16_t x = msg.readInt16();
+ uint16_t y = msg.readInt16();
effectManager->trigger(id, x, y);
}
@@ -68,11 +74,43 @@ void EffectHandler::handleCreateEffectBeing(Net::MessageIn &msg)
{
int eid = msg.readInt16();
int bid = msg.readInt16();
- Being* b = beingManager->findBeing(bid);
+ Being* b = actorSpriteManager->findBeing(bid);
if (b)
effectManager->trigger(eid, b);
else
logger->log("Warning: CreateEffect called for unknown being #%d", bid);
}
+void EffectHandler::handleShake(Net::MessageIn &msg)
+{
+ int16_t intensityX = 0;
+ int16_t intensityY = 0;
+ float decay;
+ int duration;
+
+ switch (msg.getUnreadLength())
+ {
+ case 4:
+ intensityX = msg.readInt16();
+ intensityY = msg.readInt16();
+ viewport->shakeScreen(intensityX, intensityY);
+ break;
+ case 6:
+ intensityX = msg.readInt16();
+ intensityY = msg.readInt16();
+ decay = msg.readInt16() / 10000.0f;
+ viewport->shakeScreen(intensityX, intensityY, decay);
+ break;
+ case 8:
+ intensityX = msg.readInt16();
+ intensityY = msg.readInt16();
+ decay = msg.readInt16() / 10000.0f;
+ duration = msg.readInt16();
+ viewport->shakeScreen(intensityX, intensityY, decay, duration);
+ break;
+ default:
+ logger->log("Warning: Received GPMSG_SHAKE message with unexpected length of %d bytes", msg.getUnreadLength());
+ }
+}
+
} // namespace ManaServ
diff --git a/src/net/manaserv/effecthandler.h b/src/net/manaserv/effecthandler.h
index a0445aad..d31c3421 100644
--- a/src/net/manaserv/effecthandler.h
+++ b/src/net/manaserv/effecthandler.h
@@ -36,6 +36,7 @@ class EffectHandler : public MessageHandler
private:
void handleCreateEffectPos(Net::MessageIn &msg);
void handleCreateEffectBeing(Net::MessageIn &msg);
+ void handleShake(Net::MessageIn &msg);
};
} // namespace ManaServ
diff --git a/src/net/manaserv/gamehandler.cpp b/src/net/manaserv/gamehandler.cpp
index 5e29a896..e9c2442a 100644
--- a/src/net/manaserv/gamehandler.cpp
+++ b/src/net/manaserv/gamehandler.cpp
@@ -27,7 +27,7 @@
#include "net/manaserv/chathandler.h"
#include "net/manaserv/connection.h"
#include "net/manaserv/messageout.h"
-#include "net/manaserv/protocol.h"
+#include "net/manaserv/manaserv_protocol.h"
extern Net::GameHandler *gameHandler;
@@ -115,16 +115,6 @@ void GameHandler::disconnect()
chatHandler->disconnect();
}
-void GameHandler::inGame()
-{
- // TODO
-}
-
-void GameHandler::mapLoaded(const std::string &mapName)
-{
- // TODO
-}
-
void GameHandler::who()
{
// TODO
@@ -137,11 +127,6 @@ void GameHandler::quit(bool reconnectAccount)
gameServerConnection->send(msg);
}
-void GameHandler::ping(int tick)
-{
- // TODO
-}
-
void GameHandler::gameLoading()
{
MessageOut msg(PGMSG_CONNECT);
@@ -151,7 +136,8 @@ void GameHandler::gameLoading()
chatHandler->connect();
// Attack range from item DB
- player_node->setAttackRange(-1);
+ // TODO: Deharcode it through equipment handling
+ player_node->setAttackRange(48);
}
} // namespace ManaServ
diff --git a/src/net/manaserv/gamehandler.h b/src/net/manaserv/gamehandler.h
index dde1748f..10f9d5ff 100644
--- a/src/net/manaserv/gamehandler.h
+++ b/src/net/manaserv/gamehandler.h
@@ -42,23 +42,20 @@ class GameHandler : public MessageHandler, public Net::GameHandler
void disconnect();
- void inGame();
-
- void mapLoaded(const std::string &mapName);
-
void who();
void quit(bool reconnectAccount);
void quit() { quit(false); }
- void ping(int tick);
-
bool removeDeadBeings() const { return false; }
void clear();
void gameLoading();
+
+ /** The ManaServ protocol doesn't use the MP status bar. */
+ bool canUseMagicBar() const { return false; }
};
} // namespace ManaServ
diff --git a/src/net/manaserv/generalhandler.cpp b/src/net/manaserv/generalhandler.cpp
index 4f6ade4e..a1ba746f 100644
--- a/src/net/manaserv/generalhandler.cpp
+++ b/src/net/manaserv/generalhandler.cpp
@@ -46,7 +46,7 @@
#include "net/manaserv/partyhandler.h"
#include "net/manaserv/playerhandler.h"
#include "net/manaserv/specialhandler.h"
-#include "net/manaserv/stats.h"
+#include "net/manaserv/attributes.h"
#include "net/manaserv/tradehandler.h"
#include "utils/gettext.h"
@@ -90,6 +90,9 @@ GeneralHandler::GeneralHandler():
chatServerConnection = getConnection();
generalHandler = this;
+
+ listen(Event::ClientChannel);
+ listen(Event::GameChannel);
}
void GeneralHandler::load()
@@ -127,9 +130,9 @@ void GeneralHandler::reload()
gameServer.clear();
chatServer.clear();
- Stats::unload();
- Stats::load();
- Stats::informItemDB();
+ Attributes::unload();
+ Attributes::load();
+ Attributes::informItemDB();
}
void GeneralHandler::unload()
@@ -147,7 +150,7 @@ void GeneralHandler::unload()
delete gameServerConnection;
delete chatServerConnection;
- Stats::unload();
+ Attributes::unload();
finalize();
}
@@ -163,38 +166,43 @@ void GeneralHandler::flushNetwork()
}
}
-void GeneralHandler::guiWindowsLoaded()
-{
- inventoryWindow->setSplitAllowed(true);
- skillDialog->loadSkills();
- specialsWindow->loadSpecials("specials.xml");
-
- player_node->setExpNeeded(100);
-
- Stats::informStatusWindow();
-}
-
-void GeneralHandler::guiWindowsUnloaded()
-{
- // TODO
-}
-
void GeneralHandler::clearHandlers()
{
clearNetworkHandlers();
}
-void GeneralHandler::stateChanged(State oldState, State newState)
+void GeneralHandler::event(Event::Channel channel,
+ const Event &event)
{
- if (newState == STATE_GAME)
+ if (channel == Event::ClientChannel)
{
- GameHandler *game = static_cast<GameHandler*>(Net::getGameHandler());
- game->gameLoading();
+ if (event.getType() == Event::StateChange)
+ {
+ int newState = event.getInt("newState");
+
+ if (newState == STATE_GAME)
+ {
+ GameHandler *game = static_cast<GameHandler*>(Net::getGameHandler());
+ game->gameLoading();
+ }
+ }
+ else if (event.getType() == Event::LoadingDatabases)
+ {
+ Attributes::load();
+ Attributes::informItemDB();
+ }
}
- else if (newState == STATE_LOAD_DATA)
+ else if (channel == Event::GameChannel)
{
- Stats::load();
- Stats::informItemDB();
+ if (event.getType() == Event::GuiWindowsLoaded)
+ {
+ inventoryWindow->setSplitAllowed(true);
+ skillDialog->loadSkills();
+
+ PlayerInfo::setAttribute(EXP_NEEDED, 100);
+
+ Attributes::informStatusWindow();
+ }
}
}
diff --git a/src/net/manaserv/generalhandler.h b/src/net/manaserv/generalhandler.h
index 58b95529..45ded011 100644
--- a/src/net/manaserv/generalhandler.h
+++ b/src/net/manaserv/generalhandler.h
@@ -22,6 +22,8 @@
#ifndef NET_MANASERV_GENERALHANDLER_H
#define NET_MANASERV_GENERALHANDLER_H
+#include "eventlistener.h"
+
#include "net/generalhandler.h"
#include "net/net.h"
@@ -29,7 +31,7 @@
namespace ManaServ {
-class GeneralHandler : public Net::GeneralHandler
+class GeneralHandler : public Net::GeneralHandler, public EventListener
{
public:
GeneralHandler();
@@ -42,13 +44,9 @@ class GeneralHandler : public Net::GeneralHandler
void flushNetwork();
- void guiWindowsLoaded();
-
- void guiWindowsUnloaded();
-
void clearHandlers();
- void stateChanged(State oldState, State newState);
+ void event(Event::Channel channel, const Event &event);
protected:
MessageHandlerPtr mBeingHandler;
diff --git a/src/net/manaserv/guildhandler.cpp b/src/net/manaserv/guildhandler.cpp
index 253efb01..a2c571bc 100644
--- a/src/net/manaserv/guildhandler.cpp
+++ b/src/net/manaserv/guildhandler.cpp
@@ -21,23 +21,24 @@
#include "net/manaserv/guildhandler.h"
+#include "event.h"
#include "guild.h"
#include "log.h"
#include "localplayer.h"
#include "channel.h"
#include "channelmanager.h"
-#include "gui/widgets/channeltab.h"
-#include "gui/chat.h"
#include "gui/socialwindow.h"
+#include "gui/widgets/channeltab.h"
+
#include "net/messagein.h"
#include "net/net.h"
#include "net/manaserv/connection.h"
#include "net/manaserv/messagein.h"
#include "net/manaserv/messageout.h"
-#include "net/manaserv/protocol.h"
+#include "net/manaserv/manaserv_protocol.h"
#include "utils/gettext.h"
#include "utils/stringutils.h"
@@ -78,12 +79,12 @@ void GuildHandler::handleMessage(Net::MessageIn &msg)
if (msg.readInt8() == ERRMSG_OK)
{
// TODO - Acknowledge guild was created
- localChatTab->chatLog(_("Guild created."));
+ SERVER_NOTICE(_("Guild created."))
joinedGuild(msg);
}
else
{
- localChatTab->chatLog(_("Error creating guild."));
+ SERVER_NOTICE(_("Error creating guild."))
}
} break;
@@ -93,7 +94,7 @@ void GuildHandler::handleMessage(Net::MessageIn &msg)
if (msg.readInt8() == ERRMSG_OK)
{
// TODO - Acknowledge invite was sent
- localChatTab->chatLog(_("Invite sent."));
+ SERVER_NOTICE(_("Invite sent."))
}
} break;
@@ -200,12 +201,12 @@ void GuildHandler::handleMessage(Net::MessageIn &msg)
if (msg.readInt8() == ERRMSG_OK)
{
// promotion succeeded
- localChatTab->chatLog(_("Member was promoted successfully."));
+ SERVER_NOTICE(_("Member was promoted successfully."))
}
else
{
// promotion failed
- localChatTab->chatLog(_("Failed to promote member."));
+ SERVER_NOTICE(_("Failed to promote member."))
}
}
@@ -275,9 +276,9 @@ void GuildHandler::invite(int guildId, const std::string &name)
chatServerConnection->send(msg);
}
-void GuildHandler::invite(int guildId, Player *player)
+void GuildHandler::invite(int guildId, Being *being)
{
- invite(guildId, player->getName());
+ invite(guildId, being->getName());
}
void GuildHandler::inviteResponse(int guildId, bool response)
diff --git a/src/net/manaserv/guildhandler.h b/src/net/manaserv/guildhandler.h
index 9929d135..bde677fb 100644
--- a/src/net/manaserv/guildhandler.h
+++ b/src/net/manaserv/guildhandler.h
@@ -41,7 +41,7 @@ public:
void invite(int guildId, const std::string &name);
- void invite(int guidId, Player *player);
+ void invite(int guidId, Being *being);
void inviteResponse(int guidId, bool response);
diff --git a/src/net/manaserv/inventoryhandler.cpp b/src/net/manaserv/inventoryhandler.cpp
index 76fca7ae..c8dae1c3 100644
--- a/src/net/manaserv/inventoryhandler.cpp
+++ b/src/net/manaserv/inventoryhandler.cpp
@@ -26,33 +26,155 @@
#include "item.h"
#include "itemshortcut.h"
#include "localplayer.h"
+#include "log.h"
+#include "playerinfo.h"
-#include "gui/chat.h"
+#include "gui/inventorywindow.h"
#include "net/manaserv/connection.h"
#include "net/manaserv/messagein.h"
#include "net/manaserv/messageout.h"
-#include "net/manaserv/protocol.h"
+#include "net/manaserv/manaserv_protocol.h"
#include "resources/iteminfo.h"
-#include "log.h" // <<< REMOVE ME!
-
extern Net::InventoryHandler *inventoryHandler;
namespace ManaServ {
extern Connection *gameServerConnection;
+EquipBackend::EquipBackend()
+{
+ listen(Event::ClientChannel);
+}
+
+Item *EquipBackend::getEquipment(int index) const
+{
+ if (index < 0 || (unsigned) index >= mSlots.size())
+ return 0;
+ return mSlots.at(index);
+}
+
+void EquipBackend::clear()
+{
+ for (std::vector<Item*>::iterator i = mSlots.begin(), i_end = mSlots.end();
+ i != i_end; ++i)
+ {
+ if (Item *item = *i)
+ item->setEquipped(false);
+ }
+ mSlots.assign(mSlots.size(), 0);
+}
+
+void EquipBackend::equip(int inventorySlot, int equipSlot, int amountUsed)
+{
+ if (equipSlot < 0 || (unsigned) equipSlot >= mSlotTypes.size())
+ {
+ logger->log("ManaServ::EquipBackend: Equipment slot out of range");
+ return;
+ }
+
+ const SlotType &slotType = mSlotTypes.at(equipSlot);
+ Item *item = PlayerInfo::getInventory()->getItem(inventorySlot);
+
+ if (!item)
+ {
+ logger->log("ManaServ::EquipBackend: No item at index %d",
+ inventorySlot);
+ return;
+ }
+
+ // Start at first index and search upwards for free slots to place the
+ // item at the given inventory slot in
+ int i = slotType.firstIndex;
+ const int end_i = i + slotType.count;
+
+ for (; i < end_i && amountUsed > 0; ++i)
+ {
+ if (!mSlots.at(i))
+ {
+ mSlots[i] = item;
+ --amountUsed;
+
+ item->setEquipped(true);
+ inventoryWindow->updateButtons();
+ }
+ }
+}
+
+void EquipBackend::unequip(int inventorySlot)
+{
+ Item *item = PlayerInfo::getInventory()->getItem(inventorySlot);
+
+ if (!item)
+ {
+ logger->log("ManaServ::EquipBackend: No item at index %d",
+ inventorySlot);
+ return;
+ }
+
+ for (unsigned i = 0; i < mSlots.size(); ++i)
+ if (mSlots.at(i) == item)
+ mSlots[i] = 0;
+
+ item->setEquipped(false);
+ inventoryWindow->updateButtons();
+}
+
+void EquipBackend::event(Event::Channel, const Event &event)
+{
+ if (event.getType() == Event::LoadingDatabases)
+ readEquipFile();
+}
+
+void EquipBackend::readEquipFile()
+{
+ mSlots.clear();
+ mSlotTypes.clear();
+
+ XML::Document doc("equip.xml");
+ xmlNodePtr rootNode = doc.rootNode();
+
+ if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "equip-slots"))
+ {
+ logger->log("ManaServ::EquipBackend: Error while reading equip.xml!");
+ return;
+ }
+
+ int slotCount = 0;
+
+ for_each_xml_child_node(childNode, rootNode)
+ {
+ if (!xmlStrEqual(childNode->name, BAD_CAST "slot"))
+ continue;
+
+ SlotType slotType;
+ slotType.name = XML::getProperty(childNode, "name", std::string());
+ slotType.count = XML::getProperty(childNode, "count", 1);
+ slotType.visible = XML::getBoolProperty(childNode, "visible", false);
+ slotType.firstIndex = slotCount;
+
+ mSlotTypes.push_back(slotType);
+ slotCount += slotType.count;
+ }
+
+ mSlots.resize(slotCount);
+}
+
+
InventoryHandler::InventoryHandler()
{
static const Uint16 _messages[] = {
GPMSG_INVENTORY_FULL,
GPMSG_INVENTORY,
+ GPMSG_EQUIP,
0
};
handledMessages = _messages;
inventoryHandler = this;
+
+ listen(Event::ItemChannel);
}
void InventoryHandler::handleMessage(Net::MessageIn &msg)
@@ -60,114 +182,149 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg)
switch (msg.getId())
{
case GPMSG_INVENTORY_FULL:
- player_node->clearInventory();
- player_node->mEquipment->setBackend(&mEquips);
- // no break!
-
- case GPMSG_INVENTORY:
- while (msg.getUnreadLength())
{
- unsigned int slot = msg.readInt8();
- if (slot == 255)
+ PlayerInfo::clearInventory();
+ PlayerInfo::getEquipment()->setBackend(&mEquipBackend);
+ int count = msg.readInt16();
+ while (count--)
{
- player_node->setMoney(msg.readInt32());
- continue;
+ int slot = msg.readInt16();
+ int id = msg.readInt16();
+ int amount = msg.readInt16();
+ PlayerInfo::setInventoryItem(slot, id, amount);
}
+ while (msg.getUnreadLength())
+ {
+ int equipSlot = msg.readInt8();
+ int inventorySlot = msg.readInt16();
+ mEquipBackend.equip(inventorySlot, equipSlot);
+ }
+ }
+ break;
+
+ case GPMSG_INVENTORY:
+ while (msg.getUnreadLength())
+ {
+ unsigned int slot = msg.readInt16();
int id = msg.readInt16();
- if (slot < EQUIPMENT_SIZE)
+ unsigned int amount = id ? msg.readInt16() : 0;
+ PlayerInfo::setInventoryItem(slot, id, amount);
+ }
+ break;
+
+ case GPMSG_EQUIP:
+ while (msg.getUnreadLength())
+ {
+ int inventorySlot = msg.readInt16();
+ int equipSlotCount = msg.readInt8();
+
+ if (equipSlotCount == 0)
{
- mEquips.setEquipment(slot, id);
+ // No slots means to unequip this item
+ mEquipBackend.unequip(inventorySlot);
}
- else if (slot >= 32 && slot < 32 + getSize(Inventory::INVENTORY))
+ else
{
- int amount = id ? msg.readInt8() : 0;
- player_node->setInvItem(slot - 32, id, amount);
+ // Otherwise equip the item in the given slots
+ while (equipSlotCount--)
+ {
+ unsigned int equipSlot = msg.readInt8();
+ unsigned int amountUsed = msg.readInt8();
+
+ mEquipBackend.equip(inventorySlot, equipSlot,
+ amountUsed);
+ }
}
- };
+ }
break;
}
}
-void InventoryHandler::equipItem(const Item *item)
-{
- MessageOut msg(PGMSG_EQUIP);
- msg.writeInt8(item->getInvIndex());
- gameServerConnection->send(msg);
-}
-
-void InventoryHandler::unequipItem(const Item *item)
+void InventoryHandler::event(Event::Channel channel,
+ const Event &event)
{
- MessageOut msg(PGMSG_UNEQUIP);
- msg.writeInt8(item->getInvIndex());
- gameServerConnection->send(msg);
-
- // Tidy equipment directly to avoid weapon still shown bug, for instance
- int equipSlot = item->getInvIndex();
- logger->log("Unequipping %d", equipSlot);
- mEquips.setEquipment(equipSlot, 0);
-}
+ if (channel == Event::ItemChannel)
+ {
+ Item *item = event.getItem("item");
-void InventoryHandler::useItem(const Item *item)
-{
- MessageOut msg(PGMSG_USE_ITEM);
- msg.writeInt8(item->getInvIndex());
- gameServerConnection->send(msg);
-}
+ if (!item)
+ return;
-void InventoryHandler::dropItem(const Item *item, int amount)
-{
- MessageOut msg(PGMSG_DROP);
- msg.writeInt8(item->getInvIndex());
- msg.writeInt8(amount);
- gameServerConnection->send(msg);
-}
+ int index = item->getInvIndex();
-bool InventoryHandler::canSplit(const Item *item)
-{
- return item && !item->isEquipment() && item->getQuantity() > 1;
-}
+ if (event.getType() == Event::DoEquip)
+ {
+ MessageOut msg(PGMSG_EQUIP);
+ msg.writeInt8(index);
+ gameServerConnection->send(msg);
+ }
+ else if (event.getType() == Event::DoUnequip)
+ {
+ MessageOut msg(PGMSG_UNEQUIP);
+ msg.writeInt8(index);
+ gameServerConnection->send(msg);
+ }
+ else if (event.getType() == Event::DoUse)
+ {
+ MessageOut msg(PGMSG_USE_ITEM);
+ msg.writeInt8(index);
+ gameServerConnection->send(msg);
+ }
+ else if (event.getType() == Event::DoDrop)
+ {
+ int amount = event.getInt("amount", 1);
-void InventoryHandler::splitItem(const Item *item, int amount)
-{
- int newIndex = player_node->getInventory()->getFreeSlot();
- if (newIndex > Inventory::NO_SLOT_INDEX)
- {
- MessageOut msg(PGMSG_MOVE_ITEM);
- msg.writeInt8(item->getInvIndex());
- msg.writeInt8(newIndex);
- msg.writeInt8(amount);
- gameServerConnection->send(msg);
- }
-}
+ MessageOut msg(PGMSG_DROP);
+ msg.writeInt8(index);
+ msg.writeInt8(amount);
+ gameServerConnection->send(msg);
+ }
+ else if (event.getType() == Event::DoSplit)
+ {
+ int amount = event.getInt("amount", 1);
-void InventoryHandler::moveItem(int oldIndex, int newIndex)
-{
- if (oldIndex == newIndex)
- return;
+ int newIndex = PlayerInfo::getInventory()->getFreeSlot();
+ if (newIndex > Inventory::NO_SLOT_INDEX)
+ {
+ MessageOut msg(PGMSG_MOVE_ITEM);
+ msg.writeInt8(index);
+ msg.writeInt8(newIndex);
+ msg.writeInt8(amount);
+ gameServerConnection->send(msg);
+ }
+ }
+ else if (event.getType() == Event::DoMove)
+ {
+ int newIndex = event.getInt("newIndex", -1);
- MessageOut msg(PGMSG_MOVE_ITEM);
- msg.writeInt8(oldIndex);
- msg.writeInt8(newIndex);
- msg.writeInt8(player_node->getInventory()->getItem(oldIndex)
- ->getQuantity());
- gameServerConnection->send(msg);
-}
+ if (newIndex >= 0)
+ {
+ if (index == newIndex)
+ return;
-void InventoryHandler::openStorage(int type)
-{
- // TODO
-}
+ MessageOut msg(PGMSG_MOVE_ITEM);
+ msg.writeInt8(index);
+ msg.writeInt8(newIndex);
+ msg.writeInt8(item->getQuantity());
+ gameServerConnection->send(msg);
+ }
+ else
+ {
+ /*int source = event.getInt("source");
+ int destination = event.getInt("destination");
+ int amount = event.getInt("amount", 1);*/
-void InventoryHandler::closeStorage(int type)
-{
- // TODO
+ // TODO
+ }
+ }
+ }
}
-void InventoryHandler::moveItem(int source, int slot, int amount,
- int destination)
+bool InventoryHandler::canSplit(const Item *item)
{
- // TODO
+ return item && !item->getInfo().getEquippable()
+ && item->getQuantity() > 1;
}
size_t InventoryHandler::getSize(int type) const
diff --git a/src/net/manaserv/inventoryhandler.h b/src/net/manaserv/inventoryhandler.h
index fd08b95e..255f601c 100644
--- a/src/net/manaserv/inventoryhandler.h
+++ b/src/net/manaserv/inventoryhandler.h
@@ -23,82 +23,59 @@
#define NET_MANASERV_INVENTORYHANDLER_H
#include "equipment.h"
+#include "eventlistener.h"
#include "net/inventoryhandler.h"
#include "net/manaserv/messagehandler.h"
+#include <vector>
+
namespace ManaServ {
-class EquipBackend : public Equipment::Backend
+class EquipBackend : public Equipment::Backend, public EventListener
{
public:
- EquipBackend()
- { memset(mEquipment, 0, sizeof(mEquipment)); }
-
- Item *getEquipment(int index) const
- { return mEquipment[index]; }
+ EquipBackend();
- void clear()
- {
- for (int i = 0; i < EQUIPMENT_SIZE; ++i)
- delete mEquipment[i];
+ Item *getEquipment(int index) const;
+ void clear();
- std::fill_n(mEquipment, EQUIPMENT_SIZE, (Item*) 0);
- }
+ void equip(int inventorySlot, int equipSlot, int amountUsed = 1);
+ void unequip(int inventorySlot);
- void setEquipment(int index, int id, int quantity = 0)
- {
- if (mEquipment[index] && mEquipment[index]->getId() == id)
- return;
+ void event(Event::Channel channel, const Event &event);
- delete mEquipment[index];
- mEquipment[index] = (id > 0) ? new Item(id, quantity) : 0;
+ private:
+ void readEquipFile();
- if (mEquipment[index])
- {
- mEquipment[index]->setInvIndex(index);
- mEquipment[index]->setEquipped(true);
- mEquipment[index]->setInEquipment(true);
- }
- }
+ struct SlotType {
+ std::string name;
+ int count;
+ bool visible;
+ int firstIndex;
+ };
- private:
- Item *mEquipment[EQUIPMENT_SIZE];
+ std::vector<Item*> mSlots;
+ std::vector<SlotType> mSlotTypes;
};
-class InventoryHandler : public MessageHandler, Net::InventoryHandler
+class InventoryHandler : public MessageHandler, Net::InventoryHandler,
+ public EventListener
{
public:
InventoryHandler();
void handleMessage(Net::MessageIn &msg);
- void equipItem(const Item *item);
-
- void unequipItem(const Item *item);
-
- void useItem(const Item *item);
-
- void dropItem(const Item *item, int amount);
+ void event(Event::Channel channel, const Event &event);
bool canSplit(const Item *item);
- void splitItem(const Item *item, int amount);
-
- void moveItem(int oldIndex, int newIndex);
-
- void openStorage(int type);
-
- void closeStorage(int type);
-
- void moveItem(int source, int slot, int amount,
- int destination);
-
size_t getSize(int type) const;
private:
- EquipBackend mEquips;
+ EquipBackend mEquipBackend;
};
} // namespace ManaServ
diff --git a/src/net/manaserv/itemhandler.cpp b/src/net/manaserv/itemhandler.cpp
index dc3b9f14..2b8f631f 100644
--- a/src/net/manaserv/itemhandler.cpp
+++ b/src/net/manaserv/itemhandler.cpp
@@ -21,20 +21,18 @@
#include "net/manaserv/itemhandler.h"
-#include "flooritemmanager.h"
+#include "actorspritemanager.h"
-#include "net/manaserv/protocol.h"
+#include "net/manaserv/manaserv_protocol.h"
#include "net/manaserv/messagein.h"
-#include "game.h"
-#include "map.h"
#include "log.h"
namespace ManaServ {
ItemHandler::ItemHandler()
{
- static const Uint16 _messages[] = {
+ static const uint16_t _messages[] = {
GPMSG_ITEMS,
GPMSG_ITEM_APPEAR,
0
@@ -58,26 +56,11 @@ void ItemHandler::handleMessage(Net::MessageIn &msg)
if (itemId)
{
- if (Game *game = Game::instance())
- {
- if (Map *map = game->getCurrentMap())
- {
- floorItemManager->create(id,
- itemId,
- x / map->getTileWidth(),
- y / map->getTileHeight());
- }
- else
- {
- logger->log(
- "ItemHandler: An item wasn't created "
- "because of Game/Map not initialized...");
- }
- }
+ actorSpriteManager->createItem(id, itemId, Vector(x, y));
}
- else if (FloorItem *item = floorItemManager->findById(id))
+ else if (FloorItem *item = actorSpriteManager->findItem(id))
{
- floorItemManager->destroy(item);
+ actorSpriteManager->destroy(item);
}
}
} break;
diff --git a/src/net/manaserv/loginhandler.cpp b/src/net/manaserv/loginhandler.cpp
index 61671824..f06c3262 100644
--- a/src/net/manaserv/loginhandler.cpp
+++ b/src/net/manaserv/loginhandler.cpp
@@ -29,7 +29,7 @@
#include "net/manaserv/connection.h"
#include "net/manaserv/messagein.h"
#include "net/manaserv/messageout.h"
-#include "net/manaserv/protocol.h"
+#include "net/manaserv/manaserv_protocol.h"
#include "utils/gettext.h"
#include "utils/sha256.h"
@@ -44,6 +44,7 @@ extern std::string netToken;
LoginHandler::LoginHandler()
{
static const Uint16 _messages[] = {
+ APMSG_LOGIN_RNDTRGR_RESPONSE,
APMSG_LOGIN_RESPONSE,
APMSG_REGISTER_RESPONSE,
APMSG_RECONNECT_RESPONSE,
@@ -62,6 +63,10 @@ void LoginHandler::handleMessage(Net::MessageIn &msg)
{
switch (msg.getId())
{
+ case APMSG_LOGIN_RNDTRGR_RESPONSE:
+ handleLoginRandomResponse(msg);
+ break;
+
case APMSG_LOGIN_RESPONSE:
handleLoginResponse(msg);
break;
@@ -196,7 +201,7 @@ void LoginHandler::handleMessage(Net::MessageIn &msg)
// Successful unregistration
if (errMsg == ERRMSG_OK)
{
- Client::setState(STATE_UNREGISTER);
+ Client::setState(STATE_UNREGISTER_SUCCESS);
}
// Unregistration failed
else
@@ -245,13 +250,19 @@ void LoginHandler::handleMessage(Net::MessageIn &msg)
}
}
+void LoginHandler::handleLoginRandomResponse(Net::MessageIn &msg)
+{
+ mLoginData->randomSeed = msg.readString();
+ loginAccountContinue();
+}
+
void LoginHandler::handleLoginResponse(Net::MessageIn &msg)
{
const int errMsg = msg.readInt8();
if (errMsg == ERRMSG_OK)
{
- readUpdateHost(msg);
+ readServerInfo(msg);
// No worlds atm, but future use :-D
Client::setState(STATE_WORLD_SELECT);
}
@@ -289,7 +300,7 @@ void LoginHandler::handleRegisterResponse(Net::MessageIn &msg)
if (errMsg == ERRMSG_OK)
{
- readUpdateHost(msg);
+ readServerInfo(msg);
Client::setState(STATE_WORLD_SELECT);
}
else
@@ -320,7 +331,7 @@ void LoginHandler::handleRegisterResponse(Net::MessageIn &msg)
}
}
-void LoginHandler::readUpdateHost(Net::MessageIn &msg)
+void LoginHandler::readServerInfo(Net::MessageIn &msg)
{
// Safety check for outdated manaserv versions (remove me later)
if (msg.getUnreadLength() == 0)
@@ -332,6 +343,13 @@ void LoginHandler::readUpdateHost(Net::MessageIn &msg)
mLoginData->updateHost = updateHost;
else
logger->log("Warning: server does not have an update host set!");
+
+ // Read the client data folder for dynamic data loading.
+ // This is only used by the QT client.
+ msg.readString();
+
+ // Read the number of character slots
+ mLoginData->characterSlots = msg.readInt8();
}
void LoginHandler::connect()
@@ -378,14 +396,25 @@ unsigned int LoginHandler::getMaxUserNameLength() const
void LoginHandler::loginAccount(LoginData *loginData)
{
mLoginData = loginData;
+ mTmpPassword = loginData->password;
+
+ MessageOut msg(PAMSG_LOGIN_RNDTRGR);
+ msg.writeString(mLoginData->username);
+ accountServerConnection->send(msg);
+}
+
+void LoginHandler::loginAccountContinue()
+{
MessageOut msg(PAMSG_LOGIN);
- msg.writeInt32(0); // client version
- msg.writeString(loginData->username);
- msg.writeString(sha256(loginData->username + loginData->password));
+ msg.writeInt32(PROTOCOL_VERSION); // client version
+ msg.writeString(mLoginData->username);
+
+ msg.writeString(sha256(sha256(sha256(mLoginData->username + mTmpPassword)) + mLoginData->randomSeed));
accountServerConnection->send(msg);
+ mTmpPassword = "";
}
void LoginHandler::logout()
@@ -429,7 +458,7 @@ void LoginHandler::registerAccount(LoginData *loginData)
MessageOut msg(PAMSG_REGISTER);
- msg.writeInt32(0); // client version
+ msg.writeInt32(PROTOCOL_VERSION); // client version
msg.writeString(loginData->username);
// Use a hashed password for privacy reasons
msg.writeString(sha256(loginData->username + loginData->password));
diff --git a/src/net/manaserv/loginhandler.h b/src/net/manaserv/loginhandler.h
index d2ffbc3d..294b99ac 100644
--- a/src/net/manaserv/loginhandler.h
+++ b/src/net/manaserv/loginhandler.h
@@ -77,12 +77,16 @@ class LoginHandler : public MessageHandler, public Net::LoginHandler
void reconnect();
private:
+ void handleLoginRandomResponse(Net::MessageIn &msg);
void handleLoginResponse(Net::MessageIn &msg);
void handleRegisterResponse(Net::MessageIn &msg);
- void readUpdateHost(Net::MessageIn &msg);
+ void readServerInfo(Net::MessageIn &msg);
+
+ void loginAccountContinue();
LoginData *mLoginData;
+ std::string mTmpPassword;
unsigned int mMinUserNameLength;
unsigned int mMaxUserNameLength;
};
diff --git a/src/net/manaserv/protocol.h b/src/net/manaserv/manaserv_protocol.h
index 226a27a0..27d7c7b8 100644
--- a/src/net/manaserv/protocol.h
+++ b/src/net/manaserv/manaserv_protocol.h
@@ -22,6 +22,10 @@
#ifndef MANASERV_PROTOCOL_H
#define MANASERV_PROTOCOL_H
+namespace ManaServ {
+
+enum { PROTOCOL_VERSION = 1 };
+
/**
* Enumerated type for communicated messages:
*
@@ -44,21 +48,26 @@
enum {
// Login/Register
PAMSG_REGISTER = 0x0000, // D version, S username, S password, S email, S captcha response
- APMSG_REGISTER_RESPONSE = 0x0002, // B error, [S updatehost]
+ APMSG_REGISTER_RESPONSE = 0x0002, // B error, S updatehost, S Client data URL, B Character slots
PAMSG_UNREGISTER = 0x0003, // S username, S password
APMSG_UNREGISTER_RESPONSE = 0x0004, // B error
PAMSG_REQUEST_REGISTER_INFO = 0x0005, //
APMSG_REGISTER_INFO_RESPONSE = 0x0006, // B byte registration Allowed, byte minNameLength, byte maxNameLength, string captchaURL, string captchaInstructions
PAMSG_LOGIN = 0x0010, // D version, S username, S password
- APMSG_LOGIN_RESPONSE = 0x0012, // B error, [S updatehost]
+ APMSG_LOGIN_RESPONSE = 0x0012, // B error, S updatehost, S Client data URL, B Character slots
PAMSG_LOGOUT = 0x0013, // -
APMSG_LOGOUT_RESPONSE = 0x0014, // B error
- PAMSG_CHAR_CREATE = 0x0020, // S name, B hair style, B hair color, B gender, W*6 stats
+ PAMSG_LOGIN_RNDTRGR = 0x0015, // S username
+ APMSG_LOGIN_RNDTRGR_RESPONSE = 0x0016, // S random seed
+ PAMSG_CHAR_CREATE = 0x0020, // S name, B hair style, B hair color, B gender, B slot, {W stats}*
APMSG_CHAR_CREATE_RESPONSE = 0x0021, // B error
- PAMSG_CHAR_DELETE = 0x0022, // B index
+ PAMSG_CHAR_DELETE = 0x0022, // B slot
APMSG_CHAR_DELETE_RESPONSE = 0x0023, // B error
- APMSG_CHAR_INFO = 0x0024, // B index, S name, B gender, B hair style, B hair color, W level, W character points, W correction points, D money, W*6 stats
- PAMSG_CHAR_SELECT = 0x0026, // B index
+ // B slot, S name, B gender, B hair style, B hair color, W level,
+ // W character points, W correction points,
+ // {D attr id, D base value (in 1/256ths) D mod value (in 256ths) }*
+ APMSG_CHAR_INFO = 0x0024, // ^
+ PAMSG_CHAR_SELECT = 0x0026, // B slot
APMSG_CHAR_SELECT_RESPONSE = 0x0027, // B error, B*32 token, S game address, W game port, S chat address, W chat port
PAMSG_EMAIL_CHANGE = 0x0030, // S email
APMSG_EMAIL_CHANGE_RESPONSE = 0x0031, // B error
@@ -86,18 +95,19 @@ enum {
PGMSG_EQUIP = 0x0112, // B slot
PGMSG_UNEQUIP = 0x0113, // B slot
PGMSG_MOVE_ITEM = 0x0114, // B slot1, B slot2, B amount
- GPMSG_INVENTORY = 0x0120, // { B slot, W item id [, B amount] }*
- GPMSG_INVENTORY_FULL = 0x0121, // { B slot, W item id [, B amount] }*
- GPMSG_PLAYER_ATTRIBUTE_CHANGE = 0x0130, // { W attribute, W base value, W modified value }*
+ GPMSG_INVENTORY = 0x0120, // { W slot, W item id [, W amount] (if item id is nonzero) }*
+ GPMSG_INVENTORY_FULL = 0x0121, // W inventory slot count { W slot, W itemId, W amount }, { B equip slot, W invy slot}*
+ GPMSG_EQUIP = 0x0122, // { W Invy slot, B equip slot type count { B equip slot, B number used} }*
+ GPMSG_PLAYER_ATTRIBUTE_CHANGE = 0x0130, // { W attribute, D base value (in 1/256ths), D modified value (in 1/256ths)}*
GPMSG_PLAYER_EXP_CHANGE = 0x0140, // { W skill, D exp got, D exp needed }*
GPMSG_LEVELUP = 0x0150, // W new level, W character points, W correction points
GPMSG_LEVEL_PROGRESS = 0x0151, // B percent completed to next levelup
- PGMSG_RAISE_ATTRIBUTE = 0x0160, // B attribute
- GPMSG_RAISE_ATTRIBUTE_RESPONSE = 0x0161, // B error, B attribute
- PGMSG_LOWER_ATTRIBUTE = 0x0170, // B attribute
- GPMSG_LOWER_ATTRIBUTE_RESPONSE = 0x0171, // B error, B attribute
+ PGMSG_RAISE_ATTRIBUTE = 0x0160, // W attribute
+ GPMSG_RAISE_ATTRIBUTE_RESPONSE = 0x0161, // B error, W attribute
+ PGMSG_LOWER_ATTRIBUTE = 0x0170, // W attribute
+ GPMSG_LOWER_ATTRIBUTE_RESPONSE = 0x0171, // B error, W attribute
PGMSG_RESPAWN = 0x0180, // -
- GPMSG_BEING_ENTER = 0x0200, // B type, W being id, B action, W*2 position
+ GPMSG_BEING_ENTER = 0x0200, // B type, W being id, B action, W*2 position, B direction
// character: S name, B hair style, B hair color, B gender, B item bitmask, { W item id }*
// monster: W type id
// npc: W type id
@@ -109,11 +119,11 @@ enum {
GPMSG_BEING_ACTION_CHANGE = 0x0271, // W being id, B action
PGMSG_DIRECTION_CHANGE = 0x0272, // B Direction
GPMSG_BEING_DIR_CHANGE = 0x0273, // W being id, B direction
- GPMSG_BEING_HEALTH_CHANGE = 0x0274, // W being id, W health
- GPMSG_BEINGS_MOVE = 0x0280, // { W being id, B flags [, W*2 position, B speed] }*
+ GPMSG_BEING_HEALTH_CHANGE = 0x0274, // W being id, W hp, W max hp
+ GPMSG_BEINGS_MOVE = 0x0280, // { W being id, B flags [, [W*2 position,] W*2 destination, B speed] }*
GPMSG_ITEMS = 0x0281, // { W item id, W*2 position }*
PGMSG_ATTACK = 0x0290, // W being id
- GPMSG_BEING_ATTACK = 0x0291, // W being id, B direction, B attacktype
+ GPMSG_BEING_ATTACK = 0x0291, // W being id, B direction, B attack id
PGMSG_USE_SPECIAL = 0x0292, // B specialID
GPMSG_SPECIAL_STATUS = 0x0293, // { B specialID, D current, D max, D recharge }
PGMSG_SAY = 0x02A0, // S text
@@ -155,6 +165,7 @@ enum {
GPMSG_BEINGS_DAMAGE = 0x0310, // { W being id, W amount }*
GPMSG_CREATE_EFFECT_POS = 0x0320, // W effect id, W*2 position
GPMSG_CREATE_EFFECT_BEING = 0x0321, // W effect id, W BeingID
+ GPMSG_SHAKE = 0x0330, // W intensityX, W intensityY, [W decay_times_10000, [W duration]]
// Guild
PCMSG_GUILD_CREATE = 0x0350, // S name
@@ -177,17 +188,17 @@ enum {
CPMSG_GUILD_REJOIN = 0x0389, // S name, W guild, W rights, W channel, S announce
// Party
- PCMSG_PARTY_INVITE = 0x03A0, // S name
- CPMSG_PARTY_INVITE_RESPONSE = 0x03A1, // B error, S name
- CPMSG_PARTY_INVITED = 0x03A2, // S name
- PCMSG_PARTY_ACCEPT_INVITE = 0x03A5, // S name
- CPMSG_PARTY_ACCEPT_INVITE_RESPONSE = 0x03A6, // B error, { S name }
- PCMSG_PARTY_REJECT_INVITE = 0x03A7, // S name
- CPMSG_PARTY_REJECTED = 0x03A8, // S name
+ PGMSG_PARTY_INVITE = 0x03A0, // S name
+ GPMSG_PARTY_INVITE_ERROR = 0x03A1, // S name
+ GCMSG_PARTY_INVITE = 0x03A2, // S inviter, S invitee
+ CPMSG_PARTY_INVITED = 0x03A4, // S name
+ PCMSG_PARTY_INVITE_ANSWER = 0x03A5, // S name, B accept
+ CPMSG_PARTY_INVITE_ANSWER_RESPONSE = 0x03A6, // B error, { S name }
+ CPMSG_PARTY_REJECTED = 0x03A8, // S name, B error
PCMSG_PARTY_QUIT = 0x03AA, // -
CPMSG_PARTY_QUIT_RESPONSE = 0x03AB, // B error
- CPMSG_PARTY_NEW_MEMBER = 0x03B0, // W being id, S name
- CPMSG_PARTY_MEMBER_LEFT = 0x03B1, // W being id
+ CPMSG_PARTY_NEW_MEMBER = 0x03B0, // S name, S inviter
+ CPMSG_PARTY_MEMBER_LEFT = 0x03B1, // D character id
// Chat
CPMSG_ERROR = 0x0401, // B error
@@ -255,7 +266,8 @@ enum {
ERRMSG_ALREADY_TAKEN, // name used was already taken
ERRMSG_SERVER_FULL, // the server is overloaded
ERRMSG_TIME_OUT, // data failed to arrive in due time
- ERRMSG_LIMIT_REACHED // limit reached
+ ERRMSG_LIMIT_REACHED, // limit reached
+ ERRMSG_ADMINISTRATIVE_LOGOFF // kicked by server administrator
};
// used in AGMSG_REGISTER_RESPONSE to show state of item db
@@ -272,10 +284,11 @@ enum {
// used to identify part of sync message
enum {
- SYNC_CHARACTER_POINTS = 0x01, // D charId, D charPoints, D corrPoints, B attribute id, D attribute value
- SYNC_CHARACTER_SKILL = 0x02, // D charId, B skillId, D skill value
- SYNC_ONLINE_STATUS = 0x03, // D charId, B 0x00 = offline, 0x01 = online
- SYNC_END_OF_BUFFER = 0xFF // shows, that the buffer ends here.
+ SYNC_CHARACTER_POINTS = 0x01, // D charId, D charPoints, D corrPoints
+ SYNC_CHARACTER_ATTRIBUTE = 0x02, // D charId, D attrId, DF base, DF mod
+ SYNC_CHARACTER_SKILL = 0x03, // D charId, B skillId, D skill value
+ SYNC_ONLINE_STATUS = 0x04, // D charId, B 0x00 = offline, 0x01 = online
+ SYNC_END_OF_BUFFER = 0xFF // shows, that the buffer ends here.
};
// Login specific return values
@@ -300,9 +313,10 @@ enum {
CREATE_INVALID_GENDER,
CREATE_ATTRIBUTES_TOO_HIGH,
CREATE_ATTRIBUTES_TOO_LOW,
- CREATE_ATTRIBUTES_EQUAL_TO_ZERO,
+ CREATE_ATTRIBUTES_OUT_OF_RANGE,
CREATE_EXISTS_NAME,
- CREATE_TOO_MUCH_CHARACTERS
+ CREATE_TOO_MUCH_CHARACTERS,
+ CREATE_INVALID_SLOT
};
// Character attribute modification specific return value
@@ -342,11 +356,6 @@ enum {
MOVING_DESTINATION = 2
};
-// Email change specific return values
-enum {
- EMAILCHG_EXISTS_EMAIL = 0x40
-};
-
// Chat errors return values
enum {
CHAT_USING_BAD_WORDS = 0x40,
@@ -370,8 +379,54 @@ enum {
GUILD_EVENT_OFFLINE_PLAYER
};
+/**
+ * Moves enum for beings and actors for others players vision.
+ * WARNING: Has to be in sync with the same enum in the Being class
+ * of the client!
+ */
+enum BeingAction
+{
+ STAND,
+ WALK,
+ ATTACK,
+ SIT,
+ DEAD,
+ HURT
+};
-enum
+/**
+ * Moves enum for beings and actors for others players attack types.
+ * WARNING: Has to be in sync with the same enum in the Being class
+ * of the client!
+ */
+enum AttackType
+{
+ HIT = 0x00,
+ CRITICAL = 0x0a,
+ MULTI = 0x08,
+ REFLECT = 0x04,
+ FLEE = 0x0b
+};
+
+/**
+ * Beings and actors directions
+ * WARNING: Has to be in sync with the same enum in the Being class
+ * of the client!
+ */
+enum BeingDirection
+{
+ DOWN = 1,
+ LEFT = 2,
+ UP = 4,
+ RIGHT = 8
+};
+
+/**
+ * enum for sprites layers.
+ * WARNING: Has to be in sync with the same enum in the Sprite class
+ * of the client!
+ */
+enum SpriteLayer
{
SPRITE_BASE = 0,
SPRITE_SHOE,
@@ -383,4 +438,6 @@ enum
SPRITE_VECTOREND
};
+} // namespace ManaServ
+
#endif // MANASERV_PROTOCOL_H
diff --git a/src/net/manaserv/messagein.cpp b/src/net/manaserv/messagein.cpp
index 592182f7..58e6e59a 100644
--- a/src/net/manaserv/messagein.cpp
+++ b/src/net/manaserv/messagein.cpp
@@ -21,6 +21,7 @@
#include "net/manaserv/messagein.h"
+#include <cstring>
#include <enet/enet.h>
namespace ManaServ {
@@ -32,9 +33,9 @@ MessageIn::MessageIn(const char *data, unsigned int length):
mId = readInt16();
}
-int MessageIn::readInt16()
+uint16_t MessageIn::readInt16()
{
- int value = -1;
+ uint16_t value = 0;
if (mPos + 2 <= mLength)
{
uint16_t t;
@@ -45,9 +46,9 @@ int MessageIn::readInt16()
return value;
}
-int MessageIn::readInt32()
+uint32_t MessageIn::readInt32()
{
- int value = -1;
+ uint32_t value = 0;
if (mPos + 4 <= mLength)
{
uint32_t t;
diff --git a/src/net/manaserv/messagein.h b/src/net/manaserv/messagein.h
index fe77c436..d165ac4d 100644
--- a/src/net/manaserv/messagein.h
+++ b/src/net/manaserv/messagein.h
@@ -34,13 +34,10 @@ namespace ManaServ {
class MessageIn : public Net::MessageIn
{
public:
- /**
- * Constructor.
- */
MessageIn(const char *data, unsigned int length);
- int readInt16(); /**< Reads a short. */
- int readInt32(); /**< Reads a long. */
+ uint16_t readInt16();
+ uint32_t readInt32();
};
}
diff --git a/src/net/manaserv/messageout.cpp b/src/net/manaserv/messageout.cpp
index 8779c5f6..d332a507 100644
--- a/src/net/manaserv/messageout.cpp
+++ b/src/net/manaserv/messageout.cpp
@@ -24,11 +24,10 @@
#include <enet/enet.h>
#include <cstring>
-#include <string>
namespace ManaServ {
-MessageOut::MessageOut(short id):
+MessageOut::MessageOut(uint16_t id):
Net::MessageOut(id)
{
writeInt16(id);
@@ -45,7 +44,7 @@ void MessageOut::expand(size_t bytes)
mDataSize = mPos + bytes;
}
-void MessageOut::writeInt16(Sint16 value)
+void MessageOut::writeInt16(uint16_t value)
{
expand(2);
uint16_t t = ENET_HOST_TO_NET_16(value);
@@ -53,7 +52,7 @@ void MessageOut::writeInt16(Sint16 value)
mPos += 2;
}
-void MessageOut::writeInt32(Sint32 value)
+void MessageOut::writeInt32(uint32_t value)
{
expand(4);
uint32_t t = ENET_HOST_TO_NET_32(value);
diff --git a/src/net/manaserv/messageout.h b/src/net/manaserv/messageout.h
index 7c474cda..db7c4780 100644
--- a/src/net/manaserv/messageout.h
+++ b/src/net/manaserv/messageout.h
@@ -29,18 +29,12 @@ namespace ManaServ {
class MessageOut : public Net::MessageOut
{
public:
- /**
- * Constructor.
- */
- MessageOut(short id);
+ MessageOut(uint16_t id);
- /**
- * Destructor.
- */
~MessageOut();
- void writeInt16(Sint16 value); /**< Writes a short. */
- void writeInt32(Sint32 value); /**< Writes a long. */
+ void writeInt16(uint16_t value);
+ void writeInt32(uint32_t value);
protected:
/**
diff --git a/src/net/manaserv/network.cpp b/src/net/manaserv/network.cpp
index 636585c9..543aaa00 100644
--- a/src/net/manaserv/network.cpp
+++ b/src/net/manaserv/network.cpp
@@ -53,11 +53,7 @@ void initialize()
logger->error("Failed to initialize ENet.");
}
-#ifdef ENET_VERSION_MAJOR
client = enet_host_create(NULL, 3, 0, 0, 0);
-#else
- client = enet_host_create(NULL, 3, 0, 0);
-#endif
if (!client)
{
@@ -93,7 +89,7 @@ Connection *getConnection()
void registerHandler(MessageHandler *handler)
{
- for (const Uint16 *i = handler->handledMessages; *i; i++)
+ for (const uint16_t *i = handler->handledMessages; *i; i++)
{
mMessageHandlers[*i] = handler;
}
@@ -101,7 +97,7 @@ void registerHandler(MessageHandler *handler)
void unregisterHandler(MessageHandler *handler)
{
- for (const Uint16 *i = handler->handledMessages; *i; i++)
+ for (const uint16_t *i = handler->handledMessages; *i; i++)
{
mMessageHandlers.erase(*i);
}
diff --git a/src/net/manaserv/npchandler.cpp b/src/net/manaserv/npchandler.cpp
index 392ec4fd..2cec8ce8 100644
--- a/src/net/manaserv/npchandler.cpp
+++ b/src/net/manaserv/npchandler.cpp
@@ -21,16 +21,15 @@
#include "net/manaserv/npchandler.h"
-#include "beingmanager.h"
-#include "npc.h"
-
-#include "gui/npcdialog.h"
-#include "gui/npcpostdialog.h"
+#include "actorspritemanager.h"
+#include "event.h"
#include "net/manaserv/connection.h"
#include "net/manaserv/messagein.h"
#include "net/manaserv/messageout.h"
-#include "net/manaserv/protocol.h"
+#include "net/manaserv/manaserv_protocol.h"
+
+#include "utils/stringutils.h"
extern Net::NpcHandler *npcHandler;
@@ -40,7 +39,7 @@ extern Connection *gameServerConnection;
NpcHandler::NpcHandler()
{
- static const Uint16 _messages[] = {
+ static const uint16_t _messages[] = {
GPMSG_NPC_CHOICE,
GPMSG_NPC_POST,
GPMSG_NPC_MESSAGE,
@@ -56,76 +55,112 @@ NpcHandler::NpcHandler()
void NpcHandler::handleMessage(Net::MessageIn &msg)
{
- Being *being = beingManager->findBeing(msg.readInt16());
- if (!being || being->getType() != Being::NPC)
+ Being *being = actorSpriteManager->findBeing(msg.readInt16());
+ if (!being || being->getType() != ActorSprite::NPC)
{
return;
}
- int npcId = being->getId();
- NpcDialogs::iterator diag = mNpcDialogs.find(npcId);
- NpcDialog *dialog;
-
- if (diag == mNpcDialogs.end())
- {
- if (msg.getId() == GPMSG_NPC_ERROR || msg.getId() == GPMSG_NPC_CLOSE)
- return; // Dialog is pointless in these cases
-
- dialog = new NpcDialog(npcId);
- Wrapper wrap;
- wrap.dialog = dialog;
- mNpcDialogs[npcId] = wrap;
- }
- else
- {
- dialog = diag->second.dialog;
- }
+ int npcId = being->getId(), count = 0;
+ Event *event = 0;
switch (msg.getId())
{
- case GPMSG_NPC_CHOICE:
- dialog->choiceRequest();
- while (msg.getUnreadLength())
- {
- dialog->addChoice(msg.readString());
- }
- break;
-
- case GPMSG_NPC_NUMBER:
+ case GPMSG_NPC_CHOICE:
+ event = new Event(Event::Menu);
+ event->setInt("id", npcId);
+ while (msg.getUnreadLength())
{
- int min_num = msg.readInt32();
- int max_num = msg.readInt32();
- dialog->integerRequest(msg.readInt32(), min_num, max_num);
- break;
+ count++;
+ event->setString("choice" + toString(count), msg.readString());
}
+ event->setInt("choiceCount", count);
+ event->trigger(Event::NpcChannel);
+ break;
+
+ case GPMSG_NPC_NUMBER:
+ event = new Event(Event::IntegerInput);
+ event->setInt("id", npcId);
+ event->setInt("min", msg.readInt32());
+ event->setInt("max", msg.readInt32());
+ event->setInt("default", msg.readInt32());
+ event->trigger(Event::NpcChannel);
+ break;
+
+ case GPMSG_NPC_STRING:
+ event = new Event(Event::StringInput);
+ event->setInt("id", npcId);
+ event->trigger(Event::NpcChannel);
+ break;
+
+ case GPMSG_NPC_POST:
+ event = new Event(Event::Post);
+ event->setInt("id", npcId);
+ event->trigger(Event::NpcChannel);
+ break;
+
+ case GPMSG_NPC_ERROR:
+ event = new Event(Event::End);
+ event->setInt("id", npcId);
+ event->trigger(Event::NpcChannel);
+ break;
+
+ case GPMSG_NPC_MESSAGE:
+ event = new Event(Event::Message);
+ event->setInt("id", npcId);
+ event->setString("text", msg.readString(msg.getUnreadLength()));
+ event->trigger(Event::NpcChannel);
+ delete event;
+
+ event = new Event(Event::Next);
+ event->setInt("id", npcId);
+ event->trigger(Event::NpcChannel);
+ break;
+
+ case GPMSG_NPC_CLOSE:
+ event = new Event(Event::Close);
+ event->setInt("id", npcId);
+ event->trigger(Event::NpcChannel);
+ break;
+ }
- case GPMSG_NPC_STRING:
- dialog->textRequest("");
- break;
+ delete event;
+}
- case GPMSG_NPC_POST:
- {
- new NpcPostDialog(npcId);
- break;
- }
+void NpcHandler::startShopping(int beingId)
+{
+ // TODO
+}
- case GPMSG_NPC_ERROR:
- dialog->close();
- if (diag != mNpcDialogs.end())
- {
- mNpcDialogs.erase(diag);
- }
- break;
-
- case GPMSG_NPC_MESSAGE:
- dialog->addText(msg.readString(msg.getUnreadLength()));
- dialog->showNextButton();
- break;
-
- case GPMSG_NPC_CLOSE:
- dialog->showCloseButton();
- break;
- }
+void NpcHandler::buy(int beingId)
+{
+ // TODO
+}
+
+void NpcHandler::sell(int beingId)
+{
+ // TODO
+}
+
+void NpcHandler::buyItem(int beingId, int itemId, int amount)
+{
+ MessageOut msg(PGMSG_NPC_BUYSELL);
+ msg.writeInt16(itemId);
+ msg.writeInt16(amount);
+ gameServerConnection->send(msg);
+}
+
+void NpcHandler::sellItem(int beingId, int itemId, int amount)
+{
+ MessageOut msg(PGMSG_NPC_BUYSELL);
+ msg.writeInt16(itemId);
+ msg.writeInt16(amount);
+ gameServerConnection->send(msg);
+}
+
+void NpcHandler::endShopping(int beingId)
+{
+ // TODO
}
void NpcHandler::talk(int npcId)
@@ -133,6 +168,10 @@ void NpcHandler::talk(int npcId)
MessageOut msg(PGMSG_NPC_TALK);
msg.writeInt16(npcId);
gameServerConnection->send(msg);
+
+ Event event(Event::TalkSent);
+ event.setInt("npcId", npcId);
+ event.trigger(Event::NpcChannel);
}
void NpcHandler::nextDialog(int npcId)
@@ -140,6 +179,10 @@ void NpcHandler::nextDialog(int npcId)
MessageOut msg(PGMSG_NPC_TALK_NEXT);
msg.writeInt16(npcId);
gameServerConnection->send(msg);
+
+ Event event(Event::NextSent);
+ event.setInt("npcId", npcId);
+ event.trigger(Event::NpcChannel);
}
void NpcHandler::closeDialog(int npcId)
@@ -148,20 +191,22 @@ void NpcHandler::closeDialog(int npcId)
msg.writeInt16(npcId);
gameServerConnection->send(msg);
- NpcDialogs::iterator it = mNpcDialogs.find(npcId);
- if (it != mNpcDialogs.end())
- {
- (*it).second.dialog->close();
- mNpcDialogs.erase(it);
- }
+ Event event(Event::CloseSent);
+ event.setInt("npcId", npcId);
+ event.trigger(Event::NpcChannel);
}
-void NpcHandler::listInput(int npcId, int value)
+void NpcHandler::menuSelect(int npcId, int choice)
{
MessageOut msg(PGMSG_NPC_SELECT);
msg.writeInt16(npcId);
- msg.writeInt8(value);
+ msg.writeInt8(choice);
gameServerConnection->send(msg);
+
+ Event event(Event::MenuSent);
+ event.setInt("npcId", npcId);
+ event.setInt("choice", choice);
+ event.trigger(Event::NpcChannel);
}
void NpcHandler::integerInput(int npcId, int value)
@@ -170,6 +215,11 @@ void NpcHandler::integerInput(int npcId, int value)
msg.writeInt16(npcId);
msg.writeInt32(value);
gameServerConnection->send(msg);
+
+ Event event(Event::IntegerInputSent);
+ event.setInt("npcId", npcId);
+ event.setInt("value", value);
+ event.trigger(Event::NpcChannel);
}
void NpcHandler::stringInput(int npcId, const std::string &value)
@@ -178,56 +228,26 @@ void NpcHandler::stringInput(int npcId, const std::string &value)
msg.writeInt16(npcId);
msg.writeString(value);
gameServerConnection->send(msg);
+
+ Event event(Event::StringInputSent);
+ event.setInt("npcId", npcId);
+ event.setString("value", value);
+ event.trigger(Event::NpcChannel);
}
void NpcHandler::sendLetter(int npcId, const std::string &recipient,
- const std::string &text)
+ const std::string &text)
{
MessageOut msg(PGMSG_NPC_POST_SEND);
msg.writeString(recipient);
msg.writeString(text);
gameServerConnection->send(msg);
-}
-
-void NpcHandler::startShopping(int beingId)
-{
- // TODO
-}
-
-void NpcHandler::buy(int beingId)
-{
- // TODO
-}
-
-void NpcHandler::sell(int beingId)
-{
- // TODO
-}
-void NpcHandler::buyItem(int beingId, int itemId, int amount)
-{
- MessageOut msg(PGMSG_NPC_BUYSELL);
- msg.writeInt16(itemId);
- msg.writeInt16(amount);
- gameServerConnection->send(msg);
-}
-
-void NpcHandler::sellItem(int beingId, int itemId, int amount)
-{
- MessageOut msg(PGMSG_NPC_BUYSELL);
- msg.writeInt16(itemId);
- msg.writeInt16(amount);
- gameServerConnection->send(msg);
-}
-
-void NpcHandler::endShopping(int beingId)
-{
- // TODO
-}
-
-void NpcHandler::clearDialogs()
-{
- mNpcDialogs.clear();
+ Event event(Event::SendLetterSent);
+ event.setInt("npcId", npcId);
+ event.setString("recipient", recipient);
+ event.setString("text", text);
+ event.trigger(Event::NpcChannel);
}
} // namespace ManaServ
diff --git a/src/net/manaserv/npchandler.h b/src/net/manaserv/npchandler.h
index 689fdc1d..bda4de31 100644
--- a/src/net/manaserv/npchandler.h
+++ b/src/net/manaserv/npchandler.h
@@ -22,14 +22,14 @@
#ifndef NET_MANASERV_NPCHANDLER_H
#define NET_MANASERV_NPCHANDLER_H
+#include "eventlistener.h"
+
#include "net/npchandler.h"
#include "net/manaserv/messagehandler.h"
#include <map>
-class NpcDialog;
-
namespace ManaServ {
class NpcHandler : public MessageHandler, public Net::NpcHandler
@@ -39,21 +39,6 @@ class NpcHandler : public MessageHandler, public Net::NpcHandler
void handleMessage(Net::MessageIn &msg);
- void talk(int npcId);
-
- void nextDialog(int npcId);
-
- void closeDialog(int npcId);
-
- void listInput(int npcId, int value);
-
- void integerInput(int npcId, int value);
-
- void stringInput(int npcId, const std::string &value);
-
- void sendLetter(int npcId, const std::string &recipient,
- const std::string &text);
-
void startShopping(int beingId);
void buy(int beingId);
@@ -66,14 +51,21 @@ class NpcHandler : public MessageHandler, public Net::NpcHandler
void endShopping(int beingId);
- void clearDialogs();
+ void talk(int npcId);
+
+ void nextDialog(int npcId);
+
+ void closeDialog(int npcId);
+
+ void menuSelect(int npcId, int choice);
+
+ void integerInput(int npcId, int value);
+
+ void stringInput(int npcId, const std::string &value);
+
+ void sendLetter(int npcId, const std::string &recipient,
+ const std::string &text);
- private:
- typedef struct {
- NpcDialog* dialog;
- } Wrapper;
- typedef std::map<int, Wrapper> NpcDialogs;
- NpcDialogs mNpcDialogs;
};
} // namespace ManaServ
diff --git a/src/net/manaserv/partyhandler.cpp b/src/net/manaserv/partyhandler.cpp
index ec153fa8..e1bcb624 100644
--- a/src/net/manaserv/partyhandler.cpp
+++ b/src/net/manaserv/partyhandler.cpp
@@ -21,17 +21,16 @@
#include "net/manaserv/partyhandler.h"
+#include "event.h"
#include "log.h"
#include "localplayer.h"
#include "gui/socialwindow.h"
-#include "gui/widgets/chattab.h"
-
#include "net/manaserv/connection.h"
#include "net/manaserv/messagein.h"
#include "net/manaserv/messageout.h"
-#include "net/manaserv/protocol.h"
+#include "net/manaserv/manaserv_protocol.h"
#include "utils/gettext.h"
#include "utils/stringutils.h"
@@ -45,14 +44,15 @@ extern Net::PartyHandler *partyHandler;
namespace ManaServ {
extern Connection *chatServerConnection;
+extern Connection *gameServerConnection;
PartyHandler::PartyHandler():
mParty(Party::getParty(PARTY_ID))
{
static const Uint16 _messages[] = {
- CPMSG_PARTY_INVITE_RESPONSE,
+ GPMSG_PARTY_INVITE_ERROR,
CPMSG_PARTY_INVITED,
- CPMSG_PARTY_ACCEPT_INVITE_RESPONSE,
+ CPMSG_PARTY_INVITE_ANSWER_RESPONSE,
CPMSG_PARTY_QUIT_RESPONSE,
CPMSG_PARTY_NEW_MEMBER,
CPMSG_PARTY_MEMBER_LEFT,
@@ -61,18 +61,20 @@ PartyHandler::PartyHandler():
};
handledMessages = _messages;
partyHandler = this;
+
+ mParty->setName("Party");
}
void PartyHandler::handleMessage(Net::MessageIn &msg)
{
switch (msg.getId())
{
- case CPMSG_PARTY_INVITE_RESPONSE:
+ case GPMSG_PARTY_INVITE_ERROR:
{
- if (msg.readInt8() == ERRMSG_OK)
- {
-
- }
+ std::string name = msg.readString();
+ SERVER_NOTICE(strprintf(_("Party invite failed, because no player "
+ "called %s is within the visual range."),
+ name.c_str()));
} break;
case CPMSG_PARTY_INVITED:
@@ -80,14 +82,31 @@ void PartyHandler::handleMessage(Net::MessageIn &msg)
socialWindow->showPartyInvite(msg.readString());
} break;
- case CPMSG_PARTY_ACCEPT_INVITE_RESPONSE:
+ case CPMSG_PARTY_INVITE_ANSWER_RESPONSE:
{
- if (msg.readInt8() == ERRMSG_OK)
+ switch (msg.readInt8())
{
- //
- localChatTab->chatLog(_("Joined party."));
+ case ERRMSG_OK:
+ player_node->setParty(mParty);
+ while (msg.getUnreadLength())
+ {
+ std::string name = msg.readString();
+ mParty->addMember(0, name);
+ }
+ break;
+ case ERRMSG_TIME_OUT:
+ SERVER_NOTICE(_("Joining party failed, because the "
+ "invitation has timed out on the server."));
+ break;
+ case ERRMSG_FAILURE:
+ SERVER_NOTICE(_("Joining party failed, because the "
+ "inviter has left the game."));
+ break;
+ default:
+ logger->log("Unknown CPMSG_PARTY_INVITE_ANSWER_RESPONSE.");
+ break;
}
- }
+ } break;
case CPMSG_PARTY_QUIT_RESPONSE:
{
@@ -100,28 +119,48 @@ void PartyHandler::handleMessage(Net::MessageIn &msg)
case CPMSG_PARTY_NEW_MEMBER:
{
- int id = msg.readInt16(); // being id
std::string name = msg.readString();
+ std::string inviter = msg.readString();
+ std::string s;
+ if (!inviter.empty())
+ s = strprintf(_(" on invitation from %s"), inviter.c_str());
- localChatTab->chatLog(strprintf(_("%s joined the party."),
- name.c_str()));
+ SERVER_NOTICE(strprintf(_("%s joined the party%s."),
+ name.c_str(), s.c_str()));
- if (id == player_node->getId())
+ if (name == player_node->getName())
player_node->setParty(mParty);
- mParty->addMember(id, name);
+ mParty->addMember(0, name);
} break;
case CPMSG_PARTY_MEMBER_LEFT:
{
- mParty->removeMember(msg.readString());
+ // mParty->removeMember(msg.readString());
} break;
case CPMSG_PARTY_REJECTED:
{
std::string name = msg.readString();
- localChatTab->chatLog(strprintf(_("%s rejected your invite."),
+ switch (msg.readInt8())
+ {
+ case ERRMSG_OK:
+ SERVER_NOTICE(strprintf(_("%s rejected your invite."),
name.c_str()));
+ break;
+ case ERRMSG_LIMIT_REACHED:
+ SERVER_NOTICE(_("Party invitation rejected by server, "
+ "because of too many invitations in a "
+ "short time."));
+ break;
+ case ERRMSG_FAILURE:
+ SERVER_NOTICE(strprintf(_("%s is already in a party."),
+ name.c_str()));
+ break;
+ default:
+ logger->log("Unknown CPMSG_PARTY_REJECTED.");
+ break;
+ }
} break;
}
}
@@ -136,26 +175,26 @@ void PartyHandler::join(int partyId)
// TODO
}
-void PartyHandler::invite(Player *player)
+void PartyHandler::invite(Being *being)
{
- invite(player->getName());
+ invite(being->getName());
}
void PartyHandler::invite(const std::string &name)
{
- MessageOut msg(PCMSG_PARTY_INVITE);
+ MessageOut msg(PGMSG_PARTY_INVITE);
msg.writeString(name);
- chatServerConnection->send(msg);
+ gameServerConnection->send(msg);
}
void PartyHandler::inviteResponse(const std::string &inviter, bool accept)
{
- MessageOut msg = MessageOut(accept ? PCMSG_PARTY_ACCEPT_INVITE :
- PCMSG_PARTY_REJECT_INVITE);
+ MessageOut msg = MessageOut(PCMSG_PARTY_INVITE_ANSWER);
msg.writeString(inviter);
+ msg.writeInt8(accept);
chatServerConnection->send(msg);
}
@@ -167,7 +206,7 @@ void PartyHandler::leave()
chatServerConnection->send(msg);
}
-void PartyHandler::kick(Player *player)
+void PartyHandler::kick(Being *being)
{
// TODO
}
diff --git a/src/net/manaserv/partyhandler.h b/src/net/manaserv/partyhandler.h
index 0777b49e..29dc280d 100644
--- a/src/net/manaserv/partyhandler.h
+++ b/src/net/manaserv/partyhandler.h
@@ -43,7 +43,7 @@ public:
void join(int partyId);
- void invite(Player *player);
+ void invite(Being *being);
void invite(const std::string &name);
@@ -51,7 +51,7 @@ public:
void leave();
- void kick(Player *player);
+ void kick(Being *being);
void kick(const std::string &name);
diff --git a/src/net/manaserv/playerhandler.cpp b/src/net/manaserv/playerhandler.cpp
index 33367927..a114da3d 100644
--- a/src/net/manaserv/playerhandler.cpp
+++ b/src/net/manaserv/playerhandler.cpp
@@ -24,14 +24,14 @@
#include "client.h"
#include "effectmanager.h"
+#include "event.h"
#include "game.h"
#include "localplayer.h"
#include "log.h"
#include "particle.h"
-#include "npc.h"
+#include "playerinfo.h"
#include "configuration.h"
-#include "gui/chat.h"
#include "gui/gui.h"
#include "gui/okdialog.h"
#include "gui/viewport.h"
@@ -39,18 +39,18 @@
#include "net/net.h"
#include "net/manaserv/connection.h"
+#include "net/manaserv/defines.h"
#include "net/manaserv/messagein.h"
#include "net/manaserv/messageout.h"
-#include "net/manaserv/npchandler.h"
-#include "net/manaserv/protocol.h"
+#include "net/manaserv/manaserv_protocol.h"
+#include "net/manaserv/attributes.h"
/**
- * Max. distance we are willing to scroll after a teleport;
+ * Max. distance in tiles we are willing to scroll after a teleport;
* everything beyond will reset the port hard.
- * 32 is the nominal tile width/height.
* @todo: Make this parameter read from config.
*/
-static const int MAP_TELEPORT_SCROLL_DISTANCE = 8 * 32;
+const int MAP_TELEPORT_SCROLL_DISTANCE = 256;
extern Net::PlayerHandler *playerHandler;
@@ -64,9 +64,7 @@ void RespawnRequestListener::action(const gcn::ActionEvent &event)
{
Net::getPlayerHandler()->respawn();
- ManaServ::NpcHandler *handler =
- static_cast<ManaServ::NpcHandler*>(Net::getNpcHandler());
- handler->clearDialogs();
+ Event::trigger(Event::NpcChannel, Event::CloseAll);
}
PlayerHandler::PlayerHandler()
@@ -112,23 +110,24 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
case GPMSG_PLAYER_ATTRIBUTE_CHANGE:
{
- logger->log("ATTRIBUTE UPDATE:");
while (msg.getUnreadLength())
{
- int stat = msg.readInt16();
- int base = msg.readInt16();
- int value = msg.readInt16();
- logger->log("%d set to %d %d", stat, base, value);
-
- if (stat == BASE_ATTR_HP)
+ int attrId = msg.readInt16();
+ double base = msg.readInt32() / 256.0;
+ double value = msg.readInt32() / 256.0;
+
+ // Set the core player attribute the stat
+ // depending on attribute link.
+ int playerInfoId =
+ Attributes::getPlayerInfoIdFromAttrId(attrId);
+ if (playerInfoId > -1)
{
- player_node->setMaxHp(base);
- player_node->setHp(value);
+ PlayerInfo::setAttribute(playerInfoId, value);
}
else
{
- player_node->setAttributeBase(stat, base);
- player_node->setAttributeEffective(stat, value);
+ PlayerInfo::setStatBase(attrId, base);
+ PlayerInfo::setStatMod(attrId, value - base);
}
}
} break;
@@ -142,33 +141,33 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
int current = msg.readInt32();
int next = msg.readInt32();
- player_node->setExperience(skill, current, next);
+ PlayerInfo::setStatExperience(skill, current, next);
}
} break;
case GPMSG_LEVELUP:
{
- player_node->setLevel(msg.readInt16());
- player_node->setCharacterPoints(msg.readInt16());
- player_node->setCorrectionPoints(msg.readInt16());
+ PlayerInfo::setAttribute(LEVEL, msg.readInt16());
+ PlayerInfo::setAttribute(CHAR_POINTS, msg.readInt16());
+ PlayerInfo::setAttribute(CORR_POINTS, msg.readInt16());
Particle* effect = particleEngine->addEffect(
- paths.getValue("particles", "graphics/particles/")
- + paths.getValue("levelUpEffectFile", "levelup.particle.xml"),
- 0, 0);
+ paths.getStringValue("particles")
+ + paths.getStringValue("levelUpEffectFile")
+ ,0, 0);
player_node->controlParticle(effect);
} break;
case GPMSG_LEVEL_PROGRESS:
{
- player_node->setExp(msg.readInt8(), false);
+ PlayerInfo::setAttribute(EXP, msg.readInt8());
} break;
case GPMSG_RAISE_ATTRIBUTE_RESPONSE:
{
int errCode = msg.readInt8();
- int attrNum = msg.readInt8() - CHAR_ATTR_BEGIN;
+ int attrNum = msg.readInt16();
switch (errCode)
{
case ATTRIBMOD_OK:
@@ -185,18 +184,19 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
// has to be correct. The server is always right!
// undo attribute change and set points to 0
logger->log("Warning: Server denied increase of attribute %d (no points left) ", attrNum);
- int attrValue = player_node->getAttributeBase(attrNum) - 1;
- player_node->setCharacterPoints(0);
- player_node->setAttributeBase(attrNum, attrValue);
+ int attrValue = PlayerInfo::getStatBase(attrNum) - 1;
+ PlayerInfo::setAttribute(CHAR_POINTS, 0);
+ PlayerInfo::setStatBase(attrNum, attrValue);
} break;
case ATTRIBMOD_DENIED:
{
// undo attribute change
logger->log("Warning: Server denied increase of attribute %d (reason unknown) ", attrNum);
- int points = player_node->getCharacterPoints() - 1;
- player_node->setCharacterPoints(points);
- int attrValue = player_node->getAttributeBase(attrNum) - 1;
- player_node->setAttributeBase(attrNum, attrValue);
+ int points = PlayerInfo::getAttribute(CHAR_POINTS) - 1;
+ PlayerInfo::setAttribute(CHAR_POINTS, points);
+
+ int attrValue = PlayerInfo::getStatBase(attrNum) - 1;
+ PlayerInfo::setStatBase(attrNum, attrValue);
} break;
}
} break;
@@ -204,7 +204,7 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
case GPMSG_LOWER_ATTRIBUTE_RESPONSE:
{
int errCode = msg.readInt8();
- int attrNum = msg.readInt8() - CHAR_ATTR_BEGIN;
+ int attrNum = msg.readInt16();
switch (errCode)
{
case ATTRIBMOD_OK:
@@ -221,21 +221,24 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
// has to be correct. The server is always right!
// undo attribute change and set points to 0
logger->log("Warning: Server denied reduction of attribute %d (no points left) ", attrNum);
- int attrValue = player_node->getAttributeBase(attrNum) + 1;
- player_node->setCorrectionPoints(0);
- player_node->setAttributeBase(attrNum, attrValue);
- break;
+ int attrValue = PlayerInfo::getStatBase(attrNum) + 1;
+ // TODO are these right?
+ PlayerInfo::setAttribute(CHAR_POINTS, 0);
+ PlayerInfo::setAttribute(CORR_POINTS, 0);
+ PlayerInfo::setStatBase(attrNum, attrValue);
} break;
case ATTRIBMOD_DENIED:
{
// undo attribute change
logger->log("Warning: Server denied reduction of attribute %d (reason unknown) ", attrNum);
- int charaPoints = player_node->getCharacterPoints() - 1;
- player_node->setCharacterPoints(charaPoints);
- int correctPoints = player_node->getCorrectionPoints() + 1;
- player_node->setCorrectionPoints(correctPoints);
- int attrValue = player_node->getAttributeBase(attrNum) + 1;
- player_node->setAttributeBase(attrNum, attrValue);
+ int charaPoints = PlayerInfo::getAttribute(CHAR_POINTS) - 1;
+ PlayerInfo::setAttribute(CHAR_POINTS, charaPoints);
+
+ int correctPoints = PlayerInfo::getAttribute(CORR_POINTS) + 1;
+ PlayerInfo::setAttribute(CORR_POINTS, correctPoints);
+
+ int attrValue = PlayerInfo::getStatBase(attrNum) + 1;
+ PlayerInfo::setStatBase(attrNum, attrValue);
} break;
}
@@ -250,7 +253,7 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
int current = msg.readInt32();
int max = msg.readInt32();
int recharge = msg.readInt32();
- player_node->setSpecialStatus(id, current, max, recharge);
+ PlayerInfo::setSpecialStatus(id, current, max, recharge);
}
} break;
/*
@@ -325,14 +328,14 @@ void PlayerHandler::emote(int emoteId)
void PlayerHandler::increaseAttribute(int attr)
{
MessageOut msg(PGMSG_RAISE_ATTRIBUTE);
- msg.writeInt8(attr);
+ msg.writeInt16(attr);
gameServerConnection->send(msg);
}
void PlayerHandler::decreaseAttribute(int attr)
{
MessageOut msg(PGMSG_LOWER_ATTRIBUTE);
- msg.writeInt8(attr);
+ msg.writeInt16(attr);
gameServerConnection->send(msg);
}
@@ -343,11 +346,14 @@ void PlayerHandler::increaseSkill(int skillId)
void PlayerHandler::pickUp(FloorItem *floorItem)
{
- int id = floorItem->getId();
- MessageOut msg(PGMSG_PICKUP);
- msg.writeInt16(id >> 16);
- msg.writeInt16(id & 0xFFFF);
- gameServerConnection->send(msg);
+ if (floorItem)
+ {
+ int id = floorItem->getId();
+ MessageOut msg(PGMSG_PICKUP);
+ msg.writeInt16(id >> 16);
+ msg.writeInt16(id & 0xFFFF);
+ gameServerConnection->send(msg);
+ }
}
void PlayerHandler::setDirection(char direction)
@@ -405,10 +411,35 @@ int PlayerHandler::getJobLocation()
return -1;
}
-Vector PlayerHandler::getDefaultWalkSpeed()
+Vector PlayerHandler::getDefaultMoveSpeed() const
{
- // Return translation in pixels per ticks.
- return ManaServ::BeingHandler::giveSpeedInPixelsPerTicks(6.0f);
+ // Return default speed at 6 tiles per second.
+ return Vector(6.0f, 6.0f, 0.0f);
+}
+
+Vector PlayerHandler::getPixelsPerTickMoveSpeed(const Vector &speed, Map *map)
+{
+ Vector speedInTicks;
+
+ Game *game = Game::instance();
+ if (game && !map)
+ map = game->getCurrentMap();
+
+ if (!map)
+ {
+ logger->log("Manaserv::PlayerHandler: Speed wasn't given back"
+ " because Map not initialized.");
+ return speedInTicks;
+ }
+
+ speedInTicks.x = speed.x
+ * (float)map->getTileWidth()
+ / 1000 * (float) MILLISECONDS_IN_A_TICK;
+ speedInTicks.y = speed.y
+ * (float)map->getTileHeight()
+ / 1000 * (float) MILLISECONDS_IN_A_TICK;
+
+ return speedInTicks;
}
} // namespace ManaServ
diff --git a/src/net/manaserv/playerhandler.h b/src/net/manaserv/playerhandler.h
index 5796b0d3..3e3f8aad 100644
--- a/src/net/manaserv/playerhandler.h
+++ b/src/net/manaserv/playerhandler.h
@@ -65,7 +65,12 @@ class PlayerHandler : public MessageHandler, public Net::PlayerHandler
int getJobLocation();
- Vector getDefaultWalkSpeed();
+ Vector getDefaultMoveSpeed() const;
+
+ Vector getPixelsPerTickMoveSpeed(const Vector &speed, Map *map = 0);
+
+ bool usePixelPrecision()
+ { return true; }
private:
void handleMapChangeMessage(Net::MessageIn &msg);
diff --git a/src/net/manaserv/specialhandler.cpp b/src/net/manaserv/specialhandler.cpp
index 144111c2..11d361c8 100644
--- a/src/net/manaserv/specialhandler.cpp
+++ b/src/net/manaserv/specialhandler.cpp
@@ -24,7 +24,7 @@
#include "net/manaserv/connection.h"
#include "net/manaserv/messagein.h"
#include "net/manaserv/messageout.h"
-#include "net/manaserv/protocol.h"
+#include "net/manaserv/manaserv_protocol.h"
extern Net::SpecialHandler *specialHandler;
diff --git a/src/net/manaserv/stats.cpp b/src/net/manaserv/stats.cpp
deleted file mode 100644
index ece0e72a..00000000
--- a/src/net/manaserv/stats.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * The Mana Client
- * Copyright (C) 2010 The Mana Developers
- *
- * This file is part of The Mana Client.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "net/manaserv/stats.h"
-
-#include "log.h"
-
-#include "gui/statuswindow.h"
-
-#include "resources/itemdb.h"
-
-#include "utils/gettext.h"
-#include "utils/xml.h"
-
-#include <list>
-#include <map>
-
-#define DEFAULT_ATTRIBUTESDB_FILE "attributes.xml"
-
-namespace ManaServ {
-namespace Stats {
- typedef struct {
- unsigned int id;
- std::string name;
- std::string tag;
- std::string effect;
- std::string description;
- bool modifiable;
- } Stat;
-
- typedef std::map<unsigned int, Stat> StatMap;
- StatMap stats;
-
- static void loadBuiltins()
- {
- {
- Stat s;
- s.id = 16;
- s.name = _("Strength");
- s.tag = "str";
- s.effect = _("Strength %+d");
- s.description = "";
- s.modifiable = true;
-
- stats[s.id] = s;
- }
-
- {
- Stat s;
- s.id = 17;
- s.name = _("Agility");
- s.tag = "agi";
- s.effect = _("Agility %+d");
- s.description = "";
- s.modifiable = true;
-
- stats[s.id] = s;
- }
-
- {
- Stat s;
- s.id = 18;
- s.name = _("Dexterity");
- s.tag = "dex";
- s.effect = _("Dexterity %+d");
- s.description = "";
- s.modifiable = true;
-
- stats[s.id] = s;
- }
-
- {
- Stat s;
- s.id = 19;
- s.name = _("Vitality");
- s.tag = "vit";
- s.effect = _("Vitality %+d");
- s.description = "";
- s.modifiable = true;
-
- stats[s.id] = s;
- }
-
- {
- Stat s;
- s.id = 20;
- s.name = _("Intelligence");
- s.tag = "int";
- s.effect = _("Intelligence %+d");
- s.description = "";
- s.modifiable = true;
-
- stats[s.id] = s;
- }
-
- {
- Stat s;
- s.id = 21;
- s.name = _("Willpower");
- s.tag = "will";
- s.effect = _("Willpower %+d");
- s.description = "";
- s.modifiable = true;
-
- stats[s.id] = s;
- }
- }
-
- void load()
- {
- XML::Document doc(DEFAULT_ATTRIBUTESDB_FILE);
- xmlNodePtr rootNode = doc.rootNode();
-
- if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "stats"))
- {
- logger->log("Stats: Error while loading "
- DEFAULT_ATTRIBUTESDB_FILE ". Using Built-ins.");
- loadBuiltins();
- return;
- }
-
- for_each_xml_child_node(node, rootNode)
- {
- if (!xmlStrEqual(node->name, BAD_CAST "stat"))
- continue;
-
- int id = XML::getProperty(node, "id", 0);
-
- if (id == 0)
- {
- logger->log("Stats: Invalid or missing stat ID in "
- DEFAULT_ATTRIBUTESDB_FILE "!");
- continue;
- }
- else if (stats.find(id) != stats.end())
- {
- logger->log("Stats: Redefinition of stat ID %d", id);
- }
-
- std::string name = XML::getProperty(node, "name", "");
-
- if (name.empty())
- {
- logger->log("Stats: Invalid or missing stat name in "
- DEFAULT_ATTRIBUTESDB_FILE "!");
- continue;
- }
-
- Stat s;
- s.id = id;
- s.name = name;
- s.tag = XML::getProperty(node, "tag", "");
- s.effect = XML::getProperty(node, "effect", "");
- s.description = XML::getProperty(node, "desc", "");
- s.modifiable = XML::getProperty(node, "modifiable", "false")
- == "true";
-
- stats[id] = s;
- }
- }
-
- void unload()
- {
- stats.clear();
- }
-
- void informItemDB()
- {
- std::list<ItemDB::Stat> dbStats;
-
- StatMap::const_iterator it, it_end;
- for (it = stats.begin(), it_end = stats.end(); it != it_end; it++)
- if (!it->second.tag.empty())
- dbStats.push_back(ItemDB::Stat(it->second.tag,
- it->second.effect));
-
- ItemDB::setStatsList(dbStats);
- }
-
- void informStatusWindow()
- {
- StatMap::const_iterator it, it_end;
- for (it = stats.begin(), it_end = stats.end(); it != it_end; it++)
- statusWindow->addAttribute(it->second.id, it->second.name,
- it->second.modifiable,
- it->second.description);
- }
-
- std::vector<std::string> getLabelVector()
- {
- std::vector<std::string> attributes;
- StatMap::const_iterator it, it_end;
- for (it = stats.begin(), it_end = stats.end(); it != it_end; it++)
- if (it->second.modifiable)
- attributes.push_back(it->second.name + ":");
-
- return attributes;
- }
-} // namespace Stats
-} // namespace ManaServ
diff --git a/src/net/manaserv/tradehandler.cpp b/src/net/manaserv/tradehandler.cpp
index 234a18d6..6e205e24 100644
--- a/src/net/manaserv/tradehandler.cpp
+++ b/src/net/manaserv/tradehandler.cpp
@@ -21,21 +21,21 @@
#include "net/manaserv/tradehandler.h"
-#include "beingmanager.h"
+#include "actorspritemanager.h"
+#include "event.h"
#include "item.h"
#include "localplayer.h"
+#include "playerinfo.h"
#include "gui/confirmdialog.h"
#include "gui/trade.h"
-#include "gui/widgets/chattab.h"
-
#include "net/net.h"
#include "net/manaserv/connection.h"
#include "net/manaserv/messagein.h"
#include "net/manaserv/messageout.h"
-#include "net/manaserv/protocol.h"
+#include "net/manaserv/manaserv_protocol.h"
#include "utils/gettext.h"
#include "utils/stringutils.h"
@@ -86,16 +86,15 @@ TradeHandler::TradeHandler():
};
handledMessages = _messages;
tradeHandler = this;
-
}
void TradeHandler::setAcceptTradeRequests(bool acceptTradeRequests)
{
mAcceptTradeRequests = acceptTradeRequests;
if (mAcceptTradeRequests)
- localChatTab->chatLog(_("Accepting incoming trade requests."), BY_SERVER);
+ SERVER_NOTICE(_("Accepting incoming trade requests."))
else
- localChatTab->chatLog(_("Ignoring incoming trade requests."), BY_SERVER);
+ SERVER_NOTICE(_("Ignoring incoming trade requests."))
}
void TradeHandler::handleMessage(Net::MessageIn &msg)
@@ -104,13 +103,13 @@ void TradeHandler::handleMessage(Net::MessageIn &msg)
{
case GPMSG_TRADE_REQUEST:
{
- Being *being = beingManager->findBeing(msg.readInt16());
+ Being *being = actorSpriteManager->findBeing(msg.readInt16());
if (!being || !mAcceptTradeRequests)
{
respond(false);
break;
}
- player_node->setTrading(true);
+ PlayerInfo::setTrading(true);
tradePartnerName = being->getName();
tradePartnerID = being->getId();
ConfirmDialog *dlg = new ConfirmDialog(_("Request for Trade"),
@@ -144,19 +143,19 @@ void TradeHandler::handleMessage(Net::MessageIn &msg)
case GPMSG_TRADE_AGREED:
tradeWindow->receivedOk(false);
break;
-
+
case GPMSG_TRADE_CANCEL:
- localChatTab->chatLog(_("Trade canceled."), BY_SERVER);
+ SERVER_NOTICE(_("Trade canceled."))
tradeWindow->setVisible(false);
tradeWindow->reset();
- player_node->setTrading(false);
+ PlayerInfo::setTrading(false);
break;
case GPMSG_TRADE_COMPLETE:
- localChatTab->chatLog(_("Trade completed."), BY_SERVER);
+ SERVER_NOTICE(_("Trade completed."))
tradeWindow->setVisible(false);
tradeWindow->reset();
- player_node->setTrading(false);
+ PlayerInfo::setTrading(false);
break;
}
}
@@ -177,7 +176,7 @@ void TradeHandler::respond(bool accept)
gameServerConnection->send(msg);
if (!accept)
- player_node->setTrading(false);
+ PlayerInfo::setTrading(false);
}
void TradeHandler::addItem(Item *item, int amount)
diff --git a/src/net/messagehandler.h b/src/net/messagehandler.h
index a74dab61..f9f1fd89 100644
--- a/src/net/messagehandler.h
+++ b/src/net/messagehandler.h
@@ -24,8 +24,6 @@
#include "net/messagein.h"
-#include <SDL_types.h>
-
#include <memory>
namespace Net {
@@ -36,7 +34,7 @@ namespace Net {
class MessageHandler
{
public:
- const Uint16 *handledMessages;
+ const uint16_t *handledMessages;
virtual void handleMessage(MessageIn &msg) = 0;
diff --git a/src/net/messagein.cpp b/src/net/messagein.cpp
index 3c3e9edf..ef9a36f3 100644
--- a/src/net/messagein.cpp
+++ b/src/net/messagein.cpp
@@ -25,6 +25,8 @@
((unsigned short)(((unsigned char)(low)) | \
((unsigned short)((unsigned char)(high))) << 8))
+#include <cstring>
+
namespace Net {
MessageIn::MessageIn(const char *data, unsigned int length):
@@ -34,18 +36,18 @@ MessageIn::MessageIn(const char *data, unsigned int length):
{
}
-int MessageIn::readInt8()
+uint8_t MessageIn::readInt8()
{
- int value = -1;
+ uint8_t value = 0;
if (mPos < mLength)
{
- value = (unsigned char) mData[mPos];
+ value = mData[mPos];
}
- mPos += 1;
+ mPos++;
return value;
}
-void MessageIn::readCoordinates(Uint16 &x, Uint16 &y)
+void MessageIn::readCoordinates(uint16_t &x, uint16_t &y)
{
if (mPos + 3 <= mLength)
{
@@ -56,12 +58,12 @@ void MessageIn::readCoordinates(Uint16 &x, Uint16 &y)
mPos += 3;
}
-void MessageIn::readCoordinates(Uint16 &x, Uint16 &y, Uint8 &direction)
+void MessageIn::readCoordinates(uint16_t &x, uint16_t &y, uint8_t &direction)
{
if (mPos + 3 <= mLength)
{
const char *data = mData + mPos;
- Sint16 temp;
+ uint16_t temp;
temp = MAKEWORD(data[1] & 0x00c0, data[0] & 0x00ff);
x = temp >> 6;
@@ -70,7 +72,7 @@ void MessageIn::readCoordinates(Uint16 &x, Uint16 &y, Uint8 &direction)
direction = data[2] & 0x000f;
- // Translate from eAthena format
+ // Translate from tmwAthena format
switch (direction)
{
case 0:
@@ -108,13 +110,13 @@ void MessageIn::readCoordinates(Uint16 &x, Uint16 &y, Uint8 &direction)
mPos += 3;
}
-void MessageIn::readCoordinatePair(Uint16 &srcX, Uint16 &srcY,
- Uint16 &dstX, Uint16 &dstY)
+void MessageIn::readCoordinatePair(uint16_t &srcX, uint16_t &srcY,
+ uint16_t &dstX, uint16_t &dstY)
{
if (mPos + 5 <= mLength)
{
const char *data = mData + mPos;
- Sint16 temp;
+ uint16_t temp;
temp = MAKEWORD(data[3], data[2] & 0x000f);
dstX = temp >> 2;
diff --git a/src/net/messagein.h b/src/net/messagein.h
index e6118a04..31b4dbfc 100644
--- a/src/net/messagein.h
+++ b/src/net/messagein.h
@@ -22,8 +22,7 @@
#ifndef NET_MESSAGEIN_H
#define NET_MESSAGEIN_H
-#include <SDL_types.h>
-
+#include <cstdint>
#include <string>
namespace Net {
@@ -39,7 +38,7 @@ class MessageIn
/**
* Returns the message ID.
*/
- int getId() const { return mId; }
+ uint16_t getId() const { return mId; }
/**
* Returns the message length.
@@ -51,28 +50,39 @@ class MessageIn
*/
unsigned int getUnreadLength() const { return mLength - mPos; }
- virtual int readInt8(); /**< Reads a byte. */
- virtual int readInt16() = 0; /**< Reads a short. */
- virtual int readInt32() = 0; /**< Reads a long. */
+ /**
+ * Reads an unsigned 8-bit integer from the message.
+ */
+ virtual uint8_t readInt8();
+
+ /**
+ * Reads an unsigned 16-bit integer from the message.
+ */
+ virtual uint16_t readInt16() = 0;
+
+ /**
+ * Reads an unsigned 32-bit integer from the message.
+ */
+ virtual uint32_t readInt32() = 0;
/**
* Reads a 3-byte block containing tile-based coordinates. Used by
* manaserv.
*/
- virtual void readCoordinates(Uint16 &x, Uint16 &y);
+ virtual void readCoordinates(uint16_t &x, uint16_t &y);
/**
* Reads a special 3 byte block used by eAthena, containing x and y
* coordinates and direction.
*/
- virtual void readCoordinates(Uint16 &x, Uint16 &y, Uint8 &direction);
+ virtual void readCoordinates(uint16_t &x, uint16_t &y, uint8_t &direction);
/**
* Reads a special 5 byte block used by eAthena, containing a source
* and destination coordinate pair.
*/
- virtual void readCoordinatePair(Uint16 &srcX, Uint16 &srcY,
- Uint16 &dstX, Uint16 &dstY);
+ virtual void readCoordinatePair(uint16_t &srcX, uint16_t &srcY,
+ uint16_t &dstX, uint16_t &dstY);
/**
* Skips a given number of bytes.
@@ -89,9 +99,6 @@ class MessageIn
virtual ~MessageIn() {}
protected:
- /**
- * Constructor.
- */
MessageIn(const char *data, unsigned int length);
const char *mData; /**< The message data. */
@@ -106,6 +113,6 @@ class MessageIn
unsigned int mPos;
};
-}
+} // namespace Net
#endif // NET_MESSAGEIN_H
diff --git a/src/net/messageout.cpp b/src/net/messageout.cpp
index 0ac63935..814d7094 100644
--- a/src/net/messageout.cpp
+++ b/src/net/messageout.cpp
@@ -22,18 +22,17 @@
#include "net/messageout.h"
#include <cstring>
-#include <string>
namespace Net {
-MessageOut::MessageOut(short id):
+MessageOut::MessageOut(uint16_t id):
mData(0),
mDataSize(0),
mPos(0)
{
}
-void MessageOut::writeInt8(Sint8 value)
+void MessageOut::writeInt8(uint8_t value)
{
expand(1);
mData[mPos] = value;
@@ -57,7 +56,7 @@ void MessageOut::writeString(const std::string &string, int length)
expand(length);
// Write the actual string
- memcpy(mData + mPos, string.c_str(), stringLength);
+ memcpy(mData + mPos, string.data(), stringLength);
// Pad remaining space with zeros
if (length > stringLength)
diff --git a/src/net/messageout.h b/src/net/messageout.h
index 7fd6fbc5..cecdea9d 100644
--- a/src/net/messageout.h
+++ b/src/net/messageout.h
@@ -22,9 +22,8 @@
#ifndef NET_MESSAGEOUT_H
#define NET_MESSAGEOUT_H
-#include <SDL_types.h>
-
-#include <iosfwd>
+#include <cstdint>
+#include <string>
namespace Net {
@@ -36,9 +35,20 @@ namespace Net {
class MessageOut
{
public:
- virtual void writeInt8(Sint8 value); /**< Writes a byte. */
- virtual void writeInt16(Sint16 value) = 0; /**< Writes a short. */
- virtual void writeInt32(Sint32 value) = 0; /**< Writes a long. */
+ /**
+ * Writes an unsigned 8-bit integer to the message.
+ */
+ virtual void writeInt8(uint8_t value);
+
+ /**
+ * Writes an unsigned 16-bit integer to the message.
+ */
+ virtual void writeInt16(uint16_t value) = 0;
+
+ /**
+ * Writes an unsigned 32-bit integer to the message.
+ */
+ virtual void writeInt32(uint32_t value) = 0;
/**
* Writes a string. If a fixed length is not given (-1), it is stored
@@ -59,10 +69,7 @@ class MessageOut
virtual ~MessageOut() {}
protected:
- /**
- * Constructor.
- */
- MessageOut(short id);
+ MessageOut(uint16_t id);
/**
* Expand the packet data to be able to hold more data.
diff --git a/src/net/net.cpp b/src/net/net.cpp
index 1b4bbf36..7dae6b35 100644
--- a/src/net/net.cpp
+++ b/src/net/net.cpp
@@ -133,17 +133,12 @@ void connectToServer(ServerInfo &server)
{
// TODO: Query the server about itself and choose the netcode based on
// that
-
-#ifndef MANASERV_SUPPORT
- server.type = ServerInfo::TMWATHENA;
-#else
if (server.port == 6901)
server.type = ServerInfo::TMWATHENA;
else if (server.port == 9601)
server.type = ServerInfo::MANASERV;
else
logger->error(_("Unknown Server Type! Exiting."));
-#endif
}
if (networkType == server.type && getGeneralHandler() != NULL)
@@ -159,17 +154,14 @@ void connectToServer(ServerInfo &server)
switch (server.type)
{
-#ifdef MANASERV_SUPPORT
case ServerInfo::MANASERV:
new ManaServ::GeneralHandler;
break;
-#endif
case ServerInfo::TMWATHENA:
new TmwAthena::GeneralHandler;
break;
-
default:
- // Shouldn't happen...
+ logger->error(_("Server protocol unsupported"));
break;
}
diff --git a/src/net/npchandler.h b/src/net/npchandler.h
index bba8dc31..35535c61 100644
--- a/src/net/npchandler.h
+++ b/src/net/npchandler.h
@@ -29,13 +29,27 @@ namespace Net {
class NpcHandler
{
public:
+ virtual ~NpcHandler() {}
+
+ virtual void startShopping(int beingId) = 0;
+
+ virtual void buy(int beingId) = 0;
+
+ virtual void sell(int beingId) = 0;
+
+ virtual void buyItem(int beingId, int itemId, int amount) = 0;
+
+ virtual void sellItem(int beingId, int itemId, int amount) = 0;
+
+ virtual void endShopping(int beingId) = 0;
+
virtual void talk(int npcId) = 0;
virtual void nextDialog(int npcId) = 0;
virtual void closeDialog(int npcId) = 0;
- virtual void listInput(int npcId, int value) = 0;
+ virtual void menuSelect(int npcId, int choice) = 0;
virtual void integerInput(int npcId, int value) = 0;
@@ -44,19 +58,6 @@ class NpcHandler
virtual void sendLetter(int npcId, const std::string &recipient,
const std::string &text) = 0;
- virtual void startShopping(int beingId) = 0;
-
- virtual void buy(int beingId) = 0;
-
- virtual void sell(int beingId) = 0;
-
- virtual void buyItem(int beingId, int itemId, int amount) = 0;
-
- virtual void sellItem(int beingId, int itemId, int amount) = 0;
-
- virtual void endShopping(int beingId) = 0;
-
- virtual ~NpcHandler() {}
};
} // namespace Net
diff --git a/src/net/partyhandler.h b/src/net/partyhandler.h
index dd1103fc..7ca13546 100644
--- a/src/net/partyhandler.h
+++ b/src/net/partyhandler.h
@@ -24,7 +24,7 @@
#include <string>
-class Player;
+class Being;
enum PartyShare {
PARTY_SHARE_UNKNOWN = -1,
@@ -38,11 +38,13 @@ namespace Net {
class PartyHandler
{
public:
+ virtual ~PartyHandler() {}
+
virtual void create(const std::string &name = "") = 0;
virtual void join(int partyId) = 0;
- virtual void invite(Player *player) = 0;
+ virtual void invite(Being *player) = 0;
virtual void invite(const std::string &name) = 0;
@@ -50,7 +52,7 @@ class PartyHandler
virtual void leave() = 0;
- virtual void kick(Player *player) = 0;
+ virtual void kick(Being *player) = 0;
virtual void kick(const std::string &name) = 0;
@@ -69,8 +71,6 @@ class PartyHandler
// virtual void options() = 0;
// virtual void message() = 0;
-
- virtual ~PartyHandler() {}
};
} // namespace Net
diff --git a/src/net/playerhandler.h b/src/net/playerhandler.h
index 399afb5e..f9396caf 100644
--- a/src/net/playerhandler.h
+++ b/src/net/playerhandler.h
@@ -24,13 +24,14 @@
#include "being.h"
#include "flooritem.h"
-#include "localplayer.h"
namespace Net {
class PlayerHandler
{
public:
+ virtual ~PlayerHandler() {}
+
virtual void attack(int id) = 0;
virtual void emote(int emoteId) = 0;
@@ -61,9 +62,25 @@ class PlayerHandler
virtual int getJobLocation() = 0;
- virtual Vector getDefaultWalkSpeed() = 0;
-
- virtual ~PlayerHandler() {}
+ /**
+ * Get the original default movement speed.
+ * Example:
+ * In ticks per tiles for eAthena
+ * In tiles per second for Manaserv
+ */
+ virtual Vector getDefaultMoveSpeed() const = 0;
+
+ /**
+ * Convert the original speed in pixel per tick for internal use.
+ */
+ virtual Vector getPixelsPerTickMoveSpeed(const Vector &speed,
+ Map *map = 0) = 0;
+
+ /**
+ * Tells whether the client has to use pixel paths.
+ * Return false when tiles-center positions only are to be used.
+ */
+ virtual bool usePixelPrecision() = 0;
};
} // namespace Net
diff --git a/src/net/specialhandler.h b/src/net/specialhandler.h
index 21e3a4b7..89fcdf7d 100644
--- a/src/net/specialhandler.h
+++ b/src/net/specialhandler.h
@@ -28,6 +28,8 @@ namespace Net {
class SpecialHandler
{
public:
+ virtual ~SpecialHandler () {}
+
virtual void use(int id) = 0;
virtual void use(int id, int level, int beingId) = 0;
@@ -35,8 +37,6 @@ class SpecialHandler
virtual void use(int id, int level, int x, int y) = 0;
virtual void use(int id, const std::string &map) = 0;
-
- virtual ~SpecialHandler () {}
};
}
diff --git a/src/net/tmwa/adminhandler.cpp b/src/net/tmwa/adminhandler.cpp
index e2c3c74b..d18b6fc9 100644
--- a/src/net/tmwa/adminhandler.cpp
+++ b/src/net/tmwa/adminhandler.cpp
@@ -21,14 +21,12 @@
#include "net/tmwa/adminhandler.h"
+#include "actorspritemanager.h"
#include "being.h"
-#include "beingmanager.h"
+#include "event.h"
#include "game.h"
-#include "player.h"
#include "playerrelations.h"
-#include "gui/widgets/chattab.h"
-
#include "net/chathandler.h"
#include "net/net.h"
@@ -45,7 +43,8 @@ namespace TmwAthena {
AdminHandler::AdminHandler()
{
- static const Uint16 _messages[] = {
+ static const uint16_t _messages[] =
+ {
SMSG_ADMIN_KICK_ACK,
SMSG_ADMIN_IP,
0
@@ -62,15 +61,14 @@ void AdminHandler::handleMessage(Net::MessageIn &msg)
case SMSG_ADMIN_KICK_ACK:
id = msg.readInt32();
if (id == 0)
- localChatTab->chatLog(_("Kick failed!"), BY_SERVER);
+ SERVER_NOTICE(_("Kick failed!"))
else
- localChatTab->chatLog(_("Kick succeeded!"), BY_SERVER);
+ SERVER_NOTICE(_("Kick succeeded!"))
break;
case SMSG_ADMIN_IP:
id = msg.readInt32();
int ip = msg.readInt32();
- Being *being = beingManager->findBeing(id);
- if (Player *player = dynamic_cast<Player *>(being))
+ if (Being *player = actorSpriteManager->findBeing(id))
{
player->setIp(ip);
player->updateName();
diff --git a/src/net/tmwa/beinghandler.cpp b/src/net/tmwa/beinghandler.cpp
index 2fe962c7..41345acb 100644
--- a/src/net/tmwa/beinghandler.cpp
+++ b/src/net/tmwa/beinghandler.cpp
@@ -20,32 +20,37 @@
*/
#include "net/tmwa/beinghandler.h"
+#include "net/tmwa/playerhandler.h"
+#include "actorspritemanager.h"
#include "being.h"
-#include "beingmanager.h"
#include "client.h"
#include "effectmanager.h"
+#include "game.h"
#include "guild.h"
#include "localplayer.h"
#include "log.h"
-#include "npc.h"
#include "party.h"
#include "playerrelations.h"
#include "net/tmwa/protocol.h"
#include "resources/colordb.h"
+#include "resources/emotedb.h"
#include <iostream>
+#include <cmath>
namespace TmwAthena {
-const int EMOTION_TIME = 150; /**< Duration of emotion icon */
+// Number of pixels where we decide that the position doesn't need to be reset.
+static const float POS_DEST_DIFF_TOLERANCE = 48.0f;
BeingHandler::BeingHandler(bool enableSync):
mSync(enableSync)
{
- static const Uint16 _messages[] = {
+ static const Uint16 _messages[] =
+ {
SMSG_BEING_VISIBLE,
SMSG_BEING_MOVE,
SMSG_BEING_SPAWN,
@@ -73,21 +78,21 @@ BeingHandler::BeingHandler(bool enableSync):
handledMessages = _messages;
}
-Being *createBeing(int id, short job)
+static Being *createBeing(int id, short job)
{
- Being::Type type = Being::UNKNOWN;
+ ActorSprite::Type type = ActorSprite::UNKNOWN;
if (job <= 25 || (job >= 4001 && job <= 4049))
- type = Being::PLAYER;
+ type = ActorSprite::PLAYER;
else if (job >= 46 && job <= 1000)
- type = Being::NPC;
+ type = ActorSprite::NPC;
else if (job > 1000 && job <= 2000)
- type = Being::MONSTER;
+ type = ActorSprite::MONSTER;
else if (job == 45)
return NULL; // Skip portals
- Being *being = beingManager->createBeing(id, type, job);
+ Being *being = actorSpriteManager->createBeing(id, type, job);
- if (type == Being::PLAYER || type == Being::NPC)
+ if (type == ActorSprite::PLAYER || type == ActorSprite::NPC)
{
MessageOut outMsg(0x0094);
outMsg.writeInt32(id);//readLong(2));
@@ -96,13 +101,59 @@ Being *createBeing(int id, short job)
return being;
}
+static void handleMoveMessage(Map *map, Being *dstBeing,
+ Uint16 srcX, Uint16 srcY,
+ Uint16 dstX, Uint16 dstY)
+{
+ // Avoid dealing with flawed destination
+ if (map && dstBeing && srcX && srcY && dstX && dstY)
+ {
+ Vector pos = map->getTileCenter(srcX, srcY);
+ Vector dest = map->getTileCenter(dstX, dstY);
+ Vector beingPos = dstBeing->getPosition();
+
+ // Don't set the position as the movement algorithm
+ // can guess it and it would break the animation played,
+ // when we're close enough.
+ if (std::abs(beingPos.x - pos.x) > POS_DEST_DIFF_TOLERANCE
+ || std::abs(beingPos.y - pos.y) > POS_DEST_DIFF_TOLERANCE)
+ dstBeing->setPosition(pos);
+
+ dstBeing->setDestination(dest.x, dest.y);
+ }
+}
+
+static void handlePosMessage(Map *map, Being *dstBeing, Uint16 x, Uint16 y,
+ Uint8 dir = 0)
+{
+ // Avoid dealing with flawed destination
+ if (map && dstBeing && x && y)
+ {
+ Vector pos = map->getTileCenter(x, y);
+ Vector beingPos = dstBeing->getPosition();
+ // Don't set the position as the movement algorithm
+ // can guess it and it would break the animation played,
+ // when we're close enough.
+ if (std::abs(beingPos.x - pos.x) > POS_DEST_DIFF_TOLERANCE
+ || std::abs(beingPos.y - pos.y) > POS_DEST_DIFF_TOLERANCE)
+ dstBeing->setPosition(pos);
+
+ // Set also the destination to the desired position.
+ dstBeing->setDestination(pos.x, pos.y);
+
+ if (dir)
+ dstBeing->setDirection(dir);
+ }
+}
+
void BeingHandler::handleMessage(Net::MessageIn &msg)
{
- if (!beingManager)
+ if (!actorSpriteManager)
return;
int id;
- short job, speed, gender;
+ short job, gender;
+ float speed;
Uint16 headTop, headMid, headBottom;
Uint16 shoes, gloves;
Uint16 weapon, shield;
@@ -113,22 +164,24 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
int type, guild;
Uint16 status;
Being *srcBeing, *dstBeing;
- Player *player = 0;
int hairStyle, hairColor, flag;
+ // Prepare useful translation variables
+ Map *map = Game::instance()->getCurrentMap();
+
switch (msg.getId())
{
case SMSG_BEING_VISIBLE:
case SMSG_BEING_MOVE:
// Information about a being in range
id = msg.readInt32();
- speed = msg.readInt16();
+ speed = (float)msg.readInt16();
stunMode = msg.readInt16(); // opt1
statusEffects = msg.readInt16(); // opt2
statusEffects |= ((Uint32)msg.readInt16()) << 16; // option
job = msg.readInt16(); // class
- dstBeing = beingManager->findBeing(id);
+ dstBeing = actorSpriteManager->findBeing(id);
if (!dstBeing)
{
@@ -145,22 +198,17 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
break;
}
- if (dstBeing->getType() == Being::PLAYER)
- player = static_cast<Player*>(dstBeing);
-
- if (msg.getId() == 0x0078)
+ if (msg.getId() == SMSG_BEING_VISIBLE)
{
dstBeing->clearPath();
- dstBeing->setFrame(0);
- dstBeing->setWalkTime(tick_time);
dstBeing->setAction(Being::STAND);
}
-
// Prevent division by 0 when calculating frame
- if (speed == 0) { speed = 150; }
+ if (speed == 0)
+ speed = 150.0f; // In ticks per tile * 10
- dstBeing->setWalkSpeed(Vector(speed, speed, 0));
+ dstBeing->setMoveSpeed(Vector(speed / 10, speed / 10));
dstBeing->setSubtype(job);
hairStyle = msg.readInt16();
weapon = msg.readInt16();
@@ -178,16 +226,13 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
shoes = msg.readInt16(); // clothes color - "abused" as shoes
gloves = msg.readInt16(); // head dir - "abused" as gloves
guild = msg.readInt32(); // guild
- if (player)
+ if (guild == 0)
{
- if (guild == 0)
- {
- player->clearGuilds();
- }
- else
- {
- player->addGuild(Guild::getGuild(guild));
- }
+ dstBeing->clearGuilds();
+ }
+ else
+ {
+ dstBeing->addGuild(Guild::getGuild(guild));
}
msg.readInt16(); // guild emblem
msg.readInt16(); // manner
@@ -195,36 +240,33 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
msg.readInt8(); // karma
gender = msg.readInt8();
- if (player)
+ if (dstBeing->getType() == ActorSprite::PLAYER)
{
- player->setGender((gender == 0)
- ? GENDER_FEMALE : GENDER_MALE);
+ dstBeing->setGender((gender == 0)
+ ? GENDER_FEMALE : GENDER_MALE);
// Set these after the gender, as the sprites may be gender-specific
- player->setSprite(SPRITE_HAIR, hairStyle * -1, ColorDB::get(hairColor));
- player->setSprite(SPRITE_BOTTOMCLOTHES, headBottom);
- player->setSprite(SPRITE_TOPCLOTHES, headMid);
- player->setSprite(SPRITE_HAT, headTop);
- player->setSprite(SPRITE_SHOE, shoes);
- player->setSprite(SPRITE_GLOVES, gloves);
- player->setSprite(SPRITE_WEAPON, weapon, "", true);
- player->setSprite(SPRITE_SHIELD, shield);
+ dstBeing->setSprite(SPRITE_HAIR, hairStyle * -1, ColorDB::get(hairColor));
+ dstBeing->setSprite(SPRITE_BOTTOMCLOTHES, headBottom);
+ dstBeing->setSprite(SPRITE_TOPCLOTHES, headMid);
+ dstBeing->setSprite(SPRITE_HAT, headTop);
+ dstBeing->setSprite(SPRITE_SHOE, shoes);
+ dstBeing->setSprite(SPRITE_GLOVES, gloves);
+ dstBeing->setSprite(SPRITE_WEAPON, weapon, "", true);
+ dstBeing->setSprite(SPRITE_SHIELD, shield);
}
if (msg.getId() == SMSG_BEING_MOVE)
{
Uint16 srcX, srcY, dstX, dstY;
msg.readCoordinatePair(srcX, srcY, dstX, dstY);
- dstBeing->setAction(Being::STAND);
- dstBeing->setTileCoords(srcX, srcY);
- dstBeing->setDestination(dstX, dstY);
+ handleMoveMessage(map, dstBeing, srcX, srcY, dstX, dstY);
}
else
{
Uint8 dir;
Uint16 x, y;
msg.readCoordinates(x, y, dir);
- dstBeing->setTileCoords(x, y);
- dstBeing->setDirection(dir);
+ handlePosMessage(map, dstBeing, x, y, dir);
}
msg.readInt8(); // unknown
@@ -244,16 +286,13 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
break;
case SMSG_BEING_MOVE2:
+ {
/*
* A simplified movement packet, used by the
* later versions of eAthena for both mobs and
* players
*/
- dstBeing = beingManager->findBeing(msg.readInt32());
-
- Uint16 srcX, srcY, dstX, dstY;
- msg.readCoordinatePair(srcX, srcY, dstX, dstY);
- msg.readInt32(); // Server tick
+ dstBeing = actorSpriteManager->findBeing(msg.readInt32());
/*
* This packet doesn't have enough info to actually
@@ -261,21 +300,20 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
* we'll just pretend the packet didn't happen
*/
- if (dstBeing)
- {
- dstBeing->setAction(Being::STAND);
- dstBeing->setTileCoords(srcX, srcY);
- dstBeing->setDestination(dstX, dstY);
- }
+ if (!dstBeing)
+ break;
+ Uint16 srcX, srcY, dstX, dstY;
+ msg.readCoordinatePair(srcX, srcY, dstX, dstY);
+ msg.readInt32(); // Server tick
+ handleMoveMessage(map, dstBeing, srcX, srcY, dstX, dstY);
+ }
break;
case SMSG_BEING_REMOVE:
// A being should be removed or has died
id = msg.readInt32();
-
- dstBeing = beingManager->findBeing(id);
-
+ dstBeing = actorSpriteManager->findBeing(id);
if (!dstBeing)
break;
@@ -286,16 +324,14 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
if (msg.readInt8() == 1)
dstBeing->setAction(Being::DEAD);
else
- beingManager->destroyBeing(dstBeing);
+ actorSpriteManager->destroy(dstBeing);
break;
case SMSG_BEING_RESURRECT:
// A being changed mortality status
id = msg.readInt32();
-
- dstBeing = beingManager->findBeing(id);
-
+ dstBeing = actorSpriteManager->findBeing(id);
if (!dstBeing)
break;
@@ -309,25 +345,28 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
break;
case SMSG_SKILL_DAMAGE:
+ {
msg.readInt16(); // Skill Id
- srcBeing = beingManager->findBeing(msg.readInt32());
- dstBeing = beingManager->findBeing(msg.readInt32());
+ srcBeing = actorSpriteManager->findBeing(msg.readInt32());
+ dstBeing = actorSpriteManager->findBeing(msg.readInt32());
msg.readInt32(); // Server tick
- msg.readInt32(); // src speed
+ int attackSpeed = msg.readInt32(); // src speed
msg.readInt32(); // dst speed
param1 = msg.readInt32(); // Damage
msg.readInt16(); // Skill level
msg.readInt16(); // Div
msg.readInt8(); // Skill hit/type (?)
+ if (attackSpeed && srcBeing && srcBeing != player_node)
+ srcBeing->setAttackSpeed(attackSpeed);
if (dstBeing)
dstBeing->takeDamage(srcBeing, param1, Being::HIT); // Perhaps a new skill attack type should be created and used?
if (srcBeing)
srcBeing->handleAttack(dstBeing, param1, Being::HIT);
break;
-
+ }
case SMSG_BEING_ACTION:
- srcBeing = beingManager->findBeing(msg.readInt32());
- dstBeing = beingManager->findBeing(msg.readInt32());
+ srcBeing = actorSpriteManager->findBeing(msg.readInt32());
+ dstBeing = actorSpriteManager->findBeing(msg.readInt32());
msg.readInt32(); // server tick
msg.readInt32(); // src speed
msg.readInt32(); // dst speed
@@ -354,7 +393,6 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
case 0x02: // Sit
if (srcBeing)
{
- srcBeing->setFrame(0);
srcBeing->setAction(Being::SIT);
}
break;
@@ -362,37 +400,36 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
case 0x03: // Stand up
if (srcBeing)
{
- srcBeing->setFrame(0);
srcBeing->setAction(Being::STAND);
}
break;
}
break;
- case SMSG_BEING_SELFEFFECT: {
+ case SMSG_BEING_SELFEFFECT:
+ {
id = (Uint32)msg.readInt32();
- if (!beingManager->findBeing(id))
+ Being* being = actorSpriteManager->findBeing(id);
+ if (!being)
break;
int effectType = msg.readInt32();
- Being* being = beingManager->findBeing(id);
effectManager->trigger(effectType, being);
-
break;
}
case SMSG_BEING_EMOTION:
- if (!(dstBeing = beingManager->findBeing(msg.readInt32())))
+ if (!(dstBeing = actorSpriteManager->findBeing(msg.readInt32())))
{
break;
}
if (player_relations.hasPermission(dstBeing, PlayerRelation::EMOTE))
{
- // only set emote if one doesnt already exist
- if (!dstBeing->getEmotion())
- dstBeing->setEmote(msg.readInt8(), EMOTION_TIME);
+ const int fx = EmoteDB::get(msg.readInt8())->effect;
+ //TODO: figure out why the -1 is needed
+ effectManager->trigger(fx - 1, dstBeing);
}
break;
@@ -412,14 +449,11 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
* 16 bit value will be 0.
*/
- if (!(dstBeing = beingManager->findBeing(msg.readInt32())))
+ if (!(dstBeing = actorSpriteManager->findBeing(msg.readInt32())))
{
break;
}
- if (dstBeing->getType() == Being::PLAYER)
- player = static_cast<Player*>(dstBeing);
-
int type = msg.readInt8();
int id = 0;
int id2 = 0;
@@ -437,41 +471,41 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
switch (type)
{
case 1: // eAthena LOOK_HAIR
- player->setSpriteID(SPRITE_HAIR, id *-1);
+ dstBeing->setSpriteID(SPRITE_HAIR, id *-1);
break;
case 2: // Weapon ID in id, Shield ID in id2
- player->setSprite(SPRITE_WEAPON, id, "", true);
- player->setSprite(SPRITE_SHIELD, id2);
+ dstBeing->setSprite(SPRITE_WEAPON, id, "", true);
+ dstBeing->setSprite(SPRITE_SHIELD, id2);
break;
case 3: // Change lower headgear for eAthena, pants for us
- player->setSprite(SPRITE_BOTTOMCLOTHES, id);
+ dstBeing->setSprite(SPRITE_BOTTOMCLOTHES, id);
break;
case 4: // Change upper headgear for eAthena, hat for us
- player->setSprite(SPRITE_HAT, id);
+ dstBeing->setSprite(SPRITE_HAT, id);
break;
case 5: // Change middle headgear for eathena, armor for us
- player->setSprite(SPRITE_TOPCLOTHES, id);
+ dstBeing->setSprite(SPRITE_TOPCLOTHES, id);
break;
case 6: // eAthena LOOK_HAIR_COLOR
- player->setSpriteColor(SPRITE_HAIR, ColorDB::get(id));
+ dstBeing->setSpriteColor(SPRITE_HAIR, ColorDB::get(id));
break;
case 8: // eAthena LOOK_SHIELD
- player->setSprite(SPRITE_SHIELD, id);
+ dstBeing->setSprite(SPRITE_SHIELD, id);
break;
case 9: // eAthena LOOK_SHOES
- player->setSprite(SPRITE_SHOE, id);
+ dstBeing->setSprite(SPRITE_SHOE, id);
break;
case 10: // LOOK_GLOVES
- player->setSprite(SPRITE_GLOVES, id);
+ dstBeing->setSprite(SPRITE_GLOVES, id);
break;
case 11: // LOOK_CAPE
- player->setSprite(SPRITE_CAPE, id);
+ dstBeing->setSprite(SPRITE_CAPE, id);
break;
case 12:
- player->setSprite(SPRITE_MISC1, id);
+ dstBeing->setSprite(SPRITE_MISC1, id);
break;
case 13:
- player->setSprite(SPRITE_MISC2, id);
+ dstBeing->setSprite(SPRITE_MISC2, id);
break;
default:
logger->log("SMSG_BEING_CHANGE_LOOKS: unsupported type: "
@@ -482,13 +516,13 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
break;
case SMSG_BEING_NAME_RESPONSE:
- if ((dstBeing = beingManager->findBeing(msg.readInt32())))
+ if ((dstBeing = actorSpriteManager->findBeing(msg.readInt32())))
{
dstBeing->setName(msg.readString(24));
}
break;
case SMSG_PLAYER_GUILD_PARTY_INFO:
- if ((dstBeing = beingManager->findBeing(msg.readInt32())))
+ if ((dstBeing = actorSpriteManager->findBeing(msg.readInt32())))
{
dstBeing->setPartyName(msg.readString(24));
dstBeing->setGuildName(msg.readString(24));
@@ -497,15 +531,17 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
}
break;
case SMSG_BEING_CHANGE_DIRECTION:
- if (!(dstBeing = beingManager->findBeing(msg.readInt32())))
+ {
+ if (!(dstBeing = actorSpriteManager->findBeing(msg.readInt32())))
{
break;
}
msg.readInt16(); // unused
-
- dstBeing->setDirection(msg.readInt8());
-
+ Uint8 dir = msg.readInt8();
+ if (dir)
+ dstBeing->setDirection(dir);
+ }
break;
case SMSG_PLAYER_UPDATE_1:
@@ -520,7 +556,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
<< 16; // status.options; Aethyra uses this as misc2
job = msg.readInt16();
- dstBeing = beingManager->findBeing(id);
+ dstBeing = actorSpriteManager->findBeing(id);
if (!dstBeing)
{
@@ -530,17 +566,19 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
break;
}
- if (dstBeing->getType() == Being::PLAYER)
- player = static_cast<Player*>(dstBeing);
-
if (Party *party = player_node->getParty()){
if (party->isMember(id))
{
- player->setParty(party);
+ dstBeing->setParty(party);
}
}
- dstBeing->setWalkSpeed(Vector(speed, speed, 0));
+ // The original speed is ticks per tile * 10
+ if (speed)
+ dstBeing->setMoveSpeed(Vector(speed / 10, speed / 10));
+ else
+ dstBeing->setMoveSpeed(Net::getPlayerHandler()->getDefaultMoveSpeed());
+
dstBeing->setSubtype(job);
hairStyle = msg.readInt16();
weapon = msg.readInt16();
@@ -562,41 +600,39 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
msg.readInt16(); // manner
dstBeing->setStatusEffectBlock(32, msg.readInt16()); // opt3
msg.readInt8(); // karma
- player->setGender((msg.readInt8() == 0)
+ dstBeing->setGender((msg.readInt8() == 0)
? GENDER_FEMALE : GENDER_MALE);
// Set these after the gender, as the sprites may be gender-specific
- player->setSprite(SPRITE_WEAPON, weapon, "", true);
- player->setSprite(SPRITE_SHIELD, shield);
- //player->setSprite(SPRITE_SHOE, shoes);
- player->setSprite(SPRITE_BOTTOMCLOTHES, headBottom);
- player->setSprite(SPRITE_TOPCLOTHES, headMid);
- player->setSprite(SPRITE_HAT, headTop);
- //player->setSprite(SPRITE_GLOVES, gloves);
- //player->setSprite(SPRITE_CAPE, cape);
- //player->setSprite(SPRITE_MISC1, misc1);
- //player->setSprite(SPRITE_MISC2, misc2);
- player->setSprite(SPRITE_HAIR, hairStyle * -1, ColorDB::get(hairColor));
+ dstBeing->setSprite(SPRITE_WEAPON, weapon, "", true);
+ dstBeing->setSprite(SPRITE_SHIELD, shield);
+ //dstBeing->setSprite(SPRITE_SHOE, shoes);
+ dstBeing->setSprite(SPRITE_BOTTOMCLOTHES, headBottom);
+ dstBeing->setSprite(SPRITE_TOPCLOTHES, headMid);
+ dstBeing->setSprite(SPRITE_HAT, headTop);
+ //dstBeing->setSprite(SPRITE_GLOVES, gloves);
+ //dstBeing->setSprite(SPRITE_CAPE, cape);
+ //dstBeing->setSprite(SPRITE_MISC1, misc1);
+ //dstBeing->setSprite(SPRITE_MISC2, misc2);
+ dstBeing->setSprite(SPRITE_HAIR, hairStyle * -1, ColorDB::get(hairColor));
if (msg.getId() == SMSG_PLAYER_MOVE)
{
Uint16 srcX, srcY, dstX, dstY;
msg.readCoordinatePair(srcX, srcY, dstX, dstY);
- dstBeing->setTileCoords(srcX, srcY);
- dstBeing->setDestination(dstX, dstY);
+ handleMoveMessage(map, dstBeing, srcX, srcY, dstX, dstY);
}
else
{
Uint8 dir;
Uint16 x, y;
msg.readCoordinates(x, y, dir);
- dstBeing->setTileCoords(x, y);
- dstBeing->setDirection(dir);
+ handlePosMessage(map, dstBeing, x, y, dir);
}
gmstatus = msg.readInt16();
if (gmstatus & 0x80)
- player->setGM(true);
+ dstBeing->setGM(true);
if (msg.getId() == SMSG_PLAYER_UPDATE_1)
{
@@ -619,9 +655,6 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
msg.readInt8(); // Lv
msg.readInt8(); // unknown
- dstBeing->setWalkTime(tick_time);
- dstBeing->setFrame(0);
-
dstBeing->setStunMode(stunMode);
dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff);
dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff);
@@ -643,18 +676,13 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
id = msg.readInt32();
if (mSync || id != player_node->getId())
{
- dstBeing = beingManager->findBeing(id);
+ dstBeing = actorSpriteManager->findBeing(id);
if (dstBeing)
{
Uint16 x, y;
x = msg.readInt16();
y = msg.readInt16();
- dstBeing->setTileCoords(x, y);
- if (dstBeing->getCurrentAction() == Being::WALK)
- {
- dstBeing->setFrame(0);
- dstBeing->setAction(Being::STAND);
- }
+ handlePosMessage(map, dstBeing, x, y);
}
}
break;
@@ -671,18 +699,18 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
case SMSG_PLAYER_STATUS_CHANGE:
// Change in players' flags
id = msg.readInt32();
- dstBeing = beingManager->findBeing(id);
+ dstBeing = actorSpriteManager->findBeing(id);
+ if (!dstBeing)
+ break;
+
stunMode = msg.readInt16();
statusEffects = msg.readInt16();
statusEffects |= ((Uint32) msg.readInt16()) << 16;
- msg.readInt8();
+ msg.readInt8(); // Unused?
- if (dstBeing)
- {
- dstBeing->setStunMode(stunMode);
- dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff);
- dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff);
- }
+ dstBeing->setStunMode(stunMode);
+ dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff);
+ dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff);
break;
case SMSG_BEING_STATUS_CHANGE:
@@ -691,7 +719,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
id = msg.readInt32();
flag = msg.readInt8(); // 0: stop, 1: start
- dstBeing = beingManager->findBeing(id);
+ dstBeing = actorSpriteManager->findBeing(id);
if (dstBeing)
dstBeing->setStatusEffect(status, flag);
break;
diff --git a/src/net/tmwa/buysellhandler.cpp b/src/net/tmwa/buysellhandler.cpp
index fae63c67..8daebdec 100644
--- a/src/net/tmwa/buysellhandler.cpp
+++ b/src/net/tmwa/buysellhandler.cpp
@@ -21,18 +21,17 @@
#include "net/tmwa/buysellhandler.h"
-#include "beingmanager.h"
+#include "actorspritemanager.h"
+#include "event.h"
#include "inventory.h"
#include "item.h"
#include "localplayer.h"
-#include "npc.h"
+#include "playerinfo.h"
#include "gui/buy.h"
#include "gui/buysell.h"
#include "gui/sell.h"
-#include "gui/widgets/chattab.h"
-
#include "net/messagein.h"
#include "net/tmwa/protocol.h"
@@ -62,7 +61,7 @@ void BuySellHandler::handleMessage(Net::MessageIn &msg)
switch (msg.getId())
{
case SMSG_NPC_BUY_SELL_CHOICE:
- if (!BuySellDialog::isActive())
+ if (PlayerInfo::getBuySellState() != BUYSELL_CHOOSING)
{
mNpcId = msg.readInt32();
new BuySellDialog(mNpcId);
@@ -73,7 +72,7 @@ void BuySellHandler::handleMessage(Net::MessageIn &msg)
msg.readInt16(); // length
n_items = (msg.getLength() - 4) / 11;
mBuyDialog = new BuyDialog(mNpcId);
- mBuyDialog->setMoney(player_node->getMoney());
+ mBuyDialog->setMoney(PlayerInfo::getAttribute(MONEY));
for (int k = 0; k < n_items; k++)
{
@@ -91,7 +90,7 @@ void BuySellHandler::handleMessage(Net::MessageIn &msg)
if (n_items > 0)
{
SellDialog *dialog = new SellDialog(mNpcId);
- dialog->setMoney(player_node->getMoney());
+ dialog->setMoney(PlayerInfo::getAttribute(MONEY));
for (int k = 0; k < n_items; k++)
{
@@ -99,7 +98,7 @@ void BuySellHandler::handleMessage(Net::MessageIn &msg)
int value = msg.readInt32();
msg.readInt32(); // OCvalue
- Item *item = player_node->getInventory()->getItem(index);
+ Item *item = PlayerInfo::getInventory()->getItem(index);
if (item && !(item->isEquipped()))
dialog->addItem(item, value);
@@ -107,23 +106,29 @@ void BuySellHandler::handleMessage(Net::MessageIn &msg)
}
else
{
- localChatTab->chatLog(_("Nothing to sell."), BY_SERVER);
+ SERVER_NOTICE(_("Nothing to sell."))
}
break;
case SMSG_NPC_BUY_RESPONSE:
- if (msg.readInt8() != 0)
+ if (msg.readInt8() == 0)
+ {
+ SERVER_NOTICE(_("Thanks for buying."))
+ }
+ else
{
// Reset player money since buy dialog already assumed purchase
// would go fine
- mBuyDialog->setMoney(player_node->getMoney());
- localChatTab->chatLog(_("Unable to buy."), BY_SERVER);
+ mBuyDialog->setMoney(PlayerInfo::getAttribute(MONEY));
+ SERVER_NOTICE(_("Unable to buy."))
}
break;
case SMSG_NPC_SELL_RESPONSE:
- if (msg.readInt8() != 0)
- localChatTab->chatLog(_("Unable to sell."), BY_SERVER);
+ if (msg.readInt8() == 0)
+ SERVER_NOTICE(_("Thanks for selling."))
+ else
+ SERVER_NOTICE(_("Unable to sell."))
break;
}
}
diff --git a/src/net/tmwa/charserverhandler.cpp b/src/net/tmwa/charserverhandler.cpp
index dc9b3108..1df84b84 100644
--- a/src/net/tmwa/charserverhandler.cpp
+++ b/src/net/tmwa/charserverhandler.cpp
@@ -86,12 +86,10 @@ void CharServerHandler::handleMessage(Net::MessageIn &msg)
for (int i = 0; i < count; ++i)
{
Net::Character *character = new Net::Character;
- int slot;
- character->dummy = readPlayerData(msg, &slot);
- character->slot = slot;
+ readPlayerData(msg, character);
mCharacters.push_back(character);
logger->log("CharServer: Player: %s (%d)",
- character->dummy->getName().c_str(), slot);
+ character->dummy->getName().c_str(), character->slot);
}
Client::setState(STATE_CHAR_SELECT);
@@ -118,9 +116,7 @@ void CharServerHandler::handleMessage(Net::MessageIn &msg)
case SMSG_CHAR_CREATE_SUCCEEDED:
{
Net::Character *character = new Net::Character;
- int slot;
- character->dummy = readPlayerData(msg, &slot);
- character->slot = slot;
+ readPlayerData(msg, character);
mCharacters.push_back(character);
updateCharSelectDialog();
@@ -163,8 +159,10 @@ void CharServerHandler::handleMessage(Net::MessageIn &msg)
mapServer.hostname = ipToString(msg.readInt32());
mapServer.port = msg.readInt16();
- // Prevent the selected local player from being deleted
player_node = mSelectedCharacter->dummy;
+ PlayerInfo::setBackend(mSelectedCharacter->data);
+
+ // Prevent the selected local player from being deleted
mSelectedCharacter->dummy = 0;
delete_all(mCharacters);
@@ -187,14 +185,18 @@ void CharServerHandler::handleMessage(Net::MessageIn &msg)
mNetwork->disconnect();
Client::setState(STATE_CHANGE_MAP);
- player_node->setTileCoords(x, y);
+ Map *map = player_node->getMap();
+ const int tileWidth = map->getTileWidth();
+ const int tileHeight = map->getTileHeight();
+ player_node->setPosition(Vector(x * tileWidth + tileWidth / 2,
+ y * tileHeight + tileHeight / 2));
player_node->setMap(0);
}
break;
}
}
-LocalPlayer *CharServerHandler::readPlayerData(Net::MessageIn &msg, int *slot)
+void CharServerHandler::readPlayerData(Net::MessageIn &msg, Net::Character *character)
{
const Token &token =
static_cast<LoginHandler*>(Net::getLoginHandler())->getToken();
@@ -202,30 +204,37 @@ LocalPlayer *CharServerHandler::readPlayerData(Net::MessageIn &msg, int *slot)
LocalPlayer *tempPlayer = new LocalPlayer(msg.readInt32(), 0);
tempPlayer->setGender(token.sex);
- tempPlayer->setExp(msg.readInt32());
- tempPlayer->setMoney(msg.readInt32());
- tempPlayer->setExperience(JOB, msg.readInt32(), 1);
+ character->data.mAttributes[EXP] = msg.readInt32();
+ character->data.mAttributes[MONEY] = msg.readInt32();
+ character->data.mStats[JOB].exp = msg.readInt32();
+
int temp = msg.readInt32();
- tempPlayer->setAttributeBase(JOB, temp, false);
- tempPlayer->setAttributeEffective(JOB, temp);
+ character->data.mStats[JOB].base = temp;
+ character->data.mStats[JOB].mod = temp;
+
tempPlayer->setSprite(SPRITE_SHOE, msg.readInt16());
tempPlayer->setSprite(SPRITE_GLOVES, msg.readInt16());
tempPlayer->setSprite(SPRITE_CAPE, msg.readInt16());
tempPlayer->setSprite(SPRITE_MISC1, msg.readInt16());
+
msg.readInt32(); // option
msg.readInt32(); // karma
msg.readInt32(); // manner
msg.skip(2); // unknown
- tempPlayer->setHp(msg.readInt16());
- tempPlayer->setMaxHp(msg.readInt16());
- tempPlayer->setMP(msg.readInt16());
- tempPlayer->setMaxMP(msg.readInt16());
+
+ character->data.mAttributes[HP] = msg.readInt16();
+ character->data.mAttributes[MAX_HP] = msg.readInt16();
+ character->data.mAttributes[MP] = msg.readInt16();
+ character->data.mAttributes[MAX_MP] = msg.readInt16();
+
msg.readInt16(); // speed
tempPlayer->setSubtype(msg.readInt16()); // class (used for race)
int hairStyle = msg.readInt16();
Uint16 weapon = msg.readInt16();
tempPlayer->setSprite(SPRITE_WEAPON, weapon, "", true);
- tempPlayer->setLevel(msg.readInt16());
+
+ character->data.mAttributes[LEVEL] = msg.readInt16();
+
msg.readInt16(); // skill point
tempPlayer->setSprite(SPRITE_BOTTOMCLOTHES, msg.readInt16()); // head bottom
tempPlayer->setSprite(SPRITE_SHIELD, msg.readInt16());
@@ -234,12 +243,14 @@ LocalPlayer *CharServerHandler::readPlayerData(Net::MessageIn &msg, int *slot)
tempPlayer->setSprite(SPRITE_HAIR, hairStyle * -1, ColorDB::get(msg.readInt16()));
tempPlayer->setSprite(SPRITE_MISC2, msg.readInt16());
tempPlayer->setName(msg.readString(24));
+
+ character->dummy = tempPlayer;
+
for (int i = 0; i < 6; i++)
- tempPlayer->setAttributeBase(i + STR, msg.readInt8(), false);
- *slot = msg.readInt8(); // character slot
- msg.readInt8(); // unknown
+ character->data.mStats[i + STR].base = msg.readInt8();
- return tempPlayer;
+ character->slot = msg.readInt8(); // character slot
+ msg.readInt8(); // unknown
}
void CharServerHandler::setCharSelectDialog(CharSelectDialog *window)
@@ -315,17 +326,17 @@ void CharServerHandler::switchCharacter()
outMsg.writeInt8(1);
}
-int CharServerHandler::baseSprite() const
+unsigned int CharServerHandler::baseSprite() const
{
return SPRITE_BASE;
}
-int CharServerHandler::hairSprite() const
+unsigned int CharServerHandler::hairSprite() const
{
return SPRITE_HAIR;
}
-int CharServerHandler::maxSprite() const
+unsigned int CharServerHandler::maxSprite() const
{
return SPRITE_VECTOREND;
}
diff --git a/src/net/tmwa/charserverhandler.h b/src/net/tmwa/charserverhandler.h
index e80d22c4..2076cbae 100644
--- a/src/net/tmwa/charserverhandler.h
+++ b/src/net/tmwa/charserverhandler.h
@@ -63,16 +63,16 @@ class CharServerHandler : public MessageHandler, public Net::CharHandler
void switchCharacter();
- int baseSprite() const;
+ unsigned int baseSprite() const;
- int hairSprite() const;
+ unsigned int hairSprite() const;
- int maxSprite() const;
+ unsigned int maxSprite() const;
void connect();
private:
- LocalPlayer *readPlayerData(Net::MessageIn &msg, int *slot);
+ void readPlayerData(Net::MessageIn &msg, Net::Character *character);
};
} // namespace TmwAthena
diff --git a/src/net/tmwa/chathandler.cpp b/src/net/tmwa/chathandler.cpp
index 00d29662..97304c28 100644
--- a/src/net/tmwa/chathandler.cpp
+++ b/src/net/tmwa/chathandler.cpp
@@ -21,14 +21,13 @@
#include "net/tmwa/chathandler.h"
+#include "actorspritemanager.h"
#include "being.h"
-#include "beingmanager.h"
+#include "event.h"
#include "game.h"
#include "localplayer.h"
#include "playerrelations.h"
-#include "gui/widgets/chattab.h"
-
#include "net/messagein.h"
#include "net/messageout.h"
@@ -45,7 +44,7 @@ namespace TmwAthena {
ChatHandler::ChatHandler()
{
- static const Uint16 _messages[] = {
+ static const uint16_t _messages[] = {
SMSG_BEING_CHAT,
SMSG_PLAYER_CHAT,
SMSG_WHISPER,
@@ -60,8 +59,6 @@ ChatHandler::ChatHandler()
void ChatHandler::handleMessage(Net::MessageIn &msg)
{
- if (!localChatTab) return;
-
Being *being;
std::string chatMsg;
std::string nick;
@@ -70,19 +67,36 @@ void ChatHandler::handleMessage(Net::MessageIn &msg)
switch (msg.getId())
{
case SMSG_WHISPER_RESPONSE:
+ if (mSentWhispers.empty())
+ nick = "user";
+ else
+ {
+ nick = mSentWhispers.front();
+ mSentWhispers.pop();
+ }
+
switch (msg.readInt8())
{
case 0x00:
- // comment out since we'll local echo in chat.cpp instead, then only report failures
- //localChatTab->chatLog("Whisper sent", BY_SERVER);
+ // Success (don't need to report)
break;
case 0x01:
- localChatTab->chatLog(_("Whisper could not be sent, user "
- "is offline."), BY_SERVER);
+ {
+ Event event(Event::WhisperError);
+ event.setString("nick", nick);
+ event.setString("error", strprintf(_("Whisper could "
+ "not be sent, %s is offline."), nick.c_str()));
+ event.trigger(Event::ChatChannel);
+ }
break;
case 0x02:
- localChatTab->chatLog(_("Whisper could not be sent, "
- "ignored by user."), BY_SERVER);
+ {
+ Event event(Event::WhisperError);
+ event.setString("nick", nick);
+ event.setString("error", strprintf(_("Whisper could "
+ "not be sent, ignored by %s."), nick.c_str()));
+ event.Event::trigger(Event::ChatChannel);
+ }
break;
}
break;
@@ -100,11 +114,16 @@ void ChatHandler::handleMessage(Net::MessageIn &msg)
if (nick != "Server")
{
if (player_relations.hasPermission(nick, PlayerRelation::WHISPER))
- chatWindow->whisper(nick, chatMsg);
+ {
+ Event event(Event::Whisper);
+ event.setString("nick", nick);
+ event.setString("message", chatMsg);
+ event.trigger(Event::ChatChannel);
+ }
}
else
{
- localChatTab->chatLog(chatMsg, BY_SERVER);
+ SERVER_NOTICE(chatMsg)
}
break;
@@ -113,7 +132,8 @@ void ChatHandler::handleMessage(Net::MessageIn &msg)
case SMSG_BEING_CHAT:
{
chatMsgLength = msg.readInt16() - 8;
- being = beingManager->findBeing(msg.readInt32());
+ int beingId = msg.readInt32();
+ being = actorSpriteManager->findBeing(beingId);
if (!being || chatMsgLength <= 0)
break;
@@ -135,23 +155,33 @@ void ChatHandler::handleMessage(Net::MessageIn &msg)
chatMsg.erase(0, pos + 3);
}
- trim(chatMsg);
+ int perms;
- // We use getIgnorePlayer instead of ignoringPlayer here
- // because ignorePlayer' side effects are triggered
- // right below for Being::IGNORE_SPEECH_FLOAT.
- if (player_relations.checkPermissionSilently(sender_name,
- PlayerRelation::SPEECH_LOG) && chatWindow)
+ if (being->getType() == Being::PLAYER)
{
- localChatTab->chatLog(removeColors(sender_name) + " : "
- + chatMsg, BY_OTHER);
+ perms = player_relations.checkPermissionSilently(sender_name,
+ PlayerRelation::SPEECH_LOG | PlayerRelation::SPEECH_FLOAT);
}
-
- if (player_relations.hasPermission(sender_name,
- PlayerRelation::SPEECH_FLOAT))
+ else
{
- being->setSpeech(chatMsg, SPEECH_TIME);
+ perms = player_relations.getDefault()
+ & (PlayerRelation::SPEECH_LOG
+ | PlayerRelation::SPEECH_FLOAT);
}
+
+ trim(chatMsg);
+
+ std::string reducedMessage = chatMsg;
+ chatMsg = removeColors(sender_name) + " : " + reducedMessage;
+
+ Event event(Event::Being);
+ event.setString("message", chatMsg);
+ event.setString("text", reducedMessage);
+ event.setString("nick", sender_name);
+ event.setInt("beingId", beingId);
+ event.setInt("permissions", perms);
+ event.trigger(Event::ChatChannel);
+
break;
}
@@ -164,22 +194,32 @@ void ChatHandler::handleMessage(Net::MessageIn &msg)
break;
chatMsg = msg.readString(chatMsgLength);
- std::string::size_type pos = chatMsg.find(" : ", 0);
if (msg.getId() == SMSG_PLAYER_CHAT)
{
- localChatTab->chatLog(chatMsg, BY_PLAYER);
+ std::string::size_type pos = chatMsg.find(" : ", 0);
+ std::string mes = chatMsg;
if (pos != std::string::npos)
chatMsg.erase(0, pos + 3);
trim(chatMsg);
- player_node->setSpeech(chatMsg, SPEECH_TIME);
+ Event event(Event::Player);
+ event.setString("message", mes);
+ event.setString("text", chatMsg);
+ event.setString("nick", player_node->getName());
+ event.setInt("beingId", player_node->getId());
+ event.setInt("permissions", player_relations.getDefault()
+ & (PlayerRelation::SPEECH_LOG
+ | PlayerRelation::SPEECH_FLOAT));
+ event.trigger(Event::ChatChannel);
}
else
{
- localChatTab->chatLog(chatMsg, BY_GM);
+ Event event(Event::Announcement);
+ event.setString("message", chatMsg);
+ event.trigger(Event::ChatChannel);
}
break;
}
@@ -187,7 +227,7 @@ void ChatHandler::handleMessage(Net::MessageIn &msg)
case SMSG_MVP:
// Display MVP player
msg.readInt32(); // id
- localChatTab->chatLog(_("MVP player."), BY_SERVER);
+ SERVER_NOTICE(_("MVP player."))
break;
}
}
@@ -216,47 +256,49 @@ void ChatHandler::privateMessage(const std::string &recipient,
outMsg.writeInt16(text.length() + 28);
outMsg.writeString(recipient, 24);
outMsg.writeString(text, text.length());
+
+ mSentWhispers.push(recipient);
}
void ChatHandler::channelList()
{
- localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER);
+ SERVER_NOTICE(_("Channels are not supported!"))
}
void ChatHandler::enterChannel(const std::string &channel,
const std::string &password)
{
- localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER);
+ SERVER_NOTICE(_("Channels are not supported!"))
}
void ChatHandler::quitChannel(int channelId)
{
- localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER);
+ SERVER_NOTICE(_("Channels are not supported!"))
}
void ChatHandler::sendToChannel(int channelId, const std::string &text)
{
- localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER);
+ SERVER_NOTICE(_("Channels are not supported!"))
}
void ChatHandler::userList(const std::string &channel)
{
- localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER);
+ SERVER_NOTICE(_("Channels are not supported!"))
}
void ChatHandler::setChannelTopic(int channelId, const std::string &text)
{
- localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER);
+ SERVER_NOTICE(_("Channels are not supported!"))
}
void ChatHandler::setUserMode(int channelId, const std::string &name, int mode)
{
- localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER);
+ SERVER_NOTICE(_("Channels are not supported!"))
}
void ChatHandler::kickUser(int channelId, const std::string &name)
{
- localChatTab->chatLog(_("Channels are not supported!"), BY_SERVER);
+ SERVER_NOTICE(_("Channels are not supported!"))
}
void ChatHandler::who()
diff --git a/src/net/tmwa/chathandler.h b/src/net/tmwa/chathandler.h
index 3e035f7e..6426a71e 100644
--- a/src/net/tmwa/chathandler.h
+++ b/src/net/tmwa/chathandler.h
@@ -27,6 +27,8 @@
#include "net/tmwa/messagehandler.h"
+#include <queue>
+
namespace TmwAthena {
class ChatHandler : public MessageHandler, public Net::ChatHandler
@@ -61,6 +63,10 @@ class ChatHandler : public MessageHandler, public Net::ChatHandler
void kickUser(int channelId, const std::string &name);
void who();
+
+ private:
+ typedef std::queue<std::string> WhisperQueue;
+ WhisperQueue mSentWhispers;
};
} // namespace TmwAthena
diff --git a/src/net/tmwa/gamehandler.cpp b/src/net/tmwa/gamehandler.cpp
index 435d5d30..6430b476 100644
--- a/src/net/tmwa/gamehandler.cpp
+++ b/src/net/tmwa/gamehandler.cpp
@@ -22,12 +22,11 @@
#include "net/tmwa/gamehandler.h"
#include "client.h"
+#include "event.h"
#include "game.h"
#include "localplayer.h"
#include "log.h"
-#include "gui/widgets/chattab.h"
-
#include "gui/okdialog.h"
#include "net/messagein.h"
@@ -50,7 +49,6 @@ GameHandler::GameHandler()
{
static const Uint16 _messages[] = {
SMSG_MAP_LOGIN_SUCCESS,
- SMSG_SERVER_PING,
SMSG_WHO_ANSWER,
SMSG_CHAR_SWITCH_RESPONSE,
SMSG_MAP_QUIT_RESPONSE,
@@ -58,6 +56,8 @@ GameHandler::GameHandler()
};
handledMessages = _messages;
gameHandler = this;
+
+ listen(Event::GameChannel);
}
void GameHandler::handleMessage(Net::MessageIn &msg)
@@ -75,17 +75,12 @@ void GameHandler::handleMessage(Net::MessageIn &msg)
x, y, direction);
// Switch now or we'll have problems
Client::setState(STATE_GAME);
- player_node->setTileCoords(x, y);
+ // Stores the position until the map is loaded.
+ mTileX = x; mTileY = y;
} break;
- case SMSG_SERVER_PING:
- // We ignore this for now
- // int tick = msg.readInt32()
- break;
-
case SMSG_WHO_ANSWER:
- localChatTab->chatLog(strprintf(_("Online users: %d"),
- msg.readInt32()), BY_SERVER);
+ SERVER_NOTICE(strprintf(_("Online users: %d"), msg.readInt32()))
break;
case SMSG_CHAR_SWITCH_RESPONSE:
@@ -105,6 +100,31 @@ void GameHandler::handleMessage(Net::MessageIn &msg)
}
}
+void GameHandler::event(Event::Channel channel, const Event &event)
+{
+ if (channel == Event::GameChannel)
+ {
+ if (event.getType() == Event::EnginesInitialized)
+ {
+ Game *game = Game::instance();
+ game->changeMap(mMap);
+ Map *map = game->getCurrentMap();
+ const int tileWidth = map->getTileWidth();
+ const int tileHeight = map->getTileHeight();
+ if (mTileX && mTileY)
+ {
+ player_node->setPosition(Vector(mTileX * tileWidth + tileWidth / 2,
+ mTileY * tileHeight + tileHeight / 2));
+ mTileX = mTileY = 0;
+ }
+ }
+ else if (event.getType() == Event::MapLoaded)
+ {
+ MessageOut outMsg(CMSG_MAP_LOADED);
+ }
+ }
+}
+
void GameHandler::connect()
{
mNetwork->connect(mapServer);
@@ -142,16 +162,6 @@ void GameHandler::disconnect()
mNetwork->disconnect();
}
-void GameHandler::inGame()
-{
- Game::instance()->changeMap(mMap);
-}
-
-void GameHandler::mapLoaded(const std::string &mapName)
-{
- MessageOut outMsg(CMSG_MAP_LOADED);
-}
-
void GameHandler::who()
{
}
@@ -161,12 +171,6 @@ void GameHandler::quit()
MessageOut outMsg(CMSG_CLIENT_QUIT);
}
-void GameHandler::ping(int tick)
-{
- MessageOut msg(CMSG_CLIENT_PING);
- msg.writeInt32(tick);
-}
-
void GameHandler::setMap(const std::string map)
{
mMap = map.substr(0, map.rfind("."));
diff --git a/src/net/tmwa/gamehandler.h b/src/net/tmwa/gamehandler.h
index ca8d27e6..04e0a087 100644
--- a/src/net/tmwa/gamehandler.h
+++ b/src/net/tmwa/gamehandler.h
@@ -22,6 +22,8 @@
#ifndef NET_TA_MAPHANDLER_H
#define NET_TA_MAPHANDLER_H
+#include "eventlistener.h"
+
#include "net/gamehandler.h"
#include "net/net.h"
#include "net/serverinfo.h"
@@ -31,38 +33,43 @@
namespace TmwAthena {
-class GameHandler : public MessageHandler, public Net::GameHandler
+class GameHandler : public MessageHandler, public Net::GameHandler,
+ public EventListener
{
public:
GameHandler();
void handleMessage(Net::MessageIn &msg);
+ void event(Event::Channel channel, const Event &event);
+
void connect();
bool isConnected();
void disconnect();
- void inGame();
-
- void mapLoaded(const std::string &mapName);
-
void who();
void quit();
- void ping(int tick);
-
bool removeDeadBeings() const { return true; }
void clear();
void setMap(const std::string map);
+ /** The tmwAthena protocol is making use of the MP status bar. */
+ bool canUseMagicBar() const { return true; }
+
private:
- std::string mMap;
+ std::string mMap; ///< Keeps the map filename.
int mCharID; /// < Saved for map-server switching
+ /**
+ * Keeps the local character position until the map is loaded
+ * to permit the translation in pixels.
+ */
+ int mTileX, mTileY;
};
} // namespace TmwAthena
diff --git a/src/net/tmwa/generalhandler.cpp b/src/net/tmwa/generalhandler.cpp
index 12768807..d8ce7955 100644
--- a/src/net/tmwa/generalhandler.cpp
+++ b/src/net/tmwa/generalhandler.cpp
@@ -32,6 +32,10 @@
#include "gui/socialwindow.h"
#include "gui/statuswindow.h"
+#include "net/messagein.h"
+#include "net/messageout.h"
+#include "net/serverinfo.h"
+
#include "net/tmwa/adminhandler.h"
#include "net/tmwa/beinghandler.h"
#include "net/tmwa/buysellhandler.h"
@@ -53,9 +57,6 @@
#include "net/tmwa/gui/guildtab.h"
#include "net/tmwa/gui/partytab.h"
-#include "net/messagein.h"
-#include "net/messageout.h"
-
#include "resources/itemdb.h"
#include "utils/gettext.h"
@@ -75,7 +76,7 @@ extern Party *taParty;
GeneralHandler::GeneralHandler():
mAdminHandler(new AdminHandler),
- mBeingHandler(new BeingHandler(config.getValue("EnableSync", 0) == 1)),
+ mBeingHandler(new BeingHandler(config.getBoolValue("EnableSync"))),
mBuySellHandler(new BuySellHandler),
mCharHandler(new CharServerHandler),
mChatHandler(new ChatHandler),
@@ -97,15 +98,17 @@ GeneralHandler::GeneralHandler():
handledMessages = _messages;
generalHandler = this;
- std::list<ItemDB::Stat> stats;
- stats.push_back(ItemDB::Stat("str", _("Strength %+d")));
- stats.push_back(ItemDB::Stat("agi", _("Agility %+d")));
- stats.push_back(ItemDB::Stat("vit", _("Vitality %+d")));
- stats.push_back(ItemDB::Stat("int", _("Intelligence %+d")));
- stats.push_back(ItemDB::Stat("dex", _("Dexterity %+d")));
- stats.push_back(ItemDB::Stat("luck", _("Luck %+d")));
+ std::list<ItemStat> stats;
+ stats.push_back(ItemStat("str", _("Strength %+d")));
+ stats.push_back(ItemStat("agi", _("Agility %+d")));
+ stats.push_back(ItemStat("vit", _("Vitality %+d")));
+ stats.push_back(ItemStat("int", _("Intelligence %+d")));
+ stats.push_back(ItemStat("dex", _("Dexterity %+d")));
+ stats.push_back(ItemStat("luck", _("Luck %+d")));
+
+ setStatsList(stats);
- ItemDB::setStatsList(stats);
+ listen(Event::GameChannel);
}
GeneralHandler::~GeneralHandler()
@@ -209,47 +212,53 @@ void GeneralHandler::flushNetwork()
}
}
-void GeneralHandler::guiWindowsLoaded()
-{
- inventoryWindow->setSplitAllowed(false);
- skillDialog->loadSkills();
-
- statusWindow->addAttribute(STR, _("Strength"), true, "");
- statusWindow->addAttribute(AGI, _("Agility"), true, "");
- statusWindow->addAttribute(VIT, _("Vitality"), true, "");
- statusWindow->addAttribute(INT, _("Intelligence"), true, "");
- statusWindow->addAttribute(DEX, _("Dexterity"), true, "");
- statusWindow->addAttribute(LUK, _("Luck"), true, "");
-
- statusWindow->addAttribute(ATK, _("Attack"), false, "");
- statusWindow->addAttribute(DEF, _("Defense"), false, "");
- statusWindow->addAttribute(MATK, _("M.Attack"), false, "");
- statusWindow->addAttribute(MDEF, _("M.Defense"), false, "");
- statusWindow->addAttribute(HIT, _("% Accuracy"), false, "");
- statusWindow->addAttribute(FLEE, _("% Evade"), false, "");
- statusWindow->addAttribute(CRIT, _("% Critical"), false, "");
-}
-
-void GeneralHandler::guiWindowsUnloaded()
-{
- socialWindow->removeTab(taGuild);
- socialWindow->removeTab(taParty);
-
- delete guildTab;
- guildTab = 0;
-
- delete partyTab;
- partyTab = 0;
-}
-
void GeneralHandler::clearHandlers()
{
mNetwork->clearHandlers();
}
-void GeneralHandler::stateChanged(State oldState, State newState)
+void GeneralHandler::event(Event::Channel channel,
+ const Event &event)
{
- //
+ if (channel == Event::GameChannel)
+ {
+ if (event.getType() == Event::GuiWindowsLoaded)
+ {
+ inventoryWindow->setSplitAllowed(false);
+ skillDialog->loadSkills();
+
+ statusWindow->addAttribute(STR, _("Strength"), true, "");
+ statusWindow->addAttribute(AGI, _("Agility"), true, "");
+ statusWindow->addAttribute(VIT, _("Vitality"), true, "");
+ statusWindow->addAttribute(INT, _("Intelligence"), true, "");
+ statusWindow->addAttribute(DEX, _("Dexterity"), true, "");
+ statusWindow->addAttribute(LUK, _("Luck"), true, "");
+
+ statusWindow->addAttribute(ATK, _("Attack"), false, "");
+ statusWindow->addAttribute(DEF, _("Defense"), false, "");
+ statusWindow->addAttribute(MATK, _("M.Attack"), false, "");
+ statusWindow->addAttribute(MDEF, _("M.Defense"), false, "");
+ // NOTE: Don't remove the gettext comments as they are used
+ // by the xgettext invocation.
+ //xgettext:no-c-format
+ statusWindow->addAttribute(HIT, _("% Accuracy"), false, "");
+ //xgettext:no-c-format
+ statusWindow->addAttribute(FLEE, _("% Evade"), false, "");
+ //xgettext:no-c-format
+ statusWindow->addAttribute(CRIT, _("% Critical"), false, "");
+ }
+ else if (event.getType() == Event::GuiWindowsUnloading)
+ {
+ socialWindow->removeTab(taGuild);
+ socialWindow->removeTab(taParty);
+
+ delete guildTab;
+ guildTab = 0;
+
+ delete partyTab;
+ partyTab = 0;
+ }
+ }
}
} // namespace TmwAthena
diff --git a/src/net/tmwa/generalhandler.h b/src/net/tmwa/generalhandler.h
index d680f215..3698c6d3 100644
--- a/src/net/tmwa/generalhandler.h
+++ b/src/net/tmwa/generalhandler.h
@@ -22,15 +22,17 @@
#ifndef NET_TMWA_GENERALHANDLER_H
#define NET_TMWA_GENERALHANDLER_H
+#include "eventlistener.h"
+
#include "net/generalhandler.h"
#include "net/net.h"
-#include "net/serverinfo.h"
#include "net/tmwa/messagehandler.h"
namespace TmwAthena {
-class GeneralHandler : public MessageHandler, public Net::GeneralHandler
+class GeneralHandler : public MessageHandler, public Net::GeneralHandler,
+ public EventListener
{
public:
GeneralHandler();
@@ -47,13 +49,9 @@ class GeneralHandler : public MessageHandler, public Net::GeneralHandler
void flushNetwork();
- void guiWindowsLoaded();
-
- void guiWindowsUnloaded();
-
void clearHandlers();
- void stateChanged(State oldState, State newState);
+ void event(Event::Channel channel, const Event &event);
protected:
MessageHandlerPtr mAdminHandler;
@@ -75,4 +73,4 @@ class GeneralHandler : public MessageHandler, public Net::GeneralHandler
} // namespace TmwAthena
-#endif // NET_TA_GENERALHANDLER_H
+#endif // NET_TMWA_GENERALHANDLER_H
diff --git a/src/net/tmwa/gui/guildtab.cpp b/src/net/tmwa/gui/guildtab.cpp
index 794ad5cc..ca922e55 100644
--- a/src/net/tmwa/gui/guildtab.cpp
+++ b/src/net/tmwa/gui/guildtab.cpp
@@ -21,17 +21,17 @@
#include "net/tmwa/gui/guildtab.h"
+#include "chatlog.h"
#include "commandhandler.h"
#include "guild.h"
#include "localplayer.h"
-#include "gui/theme.h"
-
#include "net/net.h"
#include "net/guildhandler.h"
#include "resources/iteminfo.h"
#include "resources/itemdb.h"
+#include "resources/theme.h"
#include "utils/dtor.h"
#include "utils/gettext.h"
@@ -114,4 +114,10 @@ void GuildTab::getAutoCompleteList(std::vector<std::string> &names) const
taGuild->getNames(names);
}
+void GuildTab::saveToLogFile(std::string &msg)
+{
+ if (chatLogger)
+ chatLogger->log("#Guild", msg);
+}
+
} // namespace TmwAthena
diff --git a/src/net/tmwa/gui/guildtab.h b/src/net/tmwa/gui/guildtab.h
index 031c81bf..12e15e16 100644
--- a/src/net/tmwa/gui/guildtab.h
+++ b/src/net/tmwa/gui/guildtab.h
@@ -39,6 +39,8 @@ class GuildTab : public ChatTab
bool handleCommand(const std::string &type, const std::string &args);
+ void saveToLogFile(std::string &msg);
+
protected:
void handleInput(const std::string &msg);
diff --git a/src/net/tmwa/gui/partytab.cpp b/src/net/tmwa/gui/partytab.cpp
index b541c498..6833831c 100644
--- a/src/net/tmwa/gui/partytab.cpp
+++ b/src/net/tmwa/gui/partytab.cpp
@@ -21,17 +21,17 @@
#include "net/tmwa/gui/partytab.h"
+#include "chatlog.h"
#include "commandhandler.h"
#include "localplayer.h"
#include "party.h"
-#include "gui/theme.h"
-
#include "net/net.h"
#include "net/partyhandler.h"
#include "resources/iteminfo.h"
#include "resources/itemdb.h"
+#include "resources/theme.h"
#include "utils/dtor.h"
#include "utils/gettext.h"
@@ -206,4 +206,10 @@ void PartyTab::getAutoCompleteList(std::vector<std::string> &names) const
p->getNames(names);
}
+void PartyTab::saveToLogFile(std::string &msg)
+{
+ if (chatLogger)
+ chatLogger->log("#Party", msg);
+}
+
} // namespace TmwAthena
diff --git a/src/net/tmwa/gui/partytab.h b/src/net/tmwa/gui/partytab.h
index 62027726..4c16ab46 100644
--- a/src/net/tmwa/gui/partytab.h
+++ b/src/net/tmwa/gui/partytab.h
@@ -39,6 +39,8 @@ class PartyTab : public ChatTab
bool handleCommand(const std::string &type, const std::string &args);
+ void saveToLogFile(std::string &msg);
+
protected:
void handleInput(const std::string &msg);
diff --git a/src/net/tmwa/guildhandler.cpp b/src/net/tmwa/guildhandler.cpp
index 93bc7807..00167d61 100644
--- a/src/net/tmwa/guildhandler.cpp
+++ b/src/net/tmwa/guildhandler.cpp
@@ -21,6 +21,7 @@
#include "net/tmwa/guildhandler.h"
#include "guild.h"
+#include "event.h"
#include "localplayer.h"
#include "log.h"
@@ -292,7 +293,7 @@ void GuildHandler::handleMessage(Net::MessageIn &msg)
switch (flag)
{
case 0:
- guildTab->chatLog(_("Could not inivte user to guild."),
+ guildTab->chatLog(_("Could not invite user to guild."),
BY_SERVER);
break;
@@ -389,8 +390,7 @@ void GuildHandler::handleMessage(Net::MessageIn &msg)
void GuildHandler::create(const std::string &name)
{
- localChatTab->chatLog(_("Guild creation isn't supported yet."),
- BY_SERVER);
+ SERVER_NOTICE(_("Guild creation isn't supported yet."))
return;
MessageOut msg(CMSG_GUILD_CREATE);
@@ -403,10 +403,10 @@ void GuildHandler::invite(int guildId, const std::string &name)
// TODO?
}
-void GuildHandler::invite(int guildId, Player *player)
+void GuildHandler::invite(int guildId, Being *being)
{
MessageOut msg(CMSG_GUILD_INVITE);
- msg.writeInt32(player->getId());
+ msg.writeInt32(being->getId());
msg.writeInt32(0); // Unused
msg.writeInt32(0); // Unused
}
diff --git a/src/net/tmwa/guildhandler.h b/src/net/tmwa/guildhandler.h
index 39dbe486..8bde222f 100644
--- a/src/net/tmwa/guildhandler.h
+++ b/src/net/tmwa/guildhandler.h
@@ -40,7 +40,7 @@ class GuildHandler : public Net::GuildHandler, public MessageHandler
void invite(int guildId, const std::string &name);
- void invite(int guildId, Player *player);
+ void invite(int guildId, Being *being);
void inviteResponse(int guildId, bool response);
diff --git a/src/net/tmwa/inventoryhandler.cpp b/src/net/tmwa/inventoryhandler.cpp
index 5e404e6c..ff875e69 100644
--- a/src/net/tmwa/inventoryhandler.cpp
+++ b/src/net/tmwa/inventoryhandler.cpp
@@ -23,6 +23,8 @@
#include "configuration.h"
#include "equipment.h"
+#include "event.h"
+#include "game.h"
#include "inventory.h"
#include "item.h"
#include "itemshortcut.h"
@@ -41,34 +43,33 @@
#include "utils/gettext.h"
#include "utils/stringutils.h"
-#include <SDL_types.h>
-
extern Net::InventoryHandler *inventoryHandler;
-const Equipment::Slot EQUIP_POINTS[Equipment::EQUIP_VECTOREND] = {
- Equipment::EQUIP_LEGS_SLOT,
- Equipment::EQUIP_FIGHT1_SLOT,
- Equipment::EQUIP_GLOVES_SLOT,
- Equipment::EQUIP_RING2_SLOT,
- Equipment::EQUIP_RING1_SLOT,
- Equipment::EQUIP_FIGHT2_SLOT,
- Equipment::EQUIP_FEET_SLOT,
- Equipment::EQUIP_NECK_SLOT,
- Equipment::EQUIP_HEAD_SLOT,
- Equipment::EQUIP_TORSO_SLOT,
- Equipment::EQUIP_PROJECTILE_SLOT};
-
namespace TmwAthena {
-int getSlot(int eAthenaSlot)
+static const EquipmentSlot EQUIP_POINTS[EQUIP_VECTOR_END] = {
+ EQUIP_LEGS_SLOT,
+ EQUIP_FIGHT1_SLOT,
+ EQUIP_ARMS_SLOT,
+ EQUIP_RING2_SLOT,
+ EQUIP_RING1_SLOT,
+ EQUIP_FIGHT2_SLOT,
+ EQUIP_FEET_SLOT,
+ EQUIP_NECKLACE_SLOT,
+ EQUIP_HEAD_SLOT,
+ EQUIP_TORSO_SLOT,
+ EQUIP_PROJECTILE_SLOT
+};
+
+static int getSlot(int eAthenaSlot)
{
if (eAthenaSlot == 0)
{
- return Equipment::EQUIP_VECTOREND;
+ return EQUIP_VECTOR_END;
}
if (eAthenaSlot & 0x8000)
- return Equipment::EQUIP_PROJECTILE_SLOT;
+ return EQUIP_PROJECTILE_SLOT;
int mask = 1;
int position = 0;
@@ -108,6 +109,8 @@ InventoryHandler::InventoryHandler()
mStorage = 0;
mStorageWindow = 0;
+
+ listen(Event::ItemChannel);
}
InventoryHandler::~InventoryHandler()
@@ -124,10 +127,10 @@ InventoryHandler::~InventoryHandler()
void InventoryHandler::handleMessage(Net::MessageIn &msg)
{
int number, flag;
- int index, amount, itemId, equipType, arrow;
+ int index, amount, itemId, equipType;
int identified, cards[4], itemType;
- Inventory *inventory = player_node->getInventory();
- player_node->mEquipment->setBackend(&mEquips);
+ Inventory *inventory = PlayerInfo::getInventory();
+ PlayerInfo::getEquipment()->setBackend(&mEquips);
switch (msg.getId())
{
@@ -154,7 +157,7 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg)
itemType = msg.readInt8();
identified = msg.readInt8();
amount = msg.readInt16();
- arrow = msg.readInt16();
+ msg.readInt16(); // Arrow
for (int i = 0; i < 4; i++)
cards[i] = msg.readInt16();
@@ -170,17 +173,10 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg)
}
if (msg.getId() == SMSG_PLAYER_INVENTORY)
- {
- // Trick because arrows are not considered equipment
- bool isEquipment = arrow & 0x8000;
-
- inventory->setItem(index, itemId, amount, isEquipment);
- }
+ inventory->setItem(index, itemId, amount);
else
- {
mInventoryItems.push_back(InventoryItem(index, itemId,
amount, false));
- }
}
break;
@@ -224,11 +220,11 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg)
msg.readInt8(); // refine
for (int i = 0; i < 4; i++)
cards[i] = msg.readInt16();
- equipType = msg.readInt16();
+ msg.readInt16(); // EquipType
itemType = msg.readInt8();
{
- const ItemInfo &itemInfo = ItemDB::get(itemId);
+ const ItemInfo &itemInfo = itemDb->get(itemId);
unsigned char err = msg.readInt8();
if (err)
@@ -244,7 +240,7 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg)
if (item && item->getId() == itemId)
amount += inventory->getItem(index)->getQuantity();
- inventory->setItem(index, itemId, amount, equipType != 0);
+ inventory->setItem(index, itemId, amount);
}
inventoryWindow->updateButtons();
@@ -287,7 +283,7 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg)
if (msg.readInt8() == 0)
{
- localChatTab->chatLog(_("Failed to use item."), BY_SERVER);
+ SERVER_NOTICE(_("Failed to use item."))
}
else
{
@@ -319,8 +315,7 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg)
InventoryItems::iterator it = mInventoryItems.begin();
InventoryItems::iterator it_end = mInventoryItems.end();
for (; it != it_end; it++)
- mStorage->setItem((*it).slot, (*it).id, (*it).quantity,
- (*it).equip);
+ mStorage->setItem((*it).slot, (*it).id, (*it).quantity);
mInventoryItems.clear();
if (!mStorageWindow)
@@ -345,9 +340,7 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg)
item->increaseQuantity(amount);
}
else
- {
- mStorage->setItem(index, itemId, amount, false);
- }
+ mStorage->setItem(index, itemId, amount);
break;
case SMSG_PLAYER_STORAGE_REMOVE:
@@ -389,7 +382,7 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg)
msg.readInt8(); // refine
msg.skip(8); // card
- inventory->setItem(index, itemId, 1, true);
+ inventory->setItem(index, itemId, 1);
if (equipType)
{
@@ -404,7 +397,7 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg)
flag = msg.readInt8();
if (!flag)
- localChatTab->chatLog(_("Unable to equip."), BY_SERVER);
+ SERVER_NOTICE(_("Unable to equip."))
else
mEquips.setEquipment(getSlot(equipType), index);
break;
@@ -415,13 +408,33 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg)
flag = msg.readInt8();
if (!flag)
- localChatTab->chatLog(_("Unable to unequip."), BY_SERVER);
+ {
+ SERVER_NOTICE(_("Unable to unequip."))
+ }
else
+ {
mEquips.setEquipment(getSlot(equipType), -1);
+ // Reset the attack range to unarmed.
+ player_node->setAttackRange(ATTACK_RANGE_NOT_SET);
+ }
break;
case SMSG_PLAYER_ATTACK_RANGE:
- player_node->setAttackRange(msg.readInt16());
+ {
+ // The range is in tiles, so we translate it back to pixels
+ Map *map = Game::instance()->getCurrentMap();
+ if (map)
+ {
+ player_node->setAttackRange(msg.readInt16()
+ * map->getTileWidth());
+ }
+ else
+ {
+ logger->log("Couldn't set attacke range due to the lack"
+ "of an initialized map.");
+ player_node->setAttackRange(ATTACK_RANGE_NOT_SET);
+ }
+ }
break;
case SMSG_PLAYER_ARROW_EQUIP:
@@ -433,46 +446,90 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg)
index -= INVENTORY_OFFSET;
logger->log("Arrows equipped: %i", index);
- mEquips.setEquipment(Equipment::EQUIP_PROJECTILE_SLOT, index);
+ mEquips.setEquipment(EQUIP_PROJECTILE_SLOT, index);
break;
}
}
-void InventoryHandler::equipItem(const Item *item)
+void InventoryHandler::event(Event::Channel channel,
+ const Event &event)
{
- if (!item)
- return;
-
- MessageOut outMsg(CMSG_PLAYER_EQUIP);
- outMsg.writeInt16(item->getInvIndex() + INVENTORY_OFFSET);
- outMsg.writeInt16(0);
-}
+ if (channel == Event::ItemChannel)
+ {
+ if (event.getType() == Event::DoCloseInventory)
+ {
+ // No need to worry about type
+ MessageOut outMsg(CMSG_CLOSE_STORAGE);
+ }
+ else
+ {
+ Item *item = event.getItem("item");
-void InventoryHandler::unequipItem(const Item *item)
-{
- if (!item)
- return;
+ if (!item)
+ return;
- MessageOut outMsg(CMSG_PLAYER_UNEQUIP);
- outMsg.writeInt16(item->getInvIndex() + INVENTORY_OFFSET);
-}
+ int index = item->getInvIndex() + INVENTORY_OFFSET;
-void InventoryHandler::useItem(const Item *item)
-{
- if (!item)
- return;
+ if (event.getType() == Event::DoEquip)
+ {
+ MessageOut outMsg(CMSG_PLAYER_EQUIP);
+ outMsg.writeInt16(index);
+ outMsg.writeInt16(0);
+ }
+ else if (event.getType() == Event::DoUnequip)
+ {
+ MessageOut outMsg(CMSG_PLAYER_UNEQUIP);
+ outMsg.writeInt16(index);
+ }
+ else if (event.getType() == Event::DoUse)
+ {
+ MessageOut outMsg(CMSG_PLAYER_INVENTORY_USE);
+ outMsg.writeInt16(index);
+ outMsg.writeInt32(item->getId()); // unused
+ }
+ else if (event.getType() == Event::DoDrop)
+ {
+ int amount = event.getInt("amount", 1);
- MessageOut outMsg(CMSG_PLAYER_INVENTORY_USE);
- outMsg.writeInt16(item->getInvIndex() + INVENTORY_OFFSET);
- outMsg.writeInt32(item->getId()); // unused
-}
+ // TODO: Fix wrong coordinates of drops, serverside?
+ // (what's wrong here?)
+ MessageOut outMsg(CMSG_PLAYER_INVENTORY_DROP);
+ outMsg.writeInt16(index);
+ outMsg.writeInt16(amount);
+ }
+ else if (event.getType() == Event::DoMove)
+ {
+ int newIndex = event.getInt("newIndex", -1);
-void InventoryHandler::dropItem(const Item *item, int amount)
-{
- // TODO: Fix wrong coordinates of drops, serverside? (what's wrong here?)
- MessageOut outMsg(CMSG_PLAYER_INVENTORY_DROP);
- outMsg.writeInt16(item->getInvIndex() + INVENTORY_OFFSET);
- outMsg.writeInt16(amount);
+ if (newIndex >= 0)
+ {
+ // Not implemented for tmwAthena (possible?)
+ }
+ else
+ {
+ int source = event.getInt("source");
+ int destination = event.getInt("destination");
+ int amount = event.getInt("amount", 1);
+
+ if (source == Inventory::INVENTORY
+ && destination == Inventory::STORAGE)
+ {
+ MessageOut outMsg(CMSG_MOVE_TO_STORAGE);
+ outMsg.writeInt16(index);
+ outMsg.writeInt32(amount);
+ }
+ else if (source == Inventory::STORAGE
+ && destination == Inventory::INVENTORY)
+ {
+ MessageOut outMsg(CMSG_MOVE_FROM_STORAGE);
+ outMsg.writeInt16(index - INVENTORY_OFFSET
+ + STORAGE_OFFSET);
+ outMsg.writeInt32(amount);
+ }
+ }
+ }
+ }
+ }
}
bool InventoryHandler::canSplit(const Item *item)
@@ -480,43 +537,6 @@ bool InventoryHandler::canSplit(const Item *item)
return false;
}
-void InventoryHandler::splitItem(const Item *item, int amount)
-{
- // Not implemented for eAthena (possible?)
-}
-
-void InventoryHandler::moveItem(int oldIndex, int newIndex)
-{
- // Not implemented for eAthena (possible?)
-}
-
-void InventoryHandler::openStorage(int type)
-{
- // Doesn't apply to eAthena, since opening happens through NPCs?
-}
-
-void InventoryHandler::closeStorage(int type)
-{
- MessageOut outMsg(CMSG_CLOSE_STORAGE);
-}
-
-void InventoryHandler::moveItem(int source, int slot, int amount,
- int destination)
-{
- if (source == Inventory::INVENTORY && destination == Inventory::STORAGE)
- {
- MessageOut outMsg(CMSG_MOVE_TO_STORAGE);
- outMsg.writeInt16(slot + INVENTORY_OFFSET);
- outMsg.writeInt32(amount);
- }
- else if (source == Inventory::STORAGE && destination == Inventory::INVENTORY)
- {
- MessageOut outMsg(CSMG_MOVE_FROM_STORAGE);
- outMsg.writeInt16(slot + STORAGE_OFFSET);
- outMsg.writeInt32(amount);
- }
-}
-
size_t InventoryHandler::getSize(int type) const
{
switch (type)
diff --git a/src/net/tmwa/inventoryhandler.h b/src/net/tmwa/inventoryhandler.h
index 0c4ad092..218723e6 100644
--- a/src/net/tmwa/inventoryhandler.h
+++ b/src/net/tmwa/inventoryhandler.h
@@ -24,7 +24,8 @@
#include "equipment.h"
#include "inventory.h"
-#include "localplayer.h"
+#include "eventlistener.h"
+#include "playerinfo.h"
#include "gui/inventorywindow.h"
@@ -37,7 +38,8 @@
namespace TmwAthena {
-class EquipBackend : public Equipment::Backend {
+class EquipBackend : public Equipment::Backend
+{
public:
EquipBackend()
{
@@ -47,11 +49,7 @@ class EquipBackend : public Equipment::Backend {
Item *getEquipment(int index) const
{
int invyIndex = mEquipment[index];
- if (invyIndex == -1)
- {
- return NULL;
- }
- return player_node->getInventory()->getItem(invyIndex);
+ return PlayerInfo::getInventory()->getItem(invyIndex);
}
void clear()
@@ -60,11 +58,8 @@ class EquipBackend : public Equipment::Backend {
{
if (mEquipment[i] != -1)
{
- Item* item = player_node->getInventory()->getItem(i);
- if (item)
- {
+ if (Item *item = PlayerInfo::getInventory()->getItem(i))
item->setEquipped(false);
- }
}
mEquipment[i] = -1;
@@ -73,20 +68,16 @@ class EquipBackend : public Equipment::Backend {
void setEquipment(int index, int inventoryIndex)
{
+ Inventory *inventory = PlayerInfo::getInventory();
+
// Unequip existing item
- Item* item = player_node->getInventory()->getItem(mEquipment[index]);
- if (item)
- {
+ if (Item *item = inventory->getItem(mEquipment[index]))
item->setEquipped(false);
- }
mEquipment[index] = inventoryIndex;
- item = player_node->getInventory()->getItem(inventoryIndex);
- if (item)
- {
+ if (Item *item = inventory->getItem(inventoryIndex))
item->setEquipped(true);
- }
inventoryWindow->updateButtons();
}
@@ -117,7 +108,8 @@ class InventoryItem
typedef std::list<InventoryItem> InventoryItems;
-class InventoryHandler : public MessageHandler, public Net::InventoryHandler
+class InventoryHandler : public MessageHandler, public Net::InventoryHandler,
+ public EventListener
{
public:
enum {
@@ -131,27 +123,10 @@ class InventoryHandler : public MessageHandler, public Net::InventoryHandler
void handleMessage(Net::MessageIn &msg);
- void equipItem(const Item *item);
-
- void unequipItem(const Item *item);
-
- void useItem(const Item *item);
-
- void dropItem(const Item *item, int amount);
+ void event(Event::Channel channel, const Event &event);
bool canSplit(const Item *item);
- void splitItem(const Item *item, int amount);
-
- void moveItem(int oldIndex, int newIndex);
-
- void openStorage(int type);
-
- void closeStorage(int type);
-
- void moveItem(int source, int slot, int amount,
- int destination);
-
size_t getSize(int type) const;
private:
diff --git a/src/net/tmwa/itemhandler.cpp b/src/net/tmwa/itemhandler.cpp
index abc8103b..9f303617 100644
--- a/src/net/tmwa/itemhandler.cpp
+++ b/src/net/tmwa/itemhandler.cpp
@@ -21,17 +21,19 @@
#include "net/tmwa/itemhandler.h"
-#include "flooritemmanager.h"
-
#include "net/messagein.h"
#include "net/tmwa/protocol.h"
+#include "actorspritemanager.h"
+#include "game.h"
+#include "map.h"
+
namespace TmwAthena {
ItemHandler::ItemHandler()
{
- static const Uint16 _messages[] = {
+ static const uint16_t _messages[] = {
SMSG_ITEM_VISIBLE,
SMSG_ITEM_DROPPED,
SMSG_ITEM_REMOVE,
@@ -54,13 +56,19 @@ void ItemHandler::handleMessage(Net::MessageIn &msg)
int y = msg.readInt16();
msg.skip(4); // amount,subX,subY / subX,subY,amount
- floorItemManager->create(id, itemId, x, y);
+ Game *game = Game::instance();
+ if (!game)
+ break;
+
+ if (Map *map = game->getCurrentMap())
+ actorSpriteManager->createItem(id, itemId,
+ map->getTileCenter(x, y));
}
break;
case SMSG_ITEM_REMOVE:
- if (FloorItem *item = floorItemManager->findById(msg.readInt32()))
- floorItemManager->destroy(item);
+ if (FloorItem *item = actorSpriteManager->findItem(msg.readInt32()))
+ actorSpriteManager->destroy(item);
break;
}
}
diff --git a/src/net/tmwa/loginhandler.cpp b/src/net/tmwa/loginhandler.cpp
index 7e654951..0edc6ae6 100644
--- a/src/net/tmwa/loginhandler.cpp
+++ b/src/net/tmwa/loginhandler.cpp
@@ -244,6 +244,8 @@ void LoginHandler::getRegistrationDetails()
void LoginHandler::loginAccount(LoginData *loginData)
{
+ loginData->characterSlots = 9;
+
sendLoginRegister(loginData->username, loginData->password);
}
diff --git a/src/net/tmwa/messagehandler.h b/src/net/tmwa/messagehandler.h
index 0fa2e80c..e7810591 100644
--- a/src/net/tmwa/messagehandler.h
+++ b/src/net/tmwa/messagehandler.h
@@ -27,8 +27,6 @@
#include "net/tmwa/messageout.h"
-#include <SDL_types.h>
-
#include <memory>
namespace TmwAthena {
diff --git a/src/net/tmwa/messagein.cpp b/src/net/tmwa/messagein.cpp
index 0074cfdd..38bc14dd 100644
--- a/src/net/tmwa/messagein.cpp
+++ b/src/net/tmwa/messagein.cpp
@@ -24,10 +24,6 @@
#include <SDL.h>
#include <SDL_endian.h>
-#define MAKEWORD(low,high) \
- ((unsigned short)(((unsigned char)(low)) | \
- ((unsigned short)((unsigned char)(high))) << 8))
-
namespace TmwAthena {
MessageIn::MessageIn(const char *data, unsigned int length):
@@ -37,34 +33,34 @@ MessageIn::MessageIn(const char *data, unsigned int length):
mId = readInt16();
}
-int MessageIn::readInt16()
+uint16_t MessageIn::readInt16()
{
- Sint16 value = -1;
+ uint16_t value = 0;
if (mPos + 2 <= mLength)
{
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
- Sint16 swap;
- memcpy(&swap, mData + mPos, sizeof(Sint16));
+ uint16_t swap;
+ memcpy(&swap, mData + mPos, sizeof(uint16_t));
value = SDL_Swap16(swap);
#else
- memcpy(&value, mData + mPos, sizeof(Sint16));
+ memcpy(&value, mData + mPos, sizeof(uint16_t));
#endif
}
mPos += 2;
return value;
}
-int MessageIn::readInt32()
+uint32_t MessageIn::readInt32()
{
- Sint32 value = -1;
+ uint32_t value = 0;
if (mPos + 4 <= mLength)
{
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
- Sint32 swap;
- memcpy(&swap, mData + mPos, sizeof(Sint32));
+ uint32_t swap;
+ memcpy(&swap, mData + mPos, sizeof(uint32_t));
value = SDL_Swap32(swap);
#else
- memcpy(&value, mData + mPos, sizeof(Sint32));
+ memcpy(&value, mData + mPos, sizeof(uint32_t));
#endif
}
mPos += 4;
diff --git a/src/net/tmwa/messagein.h b/src/net/tmwa/messagein.h
index aa94bba1..38fbb139 100644
--- a/src/net/tmwa/messagein.h
+++ b/src/net/tmwa/messagein.h
@@ -24,7 +24,6 @@
#include "net/messagein.h"
-#include <SDL_types.h>
#include <string>
namespace TmwAthena {
@@ -37,13 +36,10 @@ namespace TmwAthena {
class MessageIn : public Net::MessageIn
{
public:
- /**
- * Constructor.
- */
MessageIn(const char *data, unsigned int length);
- int readInt16(); /**< Reads a short. */
- int readInt32(); /**< Reads a long. */
+ uint16_t readInt16();
+ uint32_t readInt32();
};
}
diff --git a/src/net/tmwa/messageout.cpp b/src/net/tmwa/messageout.cpp
index 8b407c47..a08ea48d 100644
--- a/src/net/tmwa/messageout.cpp
+++ b/src/net/tmwa/messageout.cpp
@@ -31,7 +31,7 @@
namespace TmwAthena {
-MessageOut::MessageOut(short id):
+MessageOut::MessageOut(uint16_t id):
Net::MessageOut(id)
{
mNetwork = TmwAthena::Network::instance();
@@ -44,52 +44,45 @@ void MessageOut::expand(size_t bytes)
mNetwork->mOutSize += bytes;
}
-void MessageOut::writeInt16(Sint16 value)
+void MessageOut::writeInt16(uint16_t value)
{
expand(2);
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
- Sint16 swap=SDL_Swap16(value);
- memcpy(mData + mPos, &swap, sizeof(Sint16));
+ uint16_t swap=SDL_Swap16(value);
+ memcpy(mData + mPos, &swap, sizeof(uint16_t));
#else
- memcpy(mData + mPos, &value, sizeof(Sint16));
+ memcpy(mData + mPos, &value, sizeof(uint16_t));
#endif
mPos += 2;
}
-void MessageOut::writeInt32(Sint32 value)
+void MessageOut::writeInt32(uint32_t value)
{
expand(4);
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
- Sint32 swap=SDL_Swap32(value);
- memcpy(mData + mPos, &swap, sizeof(Sint32));
+ uint32_t swap=SDL_Swap32(value);
+ memcpy(mData + mPos, &swap, sizeof(uint32_t));
#else
- memcpy(mData + mPos, &value, sizeof(Sint32));
+ memcpy(mData + mPos, &value, sizeof(uint32_t));
#endif
mPos += 4;
}
-#define LOBYTE(w) ((unsigned char)(w))
-#define HIBYTE(w) ((unsigned char)(((unsigned short)(w)) >> 8))
-
-void MessageOut::writeCoordinates(unsigned short x, unsigned short y,
- unsigned char direction)
+void MessageOut::writeCoordinates(uint16_t x, uint16_t y, uint8_t direction)
{
char *data = mData + mPos;
mNetwork->mOutSize += 3;
mPos += 3;
- short temp;
- temp = x;
+ uint16_t temp = x;
temp <<= 6;
- data[0] = 0;
- data[1] = 1;
- data[2] = 2;
- data[0] = HIBYTE(temp);
- data[1] = (unsigned char) temp;
+ data[0] = temp >> 8;
+ data[1] = temp;
+
temp = y;
temp <<= 4;
- data[1] |= HIBYTE(temp);
- data[2] = LOBYTE(temp);
+ data[1] |= temp >> 8;
+ data[2] = temp;
// Translate direction to eAthena format
switch (direction)
@@ -120,7 +113,7 @@ void MessageOut::writeCoordinates(unsigned short x, unsigned short y,
break;
default:
// OOPSIE! Impossible or unknown
- direction = (unsigned char) -1;
+ direction = 15;
}
data[2] |= direction;
}
diff --git a/src/net/tmwa/messageout.h b/src/net/tmwa/messageout.h
index c9d87a1b..24a0a37c 100644
--- a/src/net/tmwa/messageout.h
+++ b/src/net/tmwa/messageout.h
@@ -24,9 +24,6 @@
#include "net/messageout.h"
-#include <iosfwd>
-#include <SDL_types.h>
-
namespace TmwAthena {
class Network;
@@ -39,19 +36,16 @@ class Network;
class MessageOut : public Net::MessageOut
{
public:
- /**
- * Constructor.
- */
- MessageOut(short id);
+ MessageOut(uint16_t id);
- void writeInt16(Sint16 value); /**< Writes a short. */
- void writeInt32(Sint32 value); /**< Writes a long. */
+ void writeInt16(uint16_t value);
+ void writeInt32(uint32_t value);
/**
* Encodes coordinates and direction in 3 bytes.
*/
- void writeCoordinates(unsigned short x, unsigned short y,
- unsigned char direction);
+ void writeCoordinates(uint16_t x, uint16_t y,
+ uint8_t direction);
private:
void expand(size_t size);
diff --git a/src/net/tmwa/npchandler.cpp b/src/net/tmwa/npchandler.cpp
index 5888c679..904fe388 100644
--- a/src/net/tmwa/npchandler.cpp
+++ b/src/net/tmwa/npchandler.cpp
@@ -21,11 +21,9 @@
#include "net/tmwa/npchandler.h"
-#include "beingmanager.h"
+#include "actorspritemanager.h"
+#include "event.h"
#include "localplayer.h"
-#include "npc.h"
-
-#include "gui/npcdialog.h"
#include "net/messagein.h"
#include "net/messageout.h"
@@ -34,15 +32,30 @@
#include "net/tmwa/protocol.h"
-#include <SDL_types.h>
+#include "utils/stringutils.h"
extern Net::NpcHandler *npcHandler;
+static void parseMenu(Event *event, const std::string &options)
+{
+ std::istringstream iss(options);
+
+ int count = 0;
+ std::string tmp;
+ while (getline(iss, tmp, ':'))
+ {
+ count++;
+ event->setString("choice" + toString(count), tmp);
+ }
+
+ event->setInt("choiceCount", count);
+}
+
namespace TmwAthena {
NpcHandler::NpcHandler()
{
- static const Uint16 _messages[] = {
+ static const uint16_t _messages[] = {
SMSG_NPC_CHOICE,
SMSG_NPC_MESSAGE,
SMSG_NPC_NEXT,
@@ -63,82 +76,118 @@ void NpcHandler::handleMessage(Net::MessageIn &msg)
}
int npcId = msg.readInt32();
- NpcDialogs::iterator diag = mNpcDialogs.find(npcId);
- NpcDialog *dialog = 0;
-
- if (diag == mNpcDialogs.end())
- {
- // Empty dialogs don't help
- if (msg.getId() == SMSG_NPC_CLOSE)
- {
- closeDialog(npcId);
- return;
- }
- else if (msg.getId() == SMSG_NPC_NEXT)
- {
- nextDialog(npcId);
- return;
- }
- else
- {
- dialog = new NpcDialog(npcId);
- Wrapper wrap;
- wrap.dialog = dialog;
- mNpcDialogs[npcId] = wrap;
- }
- }
- else
- {
- dialog = diag->second.dialog;
- }
+ Event *event = 0;
switch (msg.getId())
{
- case SMSG_NPC_CHOICE:
- dialog->choiceRequest();
- dialog->parseListItems(msg.readString(msg.getLength() - 8));
- break;
-
- case SMSG_NPC_MESSAGE:
- dialog->addText(msg.readString(msg.getLength() - 8));
- break;
-
- case SMSG_NPC_CLOSE:
- // Show the close button
- dialog->showCloseButton();
- break;
-
- case SMSG_NPC_NEXT:
- // Show the next button
- dialog->showNextButton();
- break;
-
- case SMSG_NPC_INT_INPUT:
- // Request for an integer
- dialog->integerRequest(0);
- break;
-
- case SMSG_NPC_STR_INPUT:
- // Request for a string
- dialog->textRequest("");
- break;
+ case SMSG_NPC_CHOICE:
+ event = new Event(Event::Menu);
+ event->setInt("id", npcId);
+ parseMenu(event, msg.readString(msg.getLength() - 8));
+ event->trigger(Event::NpcChannel);
+ break;
+
+ case SMSG_NPC_MESSAGE:
+ event = new Event(Event::Message);
+ event->setInt("id", npcId);
+ event->setString("text", msg.readString(msg.getLength() - 8));
+ event->trigger(Event::NpcChannel);
+ break;
+
+ case SMSG_NPC_CLOSE:
+ // Show the close button
+ event = new Event(Event::Close);
+ event->setInt("id", npcId);
+ event->trigger(Event::NpcChannel);
+ break;
+
+ case SMSG_NPC_NEXT:
+ // Show the next button
+ event = new Event(Event::Next);
+ event->setInt("id", npcId);
+ event->trigger(Event::NpcChannel);
+ break;
+
+ case SMSG_NPC_INT_INPUT:
+ // Request for an integer
+ event = new Event(Event::IntegerInput);
+ event->setInt("id", npcId);
+ event->trigger(Event::NpcChannel);
+ break;
+
+ case SMSG_NPC_STR_INPUT:
+ // Request for a string
+ event = new Event(Event::StringInput);
+ event->setInt("id", npcId);
+ event->trigger(Event::NpcChannel);
+ break;
}
+ delete event;
+
if (player_node->getCurrentAction() != Being::SIT)
player_node->setAction(Being::STAND);
}
+void NpcHandler::startShopping(int beingId)
+{
+ // TODO
+}
+
+void NpcHandler::buy(int beingId)
+{
+ MessageOut outMsg(CMSG_NPC_BUY_SELL_REQUEST);
+ outMsg.writeInt32(beingId);
+ outMsg.writeInt8(0); // Buy
+}
+
+void NpcHandler::sell(int beingId)
+{
+ MessageOut outMsg(CMSG_NPC_BUY_SELL_REQUEST);
+ outMsg.writeInt32(beingId);
+ outMsg.writeInt8(1); // Sell
+}
+
+void NpcHandler::buyItem(int beingId, int itemId, int amount)
+{
+ MessageOut outMsg(CMSG_NPC_BUY_REQUEST);
+ outMsg.writeInt16(8); // One item (length of packet)
+ outMsg.writeInt16(amount);
+ outMsg.writeInt16(itemId);
+}
+
+void NpcHandler::sellItem(int beingId, int itemId, int amount)
+{
+ MessageOut outMsg(CMSG_NPC_SELL_REQUEST);
+ outMsg.writeInt16(8); // One item (length of packet)
+ outMsg.writeInt16(itemId + INVENTORY_OFFSET);
+ outMsg.writeInt16(amount);
+}
+
+void NpcHandler::endShopping(int beingId)
+{
+ // TODO
+}
+
void NpcHandler::talk(int npcId)
{
MessageOut outMsg(CMSG_NPC_TALK);
outMsg.writeInt32(npcId);
outMsg.writeInt8(0); // Unused
+
+ Event event(Event::TalkSent);
+ event.setInt("npcId", npcId);
+ event.trigger(Event::NpcChannel);
}
void NpcHandler::nextDialog(int npcId)
{
MessageOut outMsg(CMSG_NPC_NEXT_REQUEST);
outMsg.writeInt32(npcId);
+
+ Event event(Event::NextSent);
+ event.setInt("npcId", npcId);
+ event.trigger(Event::NpcChannel);
}
void NpcHandler::closeDialog(int npcId)
@@ -146,19 +195,21 @@ void NpcHandler::closeDialog(int npcId)
MessageOut outMsg(CMSG_NPC_CLOSE);
outMsg.writeInt32(npcId);
- NpcDialogs::iterator it = mNpcDialogs.find(npcId);
- if (it != mNpcDialogs.end())
- {
- (*it).second.dialog->close();
- mNpcDialogs.erase(it);
- }
+ Event event(Event::CloseSent);
+ event.setInt("npcId", npcId);
+ event.trigger(Event::NpcChannel);
}
-void NpcHandler::listInput(int npcId, int value)
+void NpcHandler::menuSelect(int npcId, int choice)
{
MessageOut outMsg(CMSG_NPC_LIST_CHOICE);
outMsg.writeInt32(npcId);
- outMsg.writeInt8(value);
+ outMsg.writeInt8(choice);
+
+ Event event(Event::MenuSent);
+ event.setInt("npcId", npcId);
+ event.setInt("choice", choice);
+ event.trigger(Event::NpcChannel);
}
void NpcHandler::integerInput(int npcId, int value)
@@ -166,6 +217,11 @@ void NpcHandler::integerInput(int npcId, int value)
MessageOut outMsg(CMSG_NPC_INT_RESPONSE);
outMsg.writeInt32(npcId);
outMsg.writeInt32(value);
+
+ Event event(Event::IntegerInputSent);
+ event.setInt("npcId", npcId);
+ event.setInt("value", value);
+ event.trigger(Event::NpcChannel);
}
void NpcHandler::stringInput(int npcId, const std::string &value)
@@ -175,57 +231,17 @@ void NpcHandler::stringInput(int npcId, const std::string &value)
outMsg.writeInt32(npcId);
outMsg.writeString(value, value.length());
outMsg.writeInt8(0); // Prevent problems with string reading
-}
-
-void NpcHandler::sendLetter(int npcId, const std::string &recipient,
- const std::string &text)
-{
- // TODO
-}
-
-void NpcHandler::startShopping(int beingId)
-{
- // TODO
-}
-
-void NpcHandler::buy(int beingId)
-{
- MessageOut outMsg(CMSG_NPC_BUY_SELL_REQUEST);
- outMsg.writeInt32(beingId);
- outMsg.writeInt8(0); // Buy
-}
-
-void NpcHandler::sell(int beingId)
-{
- MessageOut outMsg(CMSG_NPC_BUY_SELL_REQUEST);
- outMsg.writeInt32(beingId);
- outMsg.writeInt8(1); // Sell
-}
-
-void NpcHandler::buyItem(int beingId, int itemId, int amount)
-{
- MessageOut outMsg(CMSG_NPC_BUY_REQUEST);
- outMsg.writeInt16(8); // One item (length of packet)
- outMsg.writeInt16(amount);
- outMsg.writeInt16(itemId);
-}
-void NpcHandler::sellItem(int beingId, int itemId, int amount)
-{
- MessageOut outMsg(CMSG_NPC_SELL_REQUEST);
- outMsg.writeInt16(8); // One item (length of packet)
- outMsg.writeInt16(itemId + INVENTORY_OFFSET);
- outMsg.writeInt16(amount);
+ Event event(Event::StringInputSent);
+ event.setInt("npcId", npcId);
+ event.setString("value", value);
+ event.trigger(Event::NpcChannel);
}
-void NpcHandler::endShopping(int beingId)
-{
- // TODO
-}
-
-void NpcHandler::clearDialogs()
+void NpcHandler::sendLetter(int npcId, const std::string &recipient,
+ const std::string &text)
{
- mNpcDialogs.clear();
+ //NOTE: eA doesn't have letters
}
} // namespace TmwAthena
diff --git a/src/net/tmwa/npchandler.h b/src/net/tmwa/npchandler.h
index bd696bdd..7829924b 100644
--- a/src/net/tmwa/npchandler.h
+++ b/src/net/tmwa/npchandler.h
@@ -22,15 +22,14 @@
#ifndef NET_TA_NPCHANDLER_H
#define NET_TA_NPCHANDLER_H
-#include "net/net.h"
+#include "eventlistener.h"
+
#include "net/npchandler.h"
#include "net/tmwa/messagehandler.h"
#include <map>
-class NpcDialog;
-
namespace TmwAthena {
class NpcHandler : public MessageHandler, public Net::NpcHandler
@@ -40,13 +39,25 @@ class NpcHandler : public MessageHandler, public Net::NpcHandler
void handleMessage(Net::MessageIn &msg);
+ void startShopping(int beingId);
+
+ void buy(int beingId);
+
+ void sell(int beingId);
+
+ void buyItem(int beingId, int itemId, int amount);
+
+ void sellItem(int beingId, int itemId, int amount);
+
+ void endShopping(int beingId);
+
void talk(int npcId);
void nextDialog(int npcId);
void closeDialog(int npcId);
- void listInput(int npcId, int value);
+ void menuSelect(int npcId, int choice);
void integerInput(int npcId, int value);
@@ -55,26 +66,6 @@ class NpcHandler : public MessageHandler, public Net::NpcHandler
void sendLetter(int npcId, const std::string &recipient,
const std::string &text);
- void startShopping(int beingId);
-
- void buy(int beingId);
-
- void sell(int beingId);
-
- void buyItem(int beingId, int itemId, int amount);
-
- void sellItem(int beingId, int itemId, int amount);
-
- void endShopping(int beingId);
-
- void clearDialogs();
-
- private:
- typedef struct {
- NpcDialog* dialog;
- } Wrapper;
- typedef std::map<int, Wrapper> NpcDialogs;
- NpcDialogs mNpcDialogs;
};
} // namespace TmwAthena
diff --git a/src/net/tmwa/partyhandler.cpp b/src/net/tmwa/partyhandler.cpp
index 611fe3e6..2cfc2037 100644
--- a/src/net/tmwa/partyhandler.cpp
+++ b/src/net/tmwa/partyhandler.cpp
@@ -20,7 +20,8 @@
#include "net/tmwa/partyhandler.h"
-#include "beingmanager.h"
+#include "actorspritemanager.h"
+#include "event.h"
#include "localplayer.h"
#include "log.h"
@@ -78,12 +79,9 @@ void PartyHandler::handleMessage(Net::MessageIn &msg)
{
case SMSG_PARTY_CREATE:
if (msg.readInt8())
- localChatTab->chatLog(_("Could not create party."), BY_SERVER);
+ SERVER_NOTICE(_("Could not create party."))
else
- {
- localChatTab->chatLog(_("Party successfully created."),
- BY_SERVER);
- }
+ SERVER_NOTICE(_("Party successfully created."))
break;
case SMSG_PARTY_INFO:
{
@@ -143,15 +141,12 @@ void PartyHandler::handleMessage(Net::MessageIn &msg)
std::string nick = "";
Being *being;
- if ((being = beingManager->findBeing(id)))
+ if ((being = actorSpriteManager->findBeing(id)))
{
- if (being->getType() == Being::PLAYER)
- {
- nick = being->getName();
- }
+ nick = being->getName();
}
- socialWindow->showPartyInvite(partyName, nick);
+ socialWindow->showPartyInvite(nick, partyName);
break;
}
case SMSG_PARTY_SETTINGS:
@@ -238,8 +233,7 @@ void PartyHandler::handleMessage(Net::MessageIn &msg)
{
taParty->removeFromMembers();
taParty->clearMembers();
- localChatTab->chatLog(_("You have left the party."),
- BY_SERVER);
+ SERVER_NOTICE(_("You have left the party."))
if (partyTab)
{
delete partyTab;
@@ -252,9 +246,10 @@ void PartyHandler::handleMessage(Net::MessageIn &msg)
partyTab->chatLog(strprintf(_("%s has left your party."),
nick.c_str()), BY_SERVER);
- Being *b = beingManager->findBeing(id);
- if (b && b->getType() == Being::PLAYER)
- static_cast<Player*>(b)->setParty(NULL);
+ if (Being *b = actorSpriteManager->findBeing(id))
+ {
+ b->setParty(NULL);
+ }
taParty->removeMember(id);
}
@@ -274,9 +269,9 @@ void PartyHandler::handleMessage(Net::MessageIn &msg)
// The server only sends this when the member is in range, so
// lets make sure they get the party hilight.
- if (Being *b = beingManager->findBeing(id))
+ if (Being *b = actorSpriteManager->findBeing(id))
{
- static_cast<Player*>(b)->setParty(taParty);
+ b->setParty(taParty);
}
}
break;
@@ -319,19 +314,19 @@ void PartyHandler::join(int partyId)
// TODO?
}
-void PartyHandler::invite(Player *player)
+void PartyHandler::invite(Being *being)
{
MessageOut outMsg(CMSG_PARTY_INVITE);
- outMsg.writeInt32(player->getId());
+ outMsg.writeInt32(being->getId());
}
void PartyHandler::invite(const std::string &name)
{
- Being *invitee = beingManager->findBeingByName(name, Being::PLAYER);
+ Being *invitee = actorSpriteManager->findBeingByName(name, Being::PLAYER);
if (invitee)
{
- invite((Player *)invitee);
+ invite(invitee);
partyTab->chatLog(strprintf(_("Invited user %s to party."),
invitee->getName().c_str()), BY_SERVER);
}
@@ -342,8 +337,7 @@ void PartyHandler::invite(const std::string &name)
}
else
{
- localChatTab->chatLog(_("You can only inivte when you are in a party!"),
- BY_SERVER);
+ SERVER_NOTICE(_("You can only inivte when you are in a party!"))
}
}
@@ -359,10 +353,10 @@ void PartyHandler::leave()
MessageOut outMsg(CMSG_PARTY_LEAVE);
}
-void PartyHandler::kick(Player *player)
+void PartyHandler::kick(Being *being)
{
MessageOut outMsg(CMSG_PARTY_KICK);
- outMsg.writeInt32(player->getId());
+ outMsg.writeInt32(being->getId());
outMsg.writeString("", 24); //Unused
}
diff --git a/src/net/tmwa/partyhandler.h b/src/net/tmwa/partyhandler.h
index fc8d741f..5afc8e53 100644
--- a/src/net/tmwa/partyhandler.h
+++ b/src/net/tmwa/partyhandler.h
@@ -43,7 +43,7 @@ class PartyHandler : public MessageHandler, public Net::PartyHandler
void join(int partyId);
- void invite(Player *player);
+ void invite(Being *being);
void invite(const std::string &name);
@@ -51,7 +51,7 @@ class PartyHandler : public MessageHandler, public Net::PartyHandler
void leave();
- void kick(Player *player);
+ void kick(Being *being);
void kick(const std::string &name);
diff --git a/src/net/tmwa/playerhandler.cpp b/src/net/tmwa/playerhandler.cpp
index 3dab8c34..f30baecd 100644
--- a/src/net/tmwa/playerhandler.cpp
+++ b/src/net/tmwa/playerhandler.cpp
@@ -20,30 +20,27 @@
*/
#include "net/tmwa/playerhandler.h"
+#include "net/tmwa/beinghandler.h"
#include "configuration.h"
#include "game.h"
#include "localplayer.h"
#include "log.h"
-#include "npc.h"
+#include "playerinfo.h"
#include "units.h"
#include "gui/buy.h"
#include "gui/buysell.h"
#include "gui/gui.h"
-#include "gui/npcdialog.h"
#include "gui/okdialog.h"
#include "gui/sell.h"
#include "gui/statuswindow.h"
#include "gui/viewport.h"
-#include "gui/widgets/chattab.h"
-
#include "net/messagein.h"
#include "net/messageout.h"
#include "net/tmwa/protocol.h"
-#include "net/tmwa/npchandler.h"
#include "utils/stringutils.h"
#include "utils/gettext.h"
@@ -53,10 +50,7 @@ extern OkDialog *deathNotice;
// Max. distance we are willing to scroll after a teleport;
// everything beyond will reset the port hard.
-static const int MAP_TELEPORT_SCROLL_DISTANCE = 8;
-
-#define ATTR_BONUS(atr) \
-(player_node->getAttributeEffective(atr) - player_node->getAttributeBase(atr))
+const int MAP_TELEPORT_SCROLL_DISTANCE = 8;
// TODO Move somewhere else
namespace {
@@ -84,14 +78,11 @@ namespace {
BuyDialog::closeAll();
BuySellDialog::closeAll();
- NpcDialog::closeAll();
SellDialog::closeAll();
viewport->closePopupMenu();
- TmwAthena::NpcHandler *handler =
- static_cast<TmwAthena::NpcHandler*>(Net::getNpcHandler());
- handler->clearDialogs();
+ Event::trigger(Event::NpcChannel, Event::CloseAll);
}
} deathListener;
@@ -208,21 +199,23 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
float scrollOffsetX = 0.0f;
float scrollOffsetY = 0.0f;
- /* Scroll if neccessary */
+ /* Scroll if necessary */
+ Map *map = game->getCurrentMap();
+ int tileX = player_node->getTileX();
+ int tileY = player_node->getTileY();
if (!sameMap
- || (abs(x - player_node->getTileX()) > MAP_TELEPORT_SCROLL_DISTANCE)
- || (abs(y - player_node->getTileY()) > MAP_TELEPORT_SCROLL_DISTANCE))
+ || (abs(x - tileX) > MAP_TELEPORT_SCROLL_DISTANCE)
+ || (abs(y - tileY) > MAP_TELEPORT_SCROLL_DISTANCE))
{
- Map *map = game->getCurrentMap();
- scrollOffsetX = (x - player_node->getTileX())
- * map->getTileWidth();
- scrollOffsetY = (y - player_node->getTileY())
- * map->getTileHeight();
+ scrollOffsetX = (x - tileX) * map->getTileWidth();
+ scrollOffsetY = (y - tileY) * map->getTileHeight();
}
player_node->setAction(Being::STAND);
- player_node->setFrame(0);
- player_node->setTileCoords(x, y);
+ Vector pos = map->getTileCenter(x, y);
+ player_node->setPosition(pos);
+ // Stop movement
+ player_node->setDestination(pos.x, pos.y);
logger->log("Adjust scrolling by %d:%d", (int) scrollOffsetX,
(int) scrollOffsetY);
@@ -241,20 +234,21 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
switch (type)
{
case 0x0000:
- player_node->setWalkSpeed(Vector(value, value, 0));
+ player_node->setMoveSpeed(Vector(value / 10,
+ value / 10, 0));
break;
case 0x0004: break; // manner
- case 0x0005: player_node->setHp(value); break;
- case 0x0006: player_node->setMaxHp(value); break;
- case 0x0007: player_node->setMP(value); break;
- case 0x0008: player_node->setMaxMP(value); break;
- case 0x0009: player_node->setCharacterPoints(value); break;
- case 0x000b: player_node->setLevel(value); break;
- case 0x000c: player_node->setSkillPoints(value); break;
+ case 0x0005: PlayerInfo::setAttribute(HP, value); break;
+ case 0x0006: PlayerInfo::setAttribute(MAX_HP, value); break;
+ case 0x0007: PlayerInfo::setAttribute(MP, value); break;
+ case 0x0008: PlayerInfo::setAttribute(MAX_MP, value); break;
+ case 0x0009: PlayerInfo::setAttribute(CHAR_POINTS, value); break;
+ case 0x000b: PlayerInfo::setAttribute(LEVEL, value); break;
+ case 0x000c: PlayerInfo::setAttribute(SKILL_POINTS, value); break;
case 0x0018:
- if (value >= player_node->getMaxWeight() / 2 &&
- player_node->getTotalWeight() <
- player_node->getMaxWeight() / 2)
+ if (value >= PlayerInfo::getAttribute(MAX_WEIGHT) / 2 &&
+ PlayerInfo::getAttribute(TOTAL_WEIGHT) <
+ PlayerInfo::getAttribute(MAX_WEIGHT) / 2)
{
weightNotice = new OkDialog(_("Message"),
_("You are carrying more than "
@@ -263,60 +257,39 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
weightNotice->addActionListener(
&weightListener);
}
- player_node->setTotalWeight(value);
+ PlayerInfo::setAttribute(TOTAL_WEIGHT, value);
break;
- case 0x0019: player_node->setMaxWeight(value); break;
+ case 0x0019: PlayerInfo::setAttribute(MAX_WEIGHT, value); break;
- case 0x0029: player_node->setAttributeEffective(ATK, value
- + ATTR_BONUS(ATK));
- player_node->setAttributeBase(ATK, value);
- break;
- case 0x002a: value += player_node->getAttributeBase(ATK);
- player_node->setAttributeEffective(ATK, value); break;
-
- case 0x002b: player_node->setAttributeEffective(MATK, value
- + ATTR_BONUS(MATK));
- player_node->setAttributeBase(MATK, value);
- if (statusWindow)
- statusWindow->update(StatusWindow::MP);
- break;
- case 0x002c: value += player_node->getAttributeBase(MATK);
- player_node->setAttributeEffective(MATK, value);
- if (statusWindow)
- statusWindow->update(StatusWindow::MP);
- break;
- case 0x002d: player_node->setAttributeEffective(DEF, value
- + ATTR_BONUS(DEF));
- player_node->setAttributeBase(DEF, value); break;
- case 0x002e: value += player_node->getAttributeBase(DEF);
- player_node->setAttributeEffective(DEF, value); break;
-
- case 0x002f: player_node->setAttributeEffective(MDEF, value
- + ATTR_BONUS(MDEF));
- player_node->setAttributeBase(MDEF, value); break;
- case 0x0030: value += player_node->getAttributeBase(MDEF);
- player_node->setAttributeEffective(MDEF, value); break;
-
- case 0x0031: player_node->setAttributeBase(HIT, value);
- player_node->setAttributeEffective(HIT, value); break;
-
- case 0x0032: player_node->setAttributeEffective(FLEE, value
- + ATTR_BONUS(FLEE));
- player_node->setAttributeBase(FLEE, value); break;
- case 0x0033: value += player_node->getAttributeBase(FLEE);
- player_node->setAttributeEffective(FLEE, value); break;
-
- case 0x0034: player_node->setAttributeBase(CRIT, value);
- player_node->setAttributeEffective(CRIT, value); break;
+ case 0x0029: PlayerInfo::setStatBase(ATK, value); break;
+ case 0x002a: PlayerInfo::setStatMod(ATK, value); break;
+
+ case 0x002b: PlayerInfo::setStatBase(MATK, value); break;
+ case 0x002c: PlayerInfo::setStatMod(MATK, value); break;
+
+ case 0x002d: PlayerInfo::setStatBase(DEF, value); break;
+ case 0x002e: PlayerInfo::setStatMod(DEF, value); break;
+
+ case 0x002f: PlayerInfo::setStatBase(MDEF, value); break;
+ case 0x0030: PlayerInfo::setStatMod(MDEF, value); break;
+
+ case 0x0031: PlayerInfo::setStatBase(HIT, value); break;
+
+ case 0x0032: PlayerInfo::setStatBase(FLEE, value); break;
+ case 0x0033: PlayerInfo::setStatMod(FLEE, value); break;
+
+ case 0x0034: PlayerInfo::setStatBase(CRIT, value); break;
case 0x0035: player_node->setAttackSpeed(value); break;
- case 0x0037: player_node->setAttributeBase(JOB, value);
- player_node->setAttributeEffective(JOB, value); break;
+
+ case 0x0037: PlayerInfo::setStatBase(JOB, value); break;
+
case 500: player_node->setGMLevel(value); break;
}
- if (player_node->getHp() == 0 && !deathNotice)
+ if (PlayerInfo::getAttribute(HP) == 0 && !deathNotice)
{
+ viewport->shakeScreen(100);
deathNotice = new OkDialog(_("Message"),
randomDeathMessage(),
false);
@@ -334,35 +307,39 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
switch (msg.readInt16())
{
case 0x0001:
- player_node->setExp(msg.readInt32());
+ PlayerInfo::setAttribute(EXP, msg.readInt32());
break;
case 0x0002:
- player_node->setExperience(JOB, msg.readInt32(),
- player_node->getExperience(JOB).second);
+ PlayerInfo::setStatExperience(JOB, msg.readInt32(),
+ PlayerInfo::getStatExperience(JOB).second);
break;
+
case 0x0014:
{
- const int curGp = player_node->getMoney();
- player_node->setMoney(msg.readInt32());
- if (player_node->getMoney() <= curGp)
- break;
+ int oldMoney = PlayerInfo::getAttribute(MONEY);
+ int newMoney = msg.readInt32();
std::string money = Units::formatCurrency(
- player_node->getMoney() - curGp);
- if (config.getValue("showpickupchat", 1))
- localChatTab->chatLog(strprintf(_("You picked up "
- "%s."), money.c_str()), BY_SERVER);
- if (config.getValue("showpickupparticle", 1))
- player_node->addMessageToQueue(money,
- UserPalette::PICKUP_INFO);
+ newMoney - oldMoney);
+ PlayerInfo::setAttribute(MONEY, newMoney);
+ if (newMoney > oldMoney)
+ {
+ if (config.getBoolValue("showpickupchat"))
+ SERVER_NOTICE(strprintf(_("You picked up %s."),
+ Units::formatCurrency(newMoney -
+ oldMoney).c_str()))
+ if (config.getBoolValue("showpickupparticle"))
+ player_node->addMessageToQueue(money,
+ UserPalette::PICKUP_INFO);
+ }
}
break;
case 0x0016:
- player_node->setExpNeeded(msg.readInt32());
+ PlayerInfo::setAttribute(EXP_NEEDED, msg.readInt32());
break;
case 0x0017:
- player_node->setExperience(JOB,
- player_node->getExperience(JOB).first,
- msg.readInt32());
+ PlayerInfo::setStatExperience(JOB,
+ PlayerInfo::getStatExperience(JOB).first,
+ msg.readInt32());
break;
}
break;
@@ -373,8 +350,8 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
int base = msg.readInt32();
int bonus = msg.readInt32();
- player_node->setAttributeBase(type, base);
- player_node->setAttributeEffective(type, base + bonus);
+ PlayerInfo::setStatBase(type, base, false);
+ PlayerInfo::setStatMod(type, bonus);
}
break;
@@ -386,25 +363,20 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
if (ok != 1)
{
- localChatTab->chatLog(_("Cannot raise skill!"),
- BY_SERVER);
+ SERVER_NOTICE(_("Cannot raise skill!"))
}
- int bonus = ATTR_BONUS(type);
-
- player_node->setAttributeBase(type, value);
- player_node->setAttributeEffective(type, value + bonus);
+ PlayerInfo::setStatBase(type, value);
}
break;
// Updates stats and status points
case SMSG_PLAYER_STAT_UPDATE_5:
- player_node->setCharacterPoints(msg.readInt16());
+ PlayerInfo::setAttribute(CHAR_POINTS, msg.readInt16());
{
int val = msg.readInt8();
- player_node->setAttributeEffective(STR, val + ATTR_BONUS(STR));
- player_node->setAttributeBase(STR, val);
+ PlayerInfo::setStatBase(STR, val);
if (val >= 99)
{
statusWindow->setPointsNeeded(STR, 0);
@@ -416,8 +388,7 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
}
val = msg.readInt8();
- player_node->setAttributeEffective(AGI, val + ATTR_BONUS(AGI));
- player_node->setAttributeBase(AGI, val);
+ PlayerInfo::setStatBase(AGI, val);
if (val >= 99)
{
statusWindow->setPointsNeeded(AGI, 0);
@@ -429,8 +400,7 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
}
val = msg.readInt8();
- player_node->setAttributeEffective(VIT, val + ATTR_BONUS(VIT));
- player_node->setAttributeBase(VIT, val);
+ PlayerInfo::setStatBase(VIT, val);
if (val >= 99)
{
statusWindow->setPointsNeeded(VIT, 0);
@@ -442,8 +412,7 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
}
val = msg.readInt8();
- player_node->setAttributeEffective(INT, val + ATTR_BONUS(INT));
- player_node->setAttributeBase(INT, val);
+ PlayerInfo::setStatBase(INT, val);
if (val >= 99)
{
statusWindow->setPointsNeeded(INT, 0);
@@ -455,8 +424,7 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
}
val = msg.readInt8();
- player_node->setAttributeEffective(DEX, val + ATTR_BONUS(DEX));
- player_node->setAttributeBase(DEX, val);
+ PlayerInfo::setStatBase(DEX, val);
if (val >= 99)
{
statusWindow->setPointsNeeded(DEX, 0);
@@ -468,8 +436,7 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
}
val = msg.readInt8();
- player_node->setAttributeEffective(LUK, val + ATTR_BONUS(LUK));
- player_node->setAttributeBase(LUK, val);
+ PlayerInfo::setStatBase(LUK, val);
if (val >= 99)
{
statusWindow->setPointsNeeded(LUK, 0);
@@ -480,39 +447,25 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
statusWindow->setPointsNeeded(LUK, msg.readInt8());
}
- val = msg.readInt16(); // ATK
- player_node->setAttributeBase(ATK, val);
- val += msg.readInt16(); // ATK bonus
- player_node->setAttributeEffective(ATK, val);
-
- val = msg.readInt16(); // MATK
- player_node->setAttributeBase(MATK, val);
- val += msg.readInt16(); // MATK bonus
- player_node->setAttributeEffective(MATK, val);
- statusWindow->update(StatusWindow::MP);
-
- val = msg.readInt16(); // DEF
- player_node->setAttributeBase(DEF, val);
- val += msg.readInt16(); // DEF bonus
- player_node->setAttributeEffective(DEF, val);
-
- val = msg.readInt16(); // MDEF
- player_node->setAttributeBase(MDEF, val);
- val += msg.readInt16(); // MDEF bonus
- player_node->setAttributeEffective(MDEF, val);
-
- val = msg.readInt16(); // HIT
- player_node->setAttributeBase(HIT, val);
- player_node->setAttributeEffective(HIT, val);
-
- val = msg.readInt16(); // FLEE
- player_node->setAttributeBase(FLEE, val);
- val += msg.readInt16(); // FLEE bonus
- player_node->setAttributeEffective(FLEE, val);
-
- val = msg.readInt16();
- player_node->setAttributeBase(CRIT, val);
- player_node->setAttributeEffective(CRIT, val);
+ PlayerInfo::setStatBase(ATK, msg.readInt16(), false);
+ PlayerInfo::setStatMod(ATK, msg.readInt16());
+
+ PlayerInfo::setStatBase(MATK, msg.readInt16(), false);
+ PlayerInfo::setStatMod(MATK, msg.readInt16());
+
+
+ PlayerInfo::setStatBase(DEF, msg.readInt16(), false);
+ PlayerInfo::setStatMod(DEF, msg.readInt16());
+
+ PlayerInfo::setStatBase(MDEF, msg.readInt16(), false);
+ PlayerInfo::setStatMod(MDEF, msg.readInt16());
+
+ PlayerInfo::setStatBase(HIT, msg.readInt16());
+
+ PlayerInfo::setStatBase(FLEE, msg.readInt16(), false);
+ PlayerInfo::setStatMod(FLEE, msg.readInt16());
+
+ PlayerInfo::setStatBase(CRIT, msg.readInt16());
}
msg.readInt16(); // manner
@@ -549,8 +502,9 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg)
switch (type)
{
case 0:
- localChatTab->chatLog(_("Equip arrows first."),
- BY_SERVER);
+ {
+ SERVER_NOTICE(_("Equip arrows first."))
+ }
break;
default:
logger->log("0x013b: Unhandled message %i", type);
@@ -591,7 +545,7 @@ void PlayerHandler::decreaseAttribute(int attr)
void PlayerHandler::increaseSkill(int skillId)
{
- if (player_node->getSkillPoints() <= 0)
+ if (PlayerInfo::getAttribute(SKILL_POINTS) <= 0)
return;
MessageOut outMsg(CMSG_SKILL_LEVELUP_REQUEST);
@@ -601,11 +555,15 @@ void PlayerHandler::increaseSkill(int skillId)
void PlayerHandler::pickUp(FloorItem *floorItem)
{
static Uint32 lastTime = 0;
- if (SDL_GetTicks() < lastTime + 100)
+
+ // Avoid spamming the server with pick-up requests to prevent the player
+ // from being kicked.
+ if (!floorItem || SDL_GetTicks() < lastTime + 100)
return;
MessageOut outMsg(CMSG_ITEM_PICKUP);
outMsg.writeInt32(floorItem->getId());
+
lastTime = SDL_GetTicks();
}
@@ -618,8 +576,12 @@ void PlayerHandler::setDirection(char direction)
void PlayerHandler::setDestination(int x, int y, int direction)
{
+ // The destination coordinates are received in pixel, so we translate them
+ // into tiles.
+ Map *map = Game::instance()->getCurrentMap();
MessageOut outMsg(CMSG_PLAYER_CHANGE_DEST);
- outMsg.writeCoordinates(x, y, direction);
+ outMsg.writeCoordinates(x / map->getTileWidth(), y / map->getTileHeight(),
+ direction);
}
void PlayerHandler::changeAction(Being::Action action)
@@ -655,7 +617,7 @@ void PlayerHandler::ignoreAll(bool ignore)
bool PlayerHandler::canUseMagic()
{
- return player_node->getAttributeEffective(MATK) > 0;
+ return PlayerInfo::getStatEffective(MATK) > 0;
}
bool PlayerHandler::canCorrectAttributes()
@@ -668,11 +630,35 @@ int PlayerHandler::getJobLocation()
return JOB;
}
-Vector PlayerHandler::getDefaultWalkSpeed()
+Vector PlayerHandler::getDefaultMoveSpeed() const
{
// Return an normalized speed for any side
// as the offset is calculated elsewhere.
- return Vector(150, 150, 0);
+ // in ticks per tile.
+ return Vector(15.0f, 15.0f, 0.0f);
+}
+
+Vector PlayerHandler::getPixelsPerTickMoveSpeed(const Vector &speed, Map *map)
+{
+ Game *game = Game::instance();
+
+ if (game && !map)
+ map = game->getCurrentMap();
+
+ if (!map || speed.x == 0 || speed.y == 0)
+ {
+ logger->log("TmwAthena::PlayerHandler: Speed set to default: "
+ "Map not yet initialized or invalid speed.");
+ return getDefaultMoveSpeed();
+ }
+
+ Vector speedInTicks;
+
+ // speedInTicks.z = 0; // We don't use z for now.
+ speedInTicks.x = 1 / speed.x * (float)map->getTileWidth();
+ speedInTicks.y = 1 / speed.y * (float)map->getTileHeight();
+
+ return speedInTicks;
}
} // namespace TmwAthena
diff --git a/src/net/tmwa/playerhandler.h b/src/net/tmwa/playerhandler.h
index cb352110..63812f47 100644
--- a/src/net/tmwa/playerhandler.h
+++ b/src/net/tmwa/playerhandler.h
@@ -58,7 +58,12 @@ class PlayerHandler : public MessageHandler, public Net::PlayerHandler
int getJobLocation();
- Vector getDefaultWalkSpeed();
+ Vector getDefaultMoveSpeed() const;
+
+ Vector getPixelsPerTickMoveSpeed(const Vector &speed, Map *map = 0);
+
+ bool usePixelPrecision()
+ { return false; }
};
} // namespace TmwAthena
diff --git a/src/net/tmwa/protocol.h b/src/net/tmwa/protocol.h
index 0a768d5d..0624ad2f 100644
--- a/src/net/tmwa/protocol.h
+++ b/src/net/tmwa/protocol.h
@@ -66,7 +66,6 @@ static const int STORAGE_OFFSET = 1;
*********************************/
#define SMSG_SERVER_VERSION_RESPONSE 0x7531
-#define SMSG_SERVER_PING 0x007f /**< Contains server tick */
#define SMSG_CONNECTION_PROBLEM 0x0081
#define SMSG_UPDATE_HOST 0x0063 /**< Custom update host packet */
@@ -111,7 +110,7 @@ static const int STORAGE_OFFSET = 1;
#define SMSG_PLAYER_ARROW_EQUIP 0x013c
#define SMSG_PLAYER_ARROW_MESSAGE 0x013b
#define SMSG_PLAYER_SKILLS 0x010f
-#define SMSG_PLAYER_SKILL_UP 0x010e
+#define SMSG_PLAYER_SKILL_UP 0x010e // same as SMSG_GUILD_SKILL_UP
#define SMSG_SKILL_FAILED 0x0110
#define SMSG_SKILL_DAMAGE 0x01de
#define SMSG_ITEM_USE_RESPONSE 0x00a8
@@ -203,7 +202,7 @@ static const int STORAGE_OFFSET = 1;
#define SMSG_GUILD_EXPULSION 0x015c
#define SMSG_GUILD_EXPULSION_LIST 0x0163
#define SMSG_GUILD_MESSAGE 0x017f
-#define SMSG_GUILD_SKILL_UP 0x010e
+#define SMSG_GUILD_SKILL_UP 0x010e // same as SMSG_PLAYER_SKILL_UP
#define SMSG_GUILD_REQ_ALLIANCE 0x0171
#define SMSG_GUILD_REQ_ALLIANCE_ACK 0x0173
#define SMSG_GUILD_DEL_ALLIANCE 0x0184
@@ -224,14 +223,11 @@ static const int STORAGE_OFFSET = 1;
#define CMSG_CHAR_DELETE 0x0068
#define CMSG_MAP_SERVER_CONNECT 0x0072
-#define CMSG_CLIENT_PING 0x007e /**< Send to server with tick */
#define CMSG_MAP_LOADED 0x007d
#define CMSG_CLIENT_QUIT 0x018A
#define CMSG_CHAT_MESSAGE 0x008c
#define CMSG_CHAT_WHISPER 0x0096
-#define CMSG_CHAT_ANNOUNCE 0x0099
-#define CMSG_CHAT_WHO 0x00c1
#define CMSG_SKILL_LEVELUP_REQUEST 0x0112
#define CMSG_STAT_UPDATE_REQUEST 0x00bb
@@ -249,10 +245,10 @@ static const int STORAGE_OFFSET = 1;
#define CMSG_ITEM_PICKUP 0x009f
#define CMSG_PLAYER_CHANGE_DIR 0x009b
#define CMSG_PLAYER_CHANGE_DEST 0x0085
-#define CMSG_PLAYER_CHANGE_ACT 0x0089
+#define CMSG_PLAYER_CHANGE_ACT 0x0089 // same as CMSG_PLAYER_ATTACK
#define CMSG_PLAYER_RESTART 0x00b2
#define CMSG_PLAYER_EMOTE 0x00bf
-#define CMSG_PLAYER_ATTACK 0x0089
+#define CMSG_PLAYER_ATTACK 0x0089 // same as CMSG_PLAYER_CHANGE_ACT
#define CMSG_WHO_REQUEST 0x00c1
#define CMSG_NPC_TALK 0x0090
@@ -281,7 +277,7 @@ static const int STORAGE_OFFSET = 1;
#define CMSG_PARTY_MESSAGE 0x0108
#define CMSG_MOVE_TO_STORAGE 0x00f3 /** Move item to storage */
-#define CSMG_MOVE_FROM_STORAGE 0x00f5 /** Remove item from storage */
+#define CMSG_MOVE_FROM_STORAGE 0x00f5 /** Remove item from storage */
#define CMSG_CLOSE_STORAGE 0x00f7 /** Request storage close */
#define CMSG_ADMIN_ANNOUNCE 0x0099
diff --git a/src/net/tmwa/specialhandler.cpp b/src/net/tmwa/specialhandler.cpp
index bcf5ba44..661d9e2c 100644
--- a/src/net/tmwa/specialhandler.cpp
+++ b/src/net/tmwa/specialhandler.cpp
@@ -21,13 +21,12 @@
#include "net/tmwa/specialhandler.h"
-#include "localplayer.h"
+#include "event.h"
#include "log.h"
+#include "playerinfo.h"
#include "gui/skilldialog.h"
-#include "gui/widgets/chattab.h"
-
#include "net/messagein.h"
#include "net/messageout.h"
@@ -105,8 +104,7 @@ void SpecialHandler::handleMessage(Net::MessageIn &msg)
msg.skip(24); // unused
int up = msg.readInt8();
- player_node->setAttributeBase(skillId, level);
- player_node->setAttributeEffective(skillId, level);
+ PlayerInfo::setStatBase(skillId, level);
if (skillDialog)
skillDialog->setModifiable(skillId, up);
}
@@ -120,8 +118,7 @@ void SpecialHandler::handleMessage(Net::MessageIn &msg)
msg.readInt16(); // range
int up = msg.readInt8();
- player_node->setAttributeBase(skillId, level);
- player_node->setAttributeEffective(skillId, level);
+ PlayerInfo::setStatBase(skillId, level);
skillDialog->setModifiable(skillId, up);
}
break;
@@ -219,7 +216,7 @@ void SpecialHandler::handleMessage(Net::MessageIn &msg)
}
}
- localChatTab->chatLog(msg);
+ SERVER_NOTICE(msg)
break;
}
}
diff --git a/src/net/tmwa/token.h b/src/net/tmwa/token.h
index d2a21012..3e781cd8 100644
--- a/src/net/tmwa/token.h
+++ b/src/net/tmwa/token.h
@@ -19,7 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "player.h"
+#include "being.h"
#ifndef NET_TA_TOKEN_H
#define NET_TA_TOKEN_H
diff --git a/src/net/tmwa/tradehandler.cpp b/src/net/tmwa/tradehandler.cpp
index 9089f8e6..69ba24af 100644
--- a/src/net/tmwa/tradehandler.cpp
+++ b/src/net/tmwa/tradehandler.cpp
@@ -21,22 +21,24 @@
#include "net/tmwa/tradehandler.h"
+#include "event.h"
#include "inventory.h"
#include "item.h"
#include "localplayer.h"
+#include "playerinfo.h"
#include "playerrelations.h"
#include "gui/confirmdialog.h"
#include "gui/trade.h"
-#include "gui/widgets/chattab.h"
-
#include "net/inventoryhandler.h"
#include "net/messagein.h"
#include "net/messageout.h"
#include "net/tmwa/protocol.h"
+#include "resources/iteminfo.h"
+
#include "utils/gettext.h"
#include "utils/stringutils.h"
@@ -96,14 +98,14 @@ void TradeHandler::handleMessage(Net::MessageIn &msg)
if (player_relations.hasPermission(tradePartnerName,
PlayerRelation::TRADE))
{
- if (!player_node->tradeRequestOk() || confirmDlg)
+ if (PlayerInfo::isTrading() || confirmDlg)
{
Net::getTradeHandler()->respond(false);
break;
}
tradePartnerName = tradePartnerNameTemp;
- player_node->setTrading(true);
+ PlayerInfo::setTrading(true);
confirmDlg = new ConfirmDialog(_("Request for Trade"),
strprintf(_("%s wants to trade with you, do you "
"accept?"), tradePartnerName.c_str()));
@@ -121,16 +123,16 @@ void TradeHandler::handleMessage(Net::MessageIn &msg)
switch (msg.readInt8())
{
case 0: // Too far away
- localChatTab->chatLog(_("Trading isn't possible. Trade "
- "partner is too far away."), BY_SERVER);
+ SERVER_NOTICE(_("Trading isn't possible. Trade "
+ "partner is too far away."))
break;
case 1: // Character doesn't exist
- localChatTab->chatLog(_("Trading isn't possible. Character "
- "doesn't exist."), BY_SERVER);
+ SERVER_NOTICE(_("Trading isn't possible. Character "
+ "doesn't exist."))
break;
case 2: // Invite request check failed...
- localChatTab->chatLog(_("Trade cancelled due to an unknown "
- "reason."), BY_SERVER);
+ SERVER_NOTICE(_("Trade cancelled due to an unknown "
+ "reason."))
break;
case 3: // Trade accepted
tradeWindow->reset();
@@ -141,17 +143,15 @@ void TradeHandler::handleMessage(Net::MessageIn &msg)
case 4: // Trade cancelled
if (player_relations.hasPermission(tradePartnerName,
PlayerRelation::SPEECH_LOG))
- localChatTab->chatLog(strprintf(_("Trade with %s "
- "cancelled."), tradePartnerName.c_str()),
- BY_SERVER);
+ SERVER_NOTICE(strprintf(_("Trade with %s cancelled."),
+ tradePartnerName.c_str()))
// otherwise ignore silently
tradeWindow->setVisible(false);
- player_node->setTrading(false);
+ PlayerInfo::setTrading(false);
break;
default: // Shouldn't happen as well, but to be sure
- localChatTab->chatLog(_("Unhandled trade cancel packet."),
- BY_SERVER);
+ SERVER_NOTICE(_("Unhandled trade cancel packet."))
break;
}
break;
@@ -169,7 +169,7 @@ void TradeHandler::handleMessage(Net::MessageIn &msg)
if (type == 0)
tradeWindow->setMoney(amount);
else
- tradeWindow->addItem(type, false, amount, false);
+ tradeWindow->addItem(type, false, amount);
}
break;
@@ -177,7 +177,7 @@ void TradeHandler::handleMessage(Net::MessageIn &msg)
// Trade: New Item add response (was 0x00ea, now 01b1)
{
const int index = msg.readInt16() - INVENTORY_OFFSET;
- Item *item = player_node->getInventory()->getItem(index);
+ Item *item = PlayerInfo::getInventory()->getItem(index);
if (!item)
{
tradeWindow->receivedOk(true);
@@ -189,27 +189,27 @@ void TradeHandler::handleMessage(Net::MessageIn &msg)
{
case 0:
// Successfully added item
- if (item->isEquipment() && item->isEquipped())
+ if (item->isEquippable() && item->isEquipped())
{
- Net::getInventoryHandler()->unequipItem(item);
+ item->doEvent(Event::DoUnequip);
}
- tradeWindow->addItem(item->getId(), true, quantity,
- item->isEquipment());
+ tradeWindow->addItem(item->getId(), true, quantity);
+
item->increaseQuantity(-quantity);
break;
case 1:
// Add item failed - player overweighted
- localChatTab->chatLog(_("Failed adding item. Trade "
- "partner is over weighted."), BY_SERVER);
+ SERVER_NOTICE(_("Failed adding item. Trade "
+ "partner is over weighted."))
break;
case 2:
// Add item failed - player has no free slot
- localChatTab->chatLog(_("Failed adding item. Trade "
- "partner has no free slot."), BY_SERVER);
+ SERVER_NOTICE(_("Failed adding item. Trade "
+ "partner has no free slot."))
break;
default:
- localChatTab->chatLog(_("Failed adding item for "
- "unknown reason."), BY_SERVER);
+ SERVER_NOTICE(_("Failed adding item for "
+ "unknown reason."))
break;
}
}
@@ -221,17 +221,17 @@ void TradeHandler::handleMessage(Net::MessageIn &msg)
break;
case SMSG_TRADE_CANCEL:
- localChatTab->chatLog(_("Trade canceled."), BY_SERVER);
+ SERVER_NOTICE(_("Trade canceled."))
tradeWindow->setVisible(false);
tradeWindow->reset();
- player_node->setTrading(false);
+ PlayerInfo::setTrading(false);
break;
case SMSG_TRADE_COMPLETE:
- localChatTab->chatLog(_("Trade completed."), BY_SERVER);
+ SERVER_NOTICE(_("Trade completed."))
tradeWindow->setVisible(false);
tradeWindow->reset();
- player_node->setTrading(false);
+ PlayerInfo::setTrading(false);
break;
}
}
@@ -245,7 +245,7 @@ void TradeHandler::request(Being *being)
void TradeHandler::respond(bool accept)
{
if (!accept)
- player_node->setTrading(false);
+ PlayerInfo::setTrading(false);
MessageOut outMsg(CMSG_TRADE_RESPONSE);
outMsg.writeInt8(accept ? 3 : 4);
diff --git a/src/net/tradehandler.h b/src/net/tradehandler.h
index 30798c41..ea3c4550 100644
--- a/src/net/tradehandler.h
+++ b/src/net/tradehandler.h
@@ -30,6 +30,8 @@ namespace Net {
class TradeHandler
{
public:
+ virtual ~TradeHandler() {}
+
virtual void request(Being *being) {}
virtual void respond(bool accept) {}
@@ -45,8 +47,6 @@ class TradeHandler
virtual void finish() {}
virtual void cancel() {}
-
- virtual ~TradeHandler() {}
};
}