summaryrefslogtreecommitdiff
path: root/src/game-server/inventory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game-server/inventory.cpp')
-rw-r--r--src/game-server/inventory.cpp417
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;
+ }
}