diff options
author | Guillaume Melquiond <guillaume.melquiond@gmail.com> | 2007-01-03 17:10:43 +0000 |
---|---|---|
committer | Guillaume Melquiond <guillaume.melquiond@gmail.com> | 2007-01-03 17:10:43 +0000 |
commit | 1673de8b5553f6dcd4898c84b8d44ba8b30740f1 (patch) | |
tree | 3dcc47461a6b4914c4e81492e7be885c3a1502ea /src/game-server | |
parent | 6b7441516002d6e7cca424416bb67c6bc7d7c9d2 (diff) | |
download | manaserv-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.cpp | 10 | ||||
-rw-r--r-- | src/game-server/accountconnection.hpp | 4 | ||||
-rw-r--r-- | src/game-server/being.cpp | 87 | ||||
-rw-r--r-- | src/game-server/being.hpp | 214 | ||||
-rw-r--r-- | src/game-server/gamehandler.cpp | 6 | ||||
-rw-r--r-- | src/game-server/gamehandler.hpp | 2 | ||||
-rw-r--r-- | src/game-server/inventory.cpp | 419 | ||||
-rw-r--r-- | src/game-server/inventory.hpp | 233 | ||||
-rw-r--r-- | src/game-server/itemmanager.cpp | 4 | ||||
-rw-r--r-- | src/game-server/map.cpp | 302 | ||||
-rw-r--r-- | src/game-server/map.hpp | 174 | ||||
-rw-r--r-- | src/game-server/mapcomposite.cpp | 6 | ||||
-rw-r--r-- | src/game-server/mapcomposite.hpp | 11 | ||||
-rw-r--r-- | src/game-server/mapmanager.cpp | 2 | ||||
-rw-r--r-- | src/game-server/mapreader.cpp | 2 | ||||
-rw-r--r-- | src/game-server/object.cpp | 79 | ||||
-rw-r--r-- | src/game-server/object.hpp | 258 | ||||
-rw-r--r-- | src/game-server/player.cpp | 87 | ||||
-rw-r--r-- | src/game-server/player.hpp | 124 | ||||
-rw-r--r-- | src/game-server/state.cpp | 3 | ||||
-rw-r--r-- | src/game-server/trigger.cpp | 2 | ||||
-rw-r--r-- | src/game-server/trigger.hpp | 2 |
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 { |