diff options
author | Yohann Ferreira <yohann_dot_ferreira_at_orange_dot_efer> | 2011-07-27 14:46:41 +0200 |
---|---|---|
committer | Yohann Ferreira <yohann_dot_ferreira_at_orange_dot_efer> | 2011-07-27 14:46:41 +0200 |
commit | 8aaa341a8ee51853737eabf52fe369f75be07e93 (patch) | |
tree | 2fe6df6d53955da0f06d175db303df40751faa84 | |
parent | 006a213747eb8063ad543211b9776caba027ea4a (diff) | |
download | manaserv-8aaa341a8ee51853737eabf52fe369f75be07e93.tar.gz manaserv-8aaa341a8ee51853737eabf52fe369f75be07e93.tar.bz2 manaserv-8aaa341a8ee51853737eabf52fe369f75be07e93.tar.xz manaserv-8aaa341a8ee51853737eabf52fe369f75be07e93.zip |
Begun Applying the new equipment slot handling design.
now, the equipment slots are independant from the inventory slots
according to the inventory and equipment data.
This will permit to avoid checking the equipment each time
one touches the inventory and vice versa, and make the former
delayed mode useless.
Also, note that equipped items will be removed from inventory
and readded once unequipped.
The design will permit the following, even if not implemented yet:
- To make equipment items stackable again, if wanted.
- Have more than one item with the same id equipped on different
slots using the itemInstance field.
Note: I didn't add the database structure updates yet, to see
whether other changes may later go along with those.
-rw-r--r-- | src/account-server/storage.cpp | 42 | ||||
-rw-r--r-- | src/common/inventorydata.h | 46 | ||||
-rw-r--r-- | src/game-server/buysell.cpp | 6 | ||||
-rw-r--r-- | src/game-server/inventory.cpp | 50 | ||||
-rw-r--r-- | src/game-server/state.cpp | 8 | ||||
-rw-r--r-- | src/serialize/characterdata.h | 45 | ||||
-rw-r--r-- | src/sql/mysql/createTables.sql | 6 | ||||
-rw-r--r-- | src/sql/sqlite/createTables.sql | 3 |
8 files changed, 117 insertions, 89 deletions
diff --git a/src/account-server/storage.cpp b/src/account-server/storage.cpp index 96601207..05f8ec69 100644 --- a/src/account-server/storage.cpp +++ b/src/account-server/storage.cpp @@ -490,17 +490,26 @@ Character *Storage::getCharacterBySQL(Account *owner) try { std::ostringstream sql; - sql << " select slot_type, inventory_slot from " + sql << " select slot_type, item_id, item_instance from " << CHAR_EQUIPS_TBL_NAME << " where owner_id = '" << character->getDatabaseID() << "' order by slot_type desc;"; + EquipData equipData; const dal::RecordSet &equipInfo = mDb->execSql(sql.str()); if (!equipInfo.isEmpty()) + { + EquipmentItem equipItem; for (int k = 0, size = equipInfo.rows(); k < size; ++k) - poss.equipSlots.insert(std::pair<unsigned int, unsigned int>( - toUint(equipInfo(k, 0)), - toUint(equipInfo(k, 1)))); + { + equipItem.itemId = toUint(equipInfo(k, 1)); + equipItem.itemInstance = toUint(equipInfo(k, 2)); + equipData.insert(std::pair<unsigned int, EquipmentItem>( + toUint(equipInfo(k, 0)), + equipItem)); + } + } + poss.setEquipment(equipData); } catch (const dal::DbSqlQueryExecFailure &e) { @@ -515,6 +524,7 @@ Character *Storage::getCharacterBySQL(Account *owner) << " where owner_id = '" << character->getDatabaseID() << "' order by slot asc;"; + InventoryData inventoryData; const dal::RecordSet &itemInfo = mDb->execSql(sql.str()); if (!itemInfo.isEmpty()) { @@ -524,9 +534,10 @@ Character *Storage::getCharacterBySQL(Account *owner) unsigned short slot = toUint(itemInfo(k, 2)); item.itemId = toUint(itemInfo(k, 3)); item.amount = toUint(itemInfo(k, 4)); - poss.inventory[slot] = item; + inventoryData[slot] = item; } } + poss.setInventory(inventoryData); } catch (const dal::DbSqlQueryExecFailure &e) { @@ -798,18 +809,18 @@ bool Storage::updateCharacter(Character *character) std::ostringstream sql; sql << "insert into " << CHAR_EQUIPS_TBL_NAME - << " (owner_id, slot_type, inventory_slot) values (" + << " (owner_id, slot_type, item_id, item_instance) values (" << character->getDatabaseID() << ", "; std::string base = sql.str(); const Possessions &poss = character->getPossessions(); - for (EquipData::const_iterator it = poss.equipSlots.begin(), - it_end = poss.equipSlots.end(); - it != it_end; - ++it) + const EquipData &equipData = poss.getEquipment(); + for (EquipData::const_iterator it = equipData.begin(), + it_end = equipData.end(); it != it_end; ++it) { sql.str(""); - sql << base << it->first << ", " << it->second << ");"; + sql << base << it->first << ", " << it->second.itemId + << ", " << it->second.itemInstance << ");"; mDb->execSql(sql.str()); } @@ -820,13 +831,14 @@ bool Storage::updateCharacter(Character *character) << character->getDatabaseID() << ", "; base = sql.str(); - for (InventoryData::const_iterator j = poss.inventory.begin(), - j_end = poss.inventory.end(); j != j_end; ++j) + const InventoryData &inventoryData = poss.getInventory(); + for (InventoryData::const_iterator j = inventoryData.begin(), + j_end = inventoryData.end(); j != j_end; ++j) { sql.str(""); unsigned short slot = j->first; - unsigned int itemId = j->second.itemId; - unsigned int amount = j->second.amount; + unsigned int itemId = j->second.itemId; + unsigned int amount = j->second.amount; assert(itemId); sql << base << slot << ", " << itemId << ", " << amount << ");"; mDb->execSql(sql.str()); diff --git a/src/common/inventorydata.h b/src/common/inventorydata.h index 9127c816..e7c81170 100644 --- a/src/common/inventorydata.h +++ b/src/common/inventorydata.h @@ -35,20 +35,56 @@ */ struct InventoryItem { + InventoryItem(): + itemId(0), amount(0) + {} + unsigned int itemId; unsigned int amount; }; -// slot id -> { item } -typedef std::map< unsigned short, InventoryItem > InventoryData; -// equip slot type -> { slot ids } -// Equipment taking up multiple slots will be referenced multiple times -typedef std::multimap< unsigned int, unsigned int > EquipData; + +struct EquipmentItem +{ + EquipmentItem(): + itemId(0), itemInstance(0) + {} + + // The item id taken from the item db. + unsigned int itemId; + // A unique instance number used to separate items when equipping the same + // item id multiple times on possible multiple slots. + unsigned int itemInstance; +}; + +// inventory slot id -> { item } +typedef std::map< unsigned int, InventoryItem > InventoryData; + +// equip slot id -> { item id } +// Equipment taking up multiple equip slot ids will be referenced multiple times +typedef std::multimap< unsigned int, EquipmentItem > EquipData; /** * Structure storing the equipment and inventory of a Player. */ struct Possessions { + friend class Inventory; +public: + const EquipData &getEquipment() const + { return equipSlots; } + + const InventoryData &getInventory() const + { return inventory; } + + /** + * Should be done only at character serialization and storage load time. + */ + void setEquipment(EquipData &equipData) + { equipSlots.swap(equipData); } + void setInventory(InventoryData &inventoryData) + { inventory.swap(inventoryData); } + +private: InventoryData inventory; EquipData equipSlots; }; diff --git a/src/game-server/buysell.cpp b/src/game-server/buysell.cpp index a9658546..78c2bfe0 100644 --- a/src/game-server/buysell.cpp +++ b/src/game-server/buysell.cpp @@ -72,9 +72,9 @@ int BuySell::registerPlayerItems() // We parse the player inventory and add all item // in a sell list. - const Possessions &charPoss = mChar->getPossessions(); - for (InventoryData::const_iterator it = charPoss.inventory.begin(), - it_end = charPoss.inventory.end(); it != it_end; ++it) + const InventoryData &inventoryData = mChar->getPossessions().getInventory(); + for (InventoryData::const_iterator it = inventoryData.begin(), + it_end = inventoryData.end(); it != it_end; ++it) { unsigned int nb = it->second.amount; if (!nb) diff --git a/src/game-server/inventory.cpp b/src/game-server/inventory.cpp index e218a916..8689f299 100644 --- a/src/game-server/inventory.cpp +++ b/src/game-server/inventory.cpp @@ -54,8 +54,9 @@ void Inventory::sendFull() const k != k_end; ++k) { - m.writeInt8(k->first); // equip slot - m.writeInt16(k->second); // inventory slot + m.writeInt16(k->first); // Equip slot id + m.writeInt16(k->second.itemId); // Item id + m.writeInt16(k->second.itemInstance); // Item instance } gameHandler->sendTo(mCharacter, m); @@ -106,7 +107,7 @@ void Inventory::initialize() */ for (it2 = mPoss->equipSlots.begin(); it2 != it2_end; ++it2) { - if (equipment.insert(it2->second).second) + if (equipment.insert(it2->second.itemInstance).second) { /* * Perform checks for equipped items @@ -117,7 +118,7 @@ void Inventory::initialize() /* * Apply all equip triggers. */ - itemManager->getItem(mPoss->inventory.at(it2->second).itemId) + itemManager->getItem(it2->second.itemId) ->useTrigger(mCharacter, ITT_EQUIP); } } @@ -239,8 +240,7 @@ unsigned int Inventory::count(unsigned int itemId) const unsigned int Inventory::remove(unsigned int itemId, unsigned int amount, bool force) { - bool inv = false, - eq = !itemManager->getItem(itemId)->getItemEquipData().empty(); + bool inv = false; MessageOut invMsg(GPMSG_INVENTORY); bool triggerLeaveInventory = true; @@ -251,26 +251,6 @@ unsigned int Inventory::remove(unsigned int itemId, unsigned int amount, bool fo { if (amount) { - if (eq) - { - // If the item is equippable, - // we have additional checks to make. - bool ch = false; - for (EquipData::iterator it2 = mPoss->equipSlots.begin(), - it2_end = mPoss->equipSlots.end(); - it2 != it2_end; - ++it2) - if (it2->second == it->first) - { - if (force) - unequip(it2); - else - ch = inv = true; - break; - } - if (ch && !force) - continue; - } unsigned int sub = std::min(amount, it->second.amount); amount -= sub; it->second.amount -= sub; @@ -320,15 +300,6 @@ unsigned int Inventory::move(unsigned int slot1, unsigned int slot2, if (it1 == inv_end) return amount; - EquipData::iterator it, it_end = mPoss->equipSlots.end(); - for (it = mPoss->equipSlots.begin(); - it != it_end; - ++it) - if (it->second == slot1) - // Bad things will happen when you can stack multiple equippable - // items in the same slot anyway. - it->second = slot2; - MessageOut invMsg(GPMSG_INVENTORY); unsigned int nb = std::min(amount, it1->second.amount); @@ -538,9 +509,10 @@ bool Inventory::equip(int slot, bool override) * compile time options optimising for other usage. * For now, this is adequate assuming `normal' usage. */ - for (unsigned int i = 0; i < it3->second; ++i) + /** Part disabled until reimplemented*/ + /*for (unsigned int i = 0; i < it3->second; ++i) mPoss->equipSlots.insert( - std::make_pair(it3->first, slot)); + std::make_pair(it3->first, slot));*/ } changeEquipment(0, it->second.itemId); @@ -598,7 +570,7 @@ bool Inventory::equip(int slot, bool override) bool Inventory::unequip(EquipData::iterator it) { - return unequip(it->second, &it); + return unequip(it->first, &it); } bool Inventory::unequip(unsigned int slot, EquipData::iterator *itp) @@ -611,7 +583,7 @@ bool Inventory::unequip(unsigned int slot, EquipData::iterator *itp) // Erase all equip entries that point to the given inventory slot while (it != it_end) { - if (it->second == slot) + if (it->first == slot) { changed = true; mPoss->equipSlots.erase(it++); diff --git a/src/game-server/state.cpp b/src/game-server/state.cpp index 03d4b71c..1a9c0204 100644 --- a/src/game-server/state.cpp +++ b/src/game-server/state.cpp @@ -108,7 +108,7 @@ static void updateMap(MapComposite *map) */ static void serializeLooks(Character *ch, MessageOut &msg, bool full) { - const Possessions &poss = ch->getPossessions(); + const EquipData &equipData = ch->getPossessions().getEquipment(); unsigned int nb_slots = itemManager->getVisibleSlotCount(); // Bitmask describing the changed entries. @@ -125,8 +125,8 @@ static void serializeLooks(Character *ch, MessageOut &msg, bool full) // Partially build both kinds of packet, to get their sizes. unsigned int mask_full = 0, mask_diff = 0; unsigned int nb_full = 0, nb_diff = 0; - std::map<unsigned int, unsigned int>::const_iterator it = - poss.equipSlots.begin(); + std::map<unsigned int, EquipmentItem>::const_iterator it = + equipData.begin(); for (unsigned int i = 0; i < nb_slots; ++i) { if (changed & (1 << i)) @@ -135,7 +135,7 @@ static void serializeLooks(Character *ch, MessageOut &msg, bool full) ++nb_diff; mask_diff |= 1 << i; } - if (it == poss.equipSlots.end() || it->first > i) continue; + if (it == equipData.end() || it->first > i) continue; ItemClass *eq; items[i] = it->first && (eq = itemManager->getItem(it->first)) ? eq->getSpriteID() : 0; diff --git a/src/serialize/characterdata.h b/src/serialize/characterdata.h index 4466c98e..c453e685 100644 --- a/src/serialize/characterdata.h +++ b/src/serialize/characterdata.h @@ -97,20 +97,22 @@ void serializeCharacterData(const T &data, MessageOut &msg) // inventory - must be last because size isn't transmitted const Possessions &poss = data.getPossessions(); - msg.writeInt16(poss.equipSlots.size()); // number of equipment - for (EquipData::const_iterator k = poss.equipSlots.begin(), - k_end = poss.equipSlots.end(); - k != k_end; - ++k) + const EquipData &equipData = poss.getEquipment(); + msg.writeInt16(equipData.size()); // number of equipment + for (EquipData::const_iterator k = equipData.begin(), + k_end = equipData.end(); k != k_end; ++k) { - msg.writeInt8(k->first); // Equip slot type - msg.writeInt16(k->second); // Inventory slot + msg.writeInt16(k->first); // Equip slot id + msg.writeInt16(k->second.itemId); // ItemId + msg.writeInt16(k->second.itemInstance); // Item Instance id } - for (InventoryData::const_iterator j = poss.inventory.begin(), - j_end = poss.inventory.end(); j != j_end; ++j) + + const InventoryData &inventoryData = poss.getInventory(); + for (InventoryData::const_iterator j = inventoryData.begin(), + j_end = inventoryData.end(); j != j_end; ++j) { msg.writeInt16(j->first); // slot id - msg.writeInt16(j->second.itemId); // item type + msg.writeInt16(j->second.itemId); // item id msg.writeInt16(j->second.amount); // amount } } @@ -185,26 +187,31 @@ void deserializeCharacterData(T &data, MessageIn &msg) Possessions &poss = data.getPossessions(); - poss.equipSlots.clear(); + EquipData equipData; int equipSlotsSize = msg.readInt16(); - unsigned int eqSlot, invSlot; + unsigned int eqSlot; + EquipmentItem equipItem; for (int j = 0; j < equipSlotsSize; ++j) { - eqSlot = msg.readInt8(); - invSlot = msg.readInt16(); - poss.equipSlots.insert(poss.equipSlots.end(), - std::make_pair(eqSlot, invSlot)); + eqSlot = msg.readInt16(); + equipItem.itemId = msg.readInt16(); + equipItem.itemInstance = msg.readInt16(); + equipData.insert(equipData.end(), + std::make_pair(eqSlot, equipItem)); } - poss.inventory.clear(); - // inventory - must be last because size isn't transmitted + poss.setEquipment(equipData); + + // Loads inventory - must be last because size isn't transmitted + InventoryData inventoryData; while (msg.getUnreadLength()) { InventoryItem i; int slotId = msg.readInt16(); i.itemId = msg.readInt16(); i.amount = msg.readInt16(); - poss.inventory.insert(poss.inventory.end(), std::make_pair(slotId, i)); + inventoryData.insert(inventoryData.end(), std::make_pair(slotId, i)); } + poss.setInventory(inventoryData); } #endif // SERIALIZE_CHARACTERDATA_H diff --git a/src/sql/mysql/createTables.sql b/src/sql/mysql/createTables.sql index 9e1e31a6..d017ceee 100644 --- a/src/sql/mysql/createTables.sql +++ b/src/sql/mysql/createTables.sql @@ -184,11 +184,11 @@ AUTO_INCREMENT=1 ; CREATE TABLE IF NOT EXISTS `mana_char_equips` ( `id` int(10) unsigned NOT NULL auto_increment, `owner_id` int(10) unsigned NOT NULL, - `slot_type` tinyint(3) unsigned NOT NULL, - `inventory_slot` tinyint(3) unsigned NOT NULL, + `slot_type` int(10) unsigned NOT NULL, + `item_id` int(10) unsigned NOT NULL, + `item_instance` int(10) unsigned NOT NULL, -- PRIMARY KEY (`id`), - UNIQUE KEY `owner_id` (`owner_id`, `inventory_slot`), FOREIGN KEY (`owner_id`) REFERENCES `mana_characters` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/src/sql/sqlite/createTables.sql b/src/sql/sqlite/createTables.sql index b366606b..1027b580 100644 --- a/src/sql/sqlite/createTables.sql +++ b/src/sql/sqlite/createTables.sql @@ -178,7 +178,8 @@ CREATE TABLE mana_char_equips id INTEGER PRIMARY KEY, owner_id INTEGER NOT NULL, slot_type INTEGER NOT NULL, - inventory_slot INTEGER NOT NULL, + item_id INTEGER NOT NULL, + item_instance INTEGER NOT NULL, -- FOREIGN KEY (owner_id) REFERENCES mana_characters(id) ); |