summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Melquiond <guillaume.melquiond@gmail.com>2007-08-01 11:06:46 +0000
committerGuillaume Melquiond <guillaume.melquiond@gmail.com>2007-08-01 11:06:46 +0000
commite481ad5466eb2b87036515a2a15166e41828c31f (patch)
treed2bbd3a165e54f25bfdb6901edada374697c3260
parent006fde3c4ba146c62acc03eb419ef7a32a84623d (diff)
downloadmanaserv-e481ad5466eb2b87036515a2a15166e41828c31f.tar.gz
manaserv-e481ad5466eb2b87036515a2a15166e41828c31f.tar.bz2
manaserv-e481ad5466eb2b87036515a2a15166e41828c31f.tar.xz
manaserv-e481ad5466eb2b87036515a2a15166e41828c31f.zip
Added notification on changes of look.
-rw-r--r--ChangeLog10
-rw-r--r--src/game-server/inventory.cpp195
-rw-r--r--src/game-server/inventory.hpp16
-rw-r--r--src/game-server/itemmanager.cpp33
4 files changed, 167 insertions, 87 deletions
diff --git a/ChangeLog b/ChangeLog
index 80ceee8a..6150b991 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2007-08-01 Guillaume Melquiond <guillaume.melquiond@gmail.com>
+
+ * src/game-server/itemmanager.cpp: Ensured equipment items cannot
+ stack.
+ * src/game-server/inventory.hpp, src/game-server/inventory.cpp:
+ Improved equipment change so that no empty slot is used, unless really
+ needed. Ensured equip and unequip do not modify inventory when they
+ fail in non-delayed mode. Simplified and robustified code. Added
+ notification on changes of looks.
+
2007-07-31 Guillaume Melquiond <guillaume.melquiond@gmail.com>
* src/defines.h, src/game-server/inventory.hpp,
diff --git a/src/game-server/inventory.cpp b/src/game-server/inventory.cpp
index a431b284..50e229cc 100644
--- a/src/game-server/inventory.cpp
+++ b/src/game-server/inventory.cpp
@@ -32,7 +32,8 @@
#include "net/messageout.hpp"
Inventory::Inventory(Character *p, bool d):
- mPoss(&p->getPossessions()), msg(GPMSG_INVENTORY), mClient(p), mDelayed(d)
+ mPoss(&p->getPossessions()), msg(GPMSG_INVENTORY), mClient(p),
+ mDelayed(d), mChangedLook(false)
{
}
@@ -40,49 +41,64 @@ Inventory::~Inventory()
{
if (msg.getLength() > 2)
{
- if (mDelayed)
- {
- Possessions &poss = mClient->getPossessions();
- if (mPoss != &poss)
- {
- poss = *mPoss;
- delete mPoss;
- }
- }
+ update();
gameHandler->sendTo(mClient, msg);
}
}
-void Inventory::cancel()
+void Inventory::restart()
{
msg.clear();
msg.writeShort(GPMSG_INVENTORY);
- mPoss = &mClient->getPossessions();
+ mChangedLook = false;
}
-void Inventory::commit()
+void Inventory::cancel()
{
- if (msg.getLength() > 2)
+ assert(mDelayed);
+ Possessions &poss = mClient->getPossessions();
+ if (mPoss != &poss)
+ {
+ delete mPoss;
+ mPoss = &poss;
+ }
+ restart();
+}
+
+void Inventory::update()
+{
+ if (mDelayed)
{
- if (mDelayed)
+ Possessions &poss = mClient->getPossessions();
+ if (mPoss != &poss)
{
- Possessions &poss = mClient->getPossessions();
- if (mPoss != &poss)
- {
- poss = *mPoss;
- delete mPoss;
- mPoss = &poss;
- }
+ poss = *mPoss;
+ delete mPoss;
+ mPoss = &poss;
}
+ }
+ if (mChangedLook)
+ {
+ mClient->raiseUpdateFlags(UPDATEFLAG_LOOKSCHANGE);
+ }
+}
+
+void Inventory::commit()
+{
+ if (msg.getLength() > 2)
+ {
+ update();
gameHandler->sendTo(mClient, msg);
- msg.clear();
- msg.writeShort(GPMSG_INVENTORY);
+ restart();
}
}
void Inventory::prepare()
{
- if (!mDelayed) return;
+ if (!mDelayed)
+ {
+ return;
+ }
Possessions &poss = mClient->getPossessions();
if (mPoss == &poss)
{
@@ -228,6 +244,11 @@ int Inventory::fillFreeSlot(int itemId, int amount, int maxPerSlot)
int Inventory::insert(int itemId, int amount)
{
+ if (itemId == 0 || amount == 0)
+ {
+ return 0;
+ }
+
prepare();
int maxPerSlot = ItemManager::getItem(itemId)->getMaxPerSlot();
@@ -285,25 +306,34 @@ void Inventory::freeIndex(int i)
{
InventoryItem &it = mPoss->inventory[i];
+ // Is it the last slot?
if (i == (int)mPoss->inventory.size() - 1)
{
mPoss->inventory.pop_back();
+ if (i > 0 && mPoss->inventory[i - 1].itemId == 0)
+ {
+ mPoss->inventory.pop_back();
+ }
+ return;
}
- else if (mPoss->inventory[i + 1].itemId == 0)
+
+ it.itemId = 0;
+
+ // First concatenate with an empty slot on the right.
+ if (mPoss->inventory[i + 1].itemId == 0)
{
- it.itemId = 0;
it.amount = mPoss->inventory[i + 1].amount + 1;
mPoss->inventory.erase(mPoss->inventory.begin() + i + 1);
}
else
{
- it.itemId = 0;
it.amount = 1;
}
+ // Then concatenate with an empty slot on the left.
if (i > 0 && mPoss->inventory[i - 1].itemId == 0)
{
- // Note: "it" is no longer a valid iterator.
+ // Note: "it" is no longer a valid reference, hence inventory[i] below.
mPoss->inventory[i - 1].amount += mPoss->inventory[i].amount;
mPoss->inventory.erase(mPoss->inventory.begin() + i);
}
@@ -311,6 +341,11 @@ void Inventory::freeIndex(int i)
int Inventory::remove(int itemId, int amount)
{
+ if (itemId == 0 || amount == 0)
+ {
+ return 0;
+ }
+
prepare();
for (int i = mPoss->inventory.size() - 1; i >= 0; --i)
@@ -346,6 +381,11 @@ int Inventory::remove(int itemId, int amount)
int Inventory::removeFromSlot(int slot, int amount)
{
+ if (amount == 0)
+ {
+ return 0;
+ }
+
int i = getIndex(slot);
if (i < 0)
{
@@ -374,6 +414,28 @@ int Inventory::removeFromSlot(int slot, int amount)
return amount;
}
+void Inventory::replaceInSlot(int slot, int itemId, int amount)
+{
+ int i = getIndex(slot);
+ assert(i >= 0);
+ prepare();
+
+ msg.writeByte(slot + EQUIP_CLIENT_INVENTORY);
+ if (itemId == 0 || amount == 0)
+ {
+ msg.writeShort(0);
+ freeIndex(i);
+ }
+ else
+ {
+ InventoryItem &it = mPoss->inventory[i];
+ it.itemId = itemId;
+ it.amount = amount;
+ msg.writeShort(itemId);
+ msg.writeByte(amount);
+ }
+}
+
void Inventory::equip(int slot)
{
int itemId = getItem(slot);
@@ -390,27 +452,27 @@ void Inventory::equip(int slot)
{
case ITEM_EQUIPMENT_TWO_HANDS_WEAPON:
{
- // Special case 1, the two one-handed weapons are to be placed back
- // in the inventory, if there are any.
- int id = mPoss->equipment[EQUIP_FIGHT1_SLOT];
- if (id && !insert(id, 1))
- {
- return;
- }
+ // The one-handed weapons are to be placed back in the inventory.
+ int id1 = mPoss->equipment[EQUIP_FIGHT1_SLOT],
+ id2 = mPoss->equipment[EQUIP_FIGHT2_SLOT];
- id = mPoss->equipment[EQUIP_FIGHT2_SLOT];
- if (id && !insert(id, 1))
+ if (id2)
{
- return;
+ if (id1 && insert(id1, 1) != 0)
+ {
+ return;
+ }
+ id1 = id2;
}
+ replaceInSlot(slot, id1, 1);
msg.writeByte(EQUIP_FIGHT1_SLOT);
msg.writeShort(itemId);
msg.writeByte(EQUIP_FIGHT2_SLOT);
msg.writeShort(0);
mPoss->equipment[EQUIP_FIGHT1_SLOT] = itemId;
mPoss->equipment[EQUIP_FIGHT2_SLOT] = 0;
- removeFromSlot(slot, 1);
+ mChangedLook = true;
return;
}
@@ -464,36 +526,20 @@ void Inventory::equip(int slot)
int id = mPoss->equipment[firstSlot];
- switch (availableSlots)
+ if (availableSlots == 2 && id && !mPoss->equipment[secondSlot] &&
+ ItemManager::getItem(id)->getType() != ITEM_EQUIPMENT_TWO_HANDS_WEAPON)
{
- case 2:
- if (id && !mPoss->equipment[secondSlot] &&
- ItemManager::getItem(id)->getType() !=
- ITEM_EQUIPMENT_TWO_HANDS_WEAPON)
- {
- // The first slot is full and the second slot is empty.
- msg.writeByte(secondSlot);
- msg.writeShort(itemId);
- mPoss->equipment[secondSlot] = itemId;
- removeFromSlot(slot, 1);
- return;
- }
- // no break!
-
- case 1:
- if (id && !insert(id, 1))
- {
- return;
- }
- msg.writeByte(firstSlot);
- msg.writeShort(itemId);
- mPoss->equipment[firstSlot] = itemId;
- removeFromSlot(slot, 1);
- return;
-
- default:
- return;
+ // The first equipment slot is full, but the second one is empty.
+ id = 0;
+ firstSlot = secondSlot;
}
+
+ // Put the item in the first equipment slot.
+ replaceInSlot(slot, id, 1);
+ msg.writeByte(firstSlot);
+ msg.writeShort(itemId);
+ mPoss->equipment[firstSlot] = itemId;
+ mChangedLook = true;
}
void Inventory::unequip(int slot)
@@ -503,16 +549,13 @@ void Inventory::unequip(int slot)
{
return;
}
+ // No need to prepare.
- prepare();
- msg.writeByte(slot);
- msg.writeShort(0);
- if (insert(itemId, 1))
- {
- cancel();
- }
- else
+ if (insert(itemId, 1) == 0)
{
+ msg.writeByte(slot);
+ msg.writeShort(0);
mPoss->equipment[slot] = 0;
+ mChangedLook = true;
}
}
diff --git a/src/game-server/inventory.hpp b/src/game-server/inventory.hpp
index e3a76561..c9a2643d 100644
--- a/src/game-server/inventory.hpp
+++ b/src/game-server/inventory.hpp
@@ -146,6 +146,16 @@ class Inventory
void prepare();
/**
+ * Updates the original in delayed mode.
+ */
+ void update();
+
+ /**
+ * Starts a new notification message.
+ */
+ void restart();
+
+ /**
* Fills some slots with items.
* @return number of items not inserted.
*/
@@ -166,10 +176,16 @@ class Inventory
*/
int getSlot(int index) const;
+ /**
+ * Replaces a whole slot of items from inventory.
+ */
+ void replaceInSlot(int slot, int itemId, int amount);
+
Possessions *mPoss; /**< Pointer to the modified possessions. */
MessageOut msg; /**< Update message containing all the changes. */
Character *mClient; /**< Character to notify. */
bool mDelayed; /**< Delayed changes. */
+ bool mChangedLook; /**< Need to notify of a visible equipment change. */
};
diff --git a/src/game-server/itemmanager.cpp b/src/game-server/itemmanager.cpp
index 80035847..0346ada7 100644
--- a/src/game-server/itemmanager.cpp
+++ b/src/game-server/itemmanager.cpp
@@ -106,6 +106,28 @@ void ItemManager::initialize(std::string const &itemReferenceFile)
modifiers.range = XML::getProperty(node, "range", 0);
modifiers.weaponType = XML::getProperty(node, "weapon_type", 0);
+ if (maxPerSlot == 0)
+ {
+ LOG_WARN("Item Manager: Missing max_per_slot property for "
+ "item " << id << " in " << itemReferenceFile << '.');
+ maxPerSlot = 1;
+ }
+
+ if (itemType > ITEM_USABLE && itemType < ITEM_EQUIPMENT_PROJECTILE &&
+ maxPerSlot != 1)
+ {
+ LOG_WARN("Item Manager: Setting max_per_slot property to 1 for "
+ "equipment " << id << " in " << itemReferenceFile << '.');
+ maxPerSlot = 1;
+ }
+
+ if (weight == 0)
+ {
+ LOG_WARN("Item Manager: Missing weight for item "
+ << id << " in " << itemReferenceFile << '.');
+ weight = 1;
+ }
+
ItemClass *item = new ItemClass(id, itemType);
item->setWeight(weight);
item->setCost(value);
@@ -116,17 +138,6 @@ void ItemManager::initialize(std::string const &itemReferenceFile)
itemClasses[id] = item;
++nbItems;
- if (maxPerSlot == 0)
- {
- LOG_WARN("Item Manager: Missing max per slot properties for item: "
- << id << " in " << itemReferenceFile << ".");
- }
- if (weight == 0)
- {
- LOG_WARN("Item Manager: Missing weight for item: "
- << id << " in " << itemReferenceFile << ".");
- }
-
LOG_DEBUG("Item: ID: " << id << ", itemType: " << itemType
<< ", weight: " << weight << ", value: " << value <<
", scriptName: " << scriptName << ", maxPerSlot: " << maxPerSlot << ".");