summaryrefslogtreecommitdiff
path: root/src/game-server
diff options
context:
space:
mode:
authorGuillaume Melquiond <guillaume.melquiond@gmail.com>2007-01-03 17:10:43 +0000
committerGuillaume Melquiond <guillaume.melquiond@gmail.com>2007-01-03 17:10:43 +0000
commit1673de8b5553f6dcd4898c84b8d44ba8b30740f1 (patch)
tree3dcc47461a6b4914c4e81492e7be885c3a1502ea /src/game-server
parent6b7441516002d6e7cca424416bb67c6bc7d7c9d2 (diff)
downloadmanaserv-1673de8b5553f6dcd4898c84b8d44ba8b30740f1.tar.gz
manaserv-1673de8b5553f6dcd4898c84b8d44ba8b30740f1.tar.bz2
manaserv-1673de8b5553f6dcd4898c84b8d44ba8b30740f1.tar.xz
manaserv-1673de8b5553f6dcd4898c84b8d44ba8b30740f1.zip
Split persistent player data from game server data. Enabled inventory code back.
Diffstat (limited to 'src/game-server')
-rw-r--r--src/game-server/accountconnection.cpp10
-rw-r--r--src/game-server/accountconnection.hpp4
-rw-r--r--src/game-server/being.cpp87
-rw-r--r--src/game-server/being.hpp214
-rw-r--r--src/game-server/gamehandler.cpp6
-rw-r--r--src/game-server/gamehandler.hpp2
-rw-r--r--src/game-server/inventory.cpp419
-rw-r--r--src/game-server/inventory.hpp233
-rw-r--r--src/game-server/itemmanager.cpp4
-rw-r--r--src/game-server/map.cpp302
-rw-r--r--src/game-server/map.hpp174
-rw-r--r--src/game-server/mapcomposite.cpp6
-rw-r--r--src/game-server/mapcomposite.hpp11
-rw-r--r--src/game-server/mapmanager.cpp2
-rw-r--r--src/game-server/mapreader.cpp2
-rw-r--r--src/game-server/object.cpp79
-rw-r--r--src/game-server/object.hpp258
-rw-r--r--src/game-server/player.cpp87
-rw-r--r--src/game-server/player.hpp124
-rw-r--r--src/game-server/state.cpp3
-rw-r--r--src/game-server/trigger.cpp2
-rw-r--r--src/game-server/trigger.hpp2
22 files changed, 2004 insertions, 27 deletions
diff --git a/src/game-server/accountconnection.cpp b/src/game-server/accountconnection.cpp
index ceb0b5dd..d536abfc 100644
--- a/src/game-server/accountconnection.cpp
+++ b/src/game-server/accountconnection.cpp
@@ -23,10 +23,10 @@
#include "configuration.h"
#include "defines.h"
-#include "player.h"
#include "game-server/accountconnection.hpp"
#include "game-server/gamehandler.hpp"
#include "game-server/mapmanager.hpp"
+#include "game-server/player.hpp"
#include "net/messagein.hpp"
#include "net/messageout.hpp"
#include "utils/logger.h"
@@ -53,7 +53,7 @@ bool AccountConnection::start()
return true;
}
-void AccountConnection::sendPlayerData(Player *p)
+void AccountConnection::sendPlayerData(PlayerData *p)
{
MessageOut msg(GAMSG_PLAYER_DATA);
msg.writeLong(p->getDatabaseID());
@@ -64,10 +64,10 @@ void AccountConnection::sendPlayerData(Player *p)
msg.writeShort(p->getMoney());
for (int j = 0; j < NB_RSTAT; ++j)
msg.writeShort(p->getRawStat(j));
- Point pos = p->getPosition();
+ Point pos = p->getPos();
msg.writeShort(pos.x);
msg.writeShort(pos.y);
- msg.writeShort(p->getMapId());
+ msg.writeShort(p->getMap());
send(msg);
}
@@ -80,7 +80,7 @@ void AccountConnection::processMessage(MessageIn &msg)
int id = msg.readLong();
std::string name = msg.readString();
Player *ptr = new Player(name, id);
- ptr->setGender((Gender)msg.readByte());
+ ptr->setGender(msg.readByte());
ptr->setHairStyle(msg.readByte());
ptr->setHairColor(msg.readByte());
ptr->setLevel(msg.readByte());
diff --git a/src/game-server/accountconnection.hpp b/src/game-server/accountconnection.hpp
index 9722fe69..e418a111 100644
--- a/src/game-server/accountconnection.hpp
+++ b/src/game-server/accountconnection.hpp
@@ -26,7 +26,7 @@
#include "net/connection.hpp"
-class Player;
+class PlayerData;
/**
* A connection to the account server.
@@ -43,7 +43,7 @@ class AccountConnection: public Connection
/**
* Sends data of given player.
*/
- void sendPlayerData(Player *);
+ void sendPlayerData(PlayerData *);
protected:
/**
diff --git a/src/game-server/being.cpp b/src/game-server/being.cpp
new file mode 100644
index 00000000..64986c26
--- /dev/null
+++ b/src/game-server/being.cpp
@@ -0,0 +1,87 @@
+/*
+ * The Mana World Server
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with The Mana World; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "game-server/being.hpp"
+#include "game-server/mapcomposite.hpp"
+#include "utils/logger.h"
+
+void Being::damage(Damage damage)
+{
+ int HPloss;
+
+ HPloss = damage; // TODO: Implement complex damage calculation here
+
+ mHitpoints -= HPloss;
+ mHitsTaken.push_back(HPloss);
+ LOG_DEBUG("Being " << getPublicID() << " got hit", 0);
+}
+
+void Being::performAttack(MapComposite *map)
+{
+ int SHORT_RANGE = 32;
+ Point ppos = getPosition();
+ int dir = getDirection();
+
+ /* TODO: calculate real attack power and damage properties based on
+ character equipment and stats. */
+ Damage damage = 1;
+
+ for (MovingObjectIterator i(map->getAroundObjectIterator(this, SHORT_RANGE)); i; ++i)
+ {
+ MovingObject *o = *i;
+ if (o == this)
+ {
+ continue;
+ }
+
+ int type = o->getType();
+ Point opos = o->getPosition();
+ int dx = opos.x - ppos.x, dy = opos.y - ppos.y;
+
+ if ((type != OBJECT_PLAYER && type != OBJECT_MONSTER) ||
+ (std::abs(dx) > SHORT_RANGE || std::abs(dy) > SHORT_RANGE))
+ {
+ continue;
+ }
+
+ // basic triangle-shaped damage zone
+ switch (dir)
+ {
+ case DIRECTION_UP:
+ if (!(dy <= dx && dx <= -dy)) continue;
+ break;
+ case DIRECTION_DOWN:
+ if (!(-dy <= dx && dx <= dy)) continue;
+ break;
+ case DIRECTION_LEFT:
+ if (!(dx <= dy && dy <= -dx)) continue;
+ break;
+ case DIRECTION_RIGHT:
+ if (!(-dx <= dy && dy <= dx)) continue;
+ break;
+ default:
+ break;
+ }
+
+ static_cast< Being * >(o)->damage(damage);
+ }
+}
diff --git a/src/game-server/being.hpp b/src/game-server/being.hpp
new file mode 100644
index 00000000..32b30b1e
--- /dev/null
+++ b/src/game-server/being.hpp
@@ -0,0 +1,214 @@
+/*
+ * The Mana World Server
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with The Mana World; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMWSERV_BEING_H_
+#define _TMWSERV_BEING_H_
+
+#include <list>
+#include <string>
+#include <vector>
+
+#include "defines.h"
+#include "game-server/object.hpp"
+#include "utils/countedptr.h"
+
+class MapComposite;
+
+/**
+ * Element attribute for beings, actors and items.
+ */
+enum
+{
+ ELEMENT_NEUTRAL = 0,
+ ELEMENT_FIRE,
+ ELEMENT_WATER,
+ ELEMENT_EARTH,
+ ELEMENT_AIR,
+ ELEMENT_SACRED,
+ ELEMENT_DEATH
+};
+
+/**
+ * States attribute for beings, and actors.
+ * States can be multiple for the same being.
+ */
+struct BeingState
+{
+ bool STATE_NORMAL;
+ bool STATE_POISONED;
+ bool STATE_STONED;
+ bool STATE_STUNNED;
+ bool STATE_SLOWED;
+ bool STATE_TIRED;
+ bool STATE_MAD;
+ bool STATE_BERSERK;
+ bool STATE_HASTED;
+ bool STATE_FLOATING;
+};
+
+/**
+ * Moves enum for beings and actors for others players vision.
+ */
+enum
+{
+ ACTION_DEFAULT = 0,
+ ACTION_STAND,
+ ACTION_WALK,
+ ACTION_RUN,
+ ACTION_JUMP,
+ ACTION_CRAWL,
+ ACTION_ATTACK,
+ ACTION_ATTACK_SWING,
+ ACTION_ATTACK_STAB,
+ ACTION_ATTACK_BOW,
+ ACTION_ATTACK_THROW,
+ ACTION_CAST_MAGIC,
+ ACTION_USE_ITEM,
+ ACTION_SIT,
+ ACTION_SLEEP,
+ ACTION_HURT,
+ ACTION_DEAD,
+ ACTION_INVALID
+};
+
+/**
+ * Beings and actors directions
+ */
+enum
+{
+ DIRECTION_DOWN = 1,
+ DIRECTION_UP,
+ DIRECTION_LEFT,
+ DIRECTION_RIGHT
+};
+
+
+/**
+ * Computed statistics of a Being.
+ */
+enum
+{
+ STAT_HEAT = 0,
+ STAT_ATTACK,
+ STAT_DEFENCE,
+ STAT_MAGIC,
+ STAT_ACCURACY,
+ STAT_SPEED,
+ NB_CSTAT
+};
+
+/**
+ * Structure type for the computed statistics of a Being.
+ */
+struct Statistics
+{
+ unsigned short stats[NB_CSTAT];
+};
+
+/**
+ * Placeholder for a more complex damage structure
+ */
+typedef unsigned short Damage;
+
+/**
+ * Type definition for a list of hits
+ */
+typedef std::list<unsigned int> Hits;
+
+/**
+ * Generic Being (living object).
+ * Used for players & monsters (all animated objects).
+ */
+class Being : public MovingObject
+{
+ public:
+ /**
+ * Proxy constructor.
+ */
+ Being(int type, int id)
+ : MovingObject(type, id)
+ {}
+
+ /**
+ * Sets a computed statistic.
+ *
+ * @param numStat the statistic number.
+ * @param value the new value.
+ */
+ void setStat(int numStat, unsigned short value)
+ { mStats.stats[numStat] = value; }
+
+ /**
+ * Gets a computed statistic.
+ *
+ * @param numStat the statistic number.
+ * @return the statistic value.
+ */
+ unsigned short getStat(int numStat)
+ { return mStats.stats[numStat]; }
+
+ /**
+ * Takes a damage structure, computes the real damage based on the
+ * stats, deducts the result from the hitpoints and adds the result to
+ * the HitsTaken list.
+ */
+ void damage(Damage);
+
+ /**
+ * Gets the damage list.
+ */
+ Hits const &getHitsTaken() const
+ { return mHitsTaken; }
+
+ /**
+ * Clears the damage list.
+ */
+ void clearHitsTaken()
+ { mHitsTaken.clear(); }
+
+ /**
+ * Performs an attack.
+ */
+ void performAttack(MapComposite *);
+
+ private:
+ Being(Being const &rhs);
+ Being &operator=(Being const &rhs);
+
+ Statistics mStats; /**< stats modifiers or computed stats */
+
+ int mHitpoints; /**< Hitpoints of the being */
+
+ Hits mHitsTaken; /**< List of punches taken since last update */
+};
+
+/**
+ * Type definition for a smart pointer to Being.
+ */
+typedef utils::CountedPtr<Being> BeingPtr;
+
+/**
+ * Type definition for a list of Beings.
+ */
+typedef std::vector<BeingPtr> Beings;
+
+#endif // _TMWSERV_BEING_H_
diff --git a/src/game-server/gamehandler.cpp b/src/game-server/gamehandler.cpp
index 56b9533c..f7a3905a 100644
--- a/src/game-server/gamehandler.cpp
+++ b/src/game-server/gamehandler.cpp
@@ -24,8 +24,8 @@
#include <cassert>
#include <map>
-#include "map.h"
#include "game-server/gamehandler.hpp"
+#include "game-server/map.hpp"
#include "game-server/state.hpp"
#include "net/messagein.hpp"
#include "net/messageout.hpp"
@@ -231,7 +231,6 @@ void GameHandler::processMessage(NetComputer *comp, MessageIn &message)
gameState->sayAround(computer.character, say);
} break;
- /*
case PGMSG_PICKUP:
{
// add item to inventory (this is too simplistic atm)
@@ -260,7 +259,6 @@ void GameHandler::processMessage(NetComputer *comp, MessageIn &message)
result.writeByte(ERRMSG_FAILURE);
}
} break;
- */
case PGMSG_WALK:
{
@@ -272,7 +270,6 @@ void GameHandler::processMessage(NetComputer *comp, MessageIn &message)
// no response should be required
} break;
- /*
case PGMSG_EQUIP:
{
message.readLong(); // ItemId: Not useful, the inventory knows it
@@ -282,7 +279,6 @@ void GameHandler::processMessage(NetComputer *comp, MessageIn &message)
result.writeByte(computer.character->equip(slot) ?
ERRMSG_OK : ERRMSG_FAILURE);
} break;
- */
case PGMSG_ATTACK:
{
diff --git a/src/game-server/gamehandler.hpp b/src/game-server/gamehandler.hpp
index f574d9ec..faeff656 100644
--- a/src/game-server/gamehandler.hpp
+++ b/src/game-server/gamehandler.hpp
@@ -24,7 +24,7 @@
#ifndef _TMW_SERVER_GAMEHANDLER_
#define _TMW_SERVER_GAMEHANDLER_
-#include "player.h"
+#include "game-server/player.hpp"
#include "net/connectionhandler.hpp"
/**
diff --git a/src/game-server/inventory.cpp b/src/game-server/inventory.cpp
new file mode 100644
index 00000000..b3b8a254
--- /dev/null
+++ b/src/game-server/inventory.cpp
@@ -0,0 +1,419 @@
+/*
+ * The Mana World Server
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "game-server/inventory.hpp"
+#include "game-server/itemmanager.hpp"
+
+// ---------
+// Items
+// ---------
+unsigned char
+Inventory::getInventoryFreeSlot()
+{
+ for (int a = 0; a < MAX_ITEMS_IN_INVENTORY; a++)
+ {
+ if (itemList.at(a).amount == 0)
+ return a;
+ }
+ return INVENTORY_FULL;
+}
+
+unsigned char
+Inventory::getSlotFromId(const unsigned int itemId)
+{
+ for (int a = 0; a < MAX_ITEMS_IN_INVENTORY; a++)
+ {
+ if (itemList.at(a).itemId == itemId)
+ return a;
+ }
+ return INVENTORY_FULL;
+}
+
+bool
+Inventory::hasItem(unsigned int itemId,
+ bool searchInInventory,
+ bool searchInEquipment)
+{
+ bool hasItem = false;
+ // Search in inventory
+ if (searchInInventory)
+ {
+ std::vector<StoredItem>::iterator iter = itemList.begin();
+ for (iter = itemList.begin(); iter != itemList.end(); ++iter)
+ {
+ if (iter->itemId == itemId)
+ hasItem = true;
+ }
+ }
+ // Search in equipment
+ if (searchInEquipment)
+ {
+ std::vector<EquippedItem>::iterator equipIter = equippedItemList.begin();
+ for (equipIter = equippedItemList.begin();
+ equipIter != equippedItemList.end();
+ ++equipIter)
+ {
+ if (equipIter->itemId == itemId)
+ hasItem = true;
+ }
+ if (equippedProjectiles.itemId == itemId)
+ hasItem = true;
+ }
+ return hasItem;
+}
+
+short
+Inventory::addItem(unsigned int itemId, unsigned char amount)
+{
+ // We get the max number of item we can have in the same slot
+ // for the given item.
+ unsigned char maxPerSlot = itemManager->getMaxPerSlot(itemId);
+ // We'll add items in slots with the item type and in free slots
+ // until it's all done or until the inventory will be all parsed.
+ // Searching for items with the same Id in the inventory, before
+ // seeking a free slot.
+ unsigned char amountToAdd = amount;
+
+ // Parsing inventory
+ unsigned char currentAmountInSlot = 0;
+ std::vector<StoredItem>::iterator iter = itemList.begin();
+ for (iter = itemList.begin(); iter != itemList.end(); ++iter)
+ {
+ currentAmountInSlot = iter->amount;
+ // If a slot has got place for some more of such an item.
+ if (iter->itemId == itemId && currentAmountInSlot < maxPerSlot)
+ {
+ // If there isn't enough space to put every item in the slot.
+ // We add the difference.
+ if ((maxPerSlot - currentAmountInSlot) < amountToAdd)
+ {
+ iter->amount += (maxPerSlot - currentAmountInSlot);
+ amountToAdd -= (maxPerSlot - currentAmountInSlot);
+ }
+ else // there is enough to add everything.
+ {
+ iter->amount += amountToAdd;
+ amountToAdd = 0; // Ok!
+ }
+ }
+ // Or if there is an empty slot.
+ else if (iter->amount == 0)
+ {
+ // We add the item in the new slot (setting also the Id.)
+ if (maxPerSlot < amountToAdd)
+ {
+ iter->amount = maxPerSlot;
+ amountToAdd -= maxPerSlot;
+ }
+ else
+ {
+ iter->amount += amountToAdd;
+ amountToAdd = 0; // Ok!
+ }
+ iter->itemId = itemId;
+ }
+ }
+
+ return (short)(amount - amountToAdd);
+}
+
+short
+Inventory::removeItem(unsigned int itemId, unsigned char amount)
+{
+ // We'll remove items in slots with the item type
+ // until it's all done or until the inventory will be all parsed.
+ // Searching for items with the same Id in the inventory
+ unsigned char amountToRemove = amount;
+
+ // Parsing inventory
+ unsigned char currentAmountInSlot = 0;
+ std::vector<StoredItem>::iterator iter = itemList.begin();
+ for (iter = itemList.begin(); iter != itemList.end(); ++iter)
+ {
+ currentAmountInSlot = iter->amount;
+ // If a slot has got such an item, remove it
+ if (iter->itemId == itemId && currentAmountInSlot > 0)
+ {
+ // If there isn't enough to finish, we remove the difference
+ // Emptying the slot, so we clean also the itemId.
+ if (currentAmountInSlot <= amountToRemove)
+ {
+ amountToRemove -= currentAmountInSlot;
+ iter->amount = 0;
+ iter->itemId = 0;
+ }
+ else // there is enough to remove everything.
+ {
+ iter->amount -= amountToRemove;
+ amountToRemove = 0; // Ok!
+ }
+ }
+ }
+ return (short)(amount - amountToRemove);
+}
+
+short
+Inventory::removeItem(unsigned char slot, unsigned char amount)
+{
+ if (itemList.at(slot).amount < amount)
+ {
+ unsigned char value = itemList.at(slot).amount;
+ itemList.at(slot).amount = 0;
+ return (short)value;
+ }
+ else
+ {
+ itemList.at(slot).amount -= amount;
+ return amount;
+ }
+}
+
+bool
+Inventory::use(unsigned char slot, BeingPtr itemUser)
+{
+ return false; // TODO
+}
+
+bool
+Inventory::use(unsigned int itemId, BeingPtr itemUser)
+{
+ return false; // TODO
+}
+
+// ---------
+// Equipment
+// ---------
+unsigned char
+Inventory::equipItem(unsigned int itemId)
+{
+ // First, we look for the item in the player's inventory.
+ if (!hasItem(itemId, true, false))
+ return false;
+
+ unsigned char availableSlots = 0, firstSlot = 0, secondSlot = 0;
+
+ unsigned short itemType = itemManager->getItemType(itemId);
+ switch (itemType)
+ {
+ case ITEM_EQUIPMENT_TWO_HANDS_WEAPON:
+ // Special case 1, the two one-handed weapons are to be placed back
+ // in the inventory, if there are any.
+ if (equippedItemList.at(EQUIP_FIGHT1_SLOT).itemId > 0)
+ { // Slot 1 full
+ // old two-handed weapon case:
+ if (equippedItemList.at(EQUIP_FIGHT1_SLOT).itemType
+ == ITEM_EQUIPMENT_TWO_HANDS_WEAPON)
+ {
+ equippedItemList.at(EQUIP_FIGHT2_SLOT).itemId = 0;
+ equippedItemList.at(EQUIP_FIGHT2_SLOT).itemType = 0;
+ }
+
+ if (unequipItem_(equippedItemList.at(EQUIP_FIGHT1_SLOT).itemId,
+ EQUIP_FIGHT1_SLOT) == INVENTORY_FULL)
+ return INVENTORY_FULL;
+ }
+ if (equippedItemList.at(EQUIP_FIGHT2_SLOT).itemId > 0)
+ { // Slot 2 full
+ if (unequipItem_(equippedItemList.at(EQUIP_FIGHT2_SLOT).itemId,
+ EQUIP_FIGHT2_SLOT) == INVENTORY_FULL)
+ return INVENTORY_FULL;
+ }
+ // Only the slot 1 needs to be updated.
+ return equipItem_(itemId, itemType, EQUIP_FIGHT1_SLOT);
+ break;
+
+ case ITEM_EQUIPMENT_PROJECTILE:
+ // Special case 2: the projectile is a Stored Item structure,
+ // but is still considered as part of the equipment.
+ // Case 1: Reloading
+ if (equippedProjectiles.itemId == itemId)
+ {
+ equippedProjectiles.amount += removeItem(itemId,
+ (255 - equippedProjectiles.amount));
+ return EQUIP_PROJECTILES_SLOT;
+ }
+ else // Case 2: Changing projectiles.
+ {
+ short added;
+ added = addItem(equippedProjectiles.itemId,
+ equippedProjectiles.amount);
+ if (added == equippedProjectiles.amount)
+ { // Ok, we can equip
+ equippedProjectiles.itemId = itemId;
+ equippedProjectiles.amount = removeItem(itemId, 255);
+ return EQUIP_PROJECTILES_SLOT;
+ }
+ else // Some were unequipped.
+ {
+ equippedProjectiles.amount -= added;
+ return INVENTORY_FULL;
+ }
+ }
+ break;
+
+ case ITEM_EQUIPMENT_ONE_HAND_WEAPON:
+ case ITEM_EQUIPMENT_SHIELD:
+ availableSlots = 2;
+ firstSlot = EQUIP_FIGHT1_SLOT;
+ secondSlot = EQUIP_FIGHT2_SLOT;
+ break;
+ case ITEM_EQUIPMENT_RING:
+ availableSlots = 2;
+ firstSlot = EQUIP_RING1_SLOT;
+ secondSlot = EQUIP_RING2_SLOT;
+ break;
+ case ITEM_EQUIPMENT_BREST:
+ availableSlots = 1;
+ firstSlot = EQUIP_BREST_SLOT;
+ break;
+ case ITEM_EQUIPMENT_ARMS:
+ availableSlots = 1;
+ firstSlot = EQUIP_ARMS_SLOT;
+ break;
+ case ITEM_EQUIPMENT_HEAD:
+ availableSlots = 1;
+ firstSlot = EQUIP_HEAD_SLOT;
+ break;
+ case ITEM_EQUIPMENT_LEGS:
+ availableSlots = 1;
+ firstSlot = EQUIP_LEGS_SLOT;
+ break;
+ case ITEM_EQUIPMENT_NECKLACE:
+ availableSlots = 1;
+ firstSlot = EQUIP_NECKLACE_SLOT;
+ break;
+ case ITEM_EQUIPMENT_FEET:
+ availableSlots = 1;
+ firstSlot = EQUIP_FEET_SLOT;
+ break;
+
+ case ITEM_UNUSABLE:
+ case ITEM_USABLE:
+ default:
+ return NOT_EQUIPPABLE;
+ }
+
+ switch (availableSlots)
+ {
+ case 1:
+ if (equippedItemList.at(firstSlot).itemId > 0)
+ {
+ if (unequipItem_(equippedItemList.at(firstSlot).itemId,
+ firstSlot) != INVENTORY_FULL)
+ return equipItem_(itemId, itemType, firstSlot);
+ else
+ return INVENTORY_FULL;
+ }
+ else // slot empty, we can equip.
+ {
+ return equipItem_(itemId, itemType, firstSlot);
+ }
+ break;
+
+ case 2:
+ if (equippedItemList.at(firstSlot).itemId > 0)
+ {
+ // If old weapon is two-handed one, we can unequip
+ // the first slot only, and clean the second.
+ if (equippedItemList.at(firstSlot).itemId ==
+ ITEM_EQUIPMENT_TWO_HANDS_WEAPON)
+ {
+ if (unequipItem_(equippedItemList.at(firstSlot).itemId,
+ firstSlot) != INVENTORY_FULL)
+ return equipItem_(itemId, itemType, firstSlot);
+ else
+ return INVENTORY_FULL;
+ }
+
+ if (equippedItemList.at(secondSlot).itemId > 0)
+ { // Both slots are full,
+ // we remove the first one to equip
+ if (unequipItem_(equippedItemList.at(firstSlot).itemId,
+ firstSlot) != INVENTORY_FULL)
+ return equipItem_(itemId, itemType, firstSlot);
+ else
+ return INVENTORY_FULL;
+ }
+ else // Second slot empty, we can equip.
+ {
+ return equipItem_(itemId, itemType, secondSlot);
+ }
+ }
+ else // first slot empty, we can equip.
+ {
+ return equipItem_(itemId, itemType, firstSlot);
+ }
+ break;
+
+ default:
+ return NOT_EQUIPPABLE;
+ }
+}
+
+bool
+Inventory::equipItem(unsigned char inventorySlot, unsigned char equipmentSlot)
+{
+ return false; // TODO
+}
+
+bool
+Inventory::unequipItem(unsigned int itemId)
+{
+ return false; // TODO
+}
+
+bool
+Inventory::unequipItem(unsigned char inventorySlot,
+ unsigned char equipmentSlot)
+{
+ return false; // TODO
+}
+
+unsigned char
+Inventory::equipItem_(unsigned int itemId,
+ unsigned int itemType,
+ unsigned char equipmentSlot)
+{
+ if (removeItem(itemId, 1) == 1)
+ {
+ equippedItemList.at(equipmentSlot).itemId = itemId;
+ equippedItemList.at(equipmentSlot).itemType = itemType;
+ return equipmentSlot;
+ }
+ else
+ return NO_ITEM_TO_EQUIP;
+}
+
+unsigned char
+Inventory::unequipItem_(unsigned int itemId,
+ unsigned char equipmentSlot)
+{
+ if (addItem(itemId, 1) == 1)
+ {
+ equippedItemList.at(equipmentSlot).itemId = 0;
+ equippedItemList.at(equipmentSlot).itemType = 0;
+ return equipmentSlot;
+ }
+ else
+ return INVENTORY_FULL;
+}
diff --git a/src/game-server/inventory.hpp b/src/game-server/inventory.hpp
new file mode 100644
index 00000000..61bc5818
--- /dev/null
+++ b/src/game-server/inventory.hpp
@@ -0,0 +1,233 @@
+/*
+ * The Mana World Server
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef INVENTORY_H
+#define INVENTORY_H
+
+#include "game-server/being.hpp"
+
+enum
+{
+// items in inventory :
+ MAX_ITEMS_IN_INVENTORY = 50, // Max 252.
+// Equipment rules:
+// 1 Brest equipment
+ EQUIP_BREST_SLOT = 0,
+// 1 arms equipment
+ EQUIP_ARMS_SLOT = 1,
+// 1 head equipment
+ EQUIP_HEAD_SLOT = 2,
+// 1 legs equipment
+ EQUIP_LEGS_SLOT = 3,
+// 1 feet equipment
+ EQUIP_FEET_SLOT = 4,
+// 2 rings
+ EQUIP_RING1_SLOT = 5,
+ EQUIP_RING2_SLOT = 6,
+// 1 necklace
+ EQUIP_NECKLACE_SLOT = 7,
+// Fight:
+// 2 one-handed weapons
+ 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,
+// 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
+{
+ unsigned int itemId;
+ unsigned char amount;
+};
+
+/**
+ * Equipped items that keeps which kind of item is in equipment.
+ */
+struct EquippedItem
+{
+ unsigned int itemId;
+ short itemType;
+};
+
+/**
+ * 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 Inventory
+{
+ public:
+ /**
+ * Convenience function to get slot from ItemId.
+ * If more than one occurence is found, the first is given.
+ */
+ unsigned char
+ getSlotFromId(unsigned int itemId);
+
+ /**
+ * Return StoredItem
+ */
+ StoredItem
+ getStoredItemAt(unsigned char slot) const { return itemList[slot]; };
+
+ /**
+ * Search in inventory and equipment if an item is present.
+ */
+ bool
+ hasItem(unsigned int itemId,
+ bool searchInInventory = true,
+ bool searchInEquipment = true);
+
+ /**
+ * Tells an item's amount
+ */
+ unsigned short
+ getItemAmount(unsigned char slot) const { return itemList[slot].amount; };
+
+ /**
+ * Return Item reference Id
+ */
+ unsigned int
+ getItemId(unsigned char slot) const { return itemList[slot].itemId; };
+
+ /**
+ * add an item with amount
+ * (don't create it if amount was 0)
+ * @return short value: Indicates the number of items added.
+ */
+ short
+ addItem(unsigned int itemId, unsigned char amount = 1);
+
+ /**
+ * Remove an item searched by ItemId.
+ * Delete if amount = 0.
+ * @return short value: Indicates the number of items removed.
+ * This function removes the given amount using every slots
+ * if necessary.
+ */
+ short
+ removeItem(unsigned int itemId, unsigned char amount = 0);
+
+ /**
+ * Remove an item searched by slot index.
+ * Delete if amount = 0.
+ * @return short value: Indicates the number of items removed.
+ * Removes only in the given slot.
+ */
+ short
+ removeItem(unsigned char slot, unsigned char amount = 0);
+
+ /**
+ * 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.
+ */
+ unsigned char
+ equipItem(unsigned int itemId);
+
+ /**
+ * Unequip an item searched by its id.
+ * Can unequip more than one item at a time.
+ */
+ bool
+ unequipItem(unsigned int itemId);
+
+ /**
+ * Equip an item searched by its slot index.
+ */
+ bool
+ equipItem(unsigned char inventorySlot, unsigned char equipmentSlot);
+
+ /**
+ * Unequip an equipped item searched by its slot index.
+ */
+ bool
+ unequipItem(unsigned char inventorySlot, unsigned char equipmentSlot);
+
+ /**
+ * The function called to use an item applying
+ * only the modifiers
+ */
+ bool
+ use(unsigned char slot, BeingPtr itemUser);
+
+ /**
+ * The function called to use an item applying
+ * only the modifiers
+ */
+ bool
+ use(unsigned int itemId, BeingPtr itemUser);
+
+ private:
+
+ /**
+ * Give the first free slot number in itemList.
+ */
+ unsigned char 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.
+ */
+ unsigned char equipItem_(unsigned int itemId,
+ unsigned int itemType,
+ unsigned char equipmentSlot);
+
+ /**
+ * Quick unequip an equipment with a given equipSlot,
+ * and an itemId.
+ * @return the Equipment slot if successful,
+ * the error code, if not.
+ */
+ unsigned char unequipItem_(unsigned int itemId,
+ unsigned char 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;
+};
+
+#endif
diff --git a/src/game-server/itemmanager.cpp b/src/game-server/itemmanager.cpp
index 3ce8350c..01b957a6 100644
--- a/src/game-server/itemmanager.cpp
+++ b/src/game-server/itemmanager.cpp
@@ -18,7 +18,7 @@
* 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:$
+ * $Id$
*/
#include "resourcemanager.h"
@@ -81,7 +81,7 @@ ItemManager::ItemManager(std::string const &itemReferenceFile)
std::string scriptName = XML::getProperty(node, "script_name", std::string());
Modifiers modifiers;
- modifiers.element = (Element)XML::getProperty(node, "element", 0);
+ modifiers.element = XML::getProperty(node, "element", 0);
modifiers.lifetime = XML::getProperty(node, "lifetime", 0);
modifiers.rawStats[STAT_STRENGTH] = XML::getProperty(node, "strength", 0);
modifiers.rawStats[STAT_AGILITY] = XML::getProperty(node, "agility", 0);
diff --git a/src/game-server/map.cpp b/src/game-server/map.cpp
new file mode 100644
index 00000000..876ba674
--- /dev/null
+++ b/src/game-server/map.cpp
@@ -0,0 +1,302 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include <queue>
+
+#include "game-server/map.hpp"
+
+MetaTile::MetaTile():
+ whichList(0)
+{
+}
+
+
+Location::Location(int x, int y, MetaTile *tile):
+ x(x), y(y), tile(tile)
+{
+}
+
+bool Location::operator< (const Location &loc) const
+{
+ return tile->Fcost > loc.tile->Fcost;
+}
+
+
+Map::Map():
+ width(0), height(0),
+ tileWidth(32), tileHeight(32),
+ onClosedList(1), onOpenList(2)
+{
+ metaTiles = new MetaTile[width * height];
+}
+
+Map::Map(int width, int height):
+ width(width), height(height),
+ tileWidth(32), tileHeight(32),
+ onClosedList(1), onOpenList(2)
+{
+ metaTiles = new MetaTile[width * height];
+}
+
+Map::~Map()
+{
+ delete[] metaTiles;
+}
+
+void
+Map::setSize(int width, int height)
+{
+ this->width = width;
+ this->height = height;
+ delete[] metaTiles;
+ metaTiles = new MetaTile[width * height];
+}
+
+void
+Map::setWalk(int x, int y, bool walkable)
+{
+ metaTiles[x + y * width].walkable = walkable;
+}
+
+bool
+Map::getWalk(int x, int y)
+{
+ // If walkable, check for colliding into a being
+ if (!tileCollides(x, y))
+ {
+ /*
+ std::list<Being*>::iterator i = beings.begin();
+ while (i != beings.end()) {
+ Being *being = (*i);
+ // Collision when non-portal being is found at this location
+ if (being->x == x && being->y == y && being->job != 45) {
+ return false;
+ }
+ i++;
+ }
+ */
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+bool
+Map::tileCollides(int x, int y)
+{
+ // You can't walk outside of the map
+ if (x < 0 || y < 0 || x >= width || y >= height) {
+ return true;
+ }
+
+ // Check if the tile is walkable
+ return !metaTiles[x + y * width].walkable;
+}
+
+MetaTile*
+Map::getMetaTile(int x, int y)
+{
+ return &metaTiles[x + y * width];
+}
+
+static int const basicCost = 100;
+
+std::list<PATH_NODE>
+Map::findPath(int startX, int startY, int destX, int destY)
+{
+ // Path to be built up (empty by default)
+ std::list<PATH_NODE> path;
+
+ // Declare open list, a list with open tiles sorted on F cost
+ std::priority_queue<Location> openList;
+
+ // Return when destination not walkable
+ if (!getWalk(destX, destY)) return path;
+
+ // Reset starting tile's G cost to 0
+ MetaTile *startTile = getMetaTile(startX, startY);
+ startTile->Gcost = 0;
+
+ // Add the start point to the open list
+ openList.push(Location(startX, startY, startTile));
+
+ bool foundPath = false;
+
+ // Keep trying new open tiles until no more tiles to try or target found
+ while (!openList.empty() && !foundPath)
+ {
+ // Take the location with the lowest F cost from the open list, and
+ // add it to the closed list.
+ Location curr = openList.top();
+ openList.pop();
+
+ // If the tile is already on the closed list, this means it has already
+ // been processed with a shorter path to the start point (lower G cost)
+ if (curr.tile->whichList == onClosedList)
+ {
+ continue;
+ }
+
+ // Put the current tile on the closed list
+ curr.tile->whichList = onClosedList;
+
+ // Check the adjacent tiles
+ for (int dy = -1; dy <= 1; dy++)
+ {
+ for (int dx = -1; dx <= 1; dx++)
+ {
+ // Calculate location of tile to check
+ int x = curr.x + dx;
+ int y = curr.y + dy;
+
+ // Skip if if we're checking the same tile we're leaving from,
+ // or if the new location falls outside of the map boundaries
+ if ((dx == 0 && dy == 0) ||
+ (x < 0 || y < 0 || x >= width || y >= height))
+ {
+ continue;
+ }
+
+ MetaTile *newTile = getMetaTile(x, y);
+
+ // Skip if the tile is on the closed list or is not walkable
+ if (newTile->whichList == onClosedList || !getWalk(x, y))
+ {
+ continue;
+ }
+
+ // When taking a diagonal step, verify that we can skip the
+ // corner. We allow skipping past beings but not past non-
+ // walkable tiles.
+ if (dx != 0 && dy != 0)
+ {
+ MetaTile *t1 = getMetaTile(curr.x, curr.y + dy);
+ MetaTile *t2 = getMetaTile(curr.x + dx, curr.y);
+
+ if (!(t1->walkable && t2->walkable))
+ {
+ continue;
+ }
+ }
+
+ // Calculate G cost for this route, ~sqrt(2) for moving diagonal
+ int Gcost = curr.tile->Gcost +
+ (dx == 0 || dy == 0 ? basicCost : basicCost * 362 / 256);
+
+ /* Demote an arbitrary direction to speed pathfinding by
+ adding a defect (TODO: change depending on the desired
+ visual effect, e.g. a cross-product defect toward
+ destination).
+ Important: as long as the total defect along any path is
+ less than the basicCost, the pathfinder will still find one
+ of the shortest paths! */
+ if (dx == 0 || dy == 0)
+ {
+ // Demote horizontal and vertical directions, so that two
+ // consecutive directions cannot have the same Fcost.
+ ++Gcost;
+ }
+
+ // Skip if Gcost becomes too much
+ // Warning: probably not entirely accurate
+ if (Gcost > 20 * basicCost)
+ {
+ continue;
+ }
+
+ if (newTile->whichList != onOpenList)
+ {
+ // Found a new tile (not on open nor on closed list)
+
+ /* Update Hcost of the new tile. The pathfinder does not
+ work reliably if the heuristic cost is higher than the
+ real cost. In particular, using Manhattan distance is
+ forbidden here. */
+ int dx = std::abs(x - destX), dy = std::abs(y - destY);
+ newTile->Hcost = std::abs(dx - dy) * basicCost +
+ std::min(dx, dy) * (basicCost * 362 / 256);
+
+ // Set the current tile as the parent of the new tile
+ newTile->parentX = curr.x;
+ newTile->parentY = curr.y;
+
+ // Update Gcost and Fcost of new tile
+ newTile->Gcost = Gcost;
+ newTile->Fcost = newTile->Gcost + newTile->Hcost;
+
+ if (x != destX || y != destY) {
+ // Add this tile to the open list
+ newTile->whichList = onOpenList;
+ openList.push(Location(x, y, newTile));
+ }
+ else {
+ // Target location was found
+ foundPath = true;
+ }
+ }
+ else if (Gcost < newTile->Gcost)
+ {
+ // Found a shorter route.
+ // Update Gcost and Fcost of the new tile
+ newTile->Gcost = Gcost;
+ newTile->Fcost = newTile->Gcost + newTile->Hcost;
+
+ // Set the current tile as the parent of the new tile
+ newTile->parentX = curr.x;
+ newTile->parentY = curr.y;
+
+ // Add this tile to the open list (it's already
+ // there, but this instance has a lower F score)
+ openList.push(Location(x, y, newTile));
+ }
+ }
+ }
+ }
+
+ // Two new values to indicate whether a tile is on the open or closed list,
+ // this way we don't have to clear all the values between each pathfinding.
+ onClosedList += 2;
+ onOpenList += 2;
+
+ // If a path has been found, iterate backwards using the parent locations
+ // to extract it.
+ if (foundPath)
+ {
+ int pathX = destX;
+ int pathY = destY;
+
+ while (pathX != startX || pathY != startY)
+ {
+ // Add the new path node to the start of the path list
+ path.push_front(PATH_NODE(pathX, pathY));
+
+ // Find out the next parent
+ MetaTile *tile = getMetaTile(pathX, pathY);
+ pathX = tile->parentX;
+ pathY = tile->parentY;
+ }
+ }
+
+ return path;
+}
diff --git a/src/game-server/map.hpp b/src/game-server/map.hpp
new file mode 100644
index 00000000..a7c1fe2a
--- /dev/null
+++ b/src/game-server/map.hpp
@@ -0,0 +1,174 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_MAP_H
+#define _TMW_MAP_H
+
+#include <list>
+#include <map>
+#include <string>
+
+
+struct PATH_NODE {
+ PATH_NODE(unsigned short u, unsigned short v)
+ : x(u), y(v)
+ {}
+
+ unsigned short x, y;
+};
+
+/**
+ * A meta tile stores additional information about a location on a tile map.
+ * This is information that doesn't need to be repeated for each tile in each
+ * layer of the map.
+ */
+class MetaTile
+{
+ public:
+ /**
+ * Constructor.
+ */
+ MetaTile();
+
+ // Pathfinding members
+ int Fcost; /**< Estimation of total path cost */
+ int Gcost; /**< Cost from start to this location */
+ int Hcost; /**< Estimated cost to goal */
+ int whichList; /**< No list, open list or closed list */
+ int parentX; /**< X coordinate of parent tile */
+ int parentY; /**< Y coordinate of parent tile */
+ bool walkable; /**< Can beings walk on this tile */
+};
+
+/**
+ * A location on a tile map. Used for pathfinding, open list.
+ */
+class Location
+{
+ public:
+ /**
+ * Constructor.
+ */
+ Location(int x, int y, MetaTile *tile);
+
+ /**
+ * Comparison operator.
+ */
+ bool operator< (const Location &loc) const;
+
+ int x, y;
+ MetaTile *tile;
+};
+
+/**
+ * A tile map.
+ */
+class Map
+{
+ public:
+ /**
+ * Constructor.
+ */
+ Map();
+
+ /**
+ * Constructor that takes initial map size as parameters.
+ */
+ Map(int width, int height);
+
+ /**
+ * Destructor.
+ */
+ ~Map();
+
+ /**
+ * Sets the size of the map. This will destroy any existing map data.
+ */
+ void
+ setSize(int width, int height);
+
+ /**
+ * Get tile reference.
+ */
+ MetaTile*
+ getMetaTile(int x, int y);
+
+ /**
+ * Set walkability flag for a tile
+ */
+ void
+ setWalk(int x, int y, bool walkable);
+
+ /**
+ * Tell if a tile is walkable or not, includes checking beings.
+ */
+ bool
+ getWalk(int x, int y);
+
+ /**
+ * Tell if a tile collides, not including a check on beings.
+ */
+ bool
+ tileCollides(int x, int y);
+
+ /**
+ * Returns the width of this map.
+ */
+ int getWidth() const
+ { return width; }
+
+ /**
+ * Returns the height of this map.
+ */
+ int getHeight() const
+ { return height; }
+
+ /**
+ * Returns the tile width of this map.
+ */
+ int getTileWidth() const
+ { return tileWidth; }
+
+ /**
+ * Returns the tile height used by this map.
+ */
+ int getTileHeight() const
+ { return tileHeight; }
+
+ /**
+ * Find a path from one location to the next.
+ */
+ std::list<PATH_NODE>
+ findPath(int startX, int startY,
+ int destX, int destY);
+
+ private:
+ int width, height;
+ int tileWidth, tileHeight;
+ MetaTile *metaTiles;
+
+ // Pathfinding members
+ int onClosedList, onOpenList;
+};
+
+#endif
diff --git a/src/game-server/mapcomposite.cpp b/src/game-server/mapcomposite.cpp
index 8b7ef9d7..1b824447 100644
--- a/src/game-server/mapcomposite.cpp
+++ b/src/game-server/mapcomposite.cpp
@@ -24,8 +24,10 @@
#include <algorithm>
#include <cassert>
-#include "map.h"
+#include "point.h"
+#include "game-server/map.hpp"
#include "game-server/mapcomposite.hpp"
+#include "game-server/player.hpp"
/* TODO: Implement overlapping map zones instead of strict partitioning.
Purpose: to decrease the number of zone changes, as overlapping allows for
@@ -393,7 +395,7 @@ ZoneIterator MapComposite::getInsideRectangleIterator(Rectangle const &p) const
return ZoneIterator(r, this);
}
-ZoneIterator MapComposite::getAroundPlayerIterator(Player *obj, int radius) const
+ZoneIterator MapComposite::getAroundPlayerIterator(MovingObject *obj, int radius) const
{
MapRegion r1;
fillRegion(r1, obj->getOldPosition(), radius);
diff --git a/src/game-server/mapcomposite.hpp b/src/game-server/mapcomposite.hpp
index 0623f602..526b36e2 100644
--- a/src/game-server/mapcomposite.hpp
+++ b/src/game-server/mapcomposite.hpp
@@ -26,11 +26,14 @@
#include <vector>
-#include "object.h"
-#include "player.h"
-
class Map;
class MapComposite;
+class MovingObject;
+class Object;
+class Player;
+class Point;
+class Rectangle;
+class Thing;
/**
* Ordered sets of zones of a map.
@@ -191,7 +194,7 @@ class MapComposite {
* Gets an iterator on the objects around the old and new positions of
* a player (including the ones that were but are now elsewhere).
*/
- ZoneIterator getAroundPlayerIterator(Player *, int radius) const;
+ ZoneIterator getAroundPlayerIterator(MovingObject *, int radius) const;
/**
* Gets everything related to the map.
diff --git a/src/game-server/mapmanager.cpp b/src/game-server/mapmanager.cpp
index d3f431b2..accf7ca0 100644
--- a/src/game-server/mapmanager.cpp
+++ b/src/game-server/mapmanager.cpp
@@ -23,8 +23,8 @@
#include <cassert>
-#include "map.h"
#include "resourcemanager.h"
+#include "game-server/map.hpp"
#include "game-server/mapmanager.hpp"
#include "game-server/mapreader.hpp"
#include "utils/logger.h"
diff --git a/src/game-server/mapreader.cpp b/src/game-server/mapreader.cpp
index d3a49a3c..63d81a64 100644
--- a/src/game-server/mapreader.cpp
+++ b/src/game-server/mapreader.cpp
@@ -21,8 +21,8 @@
* $Id$
*/
-#include "map.h"
#include "resourcemanager.h"
+#include "game-server/map.hpp"
#include "game-server/mapreader.hpp"
#include "utils/base64.h"
#include "utils/logger.h"
diff --git a/src/game-server/object.cpp b/src/game-server/object.cpp
new file mode 100644
index 00000000..9921182d
--- /dev/null
+++ b/src/game-server/object.cpp
@@ -0,0 +1,79 @@
+/*
+ * The Mana World Server
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with The Mana World; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "game-server/map.hpp"
+#include "game-server/mapmanager.hpp"
+#include "game-server/object.hpp"
+
+void MovingObject::move()
+{
+ mOld = getPosition();
+ if (mActionTime > 100)
+ {
+ // current move has not yet ended
+ mActionTime -= 100;
+ return;
+ }
+
+ int tileSX = mOld.x / 32, tileSY = mOld.y / 32;
+ int tileDX = mDst.x / 32, tileDY = mDst.y / 32;
+ if (tileSX == tileDX && tileSY == tileDY)
+ {
+ // moving while staying on the same tile is free
+ setPosition(mDst);
+ mActionTime = 0;
+ return;
+ }
+
+ Map *map = mapManager->getMap(getMapId());
+ // TODO: cache pathfinding results
+ std::list<PATH_NODE> path = map->findPath(tileSX, tileSY, tileDX, tileDY);
+ if (path.empty())
+ {
+ // no path was found
+ mDst = mOld;
+ mActionTime = 0;
+ return;
+ }
+
+ PATH_NODE prev(tileSX, tileSY);
+ Point pos;
+ do
+ {
+ PATH_NODE next = path.front();
+ path.pop_front();
+ mActionTime += (prev.x != next.x && prev.y != next.y)
+ ? mSpeed * 362 / 256 : mSpeed;
+ if (path.empty())
+ {
+ // skip last tile center
+ pos = mDst;
+ break;
+ }
+ pos.x = next.x * 32 + 16;
+ pos.y = next.y * 32 + 16;
+ }
+ while (mActionTime < 100);
+ setPosition(pos);
+
+ mActionTime = mActionTime > 100 ? mActionTime - 100 : 0;
+}
diff --git a/src/game-server/object.hpp b/src/game-server/object.hpp
new file mode 100644
index 00000000..498680e4
--- /dev/null
+++ b/src/game-server/object.hpp
@@ -0,0 +1,258 @@
+/*
+ * The Mana World Server
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with The Mana World; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+
+#ifndef _TMWSERV_OBJECT_H_
+#define _TMWSERV_OBJECT_H_
+
+#include <vector>
+
+#include "point.h"
+
+// Object type enumeration
+enum
+{
+ OBJECT_ITEM = 0, // A simple item
+ OBJECT_ACTOR, // An item that toggle map/quest actions (doors, switchs, ...) and can speak (map panels).
+ OBJECT_NPC, // Non-Playable-Character is an actor capable of movement and maybe actions
+ OBJECT_MONSTER, // A monster (moving actor with AI. Should be able to toggle map/quest actions, too)
+ OBJECT_PLAYER, // A normal being
+ OBJECT_OTHER // Server-only object
+};
+
+class MapComposite;
+
+enum
+{
+ NEW_ON_MAP = 1,
+ NEW_DESTINATION = 2,
+ ATTACK = 4
+};
+
+/**
+ * Base class for in-game objects.
+ */
+class Thing
+{
+ public:
+ /**
+ * Constructor.
+ */
+ Thing(int type)
+ : mType(type)
+ {}
+
+ /**
+ * Empty virtual destructor.
+ */
+ virtual ~Thing() {}
+
+ /**
+ * Gets type.
+ *
+ * @return the type.
+ */
+ int getType() const
+ { return mType; }
+
+ /**
+ * Returns whether this thing is visible on the map or not. (Object)
+ */
+ bool isVisible() const
+ { return mType != OBJECT_OTHER; }
+
+ /**
+ * Returns whether this thing can move on the map or not. (MovingObject)
+ */
+ bool canMove() const
+ { return mType == OBJECT_PLAYER || mType == OBJECT_MONSTER ||
+ mType == OBJECT_NPC; }
+
+ /**
+ * Returns whether this thing can fight or not. (Being)
+ */
+ bool canFight() const
+ { return mType == OBJECT_PLAYER || mType == OBJECT_MONSTER; }
+
+ /**
+ * Updates the internal status.
+ */
+ virtual void
+ update() = 0;
+
+ /**
+ * Gets the map this thing is located on.
+ *
+ * @return ID of map.
+ */
+ int getMapId() const
+ { return mMapId; }
+
+ /**
+ * Sets the map this thing is located on.
+ */
+ void setMapId(int mapId)
+ { mMapId = mapId; }
+
+ private:
+ unsigned short mMapId; /**< id of the map being is on */
+ char mType; /**< Object type */
+};
+
+/**
+ * Generic client-visible object definition.
+ */
+class Object: public Thing
+{
+ public:
+ /**
+ * Constructor.
+ */
+ Object(int type)
+ : Thing(type),
+ mUpdateFlags(0)
+ {}
+
+ /**
+ * Sets the coordinates.
+ *
+ * @param p the coordinates.
+ */
+ void setPosition(const Point &p)
+ { mPos = p; }
+
+ /**
+ * Gets the coordinates.
+ *
+ * @return the coordinates.
+ */
+ Point const &getPosition() const
+ { return mPos; }
+
+ /**
+ * Gets what changed in the object.
+ */
+ int getUpdateFlags() const
+ { return mUpdateFlags; }
+
+ /**
+ * Sets some changes in the object.
+ */
+ void raiseUpdateFlags(int n)
+ { mUpdateFlags |= n; }
+
+ /**
+ * Clears changes in the object.
+ */
+ void clearUpdateFlags()
+ { mUpdateFlags = 0; }
+
+ private:
+ char mUpdateFlags; /**< changes in object status */
+ Point mPos; /**< coordinates */
+};
+
+/**
+ * Base class for in-game moving objects.
+ */
+class MovingObject: public Object
+{
+ public:
+ /**
+ * Proxy constructor.
+ */
+ MovingObject(int type, int id)
+ : Object(type),
+ mPublicID(id),
+ mDirection(0),
+ mActionTime(0)
+ {}
+
+ /**
+ * Gets the destination coordinates of the object.
+ */
+ Point const &getDestination() const
+ { return mDst; }
+
+ /**
+ * Sets the destination coordinates of the object.
+ */
+ void setDestination(Point dst)
+ { mDst = dst; raiseUpdateFlags(NEW_DESTINATION); }
+
+ /**
+ * Gets the old coordinates of the object.
+ */
+ Point getOldPosition() const
+ { return mOld; }
+
+ /**
+ * Sete object direction
+ */
+ void setDirection(int direction)
+ { mDirection = direction; }
+
+ /**
+ * Gets object direction
+ */
+
+ unsigned char getDirection() const
+ { return mDirection; }
+
+ /**
+ * Sets object speed.
+ */
+ void setSpeed(unsigned s)
+ { mSpeed = s; }
+
+ /**
+ * Moves the object toward its destination.
+ */
+ void move();
+
+ /**
+ * Get public ID.
+ *
+ * @return the public ID, 65535 if none yet.
+ */
+ int getPublicID() const
+ { return mPublicID; }
+
+ /**
+ * Set public ID.
+ * The object shall not have any public ID yet.
+ */
+ void setPublicID(int id)
+ { mPublicID = id; }
+
+ private:
+ unsigned short mPublicID; /**< Object ID sent to clients (unique with respect to the map) */
+ Point mDst; /**< target coordinates */
+ Point mOld; /**< old coordinates */
+ unsigned short mSpeed; /**< speed */
+
+ protected:
+ unsigned char mDirection; /**< Facing direction */
+ unsigned short mActionTime; /**< delay until next action */
+};
+
+#endif // _TMWSERV_OBJECT_H_
diff --git a/src/game-server/player.cpp b/src/game-server/player.cpp
new file mode 100644
index 00000000..294239f9
--- /dev/null
+++ b/src/game-server/player.cpp
@@ -0,0 +1,87 @@
+/*
+ * The Mana World Server
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with The Mana World; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include <cassert>
+
+#include "defines.h"
+#include "game-server/player.hpp"
+
+/**
+ * Update the internal status.
+ */
+void Player::update()
+{
+ // computed stats.
+ setStat(STAT_HEAT, 20 + (20 * getRawStat(STAT_VITALITY)));
+ setStat(STAT_ATTACK, 10 + getRawStat(STAT_STRENGTH));
+ setStat(STAT_DEFENCE, 10 + getRawStat(STAT_STRENGTH));
+ setStat(STAT_MAGIC, 10 + getRawStat(STAT_INTELLIGENCE));
+ setStat(STAT_ACCURACY, 50 + getRawStat(STAT_DEXTERITY));
+ setStat(STAT_SPEED, getRawStat(STAT_DEXTERITY));
+
+ // Update persistent data.
+ setPos(getPosition());
+ setMap(getMapId());
+
+ // attacking
+ if (mIsAttacking)
+ {
+ // plausibility check of attack command
+ if (mActionTime <= 0)
+ {
+ // request perform attack
+ mActionTime = 1000;
+ mIsAttacking = false;
+ raiseUpdateFlags(ATTACK);
+ }
+ }
+}
+
+void Player::setInventory(const Inventory &inven)
+{
+ inventory = inven;
+}
+
+bool Player::addItem(unsigned int itemId, unsigned char amount)
+{
+ return inventory.addItem(itemId, amount);
+}
+
+bool Player::removeItem(unsigned int itemId, unsigned char amount)
+{
+ return inventory.removeItem(itemId, amount);
+}
+
+bool Player::hasItem(unsigned int itemId)
+{
+ return inventory.hasItem(itemId);
+}
+
+bool Player::equip(unsigned char slot)
+{
+ return false; // TODO
+}
+
+bool Player::unequip(unsigned char slot)
+{
+ return false; // TODO
+}
diff --git a/src/game-server/player.hpp b/src/game-server/player.hpp
new file mode 100644
index 00000000..4ecef616
--- /dev/null
+++ b/src/game-server/player.hpp
@@ -0,0 +1,124 @@
+/*
+ * The Mana World Server
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with The Mana World; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMWSERV_PLAYER_H_
+#define _TMWSERV_PLAYER_H_
+
+#include <string>
+#include <vector>
+
+#include "playerdata.hpp"
+#include "game-server/being.hpp"
+#include "game-server/inventory.hpp"
+
+class GameClient;
+
+class Player : public Being, public PlayerData
+{
+ public:
+
+ Player(std::string const &name, int id = -1)
+ : Being(OBJECT_PLAYER, 65535),
+ PlayerData(name, id),
+ mClient(NULL),
+ mIsAttacking(false)
+ {}
+
+ /**
+ * Updates the internal status.
+ */
+ void update();
+
+ /**
+ * Sets inventory.
+ */
+ void
+ setInventory(const Inventory &inven);
+
+ /**
+ * Adds item with ID to inventory.
+ *
+ * @return Item add success/failure
+ */
+ bool
+ addItem(unsigned int itemId, unsigned char amount = 1);
+
+ /**
+ * Removes item with ID from inventory.
+ *
+ * @return Item delete success/failure
+ */
+ bool
+ removeItem(unsigned int itemId, unsigned char amount = 0);
+
+ /**
+ * Checks if character has an item.
+ *
+ * @return true if being has item, false otherwise
+ */
+ bool
+ hasItem(unsigned int itemId);
+
+ /**
+ * Equips item with ID in equipment slot.
+ *
+ * @return Equip success/failure
+ */
+ bool
+ equip(unsigned char slot);
+
+ /**
+ * Un-equips item.
+ *
+ * @return Un-equip success/failure
+ */
+ bool
+ unequip(unsigned char slot);
+
+ /**
+ * Set attacking state
+ **/
+ void setAttacking(bool isAttacking)
+ { mIsAttacking = isAttacking; }
+
+ /**
+ * Gets client computer.
+ */
+ GameClient *getClient() const
+ { return mClient; }
+
+ /**
+ * Sets client computer.
+ */
+ void setClient(GameClient *c)
+ { mClient = c; }
+
+ private:
+ Player(Player const &);
+ Player &operator=(Player const &);
+
+ GameClient *mClient; /**< Client computer. */
+ Inventory inventory; /**< Player inventory and equipment. */
+ bool mIsAttacking; /**< Attacking state. */
+};
+
+#endif // _TMWSERV_PLAYER_H_
diff --git a/src/game-server/state.cpp b/src/game-server/state.cpp
index 7e78857e..9763d459 100644
--- a/src/game-server/state.cpp
+++ b/src/game-server/state.cpp
@@ -23,12 +23,11 @@
#include <cassert>
-#include "controller.h"
#include "defines.h"
-#include "map.h"
#include "point.h"
#include "game-server/accountconnection.hpp"
#include "game-server/gamehandler.hpp"
+#include "game-server/map.hpp"
#include "game-server/mapcomposite.hpp"
#include "game-server/mapmanager.hpp"
#include "game-server/state.hpp"
diff --git a/src/game-server/trigger.cpp b/src/game-server/trigger.cpp
index 22a25697..469fb544 100644
--- a/src/game-server/trigger.cpp
+++ b/src/game-server/trigger.cpp
@@ -21,8 +21,8 @@
* $Id$
*/
-#include "player.h"
#include "game-server/mapcomposite.hpp"
+#include "game-server/object.hpp"
#include "game-server/state.hpp"
#include "game-server/trigger.hpp"
diff --git a/src/game-server/trigger.hpp b/src/game-server/trigger.hpp
index a3149812..bb4f776d 100644
--- a/src/game-server/trigger.hpp
+++ b/src/game-server/trigger.hpp
@@ -24,7 +24,7 @@
#ifndef _TMWSERV_TRIGGER
#define _TMWSERV_TRIGGER
-#include "object.h"
+class Object;
class TriggerAction
{