diff options
Diffstat (limited to 'src/game-server/inventory.cpp')
-rw-r--r-- | src/game-server/inventory.cpp | 417 |
1 files changed, 163 insertions, 254 deletions
diff --git a/src/game-server/inventory.cpp b/src/game-server/inventory.cpp index c5913e15..4807d4ff 100644 --- a/src/game-server/inventory.cpp +++ b/src/game-server/inventory.cpp @@ -21,255 +21,217 @@ * $Id$ */ +#include <algorithm> #include <cassert> #include "game-server/inventory.hpp" #include "game-server/itemmanager.hpp" -// --------- -// Items -// --------- -int Inventory::getInventoryFreeSlot() +int Inventory::getItem(int slot) { - for (int a = 0; a < MAX_ITEMS_IN_INVENTORY; a++) + for (std::vector< InventoryItem >::iterator i = poss.inventory.begin(), + i_end = poss.inventory.end(); i != i_end; ++i) { - if (itemList[a].amount == 0) - return a; - } - return INVENTORY_FULL; -} + if (slot == 0) + { + return i->itemId; + } -int Inventory::getSlotFromId(int itemId) -{ - for (int a = 0; a < MAX_ITEMS_IN_INVENTORY; a++) - { - if (itemList[a].itemId == itemId) - return a; + slot -= i->itemId ? 1 : i->amount; + + if (slot < 0) + { + return 0; + } } - return INVENTORY_FULL; + return 0; } -bool Inventory::hasItem(int itemId, - bool searchInInventory, - bool searchInEquipment) +int Inventory::getIndex(int slot) { - bool hasItem = false; - // Search in inventory - if (searchInInventory) + int index = 0; + for (std::vector< InventoryItem >::iterator i = poss.inventory.begin(), + i_end = poss.inventory.end(); i != i_end; ++i, ++index) { - std::vector<StoredItem>::iterator iter = itemList.begin(); - for (iter = itemList.begin(); iter != itemList.end(); ++iter) + if (slot == 0) { - if (iter->itemId == itemId) - hasItem = true; + return index; } - } - // Search in equipment - if (searchInEquipment) - { - std::vector<EquippedItem>::iterator equipIter = equippedItemList.begin(); - for (equipIter = equippedItemList.begin(); - equipIter != equippedItemList.end(); - ++equipIter) + + slot -= i->itemId ? 1 : i->amount; + + if (slot < 0) { - if (equipIter->itemId == itemId) - hasItem = true; + return -1; } - if (equippedProjectiles.itemId == itemId) - hasItem = true; } - return hasItem; + return -1; } -int Inventory::insertItem(int itemId, int amount) +int Inventory::fillFreeSlot(int itemId, int amount, int maxPerSlot) { - if (amount <= 0) + int slot = 0; + for (int i = 0, i_end = poss.inventory.size(); i < i_end; ++i) { - return 0; - } - - // We get the max number of item we can have in the same slot - // for the given item. - int maxPerSlot = itemManager->getItem(itemId)->getMaxPerSlot(); - // We'll add items in slots with the item type and in free slots - // until it's all done or until the inventory will be all parsed. - // Searching for items with the same Id in the inventory, before - // seeking a free slot. - int amountToAdd = amount; - - // Parsing inventory - for (std::vector< StoredItem >::iterator iter = itemList.begin(), - iter_end = itemList.end(); iter != iter_end; ++iter) - { - int currentAmountInSlot = iter->amount; - // If a slot has got place for some more of such an item. - if (iter->itemId == itemId && currentAmountInSlot < maxPerSlot) + InventoryItem &it = poss.inventory[i]; + if (it.itemId == 0) { - // If there isn't enough space to put every item in the slot. - // We add the difference. - int possibleAmount = maxPerSlot - currentAmountInSlot; - assert(possibleAmount > 0); - if (possibleAmount < amountToAdd) - { - iter->amount += possibleAmount; - amountToAdd -= possibleAmount; - } - else // there is enough to add everything. + int nb = std::min(amount, maxPerSlot); + if (it.amount <= 1) { - iter->amount += amountToAdd; - amountToAdd = 0; // Ok! - break; + it.itemId = itemId; + it.amount = nb; } - } - // Or if there is an empty slot. - else if (iter->amount == 0) - { - // We add the item in the new slot (setting also the Id.) - iter->itemId = itemId; - if (maxPerSlot < amountToAdd) + else { - iter->amount = maxPerSlot; - amountToAdd -= maxPerSlot; + --it.amount; + InventoryItem iu = { itemId, nb }; + poss.inventory.insert(poss.inventory.begin() + i, iu); + ++i_end; } - else + + // TODO: fill msg + amount -= nb; + if (amount == 0) { - iter->amount += amountToAdd; - amountToAdd = 0; // Ok! - break; + return 0; } } + ++slot; } - return amount - amountToAdd; -} - -int Inventory::removeItemById(int itemId, int amount) -{ - if (amount <= 0) + while (slot < INVENTORY_SLOTS - 1 && amount > 0) { - return 0; + int nb = std::min(amount, maxPerSlot); + amount -= nb; + InventoryItem it = { itemId, nb }; + poss.inventory.push_back(it); + ++slot; + // TODO: fill msg } - // We'll remove items in slots with the item type - // until it's all done or until the inventory will be all parsed. - // Searching for items with the same Id in the inventory - int amountToRemove = amount; + return amount; +} - // Parsing inventory - for (std::vector< StoredItem >::iterator iter = itemList.begin(), - iter_end = itemList.end(); iter != iter_end; ++iter) +int Inventory::insert(int itemId, int amount) +{ + int maxPerSlot = itemManager->getItem(itemId)->getMaxPerSlot(); + + for (std::vector< InventoryItem >::iterator i = poss.inventory.begin(), + i_end = poss.inventory.end(); i != i_end; ++i) { - int currentAmountInSlot = iter->amount; - // If a slot has got such an item, remove it - if (iter->itemId == itemId && currentAmountInSlot > 0) + if (i->itemId == itemId) { - // If there isn't enough to finish, we remove the difference - // Emptying the slot, so we clean also the itemId. - if (currentAmountInSlot <= amountToRemove) + int nb = std::min(maxPerSlot - i->amount, amount); + i->amount += nb; + amount -= nb; + // TODO: fill msg + if (amount == 0) { - amountToRemove -= currentAmountInSlot; - iter->amount = 0; - iter->itemId = 0; - } - else // there is enough to remove everything. - { - iter->amount -= amountToRemove; - amountToRemove = 0; // Ok! - break; + return 0; } } } - return amount - amountToRemove; + + return amount > 0 ? fillFreeSlot(itemId, amount, maxPerSlot) : 0; } -int Inventory::removeItemBySlot(int slot, int amount) +void Inventory::freeIndex(int i) { - if (amount <= 0) + InventoryItem &it = poss.inventory[i]; + + if (i == (int)poss.inventory.size() - 1) { - return 0; + poss.inventory.pop_back(); } - - if (itemList[slot].amount < amount) + else if (poss.inventory[i + 1].itemId == 0) { - int value = itemList[slot].amount; - itemList[slot].amount = 0; - return value; + it.itemId = 0; + it.amount = poss.inventory[i + 1].amount + 1; + poss.inventory.erase(poss.inventory.begin() + i + 1); } else { - itemList[slot].amount -= amount; - return amount; + it.itemId = 0; + it.amount = 1; + } + + if (i > 0 && poss.inventory[i - 1].itemId == 0) + { + // Note: "it" is no longer a valid iterator. + poss.inventory[i - 1].amount += poss.inventory[i].amount; + poss.inventory.erase(poss.inventory.begin() + i); + } +} + +int Inventory::remove(int itemId, int amount) +{ + for (int i = poss.inventory.size() - 1; i >= 0; --i) + { + InventoryItem &it = poss.inventory[i]; + if (it.itemId == itemId) + { + int nb = std::min((int)it.amount, amount); + it.amount -= nb; + amount -= nb; + // TODO: fill msg + + // If the slot is empty, compress the inventory. + if (it.amount == 0) + { + freeIndex(i); + } + + if (amount == 0) + { + return 0; + } + } } + + return amount; } -// --------- -// Equipment -// --------- -int Inventory::equipItem(int itemId) +bool Inventory::equip(int slot) { - // First, we look for the item in the player's inventory. - if (!hasItem(itemId, true, false)) + int itemId = getItem(slot); + if (!itemId) + { return false; + } int availableSlots = 0, firstSlot = 0, secondSlot = 0; - int itemType = itemManager->getItem(itemId)->getType(); - switch (itemType) + switch (itemManager->getItem(itemId)->getType()) { case ITEM_EQUIPMENT_TWO_HANDS_WEAPON: - // Special case 1, the two one-handed weapons are to be placed back - // in the inventory, if there are any. - if (equippedItemList[EQUIP_FIGHT1_SLOT].itemId > 0) - { // Slot 1 full - // old two-handed weapon case: - if (equippedItemList[EQUIP_FIGHT1_SLOT].itemType - == ITEM_EQUIPMENT_TWO_HANDS_WEAPON) + // Special case 1, the two one-handed weapons are to be placed back + // in the inventory, if there are any. + if (int id = poss.equipment[EQUIP_FIGHT1_SLOT]) + { + // Slot 1 full + if (!insert(id, 1)) { - equippedItemList[EQUIP_FIGHT2_SLOT].itemId = 0; - equippedItemList[EQUIP_FIGHT2_SLOT].itemType = 0; + return false; } - - if (unequipItem_(equippedItemList[EQUIP_FIGHT1_SLOT].itemId, - EQUIP_FIGHT1_SLOT) == INVENTORY_FULL) - return INVENTORY_FULL; - } - if (equippedItemList[EQUIP_FIGHT2_SLOT].itemId > 0) - { // Slot 2 full - if (unequipItem_(equippedItemList[EQUIP_FIGHT2_SLOT].itemId, - EQUIP_FIGHT2_SLOT) == INVENTORY_FULL) - return INVENTORY_FULL; - } - // Only the slot 1 needs to be updated. - return equipItem_(itemId, itemType, EQUIP_FIGHT1_SLOT); - break; - - case ITEM_EQUIPMENT_PROJECTILE: - // Special case 2: the projectile is a Stored Item structure, - // but is still considered as part of the equipment. - // Case 1: Reloading - if (equippedProjectiles.itemId == itemId) - { - equippedProjectiles.amount += - removeItemById(itemId, 255 - equippedProjectiles.amount); - return EQUIP_PROJECTILES_SLOT; } - else // Case 2: Changing projectiles. + if (int id = poss.equipment[EQUIP_FIGHT2_SLOT]) { - int added = insertItem(equippedProjectiles.itemId, - equippedProjectiles.amount); - if (added == equippedProjectiles.amount) - { // Ok, we can equip - equippedProjectiles.itemId = itemId; - equippedProjectiles.amount = removeItemById(itemId, 255); - return EQUIP_PROJECTILES_SLOT; - } - else // Some were unequipped. + // Slot 2 full + if (!insert(id, 1)) { - equippedProjectiles.amount -= added; - return INVENTORY_FULL; + return false; } } - break; + + poss.equipment[EQUIP_FIGHT1_SLOT] = itemId; + poss.equipment[EQUIP_FIGHT2_SLOT] = 0; + freeIndex(getIndex(slot)); + return true; + + case ITEM_EQUIPMENT_PROJECTILE: + poss.equipment[EQUIP_PROJECTILE_SLOT] = itemId; + return true; case ITEM_EQUIPMENT_ONE_HAND_WEAPON: case ITEM_EQUIPMENT_SHIELD: @@ -310,88 +272,35 @@ int Inventory::equipItem(int itemId) case ITEM_UNUSABLE: case ITEM_USABLE: default: - return NOT_EQUIPPABLE; + return false; } + int id = poss.equipment[firstSlot]; + switch (availableSlots) { - case 1: - if (equippedItemList[firstSlot].itemId > 0) - { - if (unequipItem_(equippedItemList[firstSlot].itemId, - firstSlot) != INVENTORY_FULL) - return equipItem_(itemId, itemType, firstSlot); - else - return INVENTORY_FULL; - } - else // slot empty, we can equip. - { - return equipItem_(itemId, itemType, firstSlot); - } - break; - case 2: - if (equippedItemList[firstSlot].itemId > 0) - { - // If old weapon is two-handed one, we can unequip - // the first slot only, and clean the second. - if (equippedItemList[firstSlot].itemId == + if (id && !poss.equipment[secondSlot] && + itemManager->getItem(id)->getType() != ITEM_EQUIPMENT_TWO_HANDS_WEAPON) - { - if (unequipItem_(equippedItemList[firstSlot].itemId, - firstSlot) != INVENTORY_FULL) - return equipItem_(itemId, itemType, firstSlot); - else - return INVENTORY_FULL; - } - - if (equippedItemList[secondSlot].itemId > 0) - { // Both slots are full, - // we remove the first one to equip - if (unequipItem_(equippedItemList[firstSlot].itemId, - firstSlot) != INVENTORY_FULL) - return equipItem_(itemId, itemType, firstSlot); - else - return INVENTORY_FULL; - } - else // Second slot empty, we can equip. - { - return equipItem_(itemId, itemType, secondSlot); - } + { + // The first slot is full and the second slot is empty. + poss.equipment[secondSlot] = itemId; + freeIndex(getIndex(slot)); + return true; } - else // first slot empty, we can equip. + // no break! + + case 1: + if (id && !insert(id, 1)) { - return equipItem_(itemId, itemType, firstSlot); + return false; } - break; + poss.equipment[firstSlot] = itemId; + freeIndex(getIndex(slot)); + return true; default: - return NOT_EQUIPPABLE; - } -} - -int Inventory::equipItem_(int itemId, - int itemType, - int equipmentSlot) -{ - if (removeItemById(itemId, 1) == 1) - { - equippedItemList[equipmentSlot].itemId = itemId; - equippedItemList[equipmentSlot].itemType = itemType; - return equipmentSlot; - } - else - return NO_ITEM_TO_EQUIP; -} - -int Inventory::unequipItem_(int itemId, int equipmentSlot) -{ - if (insertItem(itemId, 1) == 1) - { - equippedItemList[equipmentSlot].itemId = 0; - equippedItemList[equipmentSlot].itemType = 0; - return equipmentSlot; - } - else - return INVENTORY_FULL; + return false; + } } |