diff options
Diffstat (limited to 'src')
39 files changed, 777 insertions, 551 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bc44a05c..3c632918 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -578,6 +578,8 @@ SET(SRCS_TMWA SET(SRCS_MANA net/manaserv/adminhandler.cpp net/manaserv/adminhandler.h + net/manaserv/attributes.cpp + net/manaserv/attributes.h net/manaserv/beinghandler.cpp net/manaserv/beinghandler.h net/manaserv/buysellhandler.cpp @@ -622,8 +624,6 @@ SET(SRCS_MANA net/manaserv/protocol.h net/manaserv/specialhandler.cpp net/manaserv/specialhandler.h - net/manaserv/stats.cpp - net/manaserv/stats.h net/manaserv/tradehandler.cpp net/manaserv/tradehandler.h ) diff --git a/src/Makefile.am b/src/Makefile.am index fa72eb08..aecca587 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -424,6 +424,8 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \ mana_SOURCES += \ net/manaserv/adminhandler.cpp \ net/manaserv/adminhandler.h \ + net/manaserv/attributes.cpp \ + net/manaserv/attributes.h \ net/manaserv/beinghandler.cpp \ net/manaserv/beinghandler.h \ net/manaserv/buysellhandler.cpp \ @@ -468,8 +470,6 @@ mana_SOURCES += \ net/manaserv/protocol.h \ net/manaserv/specialhandler.cpp \ net/manaserv/specialhandler.h \ - net/manaserv/stats.cpp \ - net/manaserv/stats.h \ net/manaserv/tradehandler.cpp \ net/manaserv/tradehandler.h diff --git a/src/being.cpp b/src/being.cpp index 1b95b17d..138e5c5a 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -153,7 +153,7 @@ void Being::setSubtype(Uint16 subtype) int id = -100 - subtype; // Prevent showing errors when sprite doesn't exist - if (!ItemDB::exists(id)) + if (!itemDb->exists(id)) id = -100; setSprite(Net::getCharHandler()->baseSprite(), id); @@ -1106,7 +1106,7 @@ void Being::setSprite(unsigned int slot, int id, const std::string &color, } else { - std::string filename = ItemDB::get(id).getSprite(mGender); + std::string filename = itemDb->get(id).getSprite(mGender); AnimatedSprite *equipmentSprite = NULL; if (!filename.empty()) @@ -1124,7 +1124,7 @@ void Being::setSprite(unsigned int slot, int id, const std::string &color, CompoundSprite::setSprite(slot, equipmentSprite); if (isWeapon) - mEquippedWeapon = &ItemDB::get(id); + mEquippedWeapon = &itemDb->get(id); setAction(mAction); } @@ -1154,7 +1154,7 @@ void Being::load() // we can go. int hairstyles = 1; - while (ItemDB::get(-hairstyles).getSprite(GENDER_MALE) != + while (itemDb->get(-hairstyles).getSprite(GENDER_MALE) != paths.getStringValue("spriteErrorFile")) hairstyles++; diff --git a/src/client.cpp b/src/client.cpp index 1e1d17a9..6ed208c0 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -120,6 +120,8 @@ KeyboardConfig keyboard; UserPalette *userPalette; Graphics *graphics; +ItemDB *itemDb; + Sound sound; void ErrorListener::action(const gcn::ActionEvent &) @@ -438,7 +440,7 @@ Client::~Client() // Unload XML databases ColorDB::unload(); EmoteDB::unload(); - ItemDB::unload(); + delete itemDb; MonsterDB::unload(); NPCDB::unload(); StatusEffect::unload(); @@ -747,7 +749,7 @@ int Client::exec() // Load XML databases ColorDB::load(); - ItemDB::load(); + itemDb = new ItemDB; Being::load(); // Hairstyles MonsterDB::load(); SpecialDB::load(); diff --git a/src/flooritem.cpp b/src/flooritem.cpp index 84e07f35..aed77351 100644 --- a/src/flooritem.cpp +++ b/src/flooritem.cpp @@ -45,10 +45,10 @@ FloorItem::FloorItem(int id, mPos.y = y * map->getTileHeight() + ((Net::getNetworkType() == ServerInfo::MANASERV) ? 15 : 32); - setupSpriteDisplay(ItemDB::get(itemId).getDisplay()); + setupSpriteDisplay(itemDb->get(itemId).getDisplay()); } const ItemInfo &FloorItem::getInfo() const { - return ItemDB::get(mId); + return itemDb->get(mId); } diff --git a/src/gui/charcreatedialog.cpp b/src/gui/charcreatedialog.cpp index a2cb2efb..2db25a35 100644 --- a/src/gui/charcreatedialog.cpp +++ b/src/gui/charcreatedialog.cpp @@ -65,10 +65,10 @@ CharCreateDialog::CharCreateDialog(CharSelectDialog *parent, int slot): mNameField = new TextField(""); mNameLabel = new Label(_("Name:")); - // TRANSLATORS: This is a narrow symbol used to denote 'next'. + // TRANSLATORS: This is an arrow symbol used to denote 'next'. // You may change this symbol if your language uses another. mNextHairColorButton = new Button(_(">"), "nextcolor", this); - // TRANSLATORS: This is a narrow symbol used to denote 'previous'. + // TRANSLATORS: This is an arrow symbol used to denote 'previous'. // You may change this symbol if your language uses another. mPrevHairColorButton = new Button(_("<"), "prevcolor", this); mHairColorLabel = new Label(_("Hair color:")); @@ -277,7 +277,8 @@ int CharCreateDialog::getDistributedPoints() const } void CharCreateDialog::setAttributes(const std::vector<std::string> &labels, - int available, int min, int max) + unsigned int available, unsigned int min, + unsigned int max) { mMaxPoints = available; diff --git a/src/gui/charcreatedialog.h b/src/gui/charcreatedialog.h index 018de3f5..d6b6d390 100644 --- a/src/gui/charcreatedialog.h +++ b/src/gui/charcreatedialog.h @@ -63,8 +63,8 @@ class CharCreateDialog : public Window, public gcn::ActionListener void unlock(); void setAttributes(const std::vector<std::string> &labels, - int available, - int min, int max); + unsigned int available, + unsigned int min, unsigned int max); void setFixedGender(bool fixed, Gender gender = GENDER_FEMALE); diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp index 5df1d4ba..6ad1b05f 100644 --- a/src/gui/inventorywindow.cpp +++ b/src/gui/inventorywindow.cpp @@ -97,7 +97,8 @@ InventoryWindow::InventoryWindow(Inventory *inventory): longestUseString = unequip; } - mUseButton = new Button(longestUseString, "use", this); + mEquipButton = new Button(_("Equip"), "equip", this); + mUseButton = new Button(_("Activate"), "activate", this); mDropButton = new Button(_("Drop..."), "drop", this); mSplitButton = new Button(_("Split"), "split", this); mOutfitButton = new Button(_("Outfits"), "outfit", this); @@ -111,8 +112,9 @@ InventoryWindow::InventoryWindow(Inventory *inventory): place(5, 0, mSlotsBar, 2); place(0, 1, invenScroll, 7).setPadding(3); place(0, 2, mUseButton); - place(1, 2, mDropButton); - place(2, 2, mSplitButton); + place(1, 2, mEquipButton); + place(2, 2, mDropButton); + place(3, 2, mSplitButton); place(6, 2, mOutfitButton); updateWeight(); @@ -183,9 +185,11 @@ void InventoryWindow::action(const gcn::ActionEvent &event) if (!item) return; - if (event.getId() == "use") + if (event.getId() == "activate") + item->doEvent("doUse"); + else if (event.getId() == "equip") { - if (item->isEquipment()) + if (item->isEquippable()) { if (item->isEquipped()) item->doEvent("doUnequip"); @@ -193,7 +197,9 @@ void InventoryWindow::action(const gcn::ActionEvent &event) item->doEvent("doEquip"); } else + { item->doEvent("doUse"); + } } else if (event.getId() == "drop") { @@ -309,25 +315,26 @@ void InventoryWindow::valueChanged(const gcn::SelectionEvent &event) if (!item || item->getQuantity() == 0) { mUseButton->setEnabled(false); + mEquipButton->setEnabled(false); mDropButton->setEnabled(false); return; } - mUseButton->setEnabled(true); mDropButton->setEnabled(true); - if (item->isEquipment()) + if (item->getInfo().getEquippable()) { if (item->isEquipped()) - mUseButton->setCaption(_("Unequip")); + mEquipButton->setCaption(_("Unequip")); else - mUseButton->setCaption(_("Equip")); + mEquipButton->setCaption(_("Equip")); + mEquipButton->setEnabled(true); } else - { - mUseButton->setCaption(_("Use")); - } + mEquipButton->setEnabled(false); + + mUseButton->setEnabled(item->getInfo().getActivatable()); if (item->getQuantity() > 1) mDropButton->setCaption(_("Drop...")); diff --git a/src/gui/inventorywindow.h b/src/gui/inventorywindow.h index af72106b..1b68b897 100644 --- a/src/gui/inventorywindow.h +++ b/src/gui/inventorywindow.h @@ -124,8 +124,8 @@ class InventoryWindow : public Window, std::string mWeight, mSlots; - gcn::Button *mUseButton, *mDropButton, *mSplitButton, *mOutfitButton, - *mStoreButton, *mRetrieveButton; + gcn::Button *mUseButton, *mEquipButton, *mDropButton, *mSplitButton, + *mOutfitButton, *mStoreButton, *mRetrieveButton; gcn::Label *mWeightLabel, *mSlotsLabel; diff --git a/src/gui/itempopup.cpp b/src/gui/itempopup.cpp index c926670a..ea33fda3 100644 --- a/src/gui/itempopup.cpp +++ b/src/gui/itempopup.cpp @@ -61,12 +61,12 @@ ItemPopup::ItemPopup(): // Item Effect mItemEffect = new TextBox; mItemEffect->setEditable(false); - mItemEffect->setPosition(getPadding(), 2 * fontHeight + 2 * getPadding()); + mItemEffect->setPosition(getPadding(), (fontHeight << 1) + (getPadding() << 1)); // Item Weight mItemWeight = new TextBox; mItemWeight->setEditable(false); - mItemWeight->setPosition(getPadding(), 3 * fontHeight + 4 * getPadding()); + mItemWeight->setPosition(getPadding(), fontHeight * 3 + (getPadding() << 2)); mIcon = new Icon(0); @@ -121,18 +121,27 @@ void ItemPopup::setItem(const ItemInfo &item, bool showImage) mIcon->setImage(0); } - mItemType = item.getType(); + //mItemType = item.getType(); mItemName->setCaption(item.getName()); mItemName->adjustSize(); - mItemName->setForegroundColor(getColor(mItemType)); + mItemName->setForegroundColor(Theme::UNKNOWN_ITEM); // TODO mItemName->setPosition(getPadding() + space, getPadding()); - mItemDesc->setTextWrapped(item.getDescription(), 196); - mItemEffect->setTextWrapped(item.getEffect(), 196); +#define ITEMPOPUP_WRAP_WIDTH 196 + + mItemDesc->setTextWrapped(item.getDescription(), ITEMPOPUP_WRAP_WIDTH); + { + const std::vector<std::string> &effect = item.getEffect(); + std::string temp = ""; + for (std::vector<std::string>::const_iterator it = effect.begin(), + it_end = effect.end(); it != it_end; ++it) + temp += temp.empty() ? *it : "\n" + *it; + mItemEffect->setTextWrapped(temp, ITEMPOPUP_WRAP_WIDTH); + } mItemWeight->setTextWrapped(strprintf(_("Weight: %s"), Units::formatWeight(item.getWeight()).c_str()), - 196); + ITEMPOPUP_WRAP_WIDTH); int minWidth = mItemName->getWidth() + space; diff --git a/src/gui/outfitwindow.cpp b/src/gui/outfitwindow.cpp index f16ebd39..7e126dc8 100644 --- a/src/gui/outfitwindow.cpp +++ b/src/gui/outfitwindow.cpp @@ -40,6 +40,7 @@ #include "net/net.h" #include "resources/image.h" +#include "resources/iteminfo.h" #include "utils/gettext.h" #include "utils/stringutils.h" @@ -170,7 +171,7 @@ void OutfitWindow::wearOutfit(int outfit) item = PlayerInfo::getInventory()->findItem(mItems[outfit][i]); if (item && !item->isEquipped() && item->getQuantity()) { - if (item->isEquipment()) + if (item->isEquippable()) item->doEvent("doEquip"); } } diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp index 41ecafc9..7a702cc2 100644 --- a/src/gui/popupmenu.cpp +++ b/src/gui/popupmenu.cpp @@ -271,10 +271,10 @@ void PopupMenu::handleLink(const std::string &link) { } - else if (link == "use") + else if (link == "activate") { assert(mItem); - if (mItem->isEquipment()) + if (mItem->isEquippable()) { if (mItem->isEquipped()) mItem->doEvent("doUnequip"); @@ -282,9 +282,10 @@ void PopupMenu::handleLink(const std::string &link) mItem->doEvent("doEquip"); } else + { mItem->doEvent("doUse"); + } } - else if (link == "chat") { if (mItem) @@ -360,15 +361,15 @@ void PopupMenu::showPopup(Window *parent, int x, int y, Item *item, if (isInventory) { - if (item->isEquipment()) + if (item->getInfo().getEquippable()) { if (item->isEquipped()) - mBrowserBox->addRow(strprintf("@@use|%s@@", _("Unequip"))); + mBrowserBox->addRow(strprintf("@@equip|%s@@", _("Unequip"))); else - mBrowserBox->addRow(strprintf("@@use|%s@@", _("Equip"))); + mBrowserBox->addRow(strprintf("@@equip|%s@@", _("Equip"))); } - else - mBrowserBox->addRow(strprintf("@@use|%s@@", _("Use"))); + if (item->getInfo().getActivatable()) + mBrowserBox->addRow(strprintf("@@activate|%s@@", _("Activate"))); if (item->getQuantity() > 1) mBrowserBox->addRow(strprintf("@@drop|%s@@", _("Drop..."))); diff --git a/src/gui/trade.cpp b/src/gui/trade.cpp index bfb61c33..37662bef 100644 --- a/src/gui/trade.cpp +++ b/src/gui/trade.cpp @@ -141,18 +141,6 @@ void TradeWindow::addItem(int id, bool own, int quantity) (own ? mMyInventory : mPartnerInventory)->addItem(id, quantity); } -void TradeWindow::addItem(int id, bool own, int quantity, bool equipment) -{ - if (own) - { - mMyInventory->addItem(id, quantity, equipment); - } - else - { - mPartnerInventory->addItem(id, quantity, equipment); - } -} - void TradeWindow::changeQuantity(int index, bool own, int quantity) { if (own) diff --git a/src/gui/widgets/chattab.cpp b/src/gui/widgets/chattab.cpp index fbde2c9c..05f34760 100644 --- a/src/gui/widgets/chattab.cpp +++ b/src/gui/widgets/chattab.cpp @@ -236,7 +236,7 @@ void ChatTab::chatInput(const std::string &message) std::string temp = msg.substr(start + 1, end - start - 1); - const ItemInfo itemInfo = ItemDB::get(temp); + const ItemInfo itemInfo = itemDb->get(temp); if (itemInfo.getId() != 0) { msg.insert(end, "@@"); diff --git a/src/gui/widgets/itemcontainer.cpp b/src/gui/widgets/itemcontainer.cpp index a9df95a6..c8c98d0a 100644 --- a/src/gui/widgets/itemcontainer.cpp +++ b/src/gui/widgets/itemcontainer.cpp @@ -257,7 +257,7 @@ void ItemContainer::mousePressed(gcn::MouseEvent &event) { if(event.getClickCount() == 2) { - if (item->isEquipment()) + if (item->getInfo().getEquippable()) { if (item->isEquipped()) item->doEvent("doUnequip"); @@ -277,7 +277,7 @@ void ItemContainer::mousePressed(gcn::MouseEvent &event) { if(event.getClickCount() == 2) { - if (item->isEquipment()) + if (item->getInfo().getEquippable()) { if (item->isEquipped()) item->doEvent("doUnequip"); @@ -285,7 +285,9 @@ void ItemContainer::mousePressed(gcn::MouseEvent &event) item->doEvent("doEquip"); } else + { item->doEvent("doUse"); + } } else { @@ -294,7 +296,8 @@ void ItemContainer::mousePressed(gcn::MouseEvent &event) itemShortcut->setItemSelected(item->getId()); } - if (item->isEquipment()) + + if (item->getInfo().getEquippable()) outfitWindow->setItemSelected(item->getId()); } else diff --git a/src/gui/widgets/itemlinkhandler.cpp b/src/gui/widgets/itemlinkhandler.cpp index b7341084..8477225f 100644 --- a/src/gui/widgets/itemlinkhandler.cpp +++ b/src/gui/widgets/itemlinkhandler.cpp @@ -49,7 +49,7 @@ void ItemLinkHandler::handleLink(const std::string &link) if (id > 0) { - const ItemInfo &itemInfo = ItemDB::get(id); + const ItemInfo &itemInfo = itemDb->get(id); mItemPopup->setItem(itemInfo, true); if (mItemPopup->isVisible()) diff --git a/src/inventory.cpp b/src/inventory.cpp index 7684b54c..245306ae 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -71,12 +71,12 @@ Item *Inventory::findItem(int itemId) const return NULL; } -void Inventory::addItem(int id, int quantity, bool equipment) +void Inventory::addItem(int id, int quantity) { - setItem(getFreeSlot(), id, quantity, equipment); + setItem(getFreeSlot(), id, quantity); } -void Inventory::setItem(int index, int id, int quantity, bool equipment) +void Inventory::setItem(int index, int id, int quantity) { if (index < 0 || index >= mSize) { @@ -86,7 +86,7 @@ void Inventory::setItem(int index, int id, int quantity, bool equipment) if (!mItems[index] && id > 0) { - Item *item = new Item(id, quantity, equipment); + Item *item = new Item(id, quantity); item->setInvIndex(index); mItems[index] = item; mUsed++; @@ -96,7 +96,6 @@ void Inventory::setItem(int index, int id, int quantity, bool equipment) { mItems[index]->setId(id); mItems[index]->setQuantity(quantity); - mItems[index]->setEquipment(equipment); } else if (mItems[index]) { diff --git a/src/inventory.h b/src/inventory.h index 088dfb8f..7af9f160 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -84,12 +84,12 @@ class Inventory /** * Adds a new item in a free slot. */ - void addItem(int id, int quantity, bool equipment = false); + void addItem(int id, int quantity); /** * Sets the item at the given position. */ - void setItem(int index, int id, int quantity, bool equipment = false); + void setItem(int index, int id, int quantity); /** * Remove a item from the inventory. diff --git a/src/item.cpp b/src/item.cpp index 7a8ccf6d..a2a1d443 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -29,11 +29,11 @@ #include "resources/resourcemanager.h" #include "resources/theme.h" -Item::Item(int id, int quantity, bool equipment, bool equipped): +Item::Item(int id, int quantity, bool equipped): mImage(0), mDrawImage(0), mQuantity(quantity), - mEquipment(equipment), mEquipped(equipped), mInEquipment(false) + mEquipped(equipped), mInEquipment(false) { setId(id); } @@ -48,9 +48,6 @@ void Item::setId(int id) { mId = id; - // Types 0 and 1 are not equippable items. - mEquipment = id && getInfo().getType() >= 2; - // Load the associated image if (mImage) mImage->decRef(); @@ -89,3 +86,8 @@ void Item::doEvent(const std::string &eventName, int amount) event.setInt("amount", amount); event.trigger("Item"); } + +bool Item::isEquippable() const +{ + return getInfo().getEquippable(); +} @@ -35,8 +35,7 @@ class Item /** * Constructor. */ - Item(int id = -1, int quantity = 0, bool equipment = false, - bool equipped = false); + Item(int id = -1, int quantity = 0, bool equipped = false); /** * Destructor. @@ -79,16 +78,6 @@ class Item int getQuantity() const { return mQuantity; } /** - * Sets whether this item is considered equipment. - */ - void setEquipment(bool equipment) { mEquipment = equipment; } - - /** - * Returns whether this item is considered equipment. - */ - bool isEquipment() const { return mEquipment; } - - /** * Sets whether this item is equipped. */ void setEquipped(bool equipped) { mEquipped = equipped; } @@ -109,6 +98,11 @@ class Item bool isInEquipment() const { return mInEquipment; } /** + * Returns whether this item is equippable. + */ + bool isEquippable() const; + + /** * Sets the inventory index of this item. */ void setInvIndex(int index) { mInvIndex = index; } @@ -125,17 +119,17 @@ class Item /** * Returns information about this item type. */ - const ItemInfo &getInfo() const { return ItemDB::get(mId); } + const ItemInfo &getInfo() const { return itemDb->get(mId); } protected: int mId; /**< Item type id. */ Image *mImage; /**< Item image. */ Image *mDrawImage; /**< Draw image. */ int mQuantity; /**< Number of items. */ - bool mEquipment; /**< Item is equipment. */ bool mEquipped; /**< Item is equipped. */ bool mInEquipment; /**< Item is in equipment */ int mInvIndex; /**< Inventory index. */ + }; #endif diff --git a/src/itemshortcut.cpp b/src/itemshortcut.cpp index eaf16889..ef4f6387 100644 --- a/src/itemshortcut.cpp +++ b/src/itemshortcut.cpp @@ -29,6 +29,8 @@ #include "net/inventoryhandler.h" #include "net/net.h" +#include "resources/iteminfo.h" + #include "utils/stringutils.h" ItemShortcut *itemShortcut; @@ -70,7 +72,7 @@ void ItemShortcut::useItem(int index) Item *item = PlayerInfo::getInventory()->findItem(mItems[index]); if (item && item->getQuantity()) { - if (item->isEquipment()) + if (item->getInfo().getEquippable()) { if (item->isEquipped()) item->doEvent("doUnequip"); @@ -78,7 +80,9 @@ void ItemShortcut::useItem(int index) item->doEvent("doEquip"); } else + { item->doEvent("doUse"); + } } } } diff --git a/src/net/manaserv/attributes.cpp b/src/net/manaserv/attributes.cpp new file mode 100644 index 00000000..7a9a761a --- /dev/null +++ b/src/net/manaserv/attributes.cpp @@ -0,0 +1,317 @@ +/* + * 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 "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; + bool modifiable; + } Attribute; + + // tag -> effect + typedef std::map< std::string, std::string > TagMap; + + typedef std::map<unsigned int, Attribute> AttributeMap; + AttributeMap attributes; + + TagMap tags; + + // List of modifiable attribute names used at character's creation. + static std::vector<std::string> attributeLabels; + + 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; + } + + static void loadBuiltins() + { + { + Attribute a; + a.id = 16; + a.name = _("Strength"); + a.description = ""; + a.modifiable = true; + + 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; + + 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; + + 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; + + 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; + + 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; + + 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(); + 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; + } + + Attribute a; + a.id = id; + a.name = name; + a.description = XML::getProperty(node, "desc", ""); + a.modifiable = XML::getProperty(node, "modifiable", "false") + == "true"; + + 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())); + + // 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) + attributeLabels.push_back(it->second.name + ":"); + } + + // 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++) + 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..9791d2cb 100644 --- a/src/net/manaserv/stats.h +++ b/src/net/manaserv/attributes.h @@ -18,14 +18,14 @@ * 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 +34,30 @@ namespace Stats { void informStatusWindow(); - std::vector<std::string> getLabelVector(); -} // namespace Stats + /** + * Returns the list of base attribute labels. + */ + std::vector<std::string>& getLabels(); + + /** + * 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/charhandler.cpp b/src/net/manaserv/charhandler.cpp index 7e401455..90909440 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); @@ -260,7 +264,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() @@ -359,11 +366,12 @@ void CharHandler::updateCharacters() character->data.mAttributes[LEVEL] = info.level; character->data.mAttributes[CHAR_POINTS] = info.characterPoints; character->data.mAttributes[CORR_POINTS] = info.correctionPoints; - character->data.mAttributes[MONEY] = info.money; - for (int i = 0; i < 7; i++) + for (CachedAttributes::const_iterator it = info.attribute.begin(), + it_end = info.attribute.end(); it != it_end; it++) { - character->data.mStats[i].base = info.attribute[i]; + 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 dac4a29e..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 { @@ -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/generalhandler.cpp b/src/net/manaserv/generalhandler.cpp index 210e3043..f4982173 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" @@ -130,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() @@ -150,7 +150,7 @@ void GeneralHandler::unload() delete gameServerConnection; delete chatServerConnection; - Stats::unload(); + Attributes::unload(); finalize(); } @@ -185,8 +185,8 @@ void GeneralHandler::event(const std::string &channel, } else if (newState == STATE_LOAD_DATA) { - Stats::load(); - Stats::informItemDB(); + Attributes::load(); + Attributes::informItemDB(); } } else if (channel == "Game") @@ -198,7 +198,7 @@ void GeneralHandler::event(const std::string &channel, PlayerInfo::setAttribute(EXP_NEEDED, 100); - Stats::informStatusWindow(); + Attributes::informStatusWindow(); } } } diff --git a/src/net/manaserv/inventoryhandler.cpp b/src/net/manaserv/inventoryhandler.cpp index 28de9c1e..da1abab5 100644 --- a/src/net/manaserv/inventoryhandler.cpp +++ b/src/net/manaserv/inventoryhandler.cpp @@ -46,6 +46,7 @@ InventoryHandler::InventoryHandler() static const Uint16 _messages[] = { GPMSG_INVENTORY_FULL, GPMSG_INVENTORY, + GPMSG_EQUIP, 0 }; handledMessages = _messages; @@ -59,31 +60,50 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg) switch (msg.getId()) { case GPMSG_INVENTORY_FULL: - PlayerInfo::clearInventory(); - PlayerInfo::getEquipment()->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--) { - PlayerInfo::setAttribute(MONEY, 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) + while (msg.getUnreadLength()) { - mEquips.setEquipment(slot, id); + unsigned int slot = msg.readInt8(); + unsigned int ref = msg.readInt16(); + + mEquips.addEquipment(slot, ref); } - else if (slot >= 32 && slot < 32 + getSize(Inventory::INVENTORY)) + } + break; + + 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; + + case GPMSG_EQUIP: + while (msg.getUnreadLength()) + { + unsigned int ref = msg.readInt16(); + int count = msg.readInt8(); + while (count--) { - int amount = id ? msg.readInt8() : 0; - PlayerInfo::setInventoryItem(slot - 32, id, amount); + unsigned int slot = msg.readInt8(); + unsigned int used = msg.readInt8(); + + mEquips.setEquipment(slot, used, ref); } - }; + } break; } } @@ -112,8 +132,9 @@ void InventoryHandler::event(const std::string &channel, msg.writeInt8(index); gameServerConnection->send(msg); - // Tidy equipment directly to avoid weapon still shown bug, for instance - mEquips.setEquipment(index, 0); + // Tidy equipment directly to avoid weapon still shown bug, + // for instance. + mEquips.setEquipment(index, 0, 0); } else if (event.getName() == "doUse") { @@ -173,7 +194,8 @@ void InventoryHandler::event(const std::string &channel, bool InventoryHandler::canSplit(const Item *item) { - return item && !item->isEquipment() && item->getQuantity() > 1; + 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 a1673e99..aa44f2ee 100644 --- a/src/net/manaserv/inventoryhandler.h +++ b/src/net/manaserv/inventoryhandler.h @@ -38,30 +38,20 @@ 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: diff --git a/src/net/manaserv/playerhandler.cpp b/src/net/manaserv/playerhandler.cpp index db2dcf7a..5bacce49 100644 --- a/src/net/manaserv/playerhandler.cpp +++ b/src/net/manaserv/playerhandler.cpp @@ -110,24 +110,20 @@ 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); + int attr = msg.readInt16(); + double base = msg.readInt32() / 256.0; + double value = msg.readInt32() / 256.0; - if (stat == BASE_ATTR_HP) - { - PlayerInfo::setAttribute(MAX_HP, base); + /* TODO handle HP + if (attr == ATTR_HP) PlayerInfo::setAttribute(HP, value); - } - else - { - PlayerInfo::setStatBase(stat, base); - PlayerInfo::setStatMod(stat, value - base); - } + else if (attr == ATTR_MAX_HP) + PlayerInfo::setAttribute(MAX_HP, value);*/ + + PlayerInfo::setStatBase(attr, base); + PlayerInfo::setStatMod(attr, value - base); } } break; @@ -166,7 +162,7 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg) 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: @@ -203,7 +199,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,9 +217,10 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg) // undo attribute change and set points to 0 logger->log("Warning: Server denied reduction of attribute %d (no points left) ", attrNum); 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; } break; case ATTRIBMOD_DENIED: { @@ -326,14 +323,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); } diff --git a/src/net/manaserv/protocol.h b/src/net/manaserv/protocol.h index 226a27a0..571879c5 100644 --- a/src/net/manaserv/protocol.h +++ b/src/net/manaserv/protocol.h @@ -57,7 +57,10 @@ enum { 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 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/tmwa/generalhandler.cpp b/src/net/tmwa/generalhandler.cpp index 8d69767f..79362a6d 100644 --- a/src/net/tmwa/generalhandler.cpp +++ b/src/net/tmwa/generalhandler.cpp @@ -106,7 +106,7 @@ GeneralHandler::GeneralHandler(): stats.push_back(ItemDB::Stat("dex", _("Dexterity %+d"))); stats.push_back(ItemDB::Stat("luck", _("Luck %+d"))); - ItemDB::setStatsList(stats); + itemDb->setStatsList(stats); listen("Game"); } diff --git a/src/net/tmwa/inventoryhandler.cpp b/src/net/tmwa/inventoryhandler.cpp index 46eb6258..4a46e475 100644 --- a/src/net/tmwa/inventoryhandler.cpp +++ b/src/net/tmwa/inventoryhandler.cpp @@ -174,17 +174,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; @@ -228,11 +221,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); if (msg.readInt8() > 0) { @@ -247,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); } } break; @@ -304,8 +297,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) @@ -330,9 +322,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: @@ -374,7 +364,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) { diff --git a/src/net/tmwa/tradehandler.cpp b/src/net/tmwa/tradehandler.cpp index 05ca3f87..c8615485 100644 --- a/src/net/tmwa/tradehandler.cpp +++ b/src/net/tmwa/tradehandler.cpp @@ -37,6 +37,8 @@ #include "net/tmwa/protocol.h" +#include "resources/iteminfo.h" + #include "utils/gettext.h" #include "utils/stringutils.h" @@ -167,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; @@ -187,12 +189,12 @@ void TradeHandler::handleMessage(Net::MessageIn &msg) { case 0: // Successfully added item - if (item->isEquipment() && item->isEquipped()) + if (item->isEquippable() && item->isEquipped()) { item->doEvent("doUnequip"); } - tradeWindow->addItem(item->getId(), true, quantity, - item->isEquipment()); + tradeWindow->addItem(item->getId(), true, quantity); + item->increaseQuantity(-quantity); break; case 1: diff --git a/src/playerinfo.cpp b/src/playerinfo.cpp index cebd15dc..beb3942e 100644 --- a/src/playerinfo.cpp +++ b/src/playerinfo.cpp @@ -186,11 +186,7 @@ void clearInventory() void setInventoryItem(int index, int id, int amount) { - bool equipment = false; - int itemType = ItemDB::get(id).getType(); - if (itemType != ITEM_UNUSABLE && itemType != ITEM_USABLE) - equipment = true; - mInventory->setItem(index, id, amount, equipment); + mInventory->setItem(index, id, amount); } Equipment *getEquipment() diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp index a8eed123..8a703bc7 100644 --- a/src/resources/itemdb.cpp +++ b/src/resources/itemdb.cpp @@ -23,6 +23,8 @@ #include "log.h" +#include "net/net.h" + #include "resources/iteminfo.h" #include "resources/resourcemanager.h" @@ -36,19 +38,7 @@ #include <cassert> -namespace -{ - ItemDB::ItemInfos mItemInfos; - ItemDB::NamedItemInfos mNamedItemInfos; - ItemInfo *mUnknown; - bool mLoaded = false; -} - // Forward declarations -static void loadSpriteRef(ItemInfo *itemInfo, xmlNodePtr node); -static void loadSoundRef(ItemInfo *itemInfo, xmlNodePtr node); -static void loadFloorSprite(SpriteDisplay *display, xmlNodePtr node); - static char const *const fields[][2] = { { "attack", N_("Attack %+d") }, @@ -59,7 +49,7 @@ static char const *const fields[][2] = static std::list<ItemDB::Stat> extraStats; -void ItemDB::setStatsList(const std::list<ItemDB::Stat> &stats) +void ItemDB::setStatsList(const std::list<Stat> &stats) { extraStats = stats; } @@ -99,8 +89,8 @@ void ItemDB::load() logger->log("Initializing item database..."); mUnknown = new ItemInfo; - mUnknown->setName(_("Unknown item")); - mUnknown->setDisplay(SpriteDisplay()); + mUnknown->mName = _("Unknown item"); + mUnknown->mDisplay = SpriteDisplay(); std::string errFile = paths.getStringValue("spriteErrorFile"); mUnknown->setSprite(errFile, GENDER_MALE); mUnknown->setSprite(errFile, GENDER_FEMALE); @@ -109,9 +99,7 @@ void ItemDB::load() xmlNodePtr rootNode = doc.rootNode(); if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "items")) - { logger->error("ItemDB: Error while loading items.xml!"); - } for_each_xml_child_node(node, rootNode) { @@ -120,15 +108,13 @@ void ItemDB::load() int id = XML::getProperty(node, "id", 0); - if (id == 0) + if (!id) { logger->log("ItemDB: Invalid or missing item ID in items.xml!"); continue; } else if (mItemInfos.find(id) != mItemInfos.end()) - { logger->log("ItemDB: Redefinition of item ID %d", id); - } std::string typeStr = XML::getProperty(node, "type", "other"); int weight = XML::getProperty(node, "weight", 0); @@ -145,37 +131,37 @@ void ItemDB::load() display.image = image; ItemInfo *itemInfo = new ItemInfo; - itemInfo->setId(id); - itemInfo->setName(name.empty() ? _("unnamed") : name); - itemInfo->setDescription(description); - itemInfo->setType(itemTypeFromString(typeStr)); - itemInfo->setView(view); - itemInfo->setWeight(weight); + itemInfo->mId = id; + itemInfo->mName = name.empty() ? _("unnamed") : name; + itemInfo->mDescription = description; + itemInfo->mType = itemTypeFromString(typeStr); + itemInfo->mActivatable = itemInfo->mType == ITEM_USABLE; + // Everything not unusable or usable is equippable by the old type system. + itemInfo->mEquippable = itemInfo->mType != ITEM_UNUSABLE + && itemInfo->mType != ITEM_USABLE; + itemInfo->mView = view; + itemInfo->mWeight = weight; itemInfo->setAttackAction(attackAction); - itemInfo->setAttackRange(attackRange); + itemInfo->mAttackRange = attackRange; itemInfo->setMissileParticle(missileParticle); - std::string effect; + std::vector<std::string> effect; for (int i = 0; i < int(sizeof(fields) / sizeof(fields[0])); ++i) { int value = XML::getProperty(node, fields[i][0], 0); if (!value) continue; - if (!effect.empty()) effect += " / "; - effect += strprintf(gettext(fields[i][1]), value); + effect.push_back(strprintf(gettext(fields[i][1]), value)); } for (std::list<Stat>::iterator it = extraStats.begin(); it != extraStats.end(); it++) { int value = XML::getProperty(node, it->tag.c_str(), 0); if (!value) continue; - if (!effect.empty()) effect += " / "; - effect += strprintf(it->format.c_str(), value); + effect.push_back(strprintf(it->format.c_str(), value)); } std::string temp = XML::getProperty(node, "effect", ""); - if (!effect.empty() && !temp.empty()) - effect += " / "; - effect += temp; - itemInfo->setEffect(effect); + if (!temp.empty()) + effect.push_back(temp); for_each_xml_child_node(itemChild, node) { @@ -183,7 +169,7 @@ void ItemDB::load() { std::string attackParticle = XML::getProperty( itemChild, "particle-effect", ""); - itemInfo->setParticleEffect(attackParticle); + itemInfo->mParticle = attackParticle; loadSpriteRef(itemInfo, itemChild); } @@ -195,9 +181,96 @@ void ItemDB::load() { loadFloorSprite(&display, itemChild); } + /* + * Begin new item definition code. Previous code is left in to + * maintain backwards compatibility. + * Exit here if tmwAthena. + */ + else if (Net::getNetworkType() == ServerInfo::TMWATHENA); + else if (xmlStrEqual(itemChild->name, BAD_CAST "equip")) + { + // The fact that there is a way to equip is enough. + // Discard any details, but mark the item as equippable. + itemInfo->mEquippable = true; + } + else if (xmlStrEqual(itemChild->name, BAD_CAST "effect")) + { + std::string trigger = XML::getProperty( + itemChild, "trigger", ""); + if (trigger.empty()) { + logger->log("Found empty trigger effect label, skipping."); + continue; + } + + if (trigger == "activation") + itemInfo->mActivatable = true; + + static std::map<std::string, const char* > triggerTable; + if (triggerTable.empty()) + { + // FIXME: This should ideally be softcoded via XML or similar. + triggerTable["existence"] = " when it is in the inventory"; + triggerTable["activation"] = " upon activation"; + triggerTable["equip"] = " upon successful equip"; + triggerTable["leave-inventory"] = " when it leaves the inventory"; + triggerTable["unequip"] = " when it is unequipped"; + triggerTable["equip-change"] = " when it changes the way it is equipped"; + } + std::map<std::string, const char* >::const_iterator triggerLabel = + triggerTable.find(trigger); + if (triggerLabel == triggerTable.end()) + { + logger->log("Warning: unknown trigger %s in item %d!", trigger.c_str(), id); + continue; + } + + for_each_xml_child_node(effectChild, itemChild) + { + if (xmlStrEqual(effectChild->name, BAD_CAST "modifier")) + { + std::string attribute = XML::getProperty( + effectChild, "attribute", ""); + double value = XML::getFloatProperty( + effectChild, "value", 0.0); + int duration = XML::getProperty( + effectChild, "duration", 0); + if (attribute.empty() || !value) + { + logger->log("Warning: incomplete modifier definition, skipping."); + continue; + } + std::list<Stat>::const_iterator + it = extraStats.begin(), + it_end = extraStats.end(); + while (it != it_end && !(*it == attribute)) + ++it; + if (it == extraStats.end()) + { + logger->log("Warning: unknown modifier tag %s, skipping.", attribute.c_str()); + continue; + } + effect.push_back( + strprintf(strprintf( + duration ? + strprintf("%%s%%s. This effect lasts %d ticks.", duration).c_str() + : "%s%s.", it->format.c_str(), triggerLabel->second).c_str(), value)); + } + else if (xmlStrEqual(effectChild->name, BAD_CAST "modifier")) + effect.push_back(strprintf("Provides an autoattack%s.", + triggerLabel->second)); + else if (xmlStrEqual(effectChild->name, BAD_CAST "consumes")) + effect.push_back(strprintf("This will be consumed%s.", + triggerLabel->second)); + else if (xmlStrEqual(effectChild->name, BAD_CAST "label")) + effect.push_back( + (const char*)effectChild->xmlChildrenNode->content); + } + } } - itemInfo->setDisplay(display); + itemInfo->mEffect = effect; + + itemInfo->mDisplay = display; mItemInfos[id] = itemInfo; if (!name.empty()) @@ -295,7 +368,7 @@ const ItemInfo &ItemDB::get(const std::string &name) return *(i->second); } -void loadSpriteRef(ItemInfo *itemInfo, xmlNodePtr node) +void ItemDB::loadSpriteRef(ItemInfo *itemInfo, xmlNodePtr node) { std::string gender = XML::getProperty(node, "gender", "unisex"); std::string filename = (const char*) node->xmlChildrenNode->content; @@ -310,7 +383,7 @@ void loadSpriteRef(ItemInfo *itemInfo, xmlNodePtr node) } } -void loadSoundRef(ItemInfo *itemInfo, xmlNodePtr node) +void ItemDB::loadSoundRef(ItemInfo *itemInfo, xmlNodePtr node) { std::string event = XML::getProperty(node, "event", ""); std::string filename = (const char*) node->xmlChildrenNode->content; @@ -330,7 +403,7 @@ void loadSoundRef(ItemInfo *itemInfo, xmlNodePtr node) } } -void loadFloorSprite(SpriteDisplay *display, xmlNodePtr floorNode) +void ItemDB::loadFloorSprite(SpriteDisplay *display, xmlNodePtr floorNode) { for_each_xml_child_node(spriteNode, floorNode) { diff --git a/src/resources/itemdb.h b/src/resources/itemdb.h index be023073..e4146131 100644 --- a/src/resources/itemdb.h +++ b/src/resources/itemdb.h @@ -26,45 +26,67 @@ #include <map> #include <string> +#include "utils/xml.h" + class ItemInfo; +class SpriteDisplay; /** * Item information database. */ -namespace ItemDB +class ItemDB { - /** - * Loads the item data from <code>items.xml</code>. - */ - void load(); - - /** - * Frees item data. - */ - void unload(); - - bool exists(int id); - - const ItemInfo &get(int id); - const ItemInfo &get(const std::string &name); - - struct Stat - { - Stat(const std::string &tag, - const std::string &format): - tag(tag), - format(format) - {} - - std::string tag; - std::string format; - }; - - void setStatsList(const std::list<Stat> &stats); - - // Items database - typedef std::map<int, ItemInfo*> ItemInfos; - typedef std::map<std::string, ItemInfo*> NamedItemInfos; -} + public: + ItemDB() : mLoaded(false) { load(); } + + ~ItemDB() { unload(); } + /** + * Loads the item data from <code>items.xml</code>. + */ + void load(); + + /** + * Frees item data. + */ + void unload(); + + bool exists(int id); + + const ItemInfo &get(int id); + const ItemInfo &get(const std::string &name); + + class Stat + { + public: + Stat(const std::string &tag, + const std::string &format): + tag(tag), format(format) {} + + bool operator ==(std::string &name) const { return tag == name; } + + private: + std::string tag; + std::string format; + friend class ItemDB; + }; + + void setStatsList(const std::list<Stat> &stats); + + private: + void loadSpriteRef(ItemInfo *itemInfo, xmlNodePtr node); + void loadSoundRef(ItemInfo *itemInfo, xmlNodePtr node); + void loadFloorSprite(SpriteDisplay *display, xmlNodePtr node); + + // Items database + typedef std::map<int, ItemInfo*> ItemInfos; + typedef std::map<std::string, ItemInfo*> NamedItemInfos; + + ItemInfos mItemInfos; + NamedItemInfos mNamedItemInfos; + ItemInfo *mUnknown; + bool mLoaded; +}; + +extern ItemDB *itemDb; #endif diff --git a/src/resources/iteminfo.cpp b/src/resources/iteminfo.cpp index 1cd3c546..32331e35 100644 --- a/src/resources/iteminfo.cpp +++ b/src/resources/iteminfo.cpp @@ -29,7 +29,7 @@ const std::string &ItemInfo::getSprite(Gender gender) const if (mView) { // Forward the request to the item defining how to view this item - return ItemDB::get(mView).getSprite(gender); + return itemDb->get(mView).getSprite(gender); } else { diff --git a/src/resources/iteminfo.h b/src/resources/iteminfo.h index ac747e33..48a14667 100644 --- a/src/resources/iteminfo.h +++ b/src/resources/iteminfo.h @@ -108,58 +108,25 @@ class ItemInfo { } - void setId(int id) - { mId = id; } - int getId() const { return mId; } - void setName(const std::string &name) - { mName = name; } - const std::string &getName() const { return mName; } - void setParticleEffect(const std::string &particleEffect) - { mParticle = particleEffect; } - std::string getParticleEffect() const { return mParticle; } - void setDisplay(SpriteDisplay display) - { mDisplay = display; } - const SpriteDisplay &getDisplay() const { return mDisplay; } - void setDescription(const std::string &description) - { mDescription = description; } - const std::string &getDescription() const { return mDescription; } - void setEffect(const std::string &effect) - { mEffect = effect; } - - const std::string &getEffect() const { return mEffect; } - - void setType(ItemType type) - { mType = type; } - - ItemType getType() const - { return mType; } - - void setWeight(int weight) - { mWeight = weight; } + const std::vector<std::string> &getEffect() const { return mEffect; } int getWeight() const { return mWeight; } - void setView(int view) - { mView = view; } - - void setSprite(const std::string &animationFile, Gender gender) - { mAnimationFiles[gender] = animationFile; } - const std::string &getSprite(Gender gender) const; void setAttackAction(std::string attackAction); @@ -175,23 +142,33 @@ class ItemInfo int getAttackRange() const { return mAttackRange; } - void setAttackRange(int r) - { mAttackRange = r; } + const std::string &getSound(EquipmentSoundEvent event) const; + + bool getEquippable() const { return mEquippable; } + + bool getActivatable() const { return mActivatable; } + + private: + + void setSprite(const std::string &animationFile, Gender gender) + { mAnimationFiles[gender] = animationFile; } void addSound(EquipmentSoundEvent event, const std::string &filename); - const std::string &getSound(EquipmentSoundEvent event) const; + void setWeaponType(int); - protected: - SpriteDisplay mDisplay; /**< Display info (like icon) */ + SpriteDisplay mDisplay; /**< Display info (like icon) */ std::string mName; - std::string mDescription; /**< Short description. */ - std::string mEffect; /**< Description of effects. */ - ItemType mType; /**< Item type. */ - std::string mParticle; /**< Particle effect used with this item */ - int mWeight; /**< Weight in grams. */ - int mView; /**< Item ID of how this item looks. */ - int mId; /**< Item ID */ + std::string mDescription; /**< Short description. */ + std::vector<std::string> mEffect; /**< Description of effects. */ + ItemType mType; /**< Item type. */ + std::string mParticle; /**< Particle effect used with this item */ + int mWeight; /**< Weight in grams. */ + int mView; /**< Item ID of how this item looks. */ + int mId; /**< Item ID */ + + bool mEquippable; /**< Whether this item can be equipped. */ + bool mActivatable; /**< Whether this item can be activated. */ // Equipment related members. /** Attack type, in case of weapon. @@ -209,6 +186,9 @@ class ItemInfo /** Stores the names of sounds to be played at certain event. */ std::map< EquipmentSoundEvent, std::vector<std::string> > mSounds; + + friend class ItemDB; + friend void loadSpriteRef(ItemInfo *itemInfo, xmlNodePtr node); }; #endif |