summaryrefslogtreecommitdiff
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
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.
-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;