summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorErik Schilling <ablu.erikschilling@googlemail.com>2013-03-10 10:27:51 +0100
committerErik Schilling <ablu.erikschilling@googlemail.com>2013-09-08 10:19:40 +0200
commitf712d68495dd8e040c32da3b1c85bcb7845543ec (patch)
treef1a314bc1ef895c31851428b4ceff8b63d209f66 /src
parent8ddda85d923a528c7497a628d2fe10fc40b80a1f (diff)
downloadmanaserv-f712d68495dd8e040c32da3b1c85bcb7845543ec.tar.gz
manaserv-f712d68495dd8e040c32da3b1c85bcb7845543ec.tar.bz2
manaserv-f712d68495dd8e040c32da3b1c85bcb7845543ec.tar.xz
manaserv-f712d68495dd8e040c32da3b1c85bcb7845543ec.zip
Cleaned up the inventory handling
Things done: - Removed the equips table and added another column which keeps track about whether the item is equipped or not - Added a message to notify the client about failing equips instead of hardcoding to chat notification - Removed the move possibillity. It was a quite long function and our future idea of the inventory does not need any moves - Removed the inInventory and inEquipment parameters from chr_inv_count, but added a equipped key to the table that chr_get_inventory returns This change makes equipped items still being in the inventory. This means in-inventory triggers are still active! However it makes no sense to disable this triggers during equipping since it will appear as still in the inventory to the client.
Diffstat (limited to 'src')
-rw-r--r--src/account-server/character.cpp53
-rw-r--r--src/account-server/storage.cpp91
-rw-r--r--src/common/inventorydata.h38
-rw-r--r--src/common/manaserv_protocol.h8
-rw-r--r--src/game-server/character.cpp48
-rw-r--r--src/game-server/gamehandler.cpp51
-rw-r--r--src/game-server/gamehandler.h1
-rw-r--r--src/game-server/inventory.cpp487
-rw-r--r--src/game-server/inventory.h36
-rw-r--r--src/game-server/state.cpp65
-rw-r--r--src/scripting/lua.cpp46
-rw-r--r--src/sql/mysql/createTables.sql18
-rw-r--r--src/sql/mysql/updates/update_24_to_25.sql18
-rw-r--r--src/sql/sqlite/createTables.sql16
-rw-r--r--src/sql/sqlite/updates/update_24_to_25.sql47
15 files changed, 329 insertions, 694 deletions
diff --git a/src/account-server/character.cpp b/src/account-server/character.cpp
index 47bca5da..cafc256b 100644
--- a/src/account-server/character.cpp
+++ b/src/account-server/character.cpp
@@ -94,25 +94,21 @@ void CharacterData::serialize(MessageOut &msg)
// inventory - must be last because size isn't transmitted
const Possessions &poss = getPossessions();
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.writeInt16(k->first); // Equip slot id
- msg.writeInt16(k->second.itemId); // ItemId
- msg.writeInt16(k->second.itemInstance); // Item Instance id
- }
const InventoryData &inventoryData = poss.getInventory();
- for (InventoryData::const_iterator j = inventoryData.begin(),
- j_end = inventoryData.end(); j != j_end; ++j)
+ for (InventoryData::const_iterator itemIt = inventoryData.begin(),
+ itemIt_end = inventoryData.end(); itemIt != itemIt_end; ++itemIt)
{
- msg.writeInt16(j->first); // slot id
- msg.writeInt16(j->second.itemId); // item id
- msg.writeInt16(j->second.amount); // amount
+ int slot = itemIt->first;
+ msg.writeInt16(slot);
+ msg.writeInt16(itemIt->second.itemId);
+ msg.writeInt16(itemIt->second.amount);
+ if (equipData.find(itemIt->first) != equipData.end())
+ msg.writeInt8(1); // equipped
+ else
+ msg.writeInt8(0); // not equipped
}
}
-
void CharacterData::deserialize(MessageIn &msg)
{
// general character properties
@@ -170,33 +166,24 @@ void CharacterData::deserialize(MessageIn &msg)
giveAbility(id);
}
-
+ // inventory - must be last because size isn't transmitted
Possessions &poss = getPossessions();
- EquipData equipData;
- int equipSlotsSize = msg.readInt16();
- unsigned equipSlot;
- EquipmentItem equipItem;
- for (int j = 0; j < equipSlotsSize; ++j)
- {
- equipSlot = msg.readInt16();
- equipItem.itemId = msg.readInt16();
- equipItem.itemInstance = msg.readInt16();
- equipData.insert(equipData.end(),
- std::make_pair(equipSlot, equipItem));
- }
- poss.setEquipment(equipData);
- // Loads inventory - must be last because size isn't transmitted
InventoryData inventoryData;
+ EquipData equipmentData;
while (msg.getUnreadLength())
{
InventoryItem i;
- int slotId = msg.readInt16();
- i.itemId = msg.readInt16();
- i.amount = msg.readInt16();
- inventoryData.insert(inventoryData.end(), std::make_pair(slotId, i));
+ i.slot = msg.readInt16();
+ i.itemId = msg.readInt16();
+ i.amount = msg.readInt16();
+ i.equipmentSlot = msg.readInt8();
+ inventoryData.insert(std::make_pair(i.slot, i));
+ if (i.equipmentSlot != 0)
+ equipmentData.insert(i.slot);
}
poss.setInventory(inventoryData);
+ poss.setEquipment(equipmentData);
}
void CharacterData::setAccount(Account *acc)
diff --git a/src/account-server/storage.cpp b/src/account-server/storage.cpp
index 2ba1e911..bcfa39f8 100644
--- a/src/account-server/storage.cpp
+++ b/src/account-server/storage.cpp
@@ -78,7 +78,6 @@ static const char *CHAR_ATTR_TBL_NAME = "mana_char_attr";
static const char *CHAR_STATUS_EFFECTS_TBL_NAME = "mana_char_status_effects";
static const char *CHAR_KILL_COUNT_TBL_NAME = "mana_char_kill_stats";
static const char *CHAR_ABILITIES_TBL_NAME = "mana_char_abilities";
-static const char *CHAR_EQUIPS_TBL_NAME = "mana_char_equips";
static const char *INVENTORIES_TBL_NAME = "mana_inventories";
static const char *ITEMS_TBL_NAME = "mana_items";
static const char *GUILDS_TBL_NAME = "mana_guilds";
@@ -480,41 +479,12 @@ CharacterData *Storage::getCharacterBySQL(Account *owner)
try
{
std::ostringstream sql;
- 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)
- {
- equipItem.itemId = toUint(equipInfo(k, 1));
- equipItem.itemInstance = toUint(equipInfo(k, 2));
- equipData.insert(std::pair<unsigned, EquipmentItem>(
- toUint(equipInfo(k, 0)),
- equipItem));
- }
- }
- poss.setEquipment(equipData);
- }
- catch (const dal::DbSqlQueryExecFailure &e)
- {
- utils::throwError("DALStorage::getCharacter #2) SQL query failure: ",
- e);
- }
-
- try
- {
- std::ostringstream sql;
- sql << " select * from " << INVENTORIES_TBL_NAME
- << " where owner_id = '"
+ sql << " select id, owner_id, slot, class_id, amount, equipped from "
+ << INVENTORIES_TBL_NAME << " where owner_id = '"
<< character->getDatabaseID() << "' order by slot asc;";
InventoryData inventoryData;
+ EquipData equipmentData;
const dal::RecordSet &itemInfo = mDb->execSql(sql.str());
if (!itemInfo.isEmpty())
{
@@ -525,9 +495,22 @@ CharacterData *Storage::getCharacterBySQL(Account *owner)
item.itemId = toUint(itemInfo(k, 3));
item.amount = toUint(itemInfo(k, 4));
inventoryData[slot] = item;
+
+ if (toUint(itemInfo(k, 5)) != 0)
+ {
+ // The game server will set the right slot anyway,
+ // but this speeds up checking if the item is equipped
+ item.equipmentSlot = 1;
+ equipmentData.insert(slot);
+ }
+ else
+ {
+ item.equipmentSlot = 0;
+ }
}
}
poss.setInventory(inventoryData);
+ poss.setEquipment(equipmentData);
}
catch (const dal::DbSqlQueryExecFailure &e)
{
@@ -781,12 +764,6 @@ bool Storage::updateCharacter(CharacterData *character)
// Delete the old inventory and equipment table first
try
{
- std::ostringstream sqlDeleteCharacterEquipment;
- sqlDeleteCharacterEquipment
- << "delete from " << CHAR_EQUIPS_TBL_NAME
- << " where owner_id = '" << character->getDatabaseID() << "';";
- mDb->execSql(sqlDeleteCharacterEquipment.str());
-
std::ostringstream sqlDeleteCharacterInventory;
sqlDeleteCharacterInventory
<< "delete from " << INVENTORIES_TBL_NAME
@@ -804,39 +781,25 @@ bool Storage::updateCharacter(CharacterData *character)
{
std::ostringstream sql;
- sql << "insert into " << CHAR_EQUIPS_TBL_NAME
- << " (owner_id, slot_type, item_id, item_instance) values ("
+ sql << "insert into " << INVENTORIES_TBL_NAME
+ << " (owner_id, slot, class_id, amount, equipped) values ("
<< character->getDatabaseID() << ", ";
std::string base = sql.str();
const Possessions &poss = character->getPossessions();
- 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.itemId
- << ", " << it->second.itemInstance << ");";
- mDb->execSql(sql.str());
- }
-
- sql.str("");
-
- sql << "insert into " << INVENTORIES_TBL_NAME
- << " (owner_id, slot, class_id, amount) values ("
- << character->getDatabaseID() << ", ";
- base = sql.str();
-
const InventoryData &inventoryData = poss.getInventory();
- for (InventoryData::const_iterator j = inventoryData.begin(),
- j_end = inventoryData.end(); j != j_end; ++j)
+ const EquipData &equipData = poss.getEquipment();
+ for (InventoryData::const_iterator itemIt = inventoryData.begin(),
+ j_end = inventoryData.end(); itemIt != j_end; ++itemIt)
{
sql.str("");
- unsigned short slot = j->first;
- unsigned itemId = j->second.itemId;
- unsigned amount = j->second.amount;
+ unsigned short slot = itemIt->first;
+ unsigned itemId = itemIt->second.itemId;
+ unsigned amount = itemIt->second.amount;
+ bool equipped = itemIt->second.equipmentSlot != 0;
assert(itemId);
- sql << base << slot << ", " << itemId << ", " << amount << ");";
+ sql << base << slot << ", " << itemId << ", " << amount << ", "
+ << (equipped ? 1 : 0) << ");";
mDb->execSql(sql.str());
}
diff --git a/src/common/inventorydata.h b/src/common/inventorydata.h
index b410b3fb..5d1d9388 100644
--- a/src/common/inventorydata.h
+++ b/src/common/inventorydata.h
@@ -23,6 +23,7 @@
#include <vector>
#include <map>
+#include <set>
/**
* Numbers of inventory slots
@@ -36,38 +37,23 @@
struct InventoryItem
{
InventoryItem():
- itemId(0), amount(0)
+ slot(0),
+ itemId(0),
+ amount(0),
+ equipmentSlot(0)
{}
+ unsigned slot;
unsigned itemId;
unsigned amount;
-};
-
-struct EquipmentItem
-{
- EquipmentItem():
- itemId(0), itemInstance(0)
- {}
-
- EquipmentItem(unsigned itemId, unsigned itemInstance)
- {
- this->itemId = itemId;
- this->itemInstance = itemInstance;
- }
-
- // The item id taken from the item db.
- unsigned itemId;
- // A unique instance number used to separate items when equipping the same
- // item id multiple times on possible multiple slots.
- unsigned itemInstance;
+ unsigned equipmentSlot; /** 0 if not equipped */
};
// inventory slot id -> { item }
typedef std::map< unsigned, InventoryItem > InventoryData;
-// equip slot id -> { item id, item instance }
-// Equipment taking up multiple equip slot ids will be referenced multiple times
-typedef std::multimap< unsigned, EquipmentItem > EquipData;
+// the slots which are equipped
+typedef std::set<int> EquipData;
/**
* Structure storing the equipment and inventory of a Player.
@@ -77,7 +63,7 @@ struct Possessions
friend class Inventory;
public:
const EquipData &getEquipment() const
- { return equipSlots; }
+ { return equipment; }
const InventoryData &getInventory() const
{ return inventory; }
@@ -86,13 +72,13 @@ public:
* Should be done only at character serialization and storage load time.
*/
void setEquipment(EquipData &equipData)
- { equipSlots.swap(equipData); }
+ { equipment.swap(equipData); }
void setInventory(InventoryData &inventoryData)
{ inventory.swap(inventoryData); }
private:
InventoryData inventory;
- EquipData equipSlots;
+ EquipData equipment;
};
#endif
diff --git a/src/common/manaserv_protocol.h b/src/common/manaserv_protocol.h
index 50bfdd84..1d5c7e56 100644
--- a/src/common/manaserv_protocol.h
+++ b/src/common/manaserv_protocol.h
@@ -113,10 +113,12 @@ enum {
PGMSG_DROP = 0x0111, // W slot, W amount
PGMSG_EQUIP = 0x0112, // W inventory slot
PGMSG_UNEQUIP = 0x0113, // W item Instance id
- PGMSG_MOVE_ITEM = 0x0114, // W slot1, W slot2, W amount
GPMSG_INVENTORY = 0x0120, // { W slot, W item id [, W amount] (if item id is nonzero) }*
- GPMSG_INVENTORY_FULL = 0x0121, // W inventory slot count { W slot, W itemId, W amount }, { W equip slot, W item Id, W item Instance}*
- GPMSG_EQUIP = 0x0122, // W item Id, W equip slot type count //{ W equip slot, W capacity used}*//<- When equipping, //{ W item instance, W 0}*//<- When unequipping
+ GPMSG_INVENTORY_FULL = 0x0121, // W inventory slot count { W slot, W itemId, W amount, W equipmentSlot }
+ GPMSG_EQUIP = 0x0122, // W equipped inventory slot, W slot equipmentSlot
+ GPMSG_EQUIP_RESPONSE = 0x0123, // B error, W slot
+ GPMSG_UNEQUIP = 0x0124, // W equipped inventory slot
+ GPMSG_UNEQUIP_RESPONE = 0x0125, // B error, W slot
GPMSG_PLAYER_ATTRIBUTE_CHANGE = 0x0130, // { W attribute, D base value (in 1/256ths), D modified value (in 1/256ths)}*
GPMSG_ATTRIBUTE_POINTS_STATUS = 0x0140, // W character points, W correction points
PGMSG_RAISE_ATTRIBUTE = 0x0160, // W attribute
diff --git a/src/game-server/character.cpp b/src/game-server/character.cpp
index 0944f757..ea9228a7 100644
--- a/src/game-server/character.cpp
+++ b/src/game-server/character.cpp
@@ -182,31 +182,23 @@ void CharacterComponent::deserialize(Entity &entity, MessageIn &msg)
Possessions &poss = getPossessions();
- EquipData equipData;
- int equipSlotsSize = msg.readInt16();
- unsigned eqSlot;
- EquipmentItem equipItem;
- for (int j = 0; j < equipSlotsSize; ++j)
- {
- eqSlot = msg.readInt16();
- equipItem.itemId = msg.readInt16();
- equipItem.itemInstance = msg.readInt16();
- equipData.insert(equipData.end(),
- std::make_pair(eqSlot, equipItem));
- }
- poss.setEquipment(equipData);
// Loads inventory - must be last because size isn't transmitted
InventoryData inventoryData;
+ EquipData equipmentData;
while (msg.getUnreadLength())
{
InventoryItem i;
- int slotId = msg.readInt16();
- i.itemId = msg.readInt16();
- i.amount = msg.readInt16();
- inventoryData.insert(inventoryData.end(), std::make_pair(slotId, i));
+ i.slot = msg.readInt16();
+ i.itemId = msg.readInt16();
+ i.amount = msg.readInt16();
+ bool isEquipped = msg.readInt8() != 0;
+ inventoryData.insert(std::make_pair(i.slot, i));
+ if (isEquipped)
+ equipmentData.insert(i.slot);
}
poss.setInventory(inventoryData);
+ poss.setEquipment(equipmentData);
}
void CharacterComponent::serialize(Entity &entity, MessageOut &msg)
@@ -271,22 +263,18 @@ void CharacterComponent::serialize(Entity &entity, MessageOut &msg)
// inventory - must be last because size isn't transmitted
const Possessions &poss = getPossessions();
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.writeInt16(k->first); // Equip slot id
- msg.writeInt16(k->second.itemId); // ItemId
- msg.writeInt16(k->second.itemInstance); // Item Instance id
- }
const InventoryData &inventoryData = poss.getInventory();
- for (InventoryData::const_iterator j = inventoryData.begin(),
- j_end = inventoryData.end(); j != j_end; ++j)
+ for (InventoryData::const_iterator itemIt = inventoryData.begin(),
+ itemIt_end = inventoryData.end(); itemIt != itemIt_end; ++itemIt)
{
- msg.writeInt16(j->first); // slot id
- msg.writeInt16(j->second.itemId); // item id
- msg.writeInt16(j->second.amount); // amount
+ msg.writeInt16(itemIt->first); // slot id
+ msg.writeInt16(itemIt->second.itemId); // item id
+ msg.writeInt16(itemIt->second.amount); // amount
+ if (equipData.find(itemIt->first) != equipData.end())
+ msg.writeInt8(1); // equipped
+ else
+ msg.writeInt8(0); // not equipped
}
}
diff --git a/src/game-server/gamehandler.cpp b/src/game-server/gamehandler.cpp
index 1a0ca158..fe274ace 100644
--- a/src/game-server/gamehandler.cpp
+++ b/src/game-server/gamehandler.cpp
@@ -249,10 +249,6 @@ void GameHandler::processMessage(NetComputer *computer, MessageIn &message)
handleUnequip(client, message);
break;
- case PGMSG_MOVE_ITEM:
- handleMoveItem(client, message);
- break;
-
case PGMSG_USE_ABILITY_ON_BEING:
handleUseAbilityOnBeing(client, message);
break;
@@ -628,42 +624,25 @@ void GameHandler::handleWalk(GameClient &client, MessageIn &message)
void GameHandler::handleEquip(GameClient &client, MessageIn &message)
{
const int slot = message.readInt16();
- if (!Inventory(client.character).equip(slot))
- {
- MessageOut msg(GPMSG_SAY);
- msg.writeInt16(0); // From the server
- msg.writeString("Unable to equip.");
- client.send(msg);
- }
+ MessageOut msg(GPMSG_EQUIP_RESPONSE);
+ if (Inventory(client.character).equip(slot))
+ msg.writeInt8(ERRMSG_OK);
+ else
+ msg.writeInt8(ERRMSG_FAILURE);
+ msg.writeInt16(slot);
+ client.send(msg);
}
void GameHandler::handleUnequip(GameClient &client, MessageIn &message)
{
- const int itemInstance = message.readInt16();
- if (!Inventory(client.character).unequip(itemInstance))
- {
- MessageOut msg(GPMSG_SAY);
- msg.writeInt16(0); // From the server
- msg.writeString("Unable to unequip.");
- client.send(msg);
- }
-}
-
-void GameHandler::handleMoveItem(GameClient &client, MessageIn &message)
-{
- const int slot1 = message.readInt16();
- const int slot2 = message.readInt16();
- const int amount = message.readInt16();
-
- Inventory(client.character).move(slot1, slot2, amount);
- // log transaction
- std::stringstream str;
- str << "User moved item "
- << " from slot " << slot1 << " to slot " << slot2;
- auto *characterComponent =
- client.character->getComponent<CharacterComponent>();
- accountHandler->sendTransaction(characterComponent->getDatabaseID(),
- TRANS_ITEM_MOVE, str.str());
+ const int slot = message.readInt16();
+ MessageOut msg(GPMSG_UNEQUIP_RESPONE);
+ if (Inventory(client.character).unequip(slot))
+ msg.writeInt8(ERRMSG_OK);
+ else
+ msg.writeInt8(ERRMSG_FAILURE);
+ msg.writeInt16(slot);
+ client.send(msg);
}
void GameHandler::handleUseAbilityOnBeing(GameClient &client, MessageIn &message)
diff --git a/src/game-server/gamehandler.h b/src/game-server/gamehandler.h
index 2f44a3c9..f4995497 100644
--- a/src/game-server/gamehandler.h
+++ b/src/game-server/gamehandler.h
@@ -132,7 +132,6 @@ class GameHandler: public ConnectionHandler
void handleEquip(GameClient &client, MessageIn &message);
void handleUnequip(GameClient &client, MessageIn &message);
- void handleMoveItem(GameClient &client, MessageIn &message);
void handleUseAbilityOnBeing(GameClient &client, MessageIn &message);
void handleUseAbilityOnPoint(GameClient &client, MessageIn &message);
diff --git a/src/game-server/inventory.cpp b/src/game-server/inventory.cpp
index bec5961b..2f17af10 100644
--- a/src/game-server/inventory.cpp
+++ b/src/game-server/inventory.cpp
@@ -48,23 +48,14 @@ void Inventory::sendFull() const
MessageOut m(GPMSG_INVENTORY_FULL);
m.writeInt16(mPoss->inventory.size());
- for (InventoryData::const_iterator l = mPoss->inventory.begin(),
- l_end = mPoss->inventory.end(); l != l_end; ++l)
+ for (InventoryData::const_iterator it = mPoss->inventory.begin(),
+ l_end = mPoss->inventory.end(); it != l_end; ++it)
{
- assert(l->second.itemId);
- m.writeInt16(l->first); // Slot id
- m.writeInt16(l->second.itemId);
- m.writeInt16(l->second.amount);
- }
-
- for (EquipData::const_iterator k = mPoss->equipSlots.begin(),
- k_end = mPoss->equipSlots.end();
- k != k_end;
- ++k)
- {
- m.writeInt16(k->first); // Equip slot id
- m.writeInt16(k->second.itemId); // Item id
- m.writeInt16(k->second.itemInstance); // Item instance
+ assert(it->second.itemId);
+ m.writeInt16(it->first); // slot
+ m.writeInt16(it->second.itemId);
+ m.writeInt16(it->second.amount);
+ m.writeInt16(it->second.equipmentSlot);
}
gameHandler->sendTo(mCharacter, m);
@@ -73,73 +64,54 @@ void Inventory::sendFull() const
void Inventory::initialize()
{
/*
+ * Set the equipment slots
+ */
+ for (EquipData::iterator it = mPoss->equipment.begin(),
+ it_end = mPoss->equipment.end(); it != it_end; ++it)
+ {
+ InventoryData::iterator itemIt = mPoss->inventory.find(*it);
+ const ItemEquipRequirement &equipReq = itemManager->getItem(
+ itemIt->second.itemId)->getItemEquipRequirement();
+ itemIt->second.equipmentSlot = equipReq.equipSlotId;
+ }
+
+ /*
* Construct a set of item Ids to keep track of duplicate item Ids.
*/
std::set<unsigned> itemIds;
+ std::set<unsigned> equipmentIds;
/*
* Construct a set of itemIds to keep track of duplicate itemIds.
*/
- InventoryData::iterator it1;
- for (it1 = mPoss->inventory.begin(); it1 != mPoss->inventory.end();)
+
+ for (InventoryData::iterator it = mPoss->inventory.begin(),
+ it_end = mPoss->inventory.end(); it != it_end;)
{
- ItemClass *item = itemManager->getItem(it1->second.itemId);
+ ItemClass *item = itemManager->getItem(it->second.itemId);
if (item)
{
// If the insertion succeeded, it's the first time we're
// adding the item in the inventory. Hence, we can trigger
// item presence in inventory effect.
- if (itemIds.insert(it1->second.itemId).second)
+ if (itemIds.insert(it->second.itemId).second)
item->useTrigger(mCharacter, ITT_IN_INVY);
- ++it1;
- }
- else
- {
- LOG_WARN("Inventory: deleting unknown item type "
- << it1->second.itemId << " from the inventory of '"
- << mCharacter->getComponent<BeingComponent>()->getName()
- << "'!");
- mPoss->inventory.erase(it1++);
- }
- }
-
- itemIds.clear();
- /*
- * Equipment effects can be cumulative if more than one item instance
- * is equipped, but we check to trigger the item presence in equipment
- * effect only based on the first item instance insertion.
- */
- EquipData::iterator it2;
- for (it2 = mPoss->equipSlots.begin(); it2 != mPoss->equipSlots.end();)
- {
- ItemClass *item = itemManager->getItem(it2->second.itemId);
- if (item)
- {
- // TODO: Check equip conditions.
- // If not all needed slots are there, put the item back
- // in the inventory.
+ if (it->second.equipmentSlot != 0 &&
+ equipmentIds.insert(it->second.itemId).second)
+ {
+ item->useTrigger(mCharacter, ITT_EQUIP);
+ }
+ ++it;
}
else
{
LOG_WARN("Equipment: deleting unknown item id "
- << it2->second.itemId << " from the equipment of '"
+ << it->second.itemId << " from the equipment of '"
<< mCharacter->getComponent<BeingComponent>()->getName()
<< "'!");
- mPoss->equipSlots.erase(it2++);
- continue;
- }
-
- /*
- * Apply all equip triggers at first item instance insertion
- */
- if (itemIds.insert(it2->second.itemInstance).second)
- {
- itemManager->getItem(it2->second.itemId)
- ->useTrigger(mCharacter, ITT_EQUIP);
+ mPoss->inventory.erase(it++);
}
-
- ++it2;
}
}
@@ -233,32 +205,14 @@ unsigned Inventory::insert(unsigned itemId, unsigned amount)
return amount;
}
-unsigned Inventory::count(unsigned itemId,
- bool inInventory, bool inEquipment) const
+unsigned Inventory::count(unsigned itemId) const
{
unsigned nb = 0;
- if (inInventory)
- {
- for (InventoryData::iterator it = mPoss->inventory.begin(),
- it_end = mPoss->inventory.end(); it != it_end; ++it)
- if (it->second.itemId == itemId)
- nb += it->second.amount;
- }
-
- if (inEquipment)
+ for (InventoryData::iterator it = mPoss->inventory.begin(),
+ it_end = mPoss->inventory.end(); it != it_end; ++it)
{
- std::set<unsigned> itemInstances;
- for (EquipData::iterator it = mPoss->equipSlots.begin(),
- it_end = mPoss->equipSlots.end(); it != it_end; ++it)
- {
- if (it->second.itemId != itemId || !it->second.itemInstance)
- continue;
-
- // If the insertion was successful, then it was the first time,
- // and can be counted.
- if ((itemInstances.insert(it->second.itemInstance)).second)
- ++nb;
- }
+ if (it->second.itemId == itemId)
+ nb += it->second.amount;
}
return nb;
@@ -336,131 +290,6 @@ unsigned Inventory::remove(unsigned itemId, unsigned amount)
return amount;
}
-unsigned Inventory::move(unsigned slot1, unsigned slot2,
- unsigned amount)
-{
- LOG_DEBUG(amount << " item(s) requested to move from: " << slot1 << " to "
- << slot2 << " for character: '"
- << mCharacter->getComponent<BeingComponent>()->getName() << "'.");
-
- if (!amount || slot1 == slot2 || slot2 >= INVENTORY_SLOTS)
- return amount;
-
- InventoryData::iterator it1 = mPoss->inventory.find(slot1),
- it2 = mPoss->inventory.find(slot2),
- inv_end = mPoss->inventory.end();
-
- if (it1 == inv_end)
- return amount;
-
- MessageOut invMsg(GPMSG_INVENTORY);
-
- unsigned nb = std::min(amount, it1->second.amount);
- if (it2 == inv_end)
- {
- // Slot2 does not yet exist.
- mPoss->inventory[slot2].itemId = it1->second.itemId;
- nb = std::min(itemManager->getItem(it1->second.itemId)->getMaxPerSlot(),
- nb);
-
- mPoss->inventory[slot2].amount = nb;
- it1->second.amount -= nb;
- amount -= nb;
-
- //Save the itemId in case of deletion of the iterator
- unsigned itemId = it1->second.itemId;
- invMsg.writeInt16(slot1); // Slot
- if (it1->second.amount)
- {
- invMsg.writeInt16(it1->second.itemId); // Item Id
- invMsg.writeInt16(it1->second.amount); // Amount
- LOG_DEBUG("Left " << amount << " item(s) id:"
- << it1->second.itemId << " into slot: " << slot1);
- }
- else
- {
- invMsg.writeInt16(0);
- mPoss->inventory.erase(it1);
- LOG_DEBUG("Slot: " << slot1 << " is now empty.");
- }
- invMsg.writeInt16(slot2); // Slot
- invMsg.writeInt16(itemId); // Item Id (same as slot 1)
- invMsg.writeInt16(nb); // Amount
- LOG_DEBUG("Slot: " << slot2 << " has now " << nb << " of item id: "
- << itemId);
- }
- else
- {
- // Slot2 exists.
- if (it2->second.itemId != it1->second.itemId)
- {
- // Swap items when they are of a different type
- // and when all the amount of slot 1 is moving onto slot 2.
- if (amount >= it1->second.amount)
- {
- unsigned itemId = it1->second.itemId;
- unsigned amount = it1->second.amount;
- it1->second.itemId = it2->second.itemId;
- it1->second.amount = it2->second.amount;
- it2->second.itemId = itemId;
- it2->second.amount = amount;
-
- // Sending swapped slots.
- invMsg.writeInt16(slot1);
- invMsg.writeInt16(it1->second.itemId);
- invMsg.writeInt16(it1->second.amount);
- invMsg.writeInt16(slot2);
- invMsg.writeInt16(it2->second.itemId);
- invMsg.writeInt16(it2->second.amount);
- LOG_DEBUG("Swapping items in slots " << slot1
- << " and " << slot2);
- }
- else
- {
- // Cannot partially stack items of a different type.
- LOG_DEBUG("Cannot move " << amount << " item(s) from slot "
- << slot1 << " to " << slot2);
- return amount;
- }
- }
- else // Same item type on slot 2.
- {
- // Number of items moving
- nb = std::min(itemManager->getItem(
- it1->second.itemId)->getMaxPerSlot()
- - it2->second.amount, nb);
-
- // If nothing can move, we can abort
- if (!nb)
- return amount;
-
- it1->second.amount -= nb;
- it2->second.amount += nb;
- amount -= nb;
-
- invMsg.writeInt16(slot1); // Slot
- if (it1->second.amount)
- {
- invMsg.writeInt16(it1->second.itemId); // Item Id
- invMsg.writeInt16(it1->second.amount); // Amount
- }
- else
- {
- invMsg.writeInt16(0);
- mPoss->inventory.erase(it1);
- }
- invMsg.writeInt16(slot2); // Slot
- invMsg.writeInt16(it2->second.itemId); // Item Id
- invMsg.writeInt16(it2->second.amount); // Amount
- }
- }
-
- if (invMsg.getLength() > 2)
- gameHandler->sendTo(mCharacter, invMsg);
-
- return amount;
-}
-
unsigned Inventory::removeFromSlot(unsigned slot, unsigned amount)
{
InventoryData::iterator it = mPoss->inventory.find(slot);
@@ -544,22 +373,6 @@ void Inventory::updateEquipmentTrigger(ItemClass *oldI, ItemClass *newI)
newI->useTrigger(mCharacter, ITT_EQUIP);
}
-unsigned Inventory::getNewEquipItemInstance()
-{
- std::set<int> alreadyUsed;
- for (EquipData::const_iterator it = mPoss->equipSlots.begin();
- it != mPoss->equipSlots.end(); ++it)
- {
- alreadyUsed.insert(it->second.itemInstance);
- }
-
- unsigned itemInstance = 1;
- while (alreadyUsed.count(itemInstance))
- itemInstance++;
-
- return itemInstance;
-}
-
bool Inventory::checkEquipmentCapacity(unsigned equipmentSlot,
unsigned capacityRequested)
{
@@ -570,15 +383,15 @@ bool Inventory::checkEquipmentCapacity(unsigned equipmentSlot,
return false;
// Test whether the slot capacity requested is reached.
- for (EquipData::const_iterator it = mPoss->equipSlots.begin(),
- it_end = mPoss->equipSlots.end(); it != it_end; ++it)
+ for (EquipData::const_iterator it = mPoss->equipment.begin(),
+ it_end = mPoss->equipment.end(); it != it_end; ++it)
{
- if (it->first == equipmentSlot)
+ InventoryData::iterator itemIt = mPoss->inventory.find(*it);
+ if (itemIt->second.equipmentSlot == equipmentSlot)
{
- if (it->second.itemInstance != 0)
- {
- capacity--;
- }
+ const int itemId = itemIt->second.itemId;
+ const ItemClass *item = itemManager->getItem(itemId);
+ capacity -= item->getItemEquipRequirement().capacityRequired;
}
}
@@ -593,29 +406,35 @@ bool Inventory::checkEquipmentCapacity(unsigned equipmentSlot,
bool Inventory::equip(int inventorySlot)
{
// Test inventory slot existence
- InventoryData::iterator it;
- if ((it = mPoss->inventory.find(inventorySlot)) == mPoss->inventory.end())
+ InventoryData::iterator itemIt;
+ if ((itemIt = mPoss->inventory.find(inventorySlot)) == mPoss->inventory.end())
{
LOG_DEBUG("No existing item in inventory at slot: " << inventorySlot);
return false;
}
+ InventoryItem &item = itemIt->second;
+
+ // Already equipped?
+ if (item.equipmentSlot != 0)
+ return false;
+
// Test the equipment scripted requirements
- if (!testEquipScriptRequirements(it->second.itemId))
+ if (!testEquipScriptRequirements(item.itemId))
return false;
// Test the equip requirements. If none, it's not an equipable item.
const ItemEquipRequirement &equipReq =
- itemManager->getItem(it->second.itemId)->getItemEquipRequirement();
+ itemManager->getItem(item.itemId)->getItemEquipRequirement();
if (!equipReq.equipSlotId)
{
- LOG_DEBUG("No equip requirements for item id: " << it->second.itemId
+ LOG_DEBUG("No equip requirements for item id: " << item.itemId
<< " at slot: " << inventorySlot);
return false;
}
// List of potential unique itemInstances to unequip first.
- std::set<unsigned> equipInstancesToUnequipFirst;
+ std::set<unsigned> slotsToUnequipFirst;
// We first check the equipment slots for:
// - 1. whether enough total equip slot space is available.
@@ -642,14 +461,15 @@ bool Inventory::equip(int inventorySlot)
&& hasInventoryEnoughSpace(equipReq.equipSlotId))
{
// Then, we unequip each iteminstance of the equip slot
- for (EquipData::iterator iter =
- mPoss->equipSlots.begin();
- iter != mPoss->equipSlots.end(); ++iter)
+ for (EquipData::iterator it = mPoss->equipment.begin(),
+ it_end = mPoss->equipment.end(); it != it_end; ++it)
{
- if (iter->first == equipReq.equipSlotId
- && iter->second.itemInstance)
- equipInstancesToUnequipFirst.insert(
- iter->second.itemInstance);
+ const unsigned slot = *it;
+ InventoryData::iterator itemIt = mPoss->inventory.find(slot);
+ assert(itemIt != mPoss->inventory.end());
+ if (itemIt->second.equipmentSlot == equipReq.equipSlotId) {
+ slotsToUnequipFirst.insert(itemIt->first);
+ }
}
}
else
@@ -662,90 +482,33 @@ bool Inventory::equip(int inventorySlot)
}
// Potential Pre-unequipment process
- for (std::set<unsigned>::const_iterator it3 =
- equipInstancesToUnequipFirst.begin();
- it3 != equipInstancesToUnequipFirst.end(); ++it3)
+ for (std::set<unsigned>::const_iterator itemsToUnequip =
+ slotsToUnequipFirst.begin(),
+ itemsToUnequip_end = slotsToUnequipFirst.end();
+ itemsToUnequip != itemsToUnequip_end; ++itemsToUnequip)
{
- if (!unequip(*it3))
+ if (!unequip(*itemsToUnequip))
{
// Something went wrong even when we tested the unequipment process.
LOG_WARN("Unable to unequip even when unequip was tested. "
"Character : "
- << mCharacter->getComponent<BeingComponent>()->getName()
- << ", unequip slot: " << *it3);
+ << mCharacter->getComponent<BeingComponent>()->getName()
+ << ", unequip slot: " << *itemsToUnequip);
return false;
}
}
// Actually equip the item now that the requirements has met.
- //W equip slot type count, W item id, { W equip slot, W capacity used}*
- MessageOut equipMsg(GPMSG_EQUIP);
- equipMsg.writeInt16(it->second.itemId); // Item Id
- equipMsg.writeInt16(1); // Number of equip slot changed.
-
- // Compute an unique equip item Instance id (unicity is per character only.)
- int itemInstance = getNewEquipItemInstance();
-
- unsigned capacityLeft = equipReq.capacityRequired;
- unsigned capacityUsed = 0;
- // Apply equipment changes
- for (EquipData::iterator it4 = mPoss->equipSlots.begin(),
- it4_end = mPoss->equipSlots.end(); it4 != it4_end; ++it4)
- {
- if (!capacityLeft)
- break;
-
- // We've found an existing equip slot
- if (it4->first == equipReq.equipSlotId)
- {
- // We've found an empty slot
- if (it4->second.itemInstance == 0)
- {
- it4->second.itemId = it->second.itemId;
- it4->second.itemInstance = itemInstance;
- --capacityLeft;
- }
- else // The slot is already in use.
- {
- ++capacityUsed;
- }
- }
- }
-
- // When there is still something to apply even when out of that loop,
- // It means that the equip multimapis missing empty slots.
- // Hence, we add them back
- if(capacityLeft)
- {
- unsigned maxCapacity =
- itemManager->getEquipSlotCapacity(equipReq.equipSlotId);
+ item.equipmentSlot = equipReq.equipSlotId;
+ mPoss->equipment.insert(inventorySlot);
- // A should never happen case
- assert(maxCapacity >= capacityUsed + capacityLeft);
-
- while (capacityLeft)
- {
- EquipmentItem equipItem(it->second.itemId, itemInstance);
- mPoss->equipSlots.insert(
- std::make_pair(equipReq.equipSlotId, equipItem));
- --capacityLeft;
- }
- }
-
- // Equip slot
- equipMsg.writeInt16(equipReq.equipSlotId);
- // Capacity used
- equipMsg.writeInt16(equipReq.capacityRequired);
- // Item instance
- equipMsg.writeInt16(itemInstance);
+ MessageOut equipMsg(GPMSG_EQUIP);
+ equipMsg.writeInt16(inventorySlot);
+ equipMsg.writeInt16(item.equipmentSlot);
+ gameHandler->sendTo(mCharacter, equipMsg);
// New item trigger
- updateEquipmentTrigger(0, it->second.itemId);
-
- // Remove item from inventory
- removeFromSlot(inventorySlot, 1);
-
- gameHandler->sendTo(mCharacter, equipMsg);
+ updateEquipmentTrigger(0, item.itemId);
// Update look when necessary
checkLookchanges(equipReq.equipSlotId);
@@ -753,87 +516,51 @@ bool Inventory::equip(int inventorySlot)
return true;
}
-unsigned Inventory::getSlotItemInstance(unsigned slot)
+bool Inventory::unequipAll(unsigned itemId)
{
- EquipData::iterator it = mPoss->equipSlots.find(slot);
- if (it != mPoss->equipSlots.end())
- return it->second.itemInstance;
- return 0;
-}
-
-bool Inventory::unequipItem(unsigned itemId)
-{
- std::set<unsigned> itemInstances;
- for (EquipData::iterator it = mPoss->equipSlots.begin(),
- it_end = mPoss->equipSlots.end(); it != it_end; ++it)
+ while (true)
{
- if (it->second.itemId == itemId)
- itemInstances.insert(it->second.itemInstance);
- }
+ const int slot = getFirstSlot(itemId);
+ // No item left
+ if (slot == -1)
+ return true;
- // Nothing to do but it's a success
- if (itemInstances.empty())
- return true;
-
- for (std::set<unsigned>::const_iterator it = itemInstances.begin(),
- it_end = itemInstances.end(); it != it_end; ++it)
- {
- if (!unequip(*it))
+ if (!unequip(slot))
return false;
}
- return true;
+
+ // silence compiler warnings
+ assert(false);
+ return false;
}
-bool Inventory::unequip(unsigned itemInstance)
+bool Inventory::unequip(unsigned itemSlot)
{
- if (!itemInstance)
- return false;
-
- // The itemId to unequip
- unsigned itemId = 0;
- unsigned slotTypeId = 0;
-
- bool addedToInventory = false;
-
- // Empties all equip entries that point to the given equipment slot
- // The equipment slots should NEVER be erased after initialization!
- for (EquipData::iterator it = mPoss->equipSlots.begin(),
- it_end = mPoss->equipSlots.end(); it != it_end; ++it)
+ InventoryData::iterator it = mPoss->inventory.find(itemSlot);
+ if (it == mPoss->inventory.end())
{
- if (it->second.itemInstance == itemInstance && it->second.itemId)
- {
- // Add the item to the inventory list if not already present there
- itemId = it->second.itemId;
+ LOG_DEBUG("Tried to unequip invalid item at slot " << itemSlot);
+ return false;
+ }
- // Move the item back to inventory and return false when it failed.
- if (!addedToInventory && insert(itemId, 1) > 0)
- return false;
- else
- addedToInventory = true;
+ InventoryItem &item = it->second;
- it->second.itemId = 0;
- it->second.itemInstance = 0;
+ // Item was not equipped
+ if (item.equipmentSlot == 0)
+ return false;
- // We keep track of the slot type to be able to raise a potential
- // change in the character sprite
- slotTypeId = it->first;
- }
- }
+ const unsigned slotTypeId = item.equipmentSlot;
- // When there were no corresponding item id, it means no item was to
- // be unequipped.
- if (!itemId)
- return false;
+ // unequip
+ item.equipmentSlot = 0;
+ mPoss->equipment.erase(mPoss->equipment.find(itemSlot));
- MessageOut equipMsg(GPMSG_EQUIP);
- equipMsg.writeInt16(0); // Item Id, useless in case of unequip.
- equipMsg.writeInt16(1); // Number of slot types touched.
- equipMsg.writeInt16(itemInstance);
- equipMsg.writeInt16(0); // Capacity used, set to 0 to unequip.
+ MessageOut equipMsg(GPMSG_UNEQUIP);
+ equipMsg.writeInt16(itemSlot);
gameHandler->sendTo(mCharacter, equipMsg);
// Apply unequip trigger
- updateEquipmentTrigger(itemId, 0);
+ updateEquipmentTrigger(item.itemId, 0);
checkLookchanges(slotTypeId);
diff --git a/src/game-server/inventory.h b/src/game-server/inventory.h
index 1740a8d9..949471b6 100644
--- a/src/game-server/inventory.h
+++ b/src/game-server/inventory.h
@@ -65,26 +65,19 @@ class Inventory
bool equip(int inventorySlot);
/**
- * Unequips all the items with the given item if
- * from given equipment slot.
+ * Unequips all the items with the given item id
* @param itemId The item Id to unequip.
* @returns whether all item id could be unequipped.
* @note returns true when no item with given ids were equipped.
*/
- bool unequipItem(unsigned itemId);
+ bool unequipAll(unsigned itemId);
/**
* Unequips item from given equipment slot.
- * @param itemInstance The item instance id used to know what to unequip
+ * @param itemSlot The item slot used to know what to unequip
* @returns Whether it was unequipped.
*/
- bool unequip(unsigned itemInstance);
-
- /**
- * Gets the item instance from the given equipment slot.
- * Return 0 if none.
- */
- unsigned getSlotItemInstance(unsigned slot);
+ bool unequip(unsigned itemSlot);
/**
* Inserts some items into the inventory.
@@ -99,13 +92,6 @@ class Inventory
unsigned remove(unsigned itemId, unsigned amount);
/**
- * Moves some items from the first slot to the second one.
- * @returns number of items not moved.
- */
- unsigned move(unsigned slot1, unsigned slot2,
- unsigned amount);
-
- /**
* Removes some items from inventory.
* @return number of items not removed.
*/
@@ -113,11 +99,9 @@ class Inventory
/**
* Counts number of items with given Id.
- * @param inInventory Search in player's inventory.
- * @param inEquipment Search in player's equipment.
+ * @param itemId The id to look for.
*/
- unsigned count(unsigned itemId, bool inInventory = true,
- bool inEquipment = true) const;
+ unsigned count(unsigned itemId) const;
/**
* Gets the ID of the items in a given slot.
@@ -163,14 +147,6 @@ class Inventory
{ return true; }
/**
- * Return an equip item instance id unique to the item used,
- * per character.
- * This is used to differenciate some items that can be equipped
- * multiple times, like one-handed weapons for instance.
- */
- unsigned getNewEquipItemInstance();
-
- /**
* Check the inventory is within the slot limit and capacity.
* Forcibly delete items from the end if it is not.
* @todo Drop items instead?
diff --git a/src/game-server/state.cpp b/src/game-server/state.cpp
index a7cac98c..b6528955 100644
--- a/src/game-server/state.cpp
+++ b/src/game-server/state.cpp
@@ -85,10 +85,8 @@ static void serializeLooks(Entity *ch, MessageOut &msg)
msg.writeInt8(characterComponent->getHairColor());
const EquipData &equipData =
characterComponent->getPossessions().getEquipment();
-
- // We'll use a set to check whether we already sent the update for the given
- // item instance.
- std::set<unsigned> itemInstances;
+ const InventoryData &inventoryData =
+ characterComponent->getPossessions().getInventory();
// The map storing the info about the look changes to send
//{ slot type id, item id }
@@ -99,17 +97,14 @@ static void serializeLooks(Entity *ch, MessageOut &msg)
for (EquipData::const_iterator it = equipData.begin(),
it_end = equipData.end(); it != it_end; ++it)
{
- if (!itemManager->isEquipSlotVisible(it->first))
+ InventoryData::const_iterator itemIt = inventoryData.find(*it);
+
+ if (!itemManager->isEquipSlotVisible(itemIt->second.equipmentSlot))
continue;
- if (!it->second.itemInstance
- || itemInstances.insert(it->second.itemInstance).second)
- {
- // When the insertion succeeds, its the first time
- // we encounter the item, so we can send the look change.
- // We also send empty slots for unequipment handling.
- lookChanges.insert(std::make_pair(it->first, it->second.itemId));
- }
+ lookChanges.insert(std::make_pair(
+ itemIt->second.equipmentSlot,
+ itemIt->second.itemId));
}
if (!lookChanges.empty())
@@ -117,12 +112,12 @@ static void serializeLooks(Entity *ch, MessageOut &msg)
// Number of look changes to send
msg.writeInt8(lookChanges.size());
- for (std::map<unsigned, unsigned>::const_iterator it2 =
- lookChanges.begin(), it2_end = lookChanges.end();
- it2 != it2_end; ++it2)
+ for (std::map<unsigned, unsigned>::const_iterator it =
+ lookChanges.begin(), it_end = lookChanges.end();
+ it != it_end; ++it)
{
- msg.writeInt8(it2->first);
- msg.writeInt16(it2->second);
+ msg.writeInt8(it->first);
+ msg.writeInt16(it->second);
}
}
}
@@ -170,20 +165,20 @@ static void informPlayer(MapComposite *map, Entity *p)
// Send action change messages.
if ((oflags & UPDATEFLAG_ACTIONCHANGE))
{
- MessageOut ActionMsg(GPMSG_BEING_ACTION_CHANGE);
- ActionMsg.writeInt16(oid);
- ActionMsg.writeInt8(
+ MessageOut actionMsg(GPMSG_BEING_ACTION_CHANGE);
+ actionMsg.writeInt16(oid);
+ actionMsg.writeInt8(
o->getComponent<BeingComponent>()->getAction());
- gameHandler->sendTo(p, ActionMsg);
+ gameHandler->sendTo(p, actionMsg);
}
// Send looks change messages.
if (oflags & UPDATEFLAG_LOOKSCHANGE)
{
- MessageOut LooksMsg(GPMSG_BEING_LOOKS_CHANGE);
- LooksMsg.writeInt16(oid);
- serializeLooks(o, LooksMsg);
- gameHandler->sendTo(p, LooksMsg);
+ MessageOut looksMsg(GPMSG_BEING_LOOKS_CHANGE);
+ looksMsg.writeInt16(oid);
+ serializeLooks(o, looksMsg);
+ gameHandler->sendTo(p, looksMsg);
}
// Send emote messages.
@@ -193,21 +188,21 @@ static void informPlayer(MapComposite *map, Entity *p)
o->getComponent<BeingComponent>()->getLastEmote();
if (emoteId > -1)
{
- MessageOut EmoteMsg(GPMSG_BEING_EMOTE);
- EmoteMsg.writeInt16(oid);
- EmoteMsg.writeInt16(emoteId);
- gameHandler->sendTo(p, EmoteMsg);
+ MessageOut emoteMsg(GPMSG_BEING_EMOTE);
+ emoteMsg.writeInt16(oid);
+ emoteMsg.writeInt16(emoteId);
+ gameHandler->sendTo(p, emoteMsg);
}
}
// Send direction change messages.
if (oflags & UPDATEFLAG_DIRCHANGE)
{
- MessageOut DirMsg(GPMSG_BEING_DIR_CHANGE);
- DirMsg.writeInt16(oid);
- DirMsg.writeInt8(
+ MessageOut dirMsg(GPMSG_BEING_DIR_CHANGE);
+ dirMsg.writeInt16(oid);
+ dirMsg.writeInt8(
o->getComponent<BeingComponent>()->getDirection());
- gameHandler->sendTo(p, DirMsg);
+ gameHandler->sendTo(p, dirMsg);
}
// Send ability uses
@@ -279,8 +274,6 @@ static void informPlayer(MapComposite *map, Entity *p)
{
case OBJECT_CHARACTER:
{
- auto *characterComponent =
- o->getComponent<CharacterComponent>();
enterMsg.writeString(
o->getComponent<BeingComponent>()->getName());
serializeLooks(o, enterMsg);
diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp
index 0193d888..50bf3f35 100644
--- a/src/scripting/lua.cpp
+++ b/src/scripting/lua.cpp
@@ -901,10 +901,8 @@ static int trade(lua_State *s)
}
/** LUA entity:inv_count (inventory)
- * entity:inv_count(bool inInventory, bool inEquipment,
- * int id1, ..., int idN)
- * entity:inv_count(bool inInventory, bool inEquipment,
- * string name1, ..., string nameN)
+ * entity:inv_count(int id1, ..., int idN)
+ * entity:inv_count(string name1, ..., string nameN)
**
* Valid only for character entities.
*
@@ -923,17 +921,14 @@ static int entity_inv_count(lua_State *s)
return 0;
}
- bool inInventory = lua_toboolean(s, 2);
- bool inEquipment = lua_toboolean(s, 3);
-
- int nb_items = lua_gettop(s) - 3;
+ int nb_items = lua_gettop(s) - 1;
Inventory inv(q);
int nb = 0;
for (int i = 4; i < nb_items + 4; ++i)
{
ItemClass *it = checkItemClass(s, i);
- nb = inv.count(it->getDatabaseID(), inInventory, inEquipment);
+ nb = inv.count(it->getDatabaseID());
lua_pushinteger(s, nb);
}
return nb_items;
@@ -1004,7 +999,7 @@ static int entity_inv_change(lua_State *s)
}
/** LUA entity:inventory (inventory)
- * entity:inventory(): table[]{slot, item id, name, amount}
+ * entity:inventory(): table[]{slot, item id, name, amount, equipped}
**
* Valid only for character entities.
*
@@ -1064,6 +1059,10 @@ static int entity_get_inventory(lua_State *s)
lua_pushinteger(s, it->second.amount);
lua_settable(s, subTableStackPosition);
+ lua_pushliteral(s, "equipped");
+ lua_pushboolean(s, it->second.equipmentSlot != 0);
+ lua_settable(s, subTableStackPosition);
+
// Add the sub-table as value of the main one.
lua_rawseti(s, firstTableStackPosition, tableIndex);
++tableIndex;
@@ -1098,39 +1097,36 @@ static int entity_get_equipment(lua_State *s)
Entity *q = checkCharacter(s, 1);
// Create a lua table with the inventory ids.
- const EquipData equipData = q->getComponent<CharacterComponent>()
- ->getPossessions().getEquipment();
+ auto *characterComponent = q->getComponent<CharacterComponent>();
+ const InventoryData inventoryData =
+ characterComponent->getPossessions().getInventory();
+ const EquipData equipData =
+ characterComponent->getPossessions().getEquipment();
lua_newtable(s);
int firstTableStackPosition = lua_gettop(s);
int tableIndex = 1;
- std::set<unsigned> itemInstances;
-
for (EquipData::const_iterator it = equipData.begin(),
it_end = equipData.end(); it != it_end; ++it)
{
- if (!it->second.itemId || !it->second.itemInstance)
- continue;
-
- // Only count multi-slot items once.
- if (!itemInstances.insert(it->second.itemInstance).second)
- continue;
+ InventoryData::const_iterator itemIt = inventoryData.find(*it);
+ const InventoryItem &item = itemIt->second;
// Create the sub-table (value of the main one)
lua_createtable(s, 0, 3);
int subTableStackPosition = lua_gettop(s);
// Stores the item info in it.
lua_pushliteral(s, "slot");
- lua_pushinteger(s, it->first); // The slot id
+ lua_pushinteger(s, item.slot); // The slot id
lua_settable(s, subTableStackPosition);
lua_pushliteral(s, "id");
- lua_pushinteger(s, it->second.itemId);
+ lua_pushinteger(s, item.itemId);
lua_settable(s, subTableStackPosition);
lua_pushliteral(s, "name");
- push(s, itemManager->getItem(it->second.itemId)->getName());
+ push(s, itemManager->getItem(item.itemId)->getName());
lua_settable(s, subTableStackPosition);
// Add the sub-table as value of the main one.
@@ -1202,7 +1198,7 @@ static int entity_unequip_slot(lua_State *s)
Inventory inv(ch);
- lua_pushboolean(s, inv.unequip(inv.getSlotItemInstance(equipmentSlot)));
+ lua_pushboolean(s, inv.unequip(equipmentSlot));
return 1;
}
@@ -1223,7 +1219,7 @@ static int entity_unequip_item(lua_State *s)
ItemClass *it = checkItemClass(s, 2);
Inventory inv(ch);
- lua_pushboolean(s, inv.unequipItem(it->getDatabaseID()));
+ lua_pushboolean(s, inv.unequipAll(it->getDatabaseID()));
return 1;
}
diff --git a/src/sql/mysql/createTables.sql b/src/sql/mysql/createTables.sql
index fc873712..c15c005b 100644
--- a/src/sql/mysql/createTables.sql
+++ b/src/sql/mysql/createTables.sql
@@ -179,21 +179,6 @@ DEFAULT CHARSET=utf8
AUTO_INCREMENT=1 ;
--
--- table: `mana_char_equips`
---
-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` int(10) unsigned NOT NULL,
- `item_id` int(10) unsigned NOT NULL,
- `item_instance` int(10) unsigned NOT NULL,
- --
- PRIMARY KEY (`id`),
- FOREIGN KEY (`owner_id`) REFERENCES `mana_characters` (`id`)
-) ENGINE=InnoDB
-DEFAULT CHARSET=utf8;
-
---
-- table: `mana_inventories`
-- todo: remove class_id and amount and reference on mana_item_instances
--
@@ -203,6 +188,7 @@ CREATE TABLE IF NOT EXISTS `mana_inventories` (
`slot` tinyint(3) unsigned NOT NULL,
`class_id` int(10) unsigned NOT NULL,
`amount` tinyint(3) unsigned NOT NULL,
+ `equipped` tinyint(3) unsigned NOT NULL,
--
PRIMARY KEY (`id`),
UNIQUE KEY `owner_id` (`owner_id`, `slot`),
@@ -420,7 +406,7 @@ AUTO_INCREMENT=0 ;
INSERT INTO mana_world_states VALUES('accountserver_startup',-1,'0', NOW());
INSERT INTO mana_world_states VALUES('accountserver_version',-1,'0', NOW());
-INSERT INTO mana_world_states VALUES('database_version', -1,'24', NOW());
+INSERT INTO mana_world_states VALUES('database_version', -1,'25', NOW());
-- all known transaction codes
diff --git a/src/sql/mysql/updates/update_24_to_25.sql b/src/sql/mysql/updates/update_24_to_25.sql
new file mode 100644
index 00000000..8f5ea24e
--- /dev/null
+++ b/src/sql/mysql/updates/update_24_to_25.sql
@@ -0,0 +1,18 @@
+START TRANSACTION;
+
+ALTER TABLE mana_inventories ADD COLUMN equipped tinyint(3) unsigned NOT NULL;
+
+INSERT INTO mana_inventories (owner_id, slot, class_id, amount, equipped)
+SELECT owner_id, (SELECT IF COUNT(slot) = 0 THEN 1 ELSE MAX(slot) + 1 END IF FROM mana_inventories
+ WHERE owner_id=owner_id),
+ item_id, 1, 1 FROM mana_char_equips;
+
+DROP TABLE mana_char_equips;
+
+-- Update database version.
+UPDATE mana_world_states
+ SET value = '25',
+ moddate = UNIX_TIMESTAMP()
+ WHERE state_name = 'database_version';
+
+COMMIT;
diff --git a/src/sql/sqlite/createTables.sql b/src/sql/sqlite/createTables.sql
index 9d7d1c2c..95dc5a23 100644
--- a/src/sql/sqlite/createTables.sql
+++ b/src/sql/sqlite/createTables.sql
@@ -173,19 +173,6 @@ CREATE TABLE mana_floor_items
-----------------------------------------------------------------------------
-CREATE TABLE mana_char_equips
-(
- id INTEGER PRIMARY KEY,
- owner_id INTEGER NOT NULL,
- slot_type INTEGER NOT NULL,
- item_id INTEGER NOT NULL,
- item_instance INTEGER NOT NULL,
- --
- FOREIGN KEY (owner_id) REFERENCES mana_characters(id)
-);
-
------------------------------------------------------------------------------
-
-- todo: remove class_id and amount and reference on mana_item_instances
CREATE TABLE mana_inventories
(
@@ -194,6 +181,7 @@ CREATE TABLE mana_inventories
slot INTEGER NOT NULL,
class_id INTEGER NOT NULL,
amount INTEGER NOT NULL,
+ equipped INTEGER NOT NULL,
--
FOREIGN KEY (owner_id) REFERENCES mana_characters(id)
);
@@ -408,7 +396,7 @@ AS
INSERT INTO mana_world_states VALUES('accountserver_startup',-1,'0', strftime('%s','now'));
INSERT INTO mana_world_states VALUES('accountserver_version',-1,'0', strftime('%s','now'));
-INSERT INTO mana_world_states VALUES('database_version', -1,'24', strftime('%s','now'));
+INSERT INTO mana_world_states VALUES('database_version', -1,'25', strftime('%s','now'));
-- all known transaction codes
diff --git a/src/sql/sqlite/updates/update_24_to_25.sql b/src/sql/sqlite/updates/update_24_to_25.sql
new file mode 100644
index 00000000..955d9c59
--- /dev/null
+++ b/src/sql/sqlite/updates/update_24_to_25.sql
@@ -0,0 +1,47 @@
+BEGIN;
+
+CREATE TABLE mana_inventories_backup
+(
+ id INTEGER PRIMARY KEY,
+ owner_id INTEGER NOT NULL,
+ slot INTEGER NOT NULL,
+ class_id INTEGER NOT NULL,
+ amount INTEGER NOT NULL,
+ equipped INTEGER NOT NULL,
+ --
+ FOREIGN KEY (owner_id) REFERENCES mana_characters(id)
+);
+
+INSERT INTO mana_inventories_backup SELECT
+ id, owner_id, slot, class_id, amount, 0 FROM mana_inventories;
+
+DROP TABLE mana_inventories;
+
+CREATE TABLE mana_inventories
+(
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ owner_id INTEGER NOT NULL,
+ slot INTEGER NOT NULL,
+ class_id INTEGER NOT NULL,
+ amount INTEGER NOT NULL,
+ equipped INTEGER NOT NULL,
+ --
+ FOREIGN KEY (owner_id) REFERENCES mana_characters(id)
+);
+
+INSERT INTO mana_inventories SELECT * FROM mana_inventories_backup;
+DROP TABLE mana_inventories_backup;
+
+
+INSERT INTO mana_inventories (owner_id, slot, class_id, amount, equipped)
+SELECT owner_id, (SELECT CASE WHEN COUNT(slot) = 0 THEN 1 ELSE MAX(slot) + 1 END as slot FROM mana_inventories
+ WHERE owner_id=owner_id),
+ item_id, 1, 1 FROM mana_char_equips;
+
+-- Update the database version, and set date of update
+UPDATE mana_world_states
+ SET value = '25',
+ moddate = strftime('%s','now')
+ WHERE state_name = 'database_version';
+
+END;