diff options
author | Yohann Ferreira <yohann_dot_ferreira_at_orange_dot_efer> | 2011-08-25 23:42:21 +0200 |
---|---|---|
committer | Yohann Ferreira <yohann_dot_ferreira_at_orange_dot_efer> | 2011-08-25 23:42:21 +0200 |
commit | 19f6ce87e69b42fb69a4739ce363e1346cd569ea (patch) | |
tree | 48a04a477ede925fd946ac62d36ccc92cf3df4e1 /src/net/manaserv/inventoryhandler.cpp | |
parent | 88e7a96bffe9758bb4f0916f6841b98f2cfccbfb (diff) | |
parent | 011135415f7f9c5cfeb220540621dfd1c46e6db9 (diff) | |
download | mana-client-19f6ce87e69b42fb69a4739ce363e1346cd569ea.tar.gz mana-client-19f6ce87e69b42fb69a4739ce363e1346cd569ea.tar.bz2 mana-client-19f6ce87e69b42fb69a4739ce363e1346cd569ea.tar.xz mana-client-19f6ce87e69b42fb69a4739ce363e1346cd569ea.zip |
Merge branch 'equipment-fix' of github.com:Bertram25/mana
Diffstat (limited to 'src/net/manaserv/inventoryhandler.cpp')
-rw-r--r-- | src/net/manaserv/inventoryhandler.cpp | 318 |
1 files changed, 233 insertions, 85 deletions
diff --git a/src/net/manaserv/inventoryhandler.cpp b/src/net/manaserv/inventoryhandler.cpp index c8dae1c3..1a74f732 100644 --- a/src/net/manaserv/inventoryhandler.cpp +++ b/src/net/manaserv/inventoryhandler.cpp @@ -29,6 +29,7 @@ #include "log.h" #include "playerinfo.h" +#include "gui/equipmentwindow.h" #include "gui/inventorywindow.h" #include "net/manaserv/connection.h" @@ -38,88 +39,152 @@ #include "resources/iteminfo.h" +#include "utils/stringutils.h" + +#define EQUIP_FILE "equip.xml" + extern Net::InventoryHandler *inventoryHandler; namespace ManaServ { +struct EquipItemInfo +{ + + EquipItemInfo(int itemId, int slotTypeId, int amountUsed): + mItemId(itemId), mSlotTypeId(slotTypeId), mAmountUsed(amountUsed) + {} + + int mItemId, mSlotTypeId, mAmountUsed; +}; + extern Connection *gameServerConnection; EquipBackend::EquipBackend() { listen(Event::ClientChannel); + mVisibleSlots = 0; +} + +Item *EquipBackend::getEquipment(int slotIndex) const +{ + Slots::const_iterator it = mSlots.find(slotIndex); + return it == mSlots.end() ? 0 : it->second.item; +} + +std::string EquipBackend::getSlotName(int slotIndex) const +{ + Slots::const_iterator it = mSlots.find(slotIndex); + return it == mSlots.end() ? std::string() : it->second.name; } -Item *EquipBackend::getEquipment(int index) const +void EquipBackend::triggerUnequip(int slotIndex) const { - if (index < 0 || (unsigned) index >= mSlots.size()) - return 0; - return mSlots.at(index); + // First get the itemInstance + Slots::const_iterator it = mSlots.find(slotIndex); + + if (it == mSlots.end() || it->second.itemInstance == 0 || !it->second.item) + return; + + Event event(Event::DoUnequip); + event.setItem("item", it->second.item); + event.setInt("itemInstance", it->second.itemInstance); + event.trigger(Event::ItemChannel); } + void EquipBackend::clear() { - for (std::vector<Item*>::iterator i = mSlots.begin(), i_end = mSlots.end(); - i != i_end; ++i) + for (Slots::iterator i = mSlots.begin(), i_end = mSlots.end(); + i != i_end; ++i) { - if (Item *item = *i) - item->setEquipped(false); + if (i->second.item) + { + delete i->second.item; + i->second.item = 0; + } } - mSlots.assign(mSlots.size(), 0); + mSlots.clear(); } -void EquipBackend::equip(int inventorySlot, int equipSlot, int amountUsed) +void EquipBackend::equip(int itemId, int slotTypeId, int amountUsed, + int itemInstance) { - if (equipSlot < 0 || (unsigned) equipSlot >= mSlotTypes.size()) + if (itemInstance <= 0) { - logger->log("ManaServ::EquipBackend: Equipment slot out of range"); + logger->log("ManaServ::EquipBackend: Equipment slot %i" + " has an invalid item instance.", slotTypeId); return; } - const SlotType &slotType = mSlotTypes.at(equipSlot); - Item *item = PlayerInfo::getInventory()->getItem(inventorySlot); + Slots::iterator it = mSlots.begin(); + Slots::iterator it_end = mSlots.end(); + bool slotTypeFound = false; + for (; it != it_end; ++it) + if (it->second.slotTypeId == (unsigned)slotTypeId) + slotTypeFound = true; - if (!item) + if (!slotTypeFound) { - logger->log("ManaServ::EquipBackend: No item at index %d", - inventorySlot); + logger->log("ManaServ::EquipBackend: Equipment slot %i" + " is not existing.", slotTypeId); return; } - // Start at first index and search upwards for free slots to place the - // item at the given inventory slot in - int i = slotType.firstIndex; - const int end_i = i + slotType.count; + if (!itemDb->exists(itemId)) + { + logger->log("ManaServ::EquipBackend: No item with id %d", + itemId); + return; + } - for (; i < end_i && amountUsed > 0; ++i) + // Place the item in the slots with corresponding id until + // the capacity requested has been reached + for (it = mSlots.begin(); it != it_end && amountUsed > 0; ++it) { - if (!mSlots.at(i)) + // If we're on the right slot type and that its unit + // isn't already equipped, we can equip there. + // The slots are already sorted by id, and subId anyway. + if (it->second.slotTypeId == (unsigned)slotTypeId + && (!it->second.itemInstance) && (!it->second.item)) { - mSlots[i] = item; + it->second.itemInstance = itemInstance; + it->second.item = new Item(itemId, 1, true); --amountUsed; - - item->setEquipped(true); - inventoryWindow->updateButtons(); } } } -void EquipBackend::unequip(int inventorySlot) +void EquipBackend::unequip(int itemInstance) { - Item *item = PlayerInfo::getInventory()->getItem(inventorySlot); - - if (!item) + Slots::iterator it = mSlots.begin(); + Slots::iterator it_end = mSlots.end(); + bool itemInstanceFound = false; + for (; it != it_end; ++it) + if (it->second.itemInstance == (unsigned)itemInstance) + itemInstanceFound = true; + + if (!itemInstanceFound) { - logger->log("ManaServ::EquipBackend: No item at index %d", - inventorySlot); + logger->log("ManaServ::EquipBackend: Equipment item instance %i" + " is not existing. The item couldn't be unequipped!", + itemInstance); return; } - for (unsigned i = 0; i < mSlots.size(); ++i) - if (mSlots.at(i) == item) - mSlots[i] = 0; + for (it = mSlots.begin(); it != it_end; ++it) + { + if (it->second.itemInstance != (unsigned)itemInstance) + continue; - item->setEquipped(false); - inventoryWindow->updateButtons(); + // We remove the item + it->second.itemInstance = 0; + // We also delete the item objects + if (it->second.item) + { + delete it->second.item; + it->second.item = 0; + } + } } void EquipBackend::event(Event::Channel, const Event &event) @@ -130,38 +195,84 @@ void EquipBackend::event(Event::Channel, const Event &event) void EquipBackend::readEquipFile() { - mSlots.clear(); - mSlotTypes.clear(); + clear(); - XML::Document doc("equip.xml"); + XML::Document doc(EQUIP_FILE); xmlNodePtr rootNode = doc.rootNode(); if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "equip-slots")) { - logger->log("ManaServ::EquipBackend: Error while reading equip.xml!"); + logger->log("ManaServ::EquipBackend: Error while reading " + EQUIP_FILE "!"); return; } - int slotCount = 0; + // The current client slot index + unsigned int slotIndex = 0; + mVisibleSlots = 0; for_each_xml_child_node(childNode, rootNode) { if (!xmlStrEqual(childNode->name, BAD_CAST "slot")) continue; - SlotType slotType; - slotType.name = XML::getProperty(childNode, "name", std::string()); - slotType.count = XML::getProperty(childNode, "count", 1); - slotType.visible = XML::getBoolProperty(childNode, "visible", false); - slotType.firstIndex = slotCount; + Slot slot; + slot.slotTypeId = XML::getProperty(childNode, "id", 0); + std::string name = XML::getProperty(childNode, "name", std::string()); + const int capacity = XML::getProperty(childNode, "capacity", 1); + slot.weaponSlot = XML::getBoolProperty(childNode, "weapon", false); + slot.ammoSlot = XML::getBoolProperty(childNode, "ammo", false); + + if (XML::getBoolProperty(childNode, "visible", false)) + ++mVisibleSlots; + + if (slot.slotTypeId > 0 && capacity > 0) + { + if (name.empty()) + slot.name = toString(slot.slotTypeId); + else + slot.name = name; + + // The map is filled until the capacity is reached + for (int i = 1; i < capacity + 1; ++i) + { + // Add the capacity part in the name + // when there is more than one slot unit. i.e: 1/3, 2/3 + if (capacity > 1) + { + slot.name = name + " " + toString(i) + + "/" + toString(capacity); + } - mSlotTypes.push_back(slotType); - slotCount += slotType.count; + slot.subId = i; + mSlots.insert(std::make_pair(slotIndex, slot)); + ++slotIndex; + } + } } +} - mSlots.resize(slotCount); +bool EquipBackend::isWeaponSlot(int slotTypeId) const +{ + for (Slots::const_iterator it = mSlots.begin(), it_end = mSlots.end(); + it != it_end; ++it) + { + if (it->second.slotTypeId == (unsigned)slotTypeId) + return it->second.weaponSlot; + } + return false; } +bool EquipBackend::isAmmoSlot(int slotTypeId) const +{ + for (Slots::const_iterator it = mSlots.begin(), it_end = mSlots.end(); + it != it_end; ++it) + { + if (it->second.slotTypeId == (unsigned)slotTypeId) + return it->second.ammoSlot; + } + return false; +} InventoryHandler::InventoryHandler() { @@ -193,13 +304,42 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg) int amount = msg.readInt16(); PlayerInfo::setInventoryItem(slot, id, amount); } + + // A map of { item instance, {slot type id, item id, amount used}} + std::map<int, EquipItemInfo> equipItemsInfo; + std::map<int, EquipItemInfo>::iterator it; while (msg.getUnreadLength()) { - int equipSlot = msg.readInt8(); - int inventorySlot = msg.readInt16(); + int slotTypeId = msg.readInt16(); + int itemId = msg.readInt16(); + int itemInstance = msg.readInt16(); - mEquipBackend.equip(inventorySlot, equipSlot); + // Turn the data received into a usable format + it = equipItemsInfo.find(itemInstance); + if (it == equipItemsInfo.end()) + { + // Add a new entry + equipItemsInfo.insert(std::make_pair(itemInstance, + EquipItemInfo(itemId, slotTypeId, 1))); + } + else + { + // Add amount to the existing entry + it->second.mAmountUsed++; + } } + + for (it = equipItemsInfo.begin(); it != equipItemsInfo.end(); + ++it) + { + mEquipBackend.equip(it->second.mItemId, + it->second.mSlotTypeId, + it->second.mAmountUsed, + it->first); + } + // The backend is ready, we can setup the equipment window. + if (equipmentWindow) + equipmentWindow->loadEquipBoxes(); } break; @@ -214,28 +354,35 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg) break; case GPMSG_EQUIP: - while (msg.getUnreadLength()) { - int inventorySlot = msg.readInt16(); - int equipSlotCount = msg.readInt8(); + int itemId = msg.readInt16(); + int equipSlotCount = msg.readInt16(); - if (equipSlotCount == 0) - { - // No slots means to unequip this item - mEquipBackend.unequip(inventorySlot); - } - else + if (equipSlotCount <= 0) + break; + + // Otherwise equip the item in the given slots + while (equipSlotCount--) { - // Otherwise equip the item in the given slots - while (equipSlotCount--) - { - unsigned int equipSlot = msg.readInt8(); - unsigned int amountUsed = msg.readInt8(); + unsigned int parameter = msg.readInt16(); + unsigned int amountUsed = msg.readInt16(); - mEquipBackend.equip(inventorySlot, equipSlot, - amountUsed); + if (amountUsed == 0) + { + // No amount means to unequip this item + // Note that in that case, the parameter is + // in fact the itemInstanceId + mEquipBackend.unequip(parameter); + } + else + { + int itemInstance = msg.readInt16(); + // The parameter is in that case the slot type id. + mEquipBackend.equip(itemId, parameter, + amountUsed, itemInstance); } } + } break; } @@ -247,8 +394,9 @@ void InventoryHandler::event(Event::Channel channel, if (channel == Event::ItemChannel) { Item *item = event.getItem("item"); + int itemInstance = event.getInt("itemInstance", 0); - if (!item) + if (!item && itemInstance == 0) return; int index = item->getInvIndex(); @@ -256,19 +404,19 @@ void InventoryHandler::event(Event::Channel channel, if (event.getType() == Event::DoEquip) { MessageOut msg(PGMSG_EQUIP); - msg.writeInt8(index); + msg.writeInt16(index); gameServerConnection->send(msg); } else if (event.getType() == Event::DoUnequip) { MessageOut msg(PGMSG_UNEQUIP); - msg.writeInt8(index); + msg.writeInt16(itemInstance); gameServerConnection->send(msg); } else if (event.getType() == Event::DoUse) { MessageOut msg(PGMSG_USE_ITEM); - msg.writeInt8(index); + msg.writeInt16(index); gameServerConnection->send(msg); } else if (event.getType() == Event::DoDrop) @@ -276,8 +424,8 @@ void InventoryHandler::event(Event::Channel channel, int amount = event.getInt("amount", 1); MessageOut msg(PGMSG_DROP); - msg.writeInt8(index); - msg.writeInt8(amount); + msg.writeInt16(index); + msg.writeInt16(amount); gameServerConnection->send(msg); } else if (event.getType() == Event::DoSplit) @@ -288,9 +436,9 @@ void InventoryHandler::event(Event::Channel channel, if (newIndex > Inventory::NO_SLOT_INDEX) { MessageOut msg(PGMSG_MOVE_ITEM); - msg.writeInt8(index); - msg.writeInt8(newIndex); - msg.writeInt8(amount); + msg.writeInt16(index); + msg.writeInt16(newIndex); + msg.writeInt16(amount); gameServerConnection->send(msg); } } @@ -304,9 +452,9 @@ void InventoryHandler::event(Event::Channel channel, return; MessageOut msg(PGMSG_MOVE_ITEM); - msg.writeInt8(index); - msg.writeInt8(newIndex); - msg.writeInt8(item->getQuantity()); + msg.writeInt16(index); + msg.writeInt16(newIndex); + msg.writeInt16(item->getQuantity()); gameServerConnection->send(msg); } else @@ -315,7 +463,8 @@ void InventoryHandler::event(Event::Channel channel, int destination = event.getInt("destination"); int amount = event.getInt("amount", 1);*/ - // TODO + // TODO Support drag'n'drop to the map ground, or with other + // windows. } } } @@ -323,8 +472,7 @@ void InventoryHandler::event(Event::Channel channel, bool InventoryHandler::canSplit(const Item *item) { - return item && !item->getInfo().getEquippable() - && item->getQuantity() > 1; + return item && item->getQuantity() > 1; } size_t InventoryHandler::getSize(int type) const |