summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPhilipp Sehmisch <tmw@crushnet.org>2007-03-11 21:38:08 +0000
committerPhilipp Sehmisch <tmw@crushnet.org>2007-03-11 21:38:08 +0000
commit99f34a8a72f63b4bd9fc2f3c370c8cbe9b9127cf (patch)
treec075dcc834e0720e6de819c7514f4fdfa7cfe554 /src
parent0a74cd8c92844e730cf6f56bdc3dd578c65a10d0 (diff)
downloadmanaserv-99f34a8a72f63b4bd9fc2f3c370c8cbe9b9127cf.tar.gz
manaserv-99f34a8a72f63b4bd9fc2f3c370c8cbe9b9127cf.tar.bz2
manaserv-99f34a8a72f63b4bd9fc2f3c370c8cbe9b9127cf.tar.xz
manaserv-99f34a8a72f63b4bd9fc2f3c370c8cbe9b9127cf.zip
Implemented stat handling infrastructure and basic damage calculation.
Diffstat (limited to 'src')
-rw-r--r--src/controller.cpp16
-rw-r--r--src/controller.h12
-rw-r--r--src/game-server/being.cpp116
-rw-r--r--src/game-server/being.hpp119
-rw-r--r--src/game-server/item.hpp6
-rw-r--r--src/game-server/itemmanager.cpp27
-rw-r--r--src/game-server/player.cpp43
-rw-r--r--src/game-server/player.hpp64
-rw-r--r--src/game-server/testing.cpp10
9 files changed, 339 insertions, 74 deletions
diff --git a/src/controller.cpp b/src/controller.cpp
index d71461f2..737a01b9 100644
--- a/src/controller.cpp
+++ b/src/controller.cpp
@@ -24,6 +24,15 @@
#include "utils/logger.h"
+Controlled::Controlled(int type):
+ Being(type, 65535),
+ mCountDown(0)
+{
+ mStats.base.resize(NB_STATS_BEING, 1); //TODO: fill with the real values
+ mStats.absoluteModificator.resize(NB_STATS_BEING, 0);
+ mStats.percentModificators.resize(NB_STATS_BEING);
+}
+
void Controlled::update()
{
/* Temporary "AI" behaviour that is purely artificial and not at all
@@ -57,3 +66,10 @@ void Controlled::die()
mCountDown = 600;
Being::die();
}
+
+void Controlled::calculateStats()
+{
+ /* All base stats of a monster should be set directly by the monster
+ * database, so there is nothing we should have to calculate here.
+ */
+}
diff --git a/src/controller.h b/src/controller.h
index 40e4b22b..f99a2b74 100644
--- a/src/controller.h
+++ b/src/controller.h
@@ -34,10 +34,7 @@ class Controlled: public Being
/**
* Constructor.
*/
- Controlled(int type):
- Being(type, 65535),
- mCountDown(0)
- {}
+ Controlled(int type);
/**
* Performs one step of controller logic.
@@ -49,6 +46,13 @@ class Controlled: public Being
*/
virtual void die();
+ /**
+ * Recalculates all stats of the being that are derived from others.
+ * Call whenever you change something that affects a derived stat.
+ * Called automatically when you manipulate a stat using setBaseStat()
+ */
+ virtual void calculateStats();
+
private:
/** Count down till next random movement (temporary). */
unsigned int mCountDown;
diff --git a/src/game-server/being.cpp b/src/game-server/being.cpp
index 046423d6..3364d23f 100644
--- a/src/game-server/being.cpp
+++ b/src/game-server/being.cpp
@@ -31,10 +31,29 @@ void Being::damage(Damage damage)
{
if (mAction == DEAD) return;
- int HPloss;
+ // TODO: Implement dodge chance
- HPloss = damage; // TODO: Implement complex damage calculation here
+ int HPloss = damage.value;
+ // TODO: Implement elemental modifier
+
+ switch (damage.type)
+ {
+ case DAMAGETYPE_PHYSICAL:
+ HPloss -= getRealStat(STAT_PHYSICAL_DEFENCE) / damage.penetration;
+ break;
+ case DAMAGETYPE_MAGICAL:
+ // NIY
+ break;
+ case DAMAGETYPE_HAZARD:
+ // NIY
+ break;
+ case DAMAGETYPE_OTHER:
+ // nothing to do here
+ break;
+ }
+
+ if (HPloss < 0) HPloss = 0;
if (HPloss > mHitpoints) HPloss = mHitpoints;
mHitpoints -= HPloss;
@@ -70,8 +89,8 @@ void Being::move()
void Being::performAttack(MapComposite *map)
{
- int SHORT_RANGE = 32;
- int SMALL_ANGLE = 15;
+ int SHORT_RANGE = 64;
+ int SMALL_ANGLE = 45;
Point ppos = getPosition();
int dir = getDirection();
@@ -95,10 +114,6 @@ void Being::performAttack(MapComposite *map)
break;
}
-/* 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;
@@ -115,7 +130,7 @@ void Being::performAttack(MapComposite *map)
ppos, SHORT_RANGE, SMALL_ANGLE, attackAngle)
)
{
- static_cast< Being * >(o)->damage(damage);
+ static_cast< Being * >(o)->damage(getPhysicalAttackDamage());
}
}
}
@@ -129,3 +144,86 @@ void Being::setAction(Action action)
raiseUpdateFlags(UPDATEFLAG_ACTIONCHANGE);
}
}
+
+void Being::addAbsoluteStatModifier(unsigned numStat, short value)
+{
+ mStats.absoluteModificator.at(numStat) = mStats.absoluteModificator.at(numStat) + value;
+}
+
+void Being::removeAbsoluteStatModifier(unsigned numStat, short value)
+{
+ mStats.absoluteModificator.at(numStat) = mStats.absoluteModificator.at(numStat) - value;
+}
+
+void Being::addPercentStatModifier(unsigned numStat, short value)
+{
+ if (value < -100)
+ {
+ LOG_WARN( "Attempt to add a stat modificator for Being"<<
+ getPublicID()<<
+ "that would make the stat negative!"
+ );
+ }
+ else
+ {
+ mStats.percentModificators.at(numStat).push_back(value);
+ }
+}
+
+void Being::removePercentStatModifier(unsigned numStat, short value)
+{
+ std::list<short>::iterator i = mStats.percentModificators.at(numStat).begin();
+
+ while (i != mStats.percentModificators.at(numStat).end())
+ {
+ if ((*i) = value)
+ {
+ mStats.percentModificators.at(numStat).erase(i);
+ return;
+ }
+ }
+ LOG_WARN( "Attempt to remove a stat modificator for Being"<<
+ getPublicID()<<
+ "that hasn't been added before!"
+ );
+}
+
+unsigned short Being::getRealStat(unsigned numStat)
+{
+ int value = mStats.base.at(numStat) + mStats.absoluteModificator.at(numStat);
+ std::list<short>::iterator i;
+
+ float multiplier = 1.0f;
+ for ( i = mStats.percentModificators.at(numStat).begin();
+ i != mStats.percentModificators.at(numStat).end();
+ i++
+ )
+ {
+ multiplier *= (100.0f + (float)(*i)) / 100.0f;
+ }
+
+ /* Floating point inaccuracies might result in a negative multiplier. That
+ * would result in a stat near 2^16. To make sure that this doesn't happen
+ * we return a value of 0 in that case
+ */
+ if (multiplier < 0.0f)
+ {
+ return 0;
+ }
+ else
+ {
+ return (unsigned short)(value * multiplier);
+ }
+}
+
+Damage Being::getPhysicalAttackDamage()
+{
+ Damage damage;
+ damage.type = DAMAGETYPE_PHYSICAL;
+ damage.value = getRealStat(STAT_PHYSICAL_ATTACK_MINIMUM) + (rand()%getRealStat(STAT_PHYSICAL_ATTACK_FLUCTUATION));
+ damage.penetration = 1; // TODO: get from equipped weapon
+ damage.element = ELEMENT_NEUTRAL; // TODO: get from equipped weapon
+ damage.source = this;
+
+ return damage;
+}
diff --git a/src/game-server/being.hpp b/src/game-server/being.hpp
index 2eaffa16..77b7bfc8 100644
--- a/src/game-server/being.hpp
+++ b/src/game-server/being.hpp
@@ -30,12 +30,14 @@
#include "defines.h"
#include "game-server/object.hpp"
+class Being;
class MapComposite;
/**
* Element attribute for beings, actors and items.
+ * Subject to change until pauan and dabe are finished with the element system.
*/
-enum
+enum Element
{
ELEMENT_NEUTRAL = 0,
ELEMENT_FIRE,
@@ -75,38 +77,43 @@ enum
DIRECTION_RIGHT
};
-
/**
- * Computed statistics of a Being.
+ * Methods of damage calculation
*/
-enum
+enum Damagetype
{
- STAT_HEAT = 0,
- STAT_ATTACK,
- STAT_DEFENCE,
- STAT_MAGIC,
- STAT_ACCURACY,
- STAT_SPEED,
- NB_CSTAT
+ DAMAGETYPE_PHYSICAL,
+ DAMAGETYPE_MAGICAL,
+ DAMAGETYPE_HAZARD,
+ DAMAGETYPE_OTHER
};
/**
- * Structure type for the computed statistics of a Being.
+ * Structure describing severity and nature of an attack a being can suffer of
*/
-struct Statistics
+struct Damage
{
- unsigned short stats[NB_CSTAT];
+ int value;
+ int penetration;
+ Element element;
+ Damagetype type;
+ Being *source;
};
/**
- * Placeholder for a more complex damage structure
+ * Type definition for a list of hits
*/
-typedef unsigned short Damage;
+typedef std::list<unsigned int> Hits;
/**
- * Type definition for a list of hits
+ * Structure type for the stats of a Being.
*/
-typedef std::list<unsigned int> Hits;
+struct Stats
+{
+ std::vector<unsigned short> base;
+ std::vector<short> absoluteModificator;
+ std::vector< std::list<short> > percentModificators;
+};
/**
* Generic Being (living object).
@@ -115,6 +122,20 @@ typedef std::list<unsigned int> Hits;
class Being : public MovingObject
{
public:
+
+ /**
+ * Computed statistics of a Being.
+ */
+ enum Stat
+ {
+ STAT_HP_MAXIMUM,
+ STAT_PHYSICAL_ATTACK_MINIMUM,
+ STAT_PHYSICAL_ATTACK_FLUCTUATION,
+ STAT_PHYSICAL_DEFENCE,
+ // add new computed statistics on demand
+ NB_STATS_BEING
+ };
+
/**
* Moves enum for beings and actors for others players vision.
* WARNING: Has to be in sync with the same enum in the Being class
@@ -128,6 +149,7 @@ class Being : public MovingObject
DEAD,
HURT
};
+
/**
* Proxy constructor.
*/
@@ -137,27 +159,70 @@ class Being : public MovingObject
{}
/**
- * Sets a computed statistic.
+ * Sets a being statistic.
*
* @param numStat the statistic number.
* @param value the new value.
*/
- void setStat(int numStat, unsigned short value)
- { mStats.stats[numStat] = value; }
+ void setBaseStat(unsigned numStat, unsigned short value)
+ { mStats.base[numStat] = value;
+ calculateBaseStats();
+ }
+
+ /**
+ * Adds a fixed value stat modifier
+ */
+ void addAbsoluteStatModifier(unsigned numStat, short value);
+
+ /**
+ * Removes a fixed value stat modifier
+ */
+ void removeAbsoluteStatModifier(unsigned numStat, short value);
+
+ /**
+ * Adds a multiplier stat modificator in percent
+ */
+ void addPercentStatModifier(unsigned numStat, short value);
/**
- * Gets a computed statistic.
+ * Removes a previously added percent stat modifier.
+ * Does nothing and logs a warning when no modifier with the same
+ * value has been added before.
+ */
+ void removePercentStatModifier(unsigned numStat, short value);
+
+ /**
+ * Returns a being statistic without temporary modifiers
*
* @param numStat the statistic number.
* @return the statistic value.
*/
- unsigned short getStat(int numStat)
- { return mStats.stats[numStat]; }
+ unsigned short getBaseStat(unsigned stat)
+ { return mStats.base.at(stat); }
+
+ /**
+ * Returns a being statistic with added temporary modifiers
+ */
+ unsigned short getRealStat(unsigned stat);
+
+ /**
+ * Recalculates all stats of the being that are derived from others.
+ * Call whenever you change something that affects a derived stat.
+ * Called automatically when you manipulate a stat using setBaseStat()
+ */
+ virtual void calculateBaseStats()
+ { /*NOOP*/ };
+
+ /**
+ * Creates a damage structure for a normal melee attack based on the
+ * current being stats and equipment.
+ */
+ Damage getPhysicalAttackDamage();
/**
* sets the hit points
*/
- void setHitpoints(int hp)
+ void setHitpoints(unsigned hp)
{ mHitpoints = hp; }
/**
@@ -206,12 +271,12 @@ class Being : public MovingObject
int mHitpoints; /**< Hitpoints of the being */
Action mAction;
+ Stats mStats;
+
private:
Being(Being const &rhs);
Being &operator=(Being const &rhs);
- Statistics mStats; /**< stats modifiers or computed stats */
-
Hits mHitsTaken; /**< List of punches taken since last update */
};
diff --git a/src/game-server/item.hpp b/src/game-server/item.hpp
index 21b9e6dd..40a687ab 100644
--- a/src/game-server/item.hpp
+++ b/src/game-server/item.hpp
@@ -111,11 +111,7 @@ struct Modifiers
unsigned short lifetime; /**< Modifiers lifetime in seconds. */
// Caracteristics Modifiers
- short rawStats[NB_RSTAT]; /**< Raw Stats modifiers */
- short computedStats[NB_CSTAT]; /**< Computed Stats modifiers */
-
- short hp; /**< HP modifier */
- short mp; /**< MP Modifier */
+ short stat[Player::NB_STATS_PLAYER]; /**< Stat modifiers */
// Weapon
unsigned short range; /**< Weapon Item Range */
diff --git a/src/game-server/itemmanager.cpp b/src/game-server/itemmanager.cpp
index b80f295b..ea060d06 100644
--- a/src/game-server/itemmanager.cpp
+++ b/src/game-server/itemmanager.cpp
@@ -84,20 +84,19 @@ ItemManager::ItemManager(std::string const &itemReferenceFile)
Modifiers modifiers;
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);
- modifiers.rawStats[STAT_VITALITY] = XML::getProperty(node, "vitality", 0);
- modifiers.rawStats[STAT_INTELLIGENCE] = XML::getProperty(node, "intelligence", 0);
- modifiers.rawStats[STAT_DEXTERITY] = XML::getProperty(node, "dexterity", 0);
- modifiers.rawStats[STAT_LUCK] = XML::getProperty(node, "luck", 0);
- modifiers.computedStats[STAT_HEAT] = XML::getProperty(node, "heat", 0);
- modifiers.computedStats[STAT_ATTACK] = XML::getProperty(node, "attack", 0);
- modifiers.computedStats[STAT_DEFENCE] = XML::getProperty(node, "defence", 0);
- modifiers.computedStats[STAT_MAGIC] = XML::getProperty(node, "magic", 0);
- modifiers.computedStats[STAT_ACCURACY] = XML::getProperty(node, "accuracy", 0);
- modifiers.computedStats[STAT_SPEED] = XML::getProperty(node, "speed", 0);
- modifiers.hp = XML::getProperty(node, "hp", 0);
- modifiers.mp = XML::getProperty(node, "mp", 0);
+ modifiers.stat[Player::STRENGTH] = XML::getProperty(node, "strength", 0);
+ modifiers.stat[Player::AGILITY] = XML::getProperty(node, "agility", 0);
+ modifiers.stat[Player::VITALITY] = XML::getProperty(node, "vitality", 0);
+ modifiers.stat[Player::INTELLIGENCE] = XML::getProperty(node, "intelligence", 0);
+ modifiers.stat[Player::DEXTERITY] = XML::getProperty(node, "dexterity", 0);
+ modifiers.stat[Player::WILLPOWER] = XML::getProperty(node, "willpower", 0);
+ modifiers.stat[Player::CHARISMA] = XML::getProperty(node, "charisma", 0);
+
+ modifiers.stat[Being::STAT_HP_MAXIMUM] = XML::getProperty(node, "hp", 0);
+ modifiers.stat[Being::STAT_PHYSICAL_ATTACK_MINIMUM] = XML::getProperty(node, "attack", 0);
+ modifiers.stat[Being::STAT_PHYSICAL_DEFENCE] = XML::getProperty(node, "defence", 0);
+
+
modifiers.range = XML::getProperty(node, "range", 0);
modifiers.weaponType = XML::getProperty(node, "weapon_type", 0);
modifiers.beingStateEffect = XML::getProperty(node, "status_effect", 0);
diff --git a/src/game-server/player.cpp b/src/game-server/player.cpp
index 5580d094..923d2513 100644
--- a/src/game-server/player.cpp
+++ b/src/game-server/player.cpp
@@ -25,19 +25,30 @@
#include "defines.h"
#include "game-server/player.hpp"
+Player::Player(std::string const &name, int id)
+ : Being(OBJECT_PLAYER, 65535),
+ PlayerData(name, id),
+ mClient(NULL)
+{
+ mStats.base.resize(NB_STATS_PLAYER, 1); //TODO: fill with the real values
+ mStats.absoluteModificator.resize(NB_STATS_PLAYER, 0);
+ mStats.percentModificators.resize(NB_STATS_PLAYER);
+
+ // some bogus values for testing purpose
+ mStats.base.at(STRENGTH) = 10;
+ mStats.base.at(SKILL_WEAPON_UNARMED) = 5;
+
+ calculateBaseStats();
+
+ mHitpoints = getRealStat(STAT_HP_MAXIMUM);
+ mSize = 16;
+}
+
/**
* 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));
-
// attacking
if (mAction == ATTACK)
{
@@ -51,3 +62,19 @@ void Player::update()
}
}
}
+
+void Player::calculateBaseStats()
+{
+ mStats.base.at(STAT_HP_MAXIMUM)
+ = getRealStat(VITALITY);
+
+ mStats.base.at(STAT_PHYSICAL_ATTACK_MINIMUM)
+ = getRealStat(STRENGTH) /* + weapon damage fluctuation*/;
+
+ // TODO: get the skill that is skill required for weapon
+ mStats.base.at(STAT_PHYSICAL_ATTACK_FLUCTUATION)
+ = getRealStat(SKILL_WEAPON_UNARMED) /* + weapon damage fluctuation*/;
+
+ mStats.base.at(STAT_PHYSICAL_DEFENCE)
+ = 42 /* + sum of equipment pieces */;
+}
diff --git a/src/game-server/player.hpp b/src/game-server/player.hpp
index bd1ec997..76c3f591 100644
--- a/src/game-server/player.hpp
+++ b/src/game-server/player.hpp
@@ -48,15 +48,59 @@ class Player : public Being, public PlayerData
{
public:
- Player(std::string const &name, int id = -1)
- : Being(OBJECT_PLAYER, 65535),
- PlayerData(name, id),
- mClient(NULL)
+ /**
+ * Base attributes of a player character
+ */
+ enum Attributes
+ {
+ STRENGTH = NB_STATS_BEING,
+ AGILITY,
+ DEXTERITY,
+ VITALITY,
+ INTELLIGENCE,
+ WILLPOWER,
+ CHARISMA,
+ NB_ATTRIBUTES
+ };
+
+ enum WeaponSkills
+ {
+ SKILL_WEAPON_UNARMED = NB_ATTRIBUTES,
+ SKILL_WEAPON_SWORD,
+ SKILL_WEAPON_AXE,
+ SKILL_WEAPON_POLEARM,
+ SKILL_WEAPON_JAVELIN,
+ SKILL_WEAPON_WHIP,
+ SKILL_WEAPON_DAGGER,
+ SKILL_WEAPON_STAFF,
+ SKILL_WEAPON_BOW,
+ SKILL_WEAPON_CROSSBOW,
+ SKILL_WEAPON_THROWN,
+ NB_WEAPONSKILLS
+ };
+
+ enum MagicSkills
+ {
+ SKILL_MAGIC_IAMJUSTAPLACEHOLDER = NB_WEAPONSKILLS,
+ NB_MAGICSKILLS
+ };
+
+ enum CraftSkills
{
- mHitpoints=5;
- mSize = 16;
+ SKILL_CRAFT_IAMJUSTAPLACEHOLDER = NB_MAGICSKILLS,
+ NB_CRAFTSKILLS
+ };
+
+ enum OtherSkills
+ {
+ SKILL_IAMJUSTAPLACEHOLDER = NB_CRAFTSKILLS,
+ NB_OTHERSKILLS
}
+ static const NB_STATS_PLAYER = NB_OTHERSKILLS;
+
+ Player(std::string const &name, int id = -1);
+
/**
* Updates the internal status.
*/
@@ -74,6 +118,14 @@ class Player : public Being, public PlayerData
void setClient(GameClient *c)
{ mClient = c; }
+ /**
+ * Recalculates all player stats that are derived from others.
+ * Call whenever you change something that affects a derived stat.
+ * Called automatically when you manipulate a stat using setBaseStat()
+ */
+ virtual void calculateBaseStats();
+
+
private:
Player(Player const &);
Player &operator=(Player const &);
diff --git a/src/game-server/testing.cpp b/src/game-server/testing.cpp
index b48a7e77..7c3f87af 100644
--- a/src/game-server/testing.cpp
+++ b/src/game-server/testing.cpp
@@ -37,7 +37,15 @@ void testingMap(int id)
Being *being = new Controlled(OBJECT_MONSTER);
being->setSpeed(150);
being->setSize(8);
- being->setHitpoints(3);
+
+ // some bogus stats for testing
+ being->setBaseStat(Being::STAT_HP_MAXIMUM, 42);
+ being->setBaseStat(Being::STAT_PHYSICAL_ATTACK_MINIMUM, 1);
+ being->setBaseStat(Being::STAT_PHYSICAL_ATTACK_FLUCTUATION, 0);
+ being->setBaseStat(Being::STAT_PHYSICAL_DEFENCE, 5);
+
+ being->setHitpoints(being->getRealStat(Being::STAT_HP_MAXIMUM));
+
being->setMapId(1);
Point pos(720, 900);
being->setPosition(pos);