/* * The Mana World Server * Copyright 2004 The Mana World Development Team * * This file is part of The Mana World. * * The Mana World 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. * * The Mana World 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 The Mana World; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id$ */ #include "inventory.h" #include "game-server/itemmanager.hpp" // --------- // Items // --------- unsigned char Inventory::getInventoryFreeSlot() { for (int a = 0; a < MAX_ITEMS_IN_INVENTORY; a++) { if (itemList.at(a).amount == 0) return a; } return INVENTORY_FULL; } unsigned char Inventory::getSlotFromId(const unsigned int itemId) { for (int a = 0; a < MAX_ITEMS_IN_INVENTORY; a++) { if (itemList.at(a).itemId == itemId) return a; } return INVENTORY_FULL; } bool Inventory::hasItem(unsigned int itemId, bool searchInInventory, bool searchInEquipment) { bool hasItem = false; // Search in inventory if (searchInInventory) { std::vector::iterator iter = itemList.begin(); for (iter = itemList.begin(); iter != itemList.end(); ++iter) { if (iter->itemId == itemId) hasItem = true; } } // Search in equipment if (searchInEquipment) { std::vector::iterator equipIter = equippedItemList.begin(); for (equipIter = equippedItemList.begin(); equipIter != equippedItemList.end(); ++equipIter) { if (equipIter->itemId == itemId) hasItem = true; } if (equippedProjectiles.itemId == itemId) hasItem = true; } return hasItem; } short Inventory::addItem(unsigned int itemId, unsigned char amount) { // We get the max number of item we can have in the same slot // for the given item. unsigned char maxPerSlot = itemManager->getMaxPerSlot(itemId); // 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. unsigned char amountToAdd = amount; // Parsing inventory unsigned char currentAmountInSlot = 0; std::vector::iterator iter = itemList.begin(); for (iter = itemList.begin(); iter != itemList.end(); ++iter) { currentAmountInSlot = iter->amount; // If a slot has got place for some more of such an item. if (iter->itemId == itemId && currentAmountInSlot < maxPerSlot) { // If there isn't enough space to put every item in the slot. // We add the difference. if ((maxPerSlot - currentAmountInSlot) < amountToAdd) { iter->amount += (maxPerSlot - currentAmountInSlot); amountToAdd -= (maxPerSlot - currentAmountInSlot); } else // there is enough to add everything. { iter->amount += amountToAdd; amountToAdd = 0; // Ok! } } // Or if there is an empty slot. else if (iter->amount == 0) { // We add the item in the new slot (setting also the Id.) if (maxPerSlot < amountToAdd) { iter->amount = maxPerSlot; amountToAdd -= maxPerSlot; } else { iter->amount += amountToAdd; amountToAdd = 0; // Ok! } iter->itemId = itemId; } } return (short)(amount - amountToAdd); } short Inventory::removeItem(unsigned int itemId, unsigned char amount) { // 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 unsigned char amountToRemove = amount; // Parsing inventory unsigned char currentAmountInSlot = 0; std::vector::iterator iter = itemList.begin(); for (iter = itemList.begin(); iter != itemList.end(); ++iter) { currentAmountInSlot = iter->amount; // If a slot has got such an item, remove it if (iter->itemId == itemId && currentAmountInSlot > 0) { // If there isn't enough to finish, we remove the difference // Emptying the slot, so we clean also the itemId. if (currentAmountInSlot <= amountToRemove) { amountToRemove -= currentAmountInSlot; iter->amount = 0; iter->itemId = 0; } else // there is enough to remove everything. { iter->amount -= amountToRemove; amountToRemove = 0; // Ok! } } } return (short)(amount - amountToRemove); } short Inventory::removeItem(unsigned char slot, unsigned char amount) { if (itemList.at(slot).amount < amount) { unsigned char value = itemList.at(slot).amount; itemList.at(slot).amount = 0; return (short)value; } else { itemList.at(slot).amount -= amount; return amount; } } bool Inventory::use(unsigned char slot, BeingPtr itemUser) { return false; // TODO } bool Inventory::use(unsigned int itemId, BeingPtr itemUser) { return false; // TODO } // --------- // Equipment // --------- unsigned char Inventory::equipItem(unsigned int itemId) { // First, we look for the item in the player's inventory. if (!hasItem(itemId, true, false)) return false; unsigned char availableSlots = 0, firstSlot = 0, secondSlot = 0; unsigned short itemType = itemManager->getItemType(itemId); switch (itemType) { 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.at(EQUIP_FIGHT1_SLOT).itemId > 0) { // Slot 1 full // old two-handed weapon case: if (equippedItemList.at(EQUIP_FIGHT1_SLOT).itemType == ITEM_EQUIPMENT_TWO_HANDS_WEAPON) { equippedItemList.at(EQUIP_FIGHT2_SLOT).itemId = 0; equippedItemList.at(EQUIP_FIGHT2_SLOT).itemType = 0; } if (unequipItem_(equippedItemList.at(EQUIP_FIGHT1_SLOT).itemId, EQUIP_FIGHT1_SLOT) == INVENTORY_FULL) return INVENTORY_FULL; } if (equippedItemList.at(EQUIP_FIGHT2_SLOT).itemId > 0) { // Slot 2 full if (unequipItem_(equippedItemList.at(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 += removeItem(itemId, (255 - equippedProjectiles.amount)); return EQUIP_PROJECTILES_SLOT; } else // Case 2: Changing projectiles. { short added; added = addItem(equippedProjectiles.itemId, equippedProjectiles.amount); if (added == equippedProjectiles.amount) { // Ok, we can equip equippedProjectiles.itemId = itemId; equippedProjectiles.amount = removeItem(itemId, 255); return EQUIP_PROJECTILES_SLOT; } else // Some were unequipped. { equippedProjectiles.amount -= added; return INVENTORY_FULL; } } break; case ITEM_EQUIPMENT_ONE_HAND_WEAPON: case ITEM_EQUIPMENT_SHIELD: availableSlots = 2; firstSlot = EQUIP_FIGHT1_SLOT; secondSlot = EQUIP_FIGHT2_SLOT; break; case ITEM_EQUIPMENT_RING: availableSlots = 2; firstSlot = EQUIP_RING1_SLOT; secondSlot = EQUIP_RING2_SLOT; break; case ITEM_EQUIPMENT_BREST: availableSlots = 1; firstSlot = EQUIP_BREST_SLOT; break; case ITEM_EQUIPMENT_ARMS: availableSlots = 1; firstSlot = EQUIP_ARMS_SLOT; break; case ITEM_EQUIPMENT_HEAD: availableSlots = 1; firstSlot = EQUIP_HEAD_SLOT; break; case ITEM_EQUIPMENT_LEGS: availableSlots = 1; firstSlot = EQUIP_LEGS_SLOT; break; case ITEM_EQUIPMENT_NECKLACE: availableSlots = 1; firstSlot = EQUIP_NECKLACE_SLOT; break; case ITEM_EQUIPMENT_FEET: availableSlots = 1; firstSlot = EQUIP_FEET_SLOT; break; case ITEM_UNUSABLE: case ITEM_USABLE: default: return NOT_EQUIPPABLE; } switch (availableSlots) { case 1: if (equippedItemList.at(firstSlot).itemId > 0) { if (unequipItem_(equippedItemList.at(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.at(firstSlot).itemId > 0) { // If old weapon is two-handed one, we can unequip // the first slot only, and clean the second. if (equippedItemList.at(firstSlot).itemId == ITEM_EQUIPMENT_TWO_HANDS_WEAPON) { if (unequipItem_(equippedItemList.at(firstSlot).itemId, firstSlot) != INVENTORY_FULL) return equipItem_(itemId, itemType, firstSlot); else return INVENTORY_FULL; } if (equippedItemList.at(secondSlot).itemId > 0) { // Both slots are full, // we remove the first one to equip if (unequipItem_(equippedItemList.at(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); } } else // first slot empty, we can equip. { return equipItem_(itemId, itemType, firstSlot); } break; default: return NOT_EQUIPPABLE; } } bool Inventory::equipItem(unsigned char inventorySlot, unsigned char equipmentSlot) { return false; // TODO } bool Inventory::unequipItem(unsigned int itemId) { return false; // TODO } bool Inventory::unequipItem(unsigned char inventorySlot, unsigned char equipmentSlot) { return false; // TODO } unsigned char Inventory::equipItem_(unsigned int itemId, unsigned int itemType, unsigned char equipmentSlot) { if (removeItem(itemId, 1) == 1) { equippedItemList.at(equipmentSlot).itemId = itemId; equippedItemList.at(equipmentSlot).itemType = itemType; return equipmentSlot; } else return NO_ITEM_TO_EQUIP; } unsigned char Inventory::unequipItem_(unsigned int itemId, unsigned char equipmentSlot) { if (addItem(itemId, 1) == 1) { equippedItemList.at(equipmentSlot).itemId = 0; equippedItemList.at(equipmentSlot).itemType = 0; return equipmentSlot; } else return INVENTORY_FULL; }