diff options
author | Guillaume Melquiond <guillaume.melquiond@gmail.com> | 2007-08-19 08:05:45 +0000 |
---|---|---|
committer | Guillaume Melquiond <guillaume.melquiond@gmail.com> | 2007-08-19 08:05:45 +0000 |
commit | 31232e3a5702a7618fe40dc74f5d987a662cb081 (patch) | |
tree | 170b799b14dc950201eb7eec63c957e542e4c96d | |
parent | 2ae3f3a3ef5caee193138a3e5c1613403302089c (diff) | |
download | manaserv-31232e3a5702a7618fe40dc74f5d987a662cb081.tar.gz manaserv-31232e3a5702a7618fe40dc74f5d987a662cb081.tar.bz2 manaserv-31232e3a5702a7618fe40dc74f5d987a662cb081.tar.xz manaserv-31232e3a5702a7618fe40dc74f5d987a662cb081.zip |
Added support for protective equipment.
-rw-r--r-- | ChangeLog | 16 | ||||
-rw-r--r-- | src/account-server/accounthandler.cpp | 2 | ||||
-rw-r--r-- | src/defines.h | 2 | ||||
-rw-r--r-- | src/game-server/being.cpp | 37 | ||||
-rw-r--r-- | src/game-server/being.hpp | 5 | ||||
-rw-r--r-- | src/game-server/character.cpp | 5 | ||||
-rw-r--r-- | src/game-server/character.hpp | 5 | ||||
-rw-r--r-- | src/game-server/inventory.cpp | 88 | ||||
-rw-r--r-- | src/game-server/inventory.hpp | 11 | ||||
-rw-r--r-- | src/game-server/item.cpp | 30 | ||||
-rw-r--r-- | src/game-server/item.hpp | 34 | ||||
-rw-r--r-- | src/game-server/itemmanager.cpp | 2 | ||||
-rw-r--r-- | src/game-server/monster.cpp | 5 |
13 files changed, 208 insertions, 34 deletions
@@ -1,3 +1,19 @@ +2007-08-19 Guillaume Melquiond <guillaume.melquiond@gmail.com> + + * src/account-server/accounthandler.cpp, src/defines.h: Fixed typos. + * src/game-server/itemmanager.cpp: Worked around inconsistent spelling. + * src/game-server/item.cpp, src/game-server/item.hpp: Added support for + equipment modifiers. + * src/game-server/inventory.hpp, src/game-server/inventory.cpp: Added + sanity checks at initialization. Applied equipment modifiers to + character. + * src/game-server/being.hpp, src/game-server/being.cpp: Set base + element resistance to 100. Added support for temporary modifiers. + * src/game-server/character.cpp: Removed redundant updates of + attributes. + * src/game-server/monster.cpp, src/game-server/character.hpp: Cleaned + fallout due to above patches. + 2007-08-18 Guillaume Melquiond <guillaume.melquiond@gmail.com> * src/serialize/characterdata.hpp, src/account-server/dalstorage.cpp, diff --git a/src/account-server/accounthandler.cpp b/src/account-server/accounthandler.cpp index d0346ade..a199a96a 100644 --- a/src/account-server/accounthandler.cpp +++ b/src/account-server/accounthandler.cpp @@ -160,7 +160,7 @@ void AccountHandler::sendCharacterData(AccountClient &computer, int slot, Charac charInfo.writeByte(ch.getLevel()); charInfo.writeLong(ch.getPossessions().money); - for (int j = BASE_ATTR_BEGIN; j < BASE_ATTR_END; ++j) + for (int j = CHAR_ATTR_BEGIN; j < CHAR_ATTR_END; ++j) { charInfo.writeShort(ch.getAttribute(j)); } diff --git a/src/defines.h b/src/defines.h index f3a91a34..138094f4 100644 --- a/src/defines.h +++ b/src/defines.h @@ -393,7 +393,7 @@ enum */ enum { - CHAR_ATTR_BEGIN = BASE_ATTR_END, + CHAR_ATTR_BEGIN = NB_BEING_ATTRIBUTES, CHAR_ATTR_STRENGTH = CHAR_ATTR_BEGIN, CHAR_ATTR_AGILITY, CHAR_ATTR_DEXTERITY, diff --git a/src/game-server/being.cpp b/src/game-server/being.cpp index 0fd03af1..aafb076a 100644 --- a/src/game-server/being.cpp +++ b/src/game-server/being.cpp @@ -36,6 +36,11 @@ Being::Being(int type, int id): { Attribute attr = { 0, 0 }; mAttributes.resize(NB_BEING_ATTRIBUTES, attr); + // Initialize element resistance to 100 (normal damage). + for (int i = BASE_ELEM_BEGIN; i < BASE_ELEM_END; ++i) + { + mAttributes[i].base = 100; + } } Being::~Being() @@ -81,7 +86,6 @@ int Being::damage(Object *, Damage const &damage) if (avoidChance > 50) avoidChance = 50; } int chance = rand() / (RAND_MAX / 100); - LOG_INFO("Chance: " << chance << " (" << avoidChance << ", " << 100 - criticalChance << "); Damage: " << HPloss); if (chance <= avoidChance) { mHitsTaken.push_back(0); @@ -89,9 +93,9 @@ int Being::damage(Object *, Damage const &damage) } if (chance >= 100 - criticalChance) HPloss *= 2; - /* Elemental modifier at 0 means normal damage. At -100, it means immune. - And at 100, it means vulnerable (double damage). */ - int mod1 = 100 + getModifiedAttribute(BASE_ELEM_BEGIN + damage.element); + /* Elemental modifier at 100 means normal damage. At 0, it means immune. + And at 200, it means vulnerable (double damage). */ + int mod1 = getModifiedAttribute(BASE_ELEM_BEGIN + damage.element); /* Resistance to damage at 0 gives normal damage. At 100, it gives halved damage. At 200, it divides damage by 3. And so on. */ @@ -245,15 +249,17 @@ void Being::removeEquipmentModifier(int attr, int value) void Being::dispellModifiers(int level) { - for (AttributeModifiers::iterator i = mModifiers.begin(); - i != mModifiers.end(); ++i) + AttributeModifiers::iterator i = mModifiers.begin(); + while (i != mModifiers.end()) { if (i->level && i->level <= level) { mAttributes[i->attr].mod -= i->value; modifiedAttribute(i->attr); i = mModifiers.erase(i); + continue; } + ++i; } } @@ -262,3 +268,22 @@ int Being::getModifiedAttribute(int attr) const int res = mAttributes[attr].base + mAttributes[attr].mod; return res <= 0 ? 0 : res; } + +void Being::update() +{ + // Update lifetime of effects. + AttributeModifiers::iterator i = mModifiers.begin(); + while (i != mModifiers.end()) + { + if (i->duration) + { + --i->duration; + if (!i->duration) + { + i = mModifiers.erase(i); + continue; + } + } + ++i; + } +} diff --git a/src/game-server/being.hpp b/src/game-server/being.hpp index 1cceb303..6c5b2669 100644 --- a/src/game-server/being.hpp +++ b/src/game-server/being.hpp @@ -129,6 +129,11 @@ class Being : public MovingObject ~Being(); /** + * Cleans obsolete attribute modifiers. + */ + void update(); + + /** * 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. diff --git a/src/game-server/character.cpp b/src/game-server/character.cpp index 29eda735..ae888d44 100644 --- a/src/game-server/character.cpp +++ b/src/game-server/character.cpp @@ -51,6 +51,7 @@ Character::Character(MessageIn &msg): mName = msg.readString(); deserializeCharacterData(*this, msg); setSize(16); + Inventory(this).initialize(); } void Character::perform() @@ -187,10 +188,10 @@ void Character::modifiedAttribute(int attr) // We have just modified the computed attributes. Mark them as such. for (int i = BASE_ATTR_BEGIN; i < BASE_ATTR_END; ++i) { - mModifiedAttributes.push_back(i); + flagAttribute(i); } } - mModifiedAttributes.push_back(attr); + flagAttribute(attr); } void Character::flagAttribute(int attr) diff --git a/src/game-server/character.hpp b/src/game-server/character.hpp index 3119da7a..62245fc7 100644 --- a/src/game-server/character.hpp +++ b/src/game-server/character.hpp @@ -50,11 +50,6 @@ class Character : public Being Character(MessageIn &msg); /** - * Updates the internal status. - */ - void update() {} - - /** * Perform actions. */ void perform(); diff --git a/src/game-server/inventory.cpp b/src/game-server/inventory.cpp index 4111e07e..c2dc8ba9 100644 --- a/src/game-server/inventory.cpp +++ b/src/game-server/inventory.cpp @@ -30,6 +30,7 @@ #include "game-server/item.hpp" #include "game-server/itemmanager.hpp" #include "net/messageout.hpp" +#include "utils/logger.h" Inventory::Inventory(Character *p, bool d): mPoss(&p->getPossessions()), msg(GPMSG_INVENTORY), mClient(p), @@ -142,6 +143,47 @@ void Inventory::sendFull() const gameHandler->sendTo(mClient, m); } +void Inventory::initialize() +{ + assert(!mDelayed); + + // First, check the equipment and apply its modifiers. + for (int i = 0; i < EQUIP_PROJECTILE_SLOT; ++i) + { + int itemId = mPoss->equipment[i]; + if (!itemId) continue; + if (ItemClass *ic = ItemManager::getItem(itemId)) + { + ic->getModifiers().applyAttributes(mClient); + } + else + { + mPoss->equipment[i] = 0; + LOG_WARN("Removed unknown item " << itemId << " from equipment " + "of character " << mClient->getDatabaseID() << '.'); + } + } + + // Second, remove unknown inventory items. + int i = 0; + while (i < (int)mPoss->inventory.size()) + { + int itemId = mPoss->inventory[i].itemId; + if (itemId) + { + ItemClass *ic = ItemManager::getItem(itemId); + if (!ic) + { + LOG_WARN("Removed unknown item " << itemId << " from inventory" + " of character " << mClient->getDatabaseID() << '.'); + freeIndex(i); + continue; + } + } + ++i; + } +} + int Inventory::getItem(int slot) const { for (std::vector< InventoryItem >::const_iterator i = mPoss->inventory.begin(), @@ -615,6 +657,33 @@ void Inventory::replaceInSlot(int slot, int itemId, int amount) } } +void Inventory::changeEquipment(int slot, int itemId) +{ + // FIXME: Changes are applied now, so it does not work in delayed mode. + assert(!mDelayed); + + int oldId = mPoss->equipment[slot]; + if (oldId == itemId) + { + return; + } + + if (oldId) + { + ItemManager::getItem(oldId)->getModifiers().cancelAttributes(mClient); + } + + if (itemId) + { + ItemManager::getItem(itemId)->getModifiers().applyAttributes(mClient); + } + + msg.writeByte(slot); + msg.writeShort(itemId); + mPoss->equipment[slot] = itemId; + mChangedLook = true; +} + void Inventory::equip(int slot) { int itemId = getItem(slot); @@ -645,13 +714,8 @@ void Inventory::equip(int slot) } replaceInSlot(slot, id1, 1); - msg.writeByte(EQUIP_FIGHT1_SLOT); - msg.writeShort(itemId); - msg.writeByte(EQUIP_FIGHT2_SLOT); - msg.writeShort(0); - mPoss->equipment[EQUIP_FIGHT1_SLOT] = itemId; - mPoss->equipment[EQUIP_FIGHT2_SLOT] = 0; - mChangedLook = true; + changeEquipment(EQUIP_FIGHT1_SLOT, itemId); + changeEquipment(EQUIP_FIGHT2_SLOT, 0); return; } @@ -715,10 +779,7 @@ void Inventory::equip(int slot) // Put the item in the first equipment slot. replaceInSlot(slot, id, 1); - msg.writeByte(firstSlot); - msg.writeShort(itemId); - mPoss->equipment[firstSlot] = itemId; - mChangedLook = true; + changeEquipment(firstSlot, itemId); } void Inventory::unequip(int slot) @@ -732,9 +793,6 @@ void Inventory::unequip(int slot) if (insert(itemId, 1) == 0) { - msg.writeByte(slot); - msg.writeShort(0); - mPoss->equipment[slot] = 0; - mChangedLook = true; + changeEquipment(slot, 0); } } diff --git a/src/game-server/inventory.hpp b/src/game-server/inventory.hpp index ff01087e..f1cdaec1 100644 --- a/src/game-server/inventory.hpp +++ b/src/game-server/inventory.hpp @@ -95,6 +95,12 @@ class Inventory void sendFull() const; /** + * Ensures the inventory is sane and apply equipment modifiers. + * Should be run only once and the very first time. + */ + void initialize(); + + /** * Equips item from given inventory slot. */ void equip(int slot); @@ -193,6 +199,11 @@ class Inventory */ void replaceInSlot(int slot, int itemId, int amount); + /** + * Changes equipment and adjusts character attributes. + */ + void changeEquipment(int slot, int itemId); + Possessions *mPoss; /**< Pointer to the modified possessions. */ MessageOut msg; /**< Update message containing all the changes. */ Character *mClient; /**< Character to notify. */ diff --git a/src/game-server/item.cpp b/src/game-server/item.cpp index dc99511d..1b32cdfa 100644 --- a/src/game-server/item.cpp +++ b/src/game-server/item.cpp @@ -23,6 +23,8 @@ #include "game-server/item.hpp" +#include "game-server/being.hpp" + int ItemModifiers::getValue(int type) const { for (std::vector< ItemModifier >::const_iterator i = mModifiers.begin(), @@ -54,6 +56,34 @@ void ItemModifiers::setAttributeValue(int attr, int value) setValue(MOD_ATTRIBUTE + attr, value); } +void ItemModifiers::applyAttributes(Being *b) const +{ + int lifetime = getValue(MOD_LIFETIME); + for (std::vector< ItemModifier >::const_iterator i = mModifiers.begin(), + i_end = mModifiers.end(); i != i_end; ++i) + { + if (i->type < MOD_ATTRIBUTE) continue; + + AttributeModifier am; + am.attr = i->type - MOD_ATTRIBUTE; + am.duration = lifetime; + am.value = i->value; + // TODO: No spell currently. + am.level = 0; + b->addModifier(am); + } +} + +void ItemModifiers::cancelAttributes(Being *b) const +{ + for (std::vector< ItemModifier >::const_iterator i = mModifiers.begin(), + i_end = mModifiers.end(); i != i_end; ++i) + { + if (i->type < MOD_ATTRIBUTE) continue; + b->removeEquipmentModifier(i->type - MOD_ATTRIBUTE, i->value); + } +} + bool ItemClass::use(Being *itemUser) { bool usedSuccessfully = true; diff --git a/src/game-server/item.hpp b/src/game-server/item.hpp index 83706b9c..b2bbd303 100644 --- a/src/game-server/item.hpp +++ b/src/game-server/item.hpp @@ -24,9 +24,12 @@ #ifndef _TMWSERV_ITEM #define _TMWSERV_ITEM +#include <string> #include <vector> -#include "game-server/character.hpp" +#include "game-server/object.hpp" + +class Being; /** * Enumeration of available Item types. @@ -119,7 +122,7 @@ enum struct ItemModifier { unsigned char type; - signed short value; + short value; }; /** @@ -128,11 +131,38 @@ struct ItemModifier class ItemModifiers { public: + + /** + * Gets the value associated to a modifier type, or zero if none. + */ int getValue(int type) const; + + /** + * Sets the value associated to a modifier type. + */ void setValue(int type, int amount); + + /** + * Gets the value associated to a MOD_ATTRIBUTE class, or zero if none. + */ int getAttributeValue(int attr) const; + + /** + * Sets the value associated to a MOD_ATTRIBUTE class. + */ void setAttributeValue(int attr, int amount); + /** + * Applies all the attribute modifiers to a given Being. + */ + void applyAttributes(Being *) const; + + /** + * Cancels all the applied modifiers to a given Being. + * Only meant for equipment. + */ + void cancelAttributes(Being *) const; + private: std::vector< ItemModifier > mModifiers; }; diff --git a/src/game-server/itemmanager.cpp b/src/game-server/itemmanager.cpp index f22f2bf2..3ee4ef48 100644 --- a/src/game-server/itemmanager.cpp +++ b/src/game-server/itemmanager.cpp @@ -97,7 +97,9 @@ void ItemManager::initialize(std::string const &itemReferenceFile) modifiers.setValue(MOD_ELEMENT_TYPE, XML::getProperty(node, "element", 0)); modifiers.setValue(MOD_LIFETIME, XML::getProperty(node, "lifetime", 0)); modifiers.setAttributeValue(BASE_ATTR_HP, XML::getProperty(node, "hp", 0)); + // FIXME: decide on one single spelling for defense/defence modifiers.setAttributeValue(BASE_ATTR_PHY_RES, XML::getProperty(node, "defense", 0)); + modifiers.setAttributeValue(BASE_ATTR_PHY_RES, XML::getProperty(node, "defence", 0)); modifiers.setAttributeValue(CHAR_ATTR_STRENGTH, XML::getProperty(node, "strength", 0)); modifiers.setAttributeValue(CHAR_ATTR_AGILITY, XML::getProperty(node, "agility", 0)); modifiers.setAttributeValue(CHAR_ATTR_DEXTERITY, XML::getProperty(node, "dexterity", 0)); diff --git a/src/game-server/monster.cpp b/src/game-server/monster.cpp index 45b0fbbe..e859c9f9 100644 --- a/src/game-server/monster.cpp +++ b/src/game-server/monster.cpp @@ -96,6 +96,8 @@ void Monster::perform() void Monster::update() { + Being::update(); + // If dead do nothing but rot if (mAction == DEAD) { @@ -235,8 +237,7 @@ void Monster::died(Being *being) int Monster::damage(Object *source, Damage const &damage) { int HPLoss = Being::damage(source, damage); - if (getModifiedAttribute(BASE_ATTR_HP) && HPLoss && source && - source->getType() == OBJECT_CHARACTER) + if (HPLoss && source && source->getType() == OBJECT_CHARACTER) { Being *s = static_cast< Being * >(source); std::pair< std::map< Being *, int >::iterator, bool > ib = |