diff options
Diffstat (limited to 'src/net/manaserv')
31 files changed, 1082 insertions, 725 deletions
diff --git a/src/net/manaserv/attributes.cpp b/src/net/manaserv/attributes.cpp new file mode 100644 index 00000000..a65dc01f --- /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<ItemDB::Stat> dbStats; + + TagMap::const_iterator it, it_end; + for (it = tags.begin(), it_end = tags.end(); it != it_end; ++it) + dbStats.push_back(ItemDB::Stat(it->first, + it->second)); + + itemDb->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..63c1e13f 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" @@ -121,7 +120,7 @@ Vector BeingHandler::giveSpeedInPixelsPerTicks(float speedInTilesPerSeconds) 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 +144,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)); } } @@ -170,23 +169,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; @@ -202,11 +201,11 @@ void BeingHandler::handleBeingEnterMessage(Net::MessageIn &msg) 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,7 +214,7 @@ void BeingHandler::handleBeingsMoveMessage(Net::MessageIn &msg) { int id = msg.readInt16(); int flags = msg.readInt8(); - Being *being = beingManager->findBeing(id); + Being *being = actorSpriteManager->findBeing(id); int sx = 0; int sy = 0; int speed = 0; @@ -257,7 +256,7 @@ void BeingHandler::handleBeingsMoveMessage(Net::MessageIn &msg) void BeingHandler::handleBeingAttackMessage(Net::MessageIn &msg) { - Being *being = beingManager->findBeing(msg.readInt16()); + Being *being = actorSpriteManager->findBeing(msg.readInt16()); const int direction = msg.readInt8(); const int attackType = msg.readInt8(); @@ -279,7 +278,7 @@ 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 +289,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,22 +328,21 @@ 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(); diff --git a/src/net/manaserv/buysellhandler.cpp b/src/net/manaserv/buysellhandler.cpp index a4ce6aa0..d4187db7 100644 --- a/src/net/manaserv/buysellhandler.cpp +++ b/src/net/manaserv/buysellhandler.cpp @@ -21,13 +21,11 @@ #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" @@ -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..6f2b4377 100644 --- a/src/net/manaserv/charhandler.cpp +++ b/src/net/manaserv/charhandler.cpp @@ -37,7 +37,7 @@ #include "net/manaserv/messagein.h" #include "net/manaserv/messageout.h" #include "net/manaserv/protocol.h" -#include "net/manaserv/stats.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,11 @@ 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; default: errorMessage = _("Unknown error."); @@ -189,7 +196,6 @@ void CharHandler::handleCharacterDeleteResponse(Net::MessageIn &msg) delete mSelectedCharacter; mCharacters.remove(mSelectedCharacter); updateCharSelectDialog(); - unlockCharSelectDialog(); new OkDialog(_("Info"), _("Player deleted.")); } else @@ -210,6 +216,7 @@ void CharHandler::handleCharacterDeleteResponse(Net::MessageIn &msg) new OkDialog(_("Error"), errorMessage); } mSelectedCharacter = 0; + unlockCharSelectDialog(); } void CharHandler::handleCharacterSelectResponse(Net::MessageIn &msg) @@ -233,6 +240,7 @@ 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); @@ -259,7 +267,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() @@ -319,17 +330,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 +361,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..db0e1084 100644 --- a/src/net/manaserv/chathandler.cpp +++ b/src/net/manaserv/chathandler.cpp @@ -21,13 +21,13 @@ #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 "playerrelations.h" #include "gui/widgets/channeltab.h" @@ -149,22 +149,29 @@ 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) { mes = being->getName() + " : " + chatMsg; - being->setSpeech(chatMsg, SPEECH_TIME); } else mes = "Unknown : " + chatMsg; - localChatTab->chatLog(mes, being == player_node ? BY_PLAYER : BY_OTHER); + Mana::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(CHANNEL_CHAT); } void ChatHandler::handleEnterChannelResponse(Net::MessageIn &msg) @@ -198,13 +205,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 +221,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 +231,18 @@ void ChatHandler::handlePrivateMessage(Net::MessageIn &msg) std::string userNick = msg.readString(); std::string chatMsg = msg.readString(); - chatWindow->whisper(userNick, chatMsg); + Mana::Event event(EVENT_WHISPER); + event.setString("nick", userNick); + event.setString("message", chatMsg); + event.trigger(CHANNEL_CHAT); } void ChatHandler::handleAnnouncement(Net::MessageIn &msg) { std::string chatMsg = msg.readString(); - localChatTab->chatLog(chatMsg, BY_GM); + Mana::Event event(EVENT_ANNOUNCEMENT); + event.setString("message", chatMsg); + event.trigger(CHANNEL_CHAT); } void ChatHandler::handleChatMessage(Net::MessageIn &msg) @@ -341,7 +353,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..b404191f 100644 --- a/src/net/manaserv/connection.cpp +++ b/src/net/manaserv/connection.cpp @@ -60,7 +60,7 @@ bool Connection::connect(const std::string &address, short port) enetAddress.port = port; // Initiate the connection, allocating channel 0. -#ifdef ENET_VERSION_MAJOR +#if defined(ENET_VERSION) && ENET_VERSION >= ENET_CUTOFF mConnection = enet_host_connect(mClient, &enetAddress, 1, 0); #else mConnection = enet_host_connect(mClient, &enetAddress, 1); diff --git a/src/net/manaserv/connection.h b/src/net/manaserv/connection.h index b39f8957..808a6d40 100644 --- a/src/net/manaserv/connection.h +++ b/src/net/manaserv/connection.h @@ -26,6 +26,12 @@ #include <iosfwd> +#ifdef ENET_VERSION_CREATE +#define ENET_CUTOFF ENET_VERSION_CREATE(1,3,0) +#else +#define ENET_CUTOFF 0xFFFFFFFF +#endif + namespace ManaServ { class MessageOut; 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..c803b441 100644 --- a/src/net/manaserv/effecthandler.cpp +++ b/src/net/manaserv/effecthandler.cpp @@ -21,7 +21,7 @@ #include "net/manaserv/effecthandler.h" -#include "beingmanager.h" +#include "actorspritemanager.h" #include "effectmanager.h" #include "log.h" @@ -68,7 +68,7 @@ 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 diff --git a/src/net/manaserv/gamehandler.cpp b/src/net/manaserv/gamehandler.cpp index 5e29a896..3cb9f0ea 100644 --- a/src/net/manaserv/gamehandler.cpp +++ b/src/net/manaserv/gamehandler.cpp @@ -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 diff --git a/src/net/manaserv/gamehandler.h b/src/net/manaserv/gamehandler.h index dde1748f..2e9f37fe 100644 --- a/src/net/manaserv/gamehandler.h +++ b/src/net/manaserv/gamehandler.h @@ -42,10 +42,6 @@ class GameHandler : public MessageHandler, public Net::GameHandler void disconnect(); - void inGame(); - - void mapLoaded(const std::string &mapName); - void who(); void quit(bool reconnectAccount); @@ -53,12 +49,15 @@ class GameHandler : public MessageHandler, public Net::GameHandler 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 0d3073f1..d2151307 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(CHANNEL_CLIENT); + listen(CHANNEL_GAME); } 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("mana-skills.xml"); - 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(Channels channel, + const Mana::Event &event) { - if (newState == STATE_GAME) + if (channel == CHANNEL_CLIENT) { - GameHandler *game = static_cast<GameHandler*>(Net::getGameHandler()); - game->gameLoading(); + if (event.getName() == EVENT_STATECHANGE) + { + int newState = event.getInt("newState"); + + if (newState == STATE_GAME) + { + GameHandler *game = static_cast<GameHandler*>(Net::getGameHandler()); + game->gameLoading(); + } + } + else if (event.getName() == EVENT_DBSLOADING) + { + Attributes::load(); + Attributes::informItemDB(); + } } - else if (newState == STATE_LOAD_DATA) + else if (channel == CHANNEL_GAME) { - Stats::load(); - Stats::informItemDB(); + if (event.getName() == EVENT_GUIWINDOWSLOADED) + { + inventoryWindow->setSplitAllowed(true); + skillDialog->loadSkills("mana-skills.xml"); + + PlayerInfo::setAttribute(EXP_NEEDED, 100); + + Attributes::informStatusWindow(); + } } } diff --git a/src/net/manaserv/generalhandler.h b/src/net/manaserv/generalhandler.h index 58b95529..c8671ec1 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 "listener.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 Mana::Listener { 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(Channels channel, const Mana::Event &event); protected: MessageHandlerPtr mBeingHandler; diff --git a/src/net/manaserv/guildhandler.cpp b/src/net/manaserv/guildhandler.cpp index 253efb01..821d70bd 100644 --- a/src/net/manaserv/guildhandler.cpp +++ b/src/net/manaserv/guildhandler.cpp @@ -21,16 +21,17 @@ #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" @@ -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..9d2fdfeb 100644 --- a/src/net/manaserv/inventoryhandler.cpp +++ b/src/net/manaserv/inventoryhandler.cpp @@ -26,8 +26,7 @@ #include "item.h" #include "itemshortcut.h" #include "localplayer.h" - -#include "gui/chat.h" +#include "playerinfo.h" #include "net/manaserv/connection.h" #include "net/manaserv/messagein.h" @@ -36,8 +35,6 @@ #include "resources/iteminfo.h" -#include "log.h" // <<< REMOVE ME! - extern Net::InventoryHandler *inventoryHandler; namespace ManaServ { @@ -49,10 +46,13 @@ InventoryHandler::InventoryHandler() static const Uint16 _messages[] = { GPMSG_INVENTORY_FULL, GPMSG_INVENTORY, + GPMSG_EQUIP, 0 }; handledMessages = _messages; inventoryHandler = this; + + listen(CHANNEL_ITEM); } void InventoryHandler::handleMessage(Net::MessageIn &msg) @@ -60,114 +60,142 @@ 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(&mEquips); + int count = msg.readInt16(); + while (count--) { - player_node->setMoney(msg.readInt32()); - continue; + unsigned int slot = msg.readInt16(); + int id = msg.readInt16(); + unsigned int amount = msg.readInt16(); + PlayerInfo::setInventoryItem(slot, id, amount); } - - int id = msg.readInt16(); - if (slot < EQUIPMENT_SIZE) - { - mEquips.setEquipment(slot, id); - } - else if (slot >= 32 && slot < 32 + getSize(Inventory::INVENTORY)) + while (msg.getUnreadLength()) { - int amount = id ? msg.readInt8() : 0; - player_node->setInvItem(slot - 32, id, amount); + unsigned int slot = msg.readInt8(); + unsigned int ref = msg.readInt16(); + + mEquips.addEquipment(slot, ref); } - }; + } break; - } -} -void InventoryHandler::equipItem(const Item *item) -{ - MessageOut msg(PGMSG_EQUIP); - msg.writeInt8(item->getInvIndex()); - gameServerConnection->send(msg); -} - -void InventoryHandler::unequipItem(const Item *item) -{ - 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); -} - -void InventoryHandler::useItem(const Item *item) -{ - MessageOut msg(PGMSG_USE_ITEM); - msg.writeInt8(item->getInvIndex()); - gameServerConnection->send(msg); -} - -void InventoryHandler::dropItem(const Item *item, int amount) -{ - MessageOut msg(PGMSG_DROP); - msg.writeInt8(item->getInvIndex()); - msg.writeInt8(amount); - gameServerConnection->send(msg); -} + case GPMSG_INVENTORY: + while (msg.getUnreadLength()) + { + unsigned int slot = msg.readInt16(); + int id = msg.readInt16(); + unsigned int amount = id ? msg.readInt16() : 0; + PlayerInfo::setInventoryItem(slot, id, amount); + } + break; -bool InventoryHandler::canSplit(const Item *item) -{ - return item && !item->isEquipment() && item->getQuantity() > 1; -} + case GPMSG_EQUIP: + while (msg.getUnreadLength()) + { + unsigned int ref = msg.readInt16(); + int count = msg.readInt8(); + while (count--) + { + unsigned int slot = msg.readInt8(); + unsigned int used = msg.readInt8(); -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); + mEquips.setEquipment(slot, used, ref); + } + } + break; } } -void InventoryHandler::moveItem(int oldIndex, int newIndex) -{ - if (oldIndex == newIndex) - return; - - MessageOut msg(PGMSG_MOVE_ITEM); - msg.writeInt8(oldIndex); - msg.writeInt8(newIndex); - msg.writeInt8(player_node->getInventory()->getItem(oldIndex) - ->getQuantity()); - gameServerConnection->send(msg); -} - -void InventoryHandler::openStorage(int type) +void InventoryHandler::event(Channels channel, + const Mana::Event &event) { - // TODO -} + if (channel == CHANNEL_ITEM) + { + Item *item = event.getItem("item"); + + if (!item) + return; + + int index = item->getInvIndex(); + + if (event.getName() == EVENT_DOEQUIP) + { + MessageOut msg(PGMSG_EQUIP); + msg.writeInt8(index); + gameServerConnection->send(msg); + } + else if (event.getName() == EVENT_DOUNEQUIP) + { + MessageOut msg(PGMSG_UNEQUIP); + msg.writeInt8(index); + gameServerConnection->send(msg); + + // Tidy equipment directly to avoid weapon still shown bug, + // for instance. + mEquips.setEquipment(index, 0, 0); + } + else if (event.getName() == EVENT_DOUSE) + { + MessageOut msg(PGMSG_USE_ITEM); + msg.writeInt8(index); + gameServerConnection->send(msg); + } + else if (event.getName() == EVENT_DODROP) + { + int amount = event.getInt("amount", 1); + + MessageOut msg(PGMSG_DROP); + msg.writeInt8(index); + msg.writeInt8(amount); + gameServerConnection->send(msg); + } + else if (event.getName() == EVENT_DOSPLIT) + { + int amount = event.getInt("amount", 1); + + 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.getName() == EVENT_DOMOVE) + { + int newIndex = event.getInt("newIndex", -1); + + if (newIndex >= 0) + { + if (index == newIndex) + return; + + 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..bb68ceeb 100644 --- a/src/net/manaserv/inventoryhandler.h +++ b/src/net/manaserv/inventoryhandler.h @@ -23,6 +23,7 @@ #define NET_MANASERV_INVENTORYHANDLER_H #include "equipment.h" +#include "listener.h" #include "net/inventoryhandler.h" @@ -37,64 +38,38 @@ class EquipBackend : public Equipment::Backend { memset(mEquipment, 0, sizeof(mEquipment)); } Item *getEquipment(int index) const - { return mEquipment[index]; } + { return 0; } void clear() { - for (int i = 0; i < EQUIPMENT_SIZE; ++i) - delete mEquipment[i]; + } - std::fill_n(mEquipment, EQUIPMENT_SIZE, (Item*) 0); + void setEquipment(unsigned int slot, unsigned int used, int reference) + { + printf("Equip: %d at %dx%d\n", reference, slot, used); } - void setEquipment(int index, int id, int quantity = 0) + void addEquipment(unsigned int slot, int reference) { - if (mEquipment[index] && mEquipment[index]->getId() == id) - return; - - delete mEquipment[index]; - mEquipment[index] = (id > 0) ? new Item(id, quantity) : 0; - - if (mEquipment[index]) - { - mEquipment[index]->setInvIndex(index); - mEquipment[index]->setEquipped(true); - mEquipment[index]->setInEquipment(true); - } + printf("Equip: %d at %d\n", reference, slot); } private: Item *mEquipment[EQUIPMENT_SIZE]; }; -class InventoryHandler : public MessageHandler, Net::InventoryHandler +class InventoryHandler : public MessageHandler, Net::InventoryHandler, + public Mana::Listener { 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(Channels channel, const Mana::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/manaserv/itemhandler.cpp b/src/net/manaserv/itemhandler.cpp index dc3b9f14..200e7fac 100644 --- a/src/net/manaserv/itemhandler.cpp +++ b/src/net/manaserv/itemhandler.cpp @@ -21,7 +21,7 @@ #include "net/manaserv/itemhandler.h" -#include "flooritemmanager.h" +#include "actorspritemanager.h" #include "net/manaserv/protocol.h" #include "net/manaserv/messagein.h" @@ -62,8 +62,7 @@ void ItemHandler::handleMessage(Net::MessageIn &msg) { if (Map *map = game->getCurrentMap()) { - floorItemManager->create(id, - itemId, + actorSpriteManager->createItem(id, itemId, x / map->getTileWidth(), y / map->getTileHeight()); } @@ -75,9 +74,9 @@ void ItemHandler::handleMessage(Net::MessageIn &msg) } } } - 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..05a51efe 100644 --- a/src/net/manaserv/loginhandler.cpp +++ b/src/net/manaserv/loginhandler.cpp @@ -196,7 +196,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 @@ -251,7 +251,7 @@ void LoginHandler::handleLoginResponse(Net::MessageIn &msg) if (errMsg == ERRMSG_OK) { - readUpdateHost(msg); + readServerInfo(msg); // No worlds atm, but future use :-D Client::setState(STATE_WORLD_SELECT); } @@ -289,7 +289,7 @@ void LoginHandler::handleRegisterResponse(Net::MessageIn &msg) if (errMsg == ERRMSG_OK) { - readUpdateHost(msg); + readServerInfo(msg); Client::setState(STATE_WORLD_SELECT); } else @@ -320,7 +320,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 +332,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() diff --git a/src/net/manaserv/loginhandler.h b/src/net/manaserv/loginhandler.h index d2ffbc3d..2062dcb5 100644 --- a/src/net/manaserv/loginhandler.h +++ b/src/net/manaserv/loginhandler.h @@ -80,7 +80,7 @@ class LoginHandler : public MessageHandler, public Net::LoginHandler void handleLoginResponse(Net::MessageIn &msg); void handleRegisterResponse(Net::MessageIn &msg); - void readUpdateHost(Net::MessageIn &msg); + void readServerInfo(Net::MessageIn &msg); LoginData *mLoginData; unsigned int mMinUserNameLength; diff --git a/src/net/manaserv/network.cpp b/src/net/manaserv/network.cpp index 636585c9..a5bf6186 100644 --- a/src/net/manaserv/network.cpp +++ b/src/net/manaserv/network.cpp @@ -53,7 +53,7 @@ void initialize() logger->error("Failed to initialize ENet."); } -#ifdef ENET_VERSION_MAJOR +#if defined(ENET_VERSION) && ENET_VERSION >= ENET_CUTOFF client = enet_host_create(NULL, 3, 0, 0, 0); #else client = enet_host_create(NULL, 3, 0, 0); diff --git a/src/net/manaserv/npchandler.cpp b/src/net/manaserv/npchandler.cpp index 392ec4fd..9620f7c1 100644 --- a/src/net/manaserv/npchandler.cpp +++ b/src/net/manaserv/npchandler.cpp @@ -21,17 +21,16 @@ #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 "utils/stringutils.h" + extern Net::NpcHandler *npcHandler; namespace ManaServ { @@ -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; + Mana::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 Mana::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(CHANNEL_NPC); + break; + + case GPMSG_NPC_NUMBER: + event = new Mana::Event(EVENT_INTEGERINPUT); + event->setInt("id", npcId); + event->setInt("min", msg.readInt32()); + event->setInt("max", msg.readInt32()); + event->setInt("default", msg.readInt32()); + event->trigger(CHANNEL_NPC); + break; + + case GPMSG_NPC_STRING: + event = new Mana::Event(EVENT_STRINGINPUT); + event->setInt("id", npcId); + event->trigger(CHANNEL_NPC); + break; + + case GPMSG_NPC_POST: + event = new Mana::Event(EVENT_POST); + event->setInt("id", npcId); + event->trigger(CHANNEL_NPC); + break; + + case GPMSG_NPC_ERROR: + event = new Mana::Event(EVENT_END); + event->setInt("id", npcId); + event->trigger(CHANNEL_NPC); + break; + + case GPMSG_NPC_MESSAGE: + event = new Mana::Event(EVENT_MESSAGE); + event->setInt("id", npcId); + event->setString("text", msg.readString(msg.getUnreadLength())); + event->trigger(CHANNEL_NPC); + delete event; + + event = new Mana::Event(EVENT_NEXT); + event->setInt("id", npcId); + event->trigger(CHANNEL_NPC); + break; + + case GPMSG_NPC_CLOSE: + event = new Mana::Event(EVENT_CLOSE); + event->setInt("id", npcId); + event->trigger(CHANNEL_NPC); + 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); + + Mana::Event event(EVENT_TALKSENT); + event.setInt("npcId", npcId); + event.trigger(CHANNEL_NPC); } 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); + + Mana::Event event(EVENT_NEXTSENT); + event.setInt("npcId", npcId); + event.trigger(CHANNEL_NPC); } 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); - } + Mana::Event event(EVENT_CLOSESENT); + event.setInt("npcId", npcId); + event.trigger(CHANNEL_NPC); } -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); + + Mana::Event event(EVENT_MENUSENT); + event.setInt("npcId", npcId); + event.setInt("choice", choice); + event.trigger(CHANNEL_NPC); } 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); + + Mana::Event event(EVENT_INTEGERINPUTSENT); + event.setInt("npcId", npcId); + event.setInt("value", value); + event.trigger(CHANNEL_NPC); } 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); + + Mana::Event event(EVENT_STRINGINPUTSENT); + event.setInt("npcId", npcId); + event.setString("value", value); + event.trigger(CHANNEL_NPC); } 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(); + Mana::Event event(EVENT_SENDLETTERSENT); + event.setInt("npcId", npcId); + event.setString("recipient", recipient); + event.setString("text", text); + event.trigger(CHANNEL_NPC); } } // namespace ManaServ diff --git a/src/net/manaserv/npchandler.h b/src/net/manaserv/npchandler.h index 689fdc1d..cb8fd67d 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 "listener.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..370d6496 100644 --- a/src/net/manaserv/partyhandler.cpp +++ b/src/net/manaserv/partyhandler.cpp @@ -21,13 +21,12 @@ #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" @@ -85,7 +84,7 @@ void PartyHandler::handleMessage(Net::MessageIn &msg) if (msg.readInt8() == ERRMSG_OK) { // - localChatTab->chatLog(_("Joined party.")); + SERVER_NOTICE(_("Joined party.")); } } @@ -103,7 +102,7 @@ void PartyHandler::handleMessage(Net::MessageIn &msg) int id = msg.readInt16(); // being id std::string name = msg.readString(); - localChatTab->chatLog(strprintf(_("%s joined the party."), + SERVER_NOTICE(strprintf(_("%s joined the party."), name.c_str())); if (id == player_node->getId()) @@ -120,8 +119,8 @@ void PartyHandler::handleMessage(Net::MessageIn &msg) case CPMSG_PARTY_REJECTED: { std::string name = msg.readString(); - localChatTab->chatLog(strprintf(_("%s rejected your invite."), - name.c_str())); + SERVER_NOTICE(strprintf( + _("%s rejected your invite."), name.c_str())); } break; } } @@ -136,9 +135,9 @@ 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) @@ -167,7 +166,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..be09ff69 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,10 +39,11 @@ #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/attributes.h" /** * Max. distance we are willing to scroll after a teleport; @@ -64,9 +65,7 @@ void RespawnRequestListener::action(const gcn::ActionEvent &event) { Net::getPlayerHandler()->respawn(); - ManaServ::NpcHandler *handler = - static_cast<ManaServ::NpcHandler*>(Net::getNpcHandler()); - handler->clearDialogs(); + Mana::Event::trigger(CHANNEL_NPC, EVENT_CLOSEALL); } PlayerHandler::PlayerHandler() @@ -112,23 +111,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 +142,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 +185,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 +205,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 +222,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 +254,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 +329,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 +347,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) diff --git a/src/net/manaserv/protocol.h b/src/net/manaserv/protocol.h index 226a27a0..a49b2dd8 100644 --- a/src/net/manaserv/protocol.h +++ b/src/net/manaserv/protocol.h @@ -44,20 +44,23 @@ 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 APMSG_CHAR_CREATE_RESPONSE = 0x0021, // B error PAMSG_CHAR_DELETE = 0x0022, // B index 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 + // B index, 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 index 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 @@ -86,16 +89,17 @@ 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 // character: S name, B hair style, B hair color, B gender, B item bitmask, { W item id }* @@ -109,7 +113,7 @@ 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_BEING_HEALTH_CHANGE = 0x0274, // W being id, W hp, W max hp GPMSG_BEINGS_MOVE = 0x0280, // { W being id, B flags [, W*2 position, B speed] }* GPMSG_ITEMS = 0x0281, // { W item id, W*2 position }* PGMSG_ATTACK = 0x0290, // W being id @@ -272,10 +276,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,7 +305,7 @@ 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 }; 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..30ff6890 100644 --- a/src/net/manaserv/tradehandler.cpp +++ b/src/net/manaserv/tradehandler.cpp @@ -21,15 +21,15 @@ #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" @@ -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) |