summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/Makefile.am4
-rw-r--r--src/being.cpp8
-rw-r--r--src/client.cpp6
-rw-r--r--src/flooritem.cpp4
-rw-r--r--src/gui/charcreatedialog.cpp7
-rw-r--r--src/gui/charcreatedialog.h4
-rw-r--r--src/gui/inventorywindow.cpp31
-rw-r--r--src/gui/inventorywindow.h4
-rw-r--r--src/gui/itempopup.cpp23
-rw-r--r--src/gui/outfitwindow.cpp3
-rw-r--r--src/gui/popupmenu.cpp17
-rw-r--r--src/gui/trade.cpp12
-rw-r--r--src/gui/widgets/chattab.cpp2
-rw-r--r--src/gui/widgets/itemcontainer.cpp9
-rw-r--r--src/gui/widgets/itemlinkhandler.cpp2
-rw-r--r--src/inventory.cpp9
-rw-r--r--src/inventory.h4
-rw-r--r--src/item.cpp12
-rw-r--r--src/item.h22
-rw-r--r--src/itemshortcut.cpp6
-rw-r--r--src/net/manaserv/attributes.cpp317
-rw-r--r--src/net/manaserv/attributes.h (renamed from src/net/manaserv/stats.h)34
-rw-r--r--src/net/manaserv/charhandler.cpp24
-rw-r--r--src/net/manaserv/charhandler.h12
-rw-r--r--src/net/manaserv/generalhandler.cpp16
-rw-r--r--src/net/manaserv/inventoryhandler.cpp64
-rw-r--r--src/net/manaserv/inventoryhandler.h24
-rw-r--r--src/net/manaserv/playerhandler.cpp35
-rw-r--r--src/net/manaserv/protocol.h31
-rw-r--r--src/net/manaserv/stats.cpp217
-rw-r--r--src/net/tmwa/generalhandler.cpp2
-rw-r--r--src/net/tmwa/inventoryhandler.cpp24
-rw-r--r--src/net/tmwa/tradehandler.cpp10
-rw-r--r--src/playerinfo.cpp6
-rw-r--r--src/resources/itemdb.cpp155
-rw-r--r--src/resources/itemdb.h90
-rw-r--r--src/resources/iteminfo.cpp2
-rw-r--r--src/resources/iteminfo.h72
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();
+}
diff --git a/src/item.h b/src/item.h
index f0d16fdd..269618f1 100644
--- a/src/item.h
+++ b/src/item.h
@@ -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