summaryrefslogtreecommitdiff
path: root/src/game-server
diff options
context:
space:
mode:
authorGuillaume Melquiond <guillaume.melquiond@gmail.com>2007-08-19 08:05:45 +0000
committerGuillaume Melquiond <guillaume.melquiond@gmail.com>2007-08-19 08:05:45 +0000
commit31232e3a5702a7618fe40dc74f5d987a662cb081 (patch)
tree170b799b14dc950201eb7eec63c957e542e4c96d /src/game-server
parent2ae3f3a3ef5caee193138a3e5c1613403302089c (diff)
downloadmanaserv-31232e3a5702a7618fe40dc74f5d987a662cb081.tar.gz
manaserv-31232e3a5702a7618fe40dc74f5d987a662cb081.tar.bz2
manaserv-31232e3a5702a7618fe40dc74f5d987a662cb081.tar.xz
manaserv-31232e3a5702a7618fe40dc74f5d987a662cb081.zip
Added support for protective equipment.
Diffstat (limited to 'src/game-server')
-rw-r--r--src/game-server/being.cpp37
-rw-r--r--src/game-server/being.hpp5
-rw-r--r--src/game-server/character.cpp5
-rw-r--r--src/game-server/character.hpp5
-rw-r--r--src/game-server/inventory.cpp88
-rw-r--r--src/game-server/inventory.hpp11
-rw-r--r--src/game-server/item.cpp30
-rw-r--r--src/game-server/item.hpp34
-rw-r--r--src/game-server/itemmanager.cpp2
-rw-r--r--src/game-server/monster.cpp5
10 files changed, 190 insertions, 32 deletions
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 =