diff options
Diffstat (limited to 'src/net')
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() {} }; } |