summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog17
-rw-r--r--src/Makefile.am2
-rw-r--r--src/account-server/account.hpp12
-rw-r--r--src/account-server/serverhandler.cpp25
-rw-r--r--src/account-server/serverhandler.hpp6
-rw-r--r--src/defines.h6
-rw-r--r--src/game-server/accountconnection.cpp29
-rw-r--r--src/game-server/gamehandler.cpp11
-rw-r--r--src/game-server/inventory.cpp417
-rw-r--r--src/game-server/inventory.hpp159
-rw-r--r--src/game-server/player.cpp2
-rw-r--r--src/game-server/player.hpp42
-rw-r--r--src/playerdata.cpp89
-rw-r--r--src/playerdata.hpp67
14 files changed, 391 insertions, 493 deletions
diff --git a/ChangeLog b/ChangeLog
index 1cdf3b18..745ac098 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2007-01-04 Guillaume Melquiond <guillaume.melquiond@gmail.com>
+
+ * src/playerdata.hpp, src/playerdata.cpp, src/defines.h,
+ src/Makefile.am: Factored serialization of PlayerData into a new file.
+ Added inventory to PlayerData. Removed counted pointers.
+ * src/account-server/serverhandler.hpp, src/account-server/account.hpp:
+ Moved counted pointers here.
+ * src/account-server/serverhandler.cpp,
+ src/game-server/accountconnection.cpp: Simplified by relying on the
+ serialization functionality of PlayerData.
+ * src/game-server/inventory.hpp, src/game-server/inventory.cpp:
+ Transformed Inventory into a strict helper class, as data are now stored
+ inside PlayerData. Reduced memory footprint of inventory by avoiding
+ storing empty slots.
+ * src/game-server/player.hpp, src/game-server/player.cpp,
+ src/game-server/gamehandler.cpp: Updated accordingly.
+
2007-01-04 Eugenio Favalli <elvenprogrammer@gmail.com>
* accountserver.cbp, gameserver.cbp,
diff --git a/src/Makefile.am b/src/Makefile.am
index 8f6f2c56..61901420 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -10,6 +10,7 @@ tmwserv_account_SOURCES = \
configuration.cpp \
defines.h \
playerdata.hpp \
+ playerdata.cpp \
point.h \
resourcemanager.h \
resourcemanager.cpp \
@@ -69,6 +70,7 @@ tmwserv_game_SOURCES = \
controller.cpp \
defines.h \
playerdata.hpp \
+ playerdata.cpp \
point.h \
resourcemanager.h \
resourcemanager.cpp \
diff --git a/src/account-server/account.hpp b/src/account-server/account.hpp
index a97158a7..e717e118 100644
--- a/src/account-server/account.hpp
+++ b/src/account-server/account.hpp
@@ -27,6 +27,18 @@
#include "defines.h"
#include "playerdata.hpp"
+#include "utils/countedptr.h"
+
+/**
+ * Type definition for a smart pointer to PlayerData.
+ */
+typedef utils::CountedPtr< PlayerData > PlayerPtr;
+
+/**
+ * Type definition for a list of Players.
+ */
+typedef std::vector< PlayerPtr > Players;
+
/**
* Notes:
diff --git a/src/account-server/serverhandler.cpp b/src/account-server/serverhandler.cpp
index 2a1af5ee..b7e51bce 100644
--- a/src/account-server/serverhandler.cpp
+++ b/src/account-server/serverhandler.cpp
@@ -75,18 +75,8 @@ void ServerHandler::registerGameClient(std::string const &token, PlayerPtr ptr)
MessageOut msg(AGMSG_PLAYER_ENTER);
msg.writeLong(ptr->getDatabaseID());
msg.writeString(ptr->getName());
- msg.writeByte(ptr->getGender());
- msg.writeByte(ptr->getHairStyle());
- msg.writeByte(ptr->getHairColor());
- msg.writeByte(ptr->getLevel());
- msg.writeShort(ptr->getMoney());
- for (int j = 0; j < NB_RSTAT; ++j)
- msg.writeShort(ptr->getRawStat(j));
- Point pos = ptr->getPos();
- msg.writeShort(pos.x);
- msg.writeShort(pos.y);
- msg.writeShort(mapId);
msg.writeString(token, 32);
+ ptr->serialize(msg);
Servers::const_iterator i = servers.find(mapId);
assert(i != servers.end());
i->second.server->send(msg);
@@ -130,18 +120,7 @@ void ServerHandler::processMessage(NetComputer *comp, MessageIn &msg)
int id = msg.readLong();
Storage &store = Storage::instance("tmw");
PlayerPtr ptr = store.getCharacter(id);
- ptr->setGender(msg.readByte());
- ptr->setHairStyle(msg.readByte());
- ptr->setHairColor(msg.readByte());
- ptr->setLevel(msg.readByte());
- ptr->setMoney(msg.readShort());
- for (int j = 0; j < NB_RSTAT; ++j)
- ptr->setRawStat(j, msg.readShort());
- int x = msg.readShort();
- int y = msg.readShort();
- Point pos = { x, y };
- ptr->setPos(pos);
- ptr->setMap(msg.readShort());
+ ptr->deserialize(msg);
} break;
case GAMSG_REDIRECT:
diff --git a/src/account-server/serverhandler.hpp b/src/account-server/serverhandler.hpp
index 1325b065..30dadd65 100644
--- a/src/account-server/serverhandler.hpp
+++ b/src/account-server/serverhandler.hpp
@@ -28,6 +28,12 @@
#include "playerdata.hpp"
#include "net/connectionhandler.hpp"
+#include "utils/countedptr.h"
+
+/**
+ * Type definition for a smart pointer to PlayerData.
+ */
+typedef utils::CountedPtr< PlayerData > PlayerPtr;
/**
* Manages communications with all the game servers. This class also keeps
diff --git a/src/defines.h b/src/defines.h
index 940f9322..6cceeaa8 100644
--- a/src/defines.h
+++ b/src/defines.h
@@ -178,10 +178,8 @@ enum {
// Inter-server
GAMSG_REGISTER = 0x500, // S address, W port, { W map id }*
AGMSG_ACTIVE_MAP = 0x501, // W map id
- AGMSG_PLAYER_ENTER = 0x510, // L id, S name, B gender, B hair style, B hair color, B level, W money,
- // W*6 stats, W x, W y, W map id, B*32 token
- GAMSG_PLAYER_DATA = 0x520, // L id, B gender, B hair style, B hair color, B level, W money,
- // W*6 stats, W x, W y, W map id
+ AGMSG_PLAYER_ENTER = 0x510, // L id, S name, B*32 token, B* player data
+ GAMSG_PLAYER_DATA = 0x520, // L id, B* player data
GAMSG_REDIRECT = 0x530, // L id
AGMSG_REDIRECT_RESPONSE = 0x531, // L id, B*32 token, S game address, W game port
diff --git a/src/game-server/accountconnection.cpp b/src/game-server/accountconnection.cpp
index d536abfc..68a1430f 100644
--- a/src/game-server/accountconnection.cpp
+++ b/src/game-server/accountconnection.cpp
@@ -57,17 +57,7 @@ void AccountConnection::sendPlayerData(PlayerData *p)
{
MessageOut msg(GAMSG_PLAYER_DATA);
msg.writeLong(p->getDatabaseID());
- msg.writeByte(p->getGender());
- msg.writeByte(p->getHairStyle());
- msg.writeByte(p->getHairColor());
- msg.writeByte(p->getLevel());
- msg.writeShort(p->getMoney());
- for (int j = 0; j < NB_RSTAT; ++j)
- msg.writeShort(p->getRawStat(j));
- Point pos = p->getPos();
- msg.writeShort(pos.x);
- msg.writeShort(pos.y);
- msg.writeShort(p->getMap());
+ p->serialize(msg);
send(msg);
}
@@ -79,21 +69,12 @@ void AccountConnection::processMessage(MessageIn &msg)
{
int id = msg.readLong();
std::string name = msg.readString();
+ std::string token = msg.readString(32);
Player *ptr = new Player(name, id);
- ptr->setGender(msg.readByte());
- ptr->setHairStyle(msg.readByte());
- ptr->setHairColor(msg.readByte());
- ptr->setLevel(msg.readByte());
- ptr->setMoney(msg.readShort());
- for (int j = 0; j < NB_RSTAT; ++j)
- ptr->setRawStat(j, msg.readShort());
- int x = msg.readShort();
- int y = msg.readShort();
- Point pos = { x, y };
- ptr->setPosition(pos);
- ptr->setMapId(msg.readShort());
+ ptr->deserialize(msg);
+ ptr->setMapId(ptr->getMap());
+ ptr->setPosition(ptr->getPos());
ptr->setSpeed(150); // TODO
- std::string token = msg.readString(32);
registerGameClient(token, ptr);
} break;
diff --git a/src/game-server/gamehandler.cpp b/src/game-server/gamehandler.cpp
index 08e043f1..7478e8d1 100644
--- a/src/game-server/gamehandler.cpp
+++ b/src/game-server/gamehandler.cpp
@@ -233,6 +233,7 @@ void GameHandler::processMessage(NetComputer *comp, MessageIn &message)
case PGMSG_PICKUP:
{
+ /*
// add item to inventory (this is too simplistic atm)
int itemId = message.readLong();
@@ -242,10 +243,12 @@ void GameHandler::processMessage(NetComputer *comp, MessageIn &message)
computer.character->insertItem(itemId, 1);
result.writeShort(GPMSG_PICKUP_RESPONSE);
result.writeByte(ERRMSG_OK);
+ */
} break;
case PGMSG_USE_ITEM:
{
+ /*
int itemId = message.readLong();
result.writeShort(GPMSG_USE_RESPONSE);
@@ -258,6 +261,7 @@ void GameHandler::processMessage(NetComputer *comp, MessageIn &message)
} else {
result.writeByte(ERRMSG_FAILURE);
}
+ */
} break;
case PGMSG_WALK:
@@ -272,12 +276,9 @@ void GameHandler::processMessage(NetComputer *comp, MessageIn &message)
case PGMSG_EQUIP:
{
- message.readLong(); // ItemId: Not useful, the inventory knows it
int slot = message.readByte();
-
- result.writeShort(GPMSG_EQUIP_RESPONSE);
- result.writeByte(computer.character->equip(slot) ?
- ERRMSG_OK : ERRMSG_FAILURE);
+ result.writeShort(GPMSG_EQUIP_RESPONSE); // TODO: something else
+ Inventory(computer.character, result).equip(slot);
} break;
case PGMSG_ATTACK:
diff --git a/src/game-server/inventory.cpp b/src/game-server/inventory.cpp
index c5913e15..4807d4ff 100644
--- a/src/game-server/inventory.cpp
+++ b/src/game-server/inventory.cpp
@@ -21,255 +21,217 @@
* $Id$
*/
+#include <algorithm>
#include <cassert>
#include "game-server/inventory.hpp"
#include "game-server/itemmanager.hpp"
-// ---------
-// Items
-// ---------
-int Inventory::getInventoryFreeSlot()
+int Inventory::getItem(int slot)
{
- for (int a = 0; a < MAX_ITEMS_IN_INVENTORY; a++)
+ for (std::vector< InventoryItem >::iterator i = poss.inventory.begin(),
+ i_end = poss.inventory.end(); i != i_end; ++i)
{
- if (itemList[a].amount == 0)
- return a;
- }
- return INVENTORY_FULL;
-}
+ if (slot == 0)
+ {
+ return i->itemId;
+ }
-int Inventory::getSlotFromId(int itemId)
-{
- for (int a = 0; a < MAX_ITEMS_IN_INVENTORY; a++)
- {
- if (itemList[a].itemId == itemId)
- return a;
+ slot -= i->itemId ? 1 : i->amount;
+
+ if (slot < 0)
+ {
+ return 0;
+ }
}
- return INVENTORY_FULL;
+ return 0;
}
-bool Inventory::hasItem(int itemId,
- bool searchInInventory,
- bool searchInEquipment)
+int Inventory::getIndex(int slot)
{
- bool hasItem = false;
- // Search in inventory
- if (searchInInventory)
+ int index = 0;
+ for (std::vector< InventoryItem >::iterator i = poss.inventory.begin(),
+ i_end = poss.inventory.end(); i != i_end; ++i, ++index)
{
- std::vector<StoredItem>::iterator iter = itemList.begin();
- for (iter = itemList.begin(); iter != itemList.end(); ++iter)
+ if (slot == 0)
{
- if (iter->itemId == itemId)
- hasItem = true;
+ return index;
}
- }
- // Search in equipment
- if (searchInEquipment)
- {
- std::vector<EquippedItem>::iterator equipIter = equippedItemList.begin();
- for (equipIter = equippedItemList.begin();
- equipIter != equippedItemList.end();
- ++equipIter)
+
+ slot -= i->itemId ? 1 : i->amount;
+
+ if (slot < 0)
{
- if (equipIter->itemId == itemId)
- hasItem = true;
+ return -1;
}
- if (equippedProjectiles.itemId == itemId)
- hasItem = true;
}
- return hasItem;
+ return -1;
}
-int Inventory::insertItem(int itemId, int amount)
+int Inventory::fillFreeSlot(int itemId, int amount, int maxPerSlot)
{
- if (amount <= 0)
+ int slot = 0;
+ for (int i = 0, i_end = poss.inventory.size(); i < i_end; ++i)
{
- return 0;
- }
-
- // We get the max number of item we can have in the same slot
- // for the given item.
- int maxPerSlot = itemManager->getItem(itemId)->getMaxPerSlot();
- // We'll add items in slots with the item type and in free slots
- // until it's all done or until the inventory will be all parsed.
- // Searching for items with the same Id in the inventory, before
- // seeking a free slot.
- int amountToAdd = amount;
-
- // Parsing inventory
- for (std::vector< StoredItem >::iterator iter = itemList.begin(),
- iter_end = itemList.end(); iter != iter_end; ++iter)
- {
- int currentAmountInSlot = iter->amount;
- // If a slot has got place for some more of such an item.
- if (iter->itemId == itemId && currentAmountInSlot < maxPerSlot)
+ InventoryItem &it = poss.inventory[i];
+ if (it.itemId == 0)
{
- // If there isn't enough space to put every item in the slot.
- // We add the difference.
- int possibleAmount = maxPerSlot - currentAmountInSlot;
- assert(possibleAmount > 0);
- if (possibleAmount < amountToAdd)
- {
- iter->amount += possibleAmount;
- amountToAdd -= possibleAmount;
- }
- else // there is enough to add everything.
+ int nb = std::min(amount, maxPerSlot);
+ if (it.amount <= 1)
{
- iter->amount += amountToAdd;
- amountToAdd = 0; // Ok!
- break;
+ it.itemId = itemId;
+ it.amount = nb;
}
- }
- // Or if there is an empty slot.
- else if (iter->amount == 0)
- {
- // We add the item in the new slot (setting also the Id.)
- iter->itemId = itemId;
- if (maxPerSlot < amountToAdd)
+ else
{
- iter->amount = maxPerSlot;
- amountToAdd -= maxPerSlot;
+ --it.amount;
+ InventoryItem iu = { itemId, nb };
+ poss.inventory.insert(poss.inventory.begin() + i, iu);
+ ++i_end;
}
- else
+
+ // TODO: fill msg
+ amount -= nb;
+ if (amount == 0)
{
- iter->amount += amountToAdd;
- amountToAdd = 0; // Ok!
- break;
+ return 0;
}
}
+ ++slot;
}
- return amount - amountToAdd;
-}
-
-int Inventory::removeItemById(int itemId, int amount)
-{
- if (amount <= 0)
+ while (slot < INVENTORY_SLOTS - 1 && amount > 0)
{
- return 0;
+ int nb = std::min(amount, maxPerSlot);
+ amount -= nb;
+ InventoryItem it = { itemId, nb };
+ poss.inventory.push_back(it);
+ ++slot;
+ // TODO: fill msg
}
- // We'll remove items in slots with the item type
- // until it's all done or until the inventory will be all parsed.
- // Searching for items with the same Id in the inventory
- int amountToRemove = amount;
+ return amount;
+}
- // Parsing inventory
- for (std::vector< StoredItem >::iterator iter = itemList.begin(),
- iter_end = itemList.end(); iter != iter_end; ++iter)
+int Inventory::insert(int itemId, int amount)
+{
+ int maxPerSlot = itemManager->getItem(itemId)->getMaxPerSlot();
+
+ for (std::vector< InventoryItem >::iterator i = poss.inventory.begin(),
+ i_end = poss.inventory.end(); i != i_end; ++i)
{
- int currentAmountInSlot = iter->amount;
- // If a slot has got such an item, remove it
- if (iter->itemId == itemId && currentAmountInSlot > 0)
+ if (i->itemId == itemId)
{
- // If there isn't enough to finish, we remove the difference
- // Emptying the slot, so we clean also the itemId.
- if (currentAmountInSlot <= amountToRemove)
+ int nb = std::min(maxPerSlot - i->amount, amount);
+ i->amount += nb;
+ amount -= nb;
+ // TODO: fill msg
+ if (amount == 0)
{
- amountToRemove -= currentAmountInSlot;
- iter->amount = 0;
- iter->itemId = 0;
- }
- else // there is enough to remove everything.
- {
- iter->amount -= amountToRemove;
- amountToRemove = 0; // Ok!
- break;
+ return 0;
}
}
}
- return amount - amountToRemove;
+
+ return amount > 0 ? fillFreeSlot(itemId, amount, maxPerSlot) : 0;
}
-int Inventory::removeItemBySlot(int slot, int amount)
+void Inventory::freeIndex(int i)
{
- if (amount <= 0)
+ InventoryItem &it = poss.inventory[i];
+
+ if (i == (int)poss.inventory.size() - 1)
{
- return 0;
+ poss.inventory.pop_back();
}
-
- if (itemList[slot].amount < amount)
+ else if (poss.inventory[i + 1].itemId == 0)
{
- int value = itemList[slot].amount;
- itemList[slot].amount = 0;
- return value;
+ it.itemId = 0;
+ it.amount = poss.inventory[i + 1].amount + 1;
+ poss.inventory.erase(poss.inventory.begin() + i + 1);
}
else
{
- itemList[slot].amount -= amount;
- return amount;
+ it.itemId = 0;
+ it.amount = 1;
+ }
+
+ if (i > 0 && poss.inventory[i - 1].itemId == 0)
+ {
+ // Note: "it" is no longer a valid iterator.
+ poss.inventory[i - 1].amount += poss.inventory[i].amount;
+ poss.inventory.erase(poss.inventory.begin() + i);
+ }
+}
+
+int Inventory::remove(int itemId, int amount)
+{
+ for (int i = poss.inventory.size() - 1; i >= 0; --i)
+ {
+ InventoryItem &it = poss.inventory[i];
+ if (it.itemId == itemId)
+ {
+ int nb = std::min((int)it.amount, amount);
+ it.amount -= nb;
+ amount -= nb;
+ // TODO: fill msg
+
+ // If the slot is empty, compress the inventory.
+ if (it.amount == 0)
+ {
+ freeIndex(i);
+ }
+
+ if (amount == 0)
+ {
+ return 0;
+ }
+ }
}
+
+ return amount;
}
-// ---------
-// Equipment
-// ---------
-int Inventory::equipItem(int itemId)
+bool Inventory::equip(int slot)
{
- // First, we look for the item in the player's inventory.
- if (!hasItem(itemId, true, false))
+ int itemId = getItem(slot);
+ if (!itemId)
+ {
return false;
+ }
int availableSlots = 0, firstSlot = 0, secondSlot = 0;
- int itemType = itemManager->getItem(itemId)->getType();
- switch (itemType)
+ switch (itemManager->getItem(itemId)->getType())
{
case ITEM_EQUIPMENT_TWO_HANDS_WEAPON:
- // Special case 1, the two one-handed weapons are to be placed back
- // in the inventory, if there are any.
- if (equippedItemList[EQUIP_FIGHT1_SLOT].itemId > 0)
- { // Slot 1 full
- // old two-handed weapon case:
- if (equippedItemList[EQUIP_FIGHT1_SLOT].itemType
- == ITEM_EQUIPMENT_TWO_HANDS_WEAPON)
+ // Special case 1, the two one-handed weapons are to be placed back
+ // in the inventory, if there are any.
+ if (int id = poss.equipment[EQUIP_FIGHT1_SLOT])
+ {
+ // Slot 1 full
+ if (!insert(id, 1))
{
- equippedItemList[EQUIP_FIGHT2_SLOT].itemId = 0;
- equippedItemList[EQUIP_FIGHT2_SLOT].itemType = 0;
+ return false;
}
-
- if (unequipItem_(equippedItemList[EQUIP_FIGHT1_SLOT].itemId,
- EQUIP_FIGHT1_SLOT) == INVENTORY_FULL)
- return INVENTORY_FULL;
- }
- if (equippedItemList[EQUIP_FIGHT2_SLOT].itemId > 0)
- { // Slot 2 full
- if (unequipItem_(equippedItemList[EQUIP_FIGHT2_SLOT].itemId,
- EQUIP_FIGHT2_SLOT) == INVENTORY_FULL)
- return INVENTORY_FULL;
- }
- // Only the slot 1 needs to be updated.
- return equipItem_(itemId, itemType, EQUIP_FIGHT1_SLOT);
- break;
-
- case ITEM_EQUIPMENT_PROJECTILE:
- // Special case 2: the projectile is a Stored Item structure,
- // but is still considered as part of the equipment.
- // Case 1: Reloading
- if (equippedProjectiles.itemId == itemId)
- {
- equippedProjectiles.amount +=
- removeItemById(itemId, 255 - equippedProjectiles.amount);
- return EQUIP_PROJECTILES_SLOT;
}
- else // Case 2: Changing projectiles.
+ if (int id = poss.equipment[EQUIP_FIGHT2_SLOT])
{
- int added = insertItem(equippedProjectiles.itemId,
- equippedProjectiles.amount);
- if (added == equippedProjectiles.amount)
- { // Ok, we can equip
- equippedProjectiles.itemId = itemId;
- equippedProjectiles.amount = removeItemById(itemId, 255);
- return EQUIP_PROJECTILES_SLOT;
- }
- else // Some were unequipped.
+ // Slot 2 full
+ if (!insert(id, 1))
{
- equippedProjectiles.amount -= added;
- return INVENTORY_FULL;
+ return false;
}
}
- break;
+
+ poss.equipment[EQUIP_FIGHT1_SLOT] = itemId;
+ poss.equipment[EQUIP_FIGHT2_SLOT] = 0;
+ freeIndex(getIndex(slot));
+ return true;
+
+ case ITEM_EQUIPMENT_PROJECTILE:
+ poss.equipment[EQUIP_PROJECTILE_SLOT] = itemId;
+ return true;
case ITEM_EQUIPMENT_ONE_HAND_WEAPON:
case ITEM_EQUIPMENT_SHIELD:
@@ -310,88 +272,35 @@ int Inventory::equipItem(int itemId)
case ITEM_UNUSABLE:
case ITEM_USABLE:
default:
- return NOT_EQUIPPABLE;
+ return false;
}
+ int id = poss.equipment[firstSlot];
+
switch (availableSlots)
{
- case 1:
- if (equippedItemList[firstSlot].itemId > 0)
- {
- if (unequipItem_(equippedItemList[firstSlot].itemId,
- firstSlot) != INVENTORY_FULL)
- return equipItem_(itemId, itemType, firstSlot);
- else
- return INVENTORY_FULL;
- }
- else // slot empty, we can equip.
- {
- return equipItem_(itemId, itemType, firstSlot);
- }
- break;
-
case 2:
- if (equippedItemList[firstSlot].itemId > 0)
- {
- // If old weapon is two-handed one, we can unequip
- // the first slot only, and clean the second.
- if (equippedItemList[firstSlot].itemId ==
+ if (id && !poss.equipment[secondSlot] &&
+ itemManager->getItem(id)->getType() !=
ITEM_EQUIPMENT_TWO_HANDS_WEAPON)
- {
- if (unequipItem_(equippedItemList[firstSlot].itemId,
- firstSlot) != INVENTORY_FULL)
- return equipItem_(itemId, itemType, firstSlot);
- else
- return INVENTORY_FULL;
- }
-
- if (equippedItemList[secondSlot].itemId > 0)
- { // Both slots are full,
- // we remove the first one to equip
- if (unequipItem_(equippedItemList[firstSlot].itemId,
- firstSlot) != INVENTORY_FULL)
- return equipItem_(itemId, itemType, firstSlot);
- else
- return INVENTORY_FULL;
- }
- else // Second slot empty, we can equip.
- {
- return equipItem_(itemId, itemType, secondSlot);
- }
+ {
+ // The first slot is full and the second slot is empty.
+ poss.equipment[secondSlot] = itemId;
+ freeIndex(getIndex(slot));
+ return true;
}
- else // first slot empty, we can equip.
+ // no break!
+
+ case 1:
+ if (id && !insert(id, 1))
{
- return equipItem_(itemId, itemType, firstSlot);
+ return false;
}
- break;
+ poss.equipment[firstSlot] = itemId;
+ freeIndex(getIndex(slot));
+ return true;
default:
- return NOT_EQUIPPABLE;
- }
-}
-
-int Inventory::equipItem_(int itemId,
- int itemType,
- int equipmentSlot)
-{
- if (removeItemById(itemId, 1) == 1)
- {
- equippedItemList[equipmentSlot].itemId = itemId;
- equippedItemList[equipmentSlot].itemType = itemType;
- return equipmentSlot;
- }
- else
- return NO_ITEM_TO_EQUIP;
-}
-
-int Inventory::unequipItem_(int itemId, int equipmentSlot)
-{
- if (insertItem(itemId, 1) == 1)
- {
- equippedItemList[equipmentSlot].itemId = 0;
- equippedItemList[equipmentSlot].itemType = 0;
- return equipmentSlot;
- }
- else
- return INVENTORY_FULL;
+ return false;
+ }
}
diff --git a/src/game-server/inventory.hpp b/src/game-server/inventory.hpp
index 1fa66373..87c1010c 100644
--- a/src/game-server/inventory.hpp
+++ b/src/game-server/inventory.hpp
@@ -24,12 +24,10 @@
#ifndef INVENTORY_H
#define INVENTORY_H
-#include "game-server/being.hpp"
+#include "playerdata.hpp"
enum
{
-// items in inventory :
- MAX_ITEMS_IN_INVENTORY = 50, // Max 252.
// Equipment rules:
// 1 Brest equipment
EQUIP_BREST_SLOT = 0,
@@ -47,158 +45,69 @@ enum
// 1 necklace
EQUIP_NECKLACE_SLOT = 7,
// Fight:
-// 2 one-handed weapons
+// 2 one-handed weapons
+// or 1 two-handed weapon
+// or 1 one-handed weapon + 1 shield.
EQUIP_FIGHT1_SLOT = 8,
EQUIP_FIGHT2_SLOT = 9,
-// or 1 two-handed weapon
-// or 1 one-handed weapon + 1 shield.
-// Projectiles
- EQUIP_PROJECTILES_SLOT = 10,
-// = 10 total slots for equipment.
- TOTAL_EQUIPMENT_SLOTS = 11,
+// Projectile:
+// this item does not amount to one, it only indicates the chosen projectile.
+ EQUIP_PROJECTILE_SLOT = 10,
+
// Error codes
NOT_EQUIPPABLE = 253,
NO_ITEM_TO_EQUIP = 254,
INVENTORY_FULL = 255
};
-/**
- * Stored Item only contains id reference to items
- * in the order not to carry every item info for each carried items
- * in the inventory.
- * Also contains amount.
- */
-struct StoredItem
-{
- int itemId;
- unsigned char amount;
-};
-
-/**
- * Equipped items that keeps which kind of item is in equipment.
- */
-struct EquippedItem
-{
- int itemId;
- short itemType;
-};
+class MessageOut;
/**
- * Class used to store minimal info on player's inventories
- * to keep it fast.
- * See Item and ItemManager to get more info on an item.
+ * Class used to handle Player possessions and prepare outgoing messages.
*/
class Inventory
{
+ Possessions &poss;
+ MessageOut &msg;
public:
- /**
- * Convenience function to get slot from ItemId.
- * If more than one occurence is found, the first is given.
- */
- int getSlotFromId(int itemId);
+ Inventory(PlayerData *p, MessageOut &m)
+ : poss(p->getPossessions()), msg(m)
+ {}
/**
- * Returns item.
+ * Equips item from given inventory slot.
*/
- StoredItem const &getStoredItemAt(int slot) const
- { return itemList[slot]; };
+ bool equip(int slot);
/**
- * Looks in inventory and equipment whether an item is present or not.
+ * Gets the ID of projectiles. Removes one of these projectiles from
+ * inventory.
*/
- bool hasItem(int itemId,
- bool searchInInventory = true,
- bool searchInEquipment = true);
+ int fireProjectile();
/**
- * Tells an item's amount
+ * Inserts some items into the inventory.
+ * @return number of items not inserted (to be dropped on floor?).
*/
- int getItemAmount(int slot) const
- { return itemList[slot].amount; };
+ int insert(int itemId, int amount);
/**
- * Returns item reference ID.
+ * Removes some items from inventory.
+ * @return number of items not removed.
*/
- int getItemId(int slot) const
- { return itemList[slot].itemId; };
-
- /**
- * Adds a given amount of items.
- * @return Number of items really added.
- */
- int insertItem(int itemId, int amount = 1);
-
- /**
- * Removes an item given by ID.
- * @return Number of items really removed.
- */
- int removeItemById(int itemId, int amount);
-
- /**
- * Removes an item given by slot.
- * @return Number of items really removed.
- */
- int removeItemBySlot(int slot, int amount);
-
- /**
- * Equip an item searched by its id.
- * Can equip more than one item at a time.
- * @return unsigned char value: Returns the slot if successful
- * or the error code if not.
- */
- int equipItem(int itemId);
-
- /**
- * Unequip an item searched by its id.
- * Can unequip more than one item at a time.
- */
- bool unequipItem(int itemId);
-
- /**
- * Equips an item searched by its slot index.
- */
- bool equipItem(int inventorySlot, int equipmentSlot);
-
- /**
- * Unequips an equipped item searched by its slot index.
- */
- bool unequipItem(int inventorySlot, int equipmentSlot);
+ int remove(int itemId, int amount);
+ int countItem(int itemId);
private:
-
/**
- * Gives the first free slot number in itemList.
+ * Fills some slots with items.
+ * @return number of items not inserted.
*/
- int getInventoryFreeSlot();
-
- /**
- * Quick equip an equipment with a given equipSlot,
- * an itemId and an itemType.
- * @return the equipment slot if successful,
- * the error code, if not.
- */
- int equipItem_(int itemId,
- int itemType,
- int equipmentSlot);
-
- /**
- * Quick unequip an equipment with a given equipSlot,
- * and an itemId.
- * @return the Equipment slot if successful,
- * the error code, if not.
- */
- int unequipItem_(int itemId,
- int equipmentSlot);
-
-
- // Stored items in inventory and equipment
- std::vector<StoredItem> itemList; /**< Items in inventory */
- std::vector<EquippedItem> equippedItemList; /**< Equipped Items */
- /**
- * Used to know which type of arrow is used with a bow,
- * for instance
- */
- StoredItem equippedProjectiles;
+ int fillFreeSlot(int itemId, int amount, int MaxPerSlot);
+ void freeIndex(int index);
+ int getItem(int slot);
+ int getIndex(int slot);
};
+
#endif
diff --git a/src/game-server/player.cpp b/src/game-server/player.cpp
index 99884661..1f6fc935 100644
--- a/src/game-server/player.cpp
+++ b/src/game-server/player.cpp
@@ -56,6 +56,7 @@ void Player::update()
}
}
+/*
bool Player::insertItem(int itemId, int amount)
{
return inventory.insertItem(itemId, amount);
@@ -80,3 +81,4 @@ bool Player::unequip(int slot)
{
return false; // TODO
}
+*/
diff --git a/src/game-server/player.hpp b/src/game-server/player.hpp
index eaf4d9e9..63bf06c7 100644
--- a/src/game-server/player.hpp
+++ b/src/game-server/player.hpp
@@ -49,47 +49,6 @@ class Player : public Being, public PlayerData
void update();
/**
- * Sets inventory.
- */
- void setInventory(Inventory const &inven)
- { inventory = inven; }
-
- /**
- * Adds item with ID to inventory.
- *
- * @return Item add success/failure
- */
- bool insertItem(int itemId, int amount);
-
- /**
- * Removes item with ID from inventory.
- *
- * @return Item delete success/failure
- */
- bool removeItem(int itemId, int amount);
-
- /**
- * Checks if character has an item.
- *
- * @return true if being has item, false otherwise
- */
- bool hasItem(int itemId);
-
- /**
- * Equips item with ID in equipment slot.
- *
- * @return Equip success/failure
- */
- bool equip(int slot);
-
- /**
- * Un-equips item.
- *
- * @return Un-equip success/failure
- */
- bool unequip(int slot);
-
- /**
* Set attacking state
**/
void setAttacking(bool isAttacking)
@@ -112,7 +71,6 @@ class Player : public Being, public PlayerData
Player &operator=(Player const &);
GameClient *mClient; /**< Client computer. */
- Inventory inventory; /**< Player inventory and equipment. */
bool mIsAttacking; /**< Attacking state. */
};
diff --git a/src/playerdata.cpp b/src/playerdata.cpp
new file mode 100644
index 00000000..1b9760d2
--- /dev/null
+++ b/src/playerdata.cpp
@@ -0,0 +1,89 @@
+/*
+ * The Mana World Server
+ * Copyright 2007 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with The Mana World; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "playerdata.hpp"
+#include "net/messagein.hpp"
+#include "net/messageout.hpp"
+
+PlayerData::PlayerData(std::string const &name, int id)
+ : mDatabaseID(id),
+ mName(name)
+{
+ for (int j = 0; j < EQUIPMENT_SLOTS; ++j)
+ {
+ mPossessions.equipment[j] = 0;
+ }
+}
+
+void PlayerData::serialize(MessageOut &msg) const
+{
+ msg.writeByte(mGender);
+ msg.writeByte(mHairStyle);
+ msg.writeByte(mHairColor);
+ msg.writeByte(mLevel);
+ msg.writeShort(mMoney);
+ for (int j = 0; j < NB_RSTAT; ++j)
+ {
+ msg.writeByte(mRawStats.stats[j]);
+ }
+ msg.writeShort(mMapId);
+ msg.writeShort(mPos.x);
+ msg.writeShort(mPos.y);
+ for (int j = 0; j < EQUIPMENT_SLOTS; ++j)
+ {
+ msg.writeShort(mPossessions.equipment[j]);
+ }
+ for (std::vector< InventoryItem >::const_iterator j = mPossessions.inventory.begin(),
+ j_end = mPossessions.inventory.end(); j != j_end; ++j)
+ {
+ msg.writeShort(j->itemId);
+ msg.writeByte(j->amount);
+ }
+}
+
+void PlayerData::deserialize(MessageIn &msg)
+{
+ mGender = msg.readByte();
+ mHairStyle = msg.readByte();
+ mHairColor = msg.readByte();
+ mLevel = msg.readByte();
+ mMoney = msg.readShort();
+ for (int j = 0; j < NB_RSTAT; ++j)
+ {
+ mRawStats.stats[j] = msg.readByte();
+ }
+ mMapId = msg.readShort();
+ mPos.x = msg.readShort();
+ mPos.y = msg.readShort();
+ for (int j = 0; j < EQUIPMENT_SLOTS; ++j)
+ {
+ mPossessions.equipment[j] = msg.readShort();
+ }
+ mPossessions.inventory.clear();
+ while (msg.getUnreadLength())
+ {
+ InventoryItem i;
+ i.itemId = msg.readShort();
+ i.amount = msg.readByte();
+ mPossessions.inventory.push_back(i);
+ }
+}
diff --git a/src/playerdata.hpp b/src/playerdata.hpp
index cc4a4b46..a7fffe99 100644
--- a/src/playerdata.hpp
+++ b/src/playerdata.hpp
@@ -27,7 +27,9 @@
#include <vector>
#include "point.h"
-#include "utils/countedptr.h"
+
+class MessageIn;
+class MessageOut;
/**
* Gender of a Player.
@@ -53,22 +55,48 @@ enum
};
/**
- * Structure types for the raw statistics of a Player.
+ * Structure storing the raw statistics of a Player.
*/
struct RawStatistics
{
unsigned short stats[NB_RSTAT];
};
+/**
+ * Numbers of inventory slots
+ */
+
+enum
+{
+ EQUIPMENT_SLOTS = 11,
+ INVENTORY_SLOTS = 50
+};
+
+/**
+ * Structure storing an item in the inventory.
+ * When the itemId, it represents "amount" consecutive empty slots.
+ */
+
+struct InventoryItem
+{
+ unsigned short itemId;
+ unsigned char amount;
+};
+
+/**
+ * Structure storing the equipment and inventory of a Player.
+ */
+struct Possessions
+{
+ unsigned short equipment[EQUIPMENT_SLOTS];
+ std::vector< InventoryItem > inventory;
+};
class PlayerData
{
public:
- PlayerData(std::string const &name, int id = -1)
- : mDatabaseID(id),
- mName(name)
- {}
+ PlayerData(std::string const &name, int id = -1);
/**
* Gets the name.
@@ -221,6 +249,22 @@ class PlayerData
Point const &getPos() const
{ return mPos; }
+ /**
+ * Gets a reference on the possession.
+ */
+ Possessions &getPossessions()
+ { return mPossessions; }
+
+ /**
+ * Stores data into a packet.
+ */
+ void serialize(MessageOut &) const;
+
+ /**
+ * Restores data from a packet.
+ */
+ void deserialize(MessageIn &);
+
private:
PlayerData(PlayerData const &);
PlayerData &operator=(PlayerData const &);
@@ -235,16 +279,7 @@ class PlayerData
Point mPos; /**< Position the being is at. */
unsigned int mMoney; /**< Wealth of the being. */
RawStatistics mRawStats; /**< Raw statistics of the being. */
+ Possessions mPossessions; /**< Possesssions of the being. */
};
-/**
- * Type definition for a smart pointer to PlayerData.
- */
-typedef utils::CountedPtr< PlayerData > PlayerPtr;
-
-/**
- * Type definition for a list of Players.
- */
-typedef std::vector< PlayerPtr > Players;
-
#endif