summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog14
-rw-r--r--src/defines.h9
-rw-r--r--src/game-server/item.hpp5
-rw-r--r--src/game-server/itemmanager.cpp78
-rw-r--r--src/game-server/monster.cpp45
-rw-r--r--src/game-server/monster.hpp36
-rw-r--r--src/game-server/monstermanager.cpp43
-rw-r--r--src/utils/xml.cpp72
-rw-r--r--src/utils/xml.hpp23
9 files changed, 235 insertions, 90 deletions
diff --git a/ChangeLog b/ChangeLog
index 83033069..83bf81b8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2008-02-21 Philipp Sehmisch <tmw@crushnet.org>
+
+ * src/util/xml.cpp, src/util/xml.hpp, src/game-server/itemmanager.cpp,
+ src/game-server/monstermanager.cpp, src/game-server/item.hpp:
+ Moved the functions which translate strings in XML files into
+ enumerations from the parsers to the XML utilities.
+ * src/game-server/itemmanager.cpp, src/game-server/item.hpp: Added
+ "item types" hairsprite and racesprite and made the server ignore
+ items of these types so it stops complaining about these entries
+ (which only concern the client) being incomplete.
+ * src/defines.h, src/game-server/monstermanager.cpp,
+ src/game-server/monster.cpp, src/game-server/monster.hpp: Implemented
+ getting attack distance and attack properties from monsters.xml.
+
2008-02-20 Philipp Sehmisch <tmw@crushnet.org>
* src/game-server/monster.cpp: Fixed a bug which made wandering
diff --git a/src/defines.h b/src/defines.h
index 61c18e24..665adecf 100644
--- a/src/defines.h
+++ b/src/defines.h
@@ -355,15 +355,18 @@ enum BeingState
* Subject to change until Pauan and Dabe are finished with the element system.
* Please keep element modifier of BeingAttribute in sync.
*/
-enum
+enum Element
{
ELEMENT_NEUTRAL = 0,
ELEMENT_FIRE,
ELEMENT_WATER,
ELEMENT_EARTH,
ELEMENT_AIR,
- ELEMENT_SACRED,
- ELEMENT_DEATH
+ ELEMENT_LIGHTNING,
+ ELEMENT_METAL,
+ ELEMENT_WOOD,
+ ELEMENT_ICE,
+ ELEMENT_ILLEGAL
};
/**
diff --git a/src/game-server/item.hpp b/src/game-server/item.hpp
index 4f1186be..018cac48 100644
--- a/src/game-server/item.hpp
+++ b/src/game-server/item.hpp
@@ -47,7 +47,10 @@ enum ItemType
ITEM_EQUIPMENT_RING,// 9
ITEM_EQUIPMENT_NECKLACE,// 10
ITEM_EQUIPMENT_FEET,// 11
- ITEM_EQUIPMENT_AMMO// 12
+ ITEM_EQUIPMENT_AMMO,// 12
+ ITEM_HAIRSPRITE,
+ ITEM_RACESPRITE,
+ ITEM_UNKNOWN
};
/**
diff --git a/src/game-server/itemmanager.cpp b/src/game-server/itemmanager.cpp
index ef3963d4..78c7f04a 100644
--- a/src/game-server/itemmanager.cpp
+++ b/src/game-server/itemmanager.cpp
@@ -22,6 +22,7 @@
*/
#include <map>
+#include <set>
#include "game-server/itemmanager.hpp"
@@ -36,61 +37,6 @@ static ItemClasses itemClasses; /**< Item reference */
static std::string itemReferenceFile;
-ItemType itemTypeFromString (std::string name, int id = 0)
-{
- if (name=="generic") return ITEM_UNUSABLE;
- else if (name=="usable") return ITEM_USABLE;
- else if (name=="equip-1hand") return ITEM_EQUIPMENT_ONE_HAND_WEAPON;
- else if (name=="equip-2hand") return ITEM_EQUIPMENT_TWO_HANDS_WEAPON;
- else if (name=="equip-torso") return ITEM_EQUIPMENT_TORSO;
- else if (name=="equip-arms") return ITEM_EQUIPMENT_ARMS;
- else if (name=="equip-head") return ITEM_EQUIPMENT_HEAD;
- else if (name=="equip-legs") return ITEM_EQUIPMENT_LEGS;
- else if (name=="equip-shield") return ITEM_EQUIPMENT_SHIELD;
- else if (name=="equip-ring") return ITEM_EQUIPMENT_RING;
- else if (name=="equip-necklace") return ITEM_EQUIPMENT_NECKLACE;
- else if (name=="equip-feet") return ITEM_EQUIPMENT_FEET;
- else if (name=="equip-ammo") return ITEM_EQUIPMENT_AMMO;
- else if (name=="")
- {
- LOG_WARN("No item type defined for item "<<id<<" in items.xml");
- return ITEM_UNUSABLE;
- }
- else
- {
- LOG_WARN("Unknown item type \""<<name<<"\" for item "<<id<<" in items.xml");
- if (name.find("weapon") != std::string::npos)
- LOG_WARN("do you mean \"equip-1hand\" or \"equip-2hand\"?");
- if (name.find("armor") != std::string::npos)
- LOG_WARN("do you mean \"equip-...\" instead of \"armor-...\"?");
- return ITEM_UNUSABLE;
- }
-}
-
-WeaponType weaponTypeFromString (std::string name, int id = 0)
-{
- if (name=="knife") return WPNTYPE_KNIFE;
- else if (name=="sword") return WPNTYPE_SWORD;
- else if (name=="polearm") return WPNTYPE_POLEARM;
- else if (name=="staff") return WPNTYPE_STAFF;
- else if (name=="whip") return WPNTYPE_WHIP;
- else if (name=="bow") return WPNTYPE_BOW;
- else if (name=="shooting") return WPNTYPE_SHOOTING;
- else if (name=="mace") return WPNTYPE_MACE;
- else if (name=="axe") return WPNTYPE_AXE;
- else if (name=="thrown") return WPNTYPE_THROWN;
- else if (name=="")
- {
- LOG_WARN("ItemManager: No weapon type defined for weapon with item id "<<id);
- return WPNTYPE_NONE;
- }
- else
- {
- LOG_WARN("ItemManager: Unknown weapon type \""<<name<<"\" for item "<<id);
- return WPNTYPE_NONE;
- }
-}
-
void ItemManager::initialize(std::string const &file)
{
itemReferenceFile = file;
@@ -145,7 +91,19 @@ void ItemManager::reload()
}
std::string sItemType = XML::getProperty(node, "type", "");
- ItemType itemType = itemTypeFromString(sItemType, id);
+ ItemType itemType = XML::itemTypeFromString(sItemType);
+
+ if (itemType == ITEM_UNKNOWN)
+ {
+ LOG_WARN(itemReferenceFile<<": Unknown item type \""<<sItemType
+ <<"\" for item #"<<id<<" - treating it as \"generic\"");
+ itemType = ITEM_UNUSABLE;
+ }
+
+ if (itemType == ITEM_HAIRSPRITE || itemType == ITEM_RACESPRITE)
+ {
+ continue;
+ }
ItemClass *item;
ItemClasses::iterator i = itemClasses.find(id);
@@ -170,7 +128,13 @@ void ItemManager::reload()
itemType == ITEM_EQUIPMENT_TWO_HANDS_WEAPON)
{
std::string sWeaponType = XML::getProperty(node, "weapon-type", "");
- WeaponType weaponType = weaponTypeFromString(sWeaponType, id);
+ WeaponType weaponType = XML::weaponTypeFromString(sWeaponType);
+ if (weaponType == WPNTYPE_NONE)
+ {
+ LOG_WARN(itemReferenceFile<<": Unknown weapon type \""
+ <<sWeaponType<<"\" for item #"<<id<<" - treating it as generic item");
+ itemType = ITEM_UNUSABLE;
+ }
modifiers.setValue(MOD_WEAPON_TYPE, weaponType);
modifiers.setValue(MOD_WEAPON_RANGE, XML::getProperty(node, "range", 0));
modifiers.setValue(MOD_ELEMENT_TYPE, XML::getProperty(node, "element", 0));
diff --git a/src/game-server/monster.cpp b/src/game-server/monster.cpp
index c8dc55b5..525b3c73 100644
--- a/src/game-server/monster.cpp
+++ b/src/game-server/monster.cpp
@@ -64,7 +64,8 @@ Monster::Monster(MonsterClass *specy):
mTargetListener(&monsterTargetEventDispatch),
mOwner(NULL),
mOwnerTimer(0),
- mAttackTime(0)
+ mAttackTime(0),
+ mCurrentAttack(NULL)
{
LOG_DEBUG("Monster spawned!");
@@ -83,18 +84,12 @@ Monster::Monster(MonsterClass *specy):
setSpeed(specy->getSpeed());
setSize(specy->getSize());
- // Some bogus stats for testing.
- // TODO: Get all this stuff from the monster database.
- mAttackPreDelay = 10;
- mAttackAftDelay = 10;
- mAttackRange = 32;
- mAttackAngle = 10;
-
// Set positions relative to target from which the monster can attack
- mAttackPositions.push_back(AttackPosition(+32, 0, DIRECTION_LEFT));
- mAttackPositions.push_back(AttackPosition(-32, 0, DIRECTION_RIGHT));
- mAttackPositions.push_back(AttackPosition(0, +32, DIRECTION_DOWN));
- mAttackPositions.push_back(AttackPosition(0, -32, DIRECTION_UP));
+ int dist = specy->getAttackDistance();
+ mAttackPositions.push_back(AttackPosition(dist, 0, DIRECTION_LEFT));
+ mAttackPositions.push_back(AttackPosition(-dist, 0, DIRECTION_RIGHT));
+ mAttackPositions.push_back(AttackPosition(0, dist, DIRECTION_DOWN));
+ mAttackPositions.push_back(AttackPosition(0, -dist, DIRECTION_UP));
}
Monster::~Monster()
@@ -110,19 +105,19 @@ Monster::~Monster()
void Monster::perform()
{
- if (mAction == ATTACK)
+ if (mAction == ATTACK && mCurrentAttack)
{
- if (mAttackTime == mAttackAftDelay)
+ if (mAttackTime == mCurrentAttack->aftDelay)
{
// Hard-coded values for now.
Damage damage;
- damage.base = getModifiedAttribute(BASE_ATTR_PHY_ATK_MIN);
- damage.delta = getModifiedAttribute(BASE_ATTR_PHY_ATK_DELTA);
+ damage.base = (int) (getModifiedAttribute(BASE_ATTR_PHY_ATK_MIN) * mCurrentAttack->damageFactor);
+ damage.delta = (int) (getModifiedAttribute(BASE_ATTR_PHY_ATK_DELTA) * mCurrentAttack->damageFactor);
damage.cth = getModifiedAttribute(BASE_ATTR_HIT);
- damage.element = ELEMENT_NEUTRAL;
- damage.type = DAMAGE_PHYSICAL;
+ damage.element = mCurrentAttack->element;
+ damage.type = mCurrentAttack->type;
damage.usedSkill = 0;
- performAttack(damage, mAttackRange, mAttackAngle);
+ performAttack(damage, mCurrentAttack->range, mCurrentAttack->angle);
}
if (!mAttackTime)
{
@@ -222,9 +217,15 @@ void Monster::update()
{
// We are there - let's beat the crap out of the target
setDirection(bestAttackDirection);
- setAction(ATTACK);
- raiseUpdateFlags(UPDATEFLAG_ATTACK);
- mAttackTime = mAttackPreDelay + mAttackAftDelay;
+ MonsterAttacks allAttacks = mSpecy->getAttacks();
+
+ if (!allAttacks.empty())
+ {
+ mCurrentAttack = allAttacks.at(rand()%allAttacks.size()); //TODO: this ignores priority -> fix it
+ mAttackTime = mCurrentAttack->preDelay + mCurrentAttack->aftDelay;
+ setAction(ATTACK);
+ raiseUpdateFlags(UPDATEFLAG_ATTACK);
+ }
}
else
{
diff --git a/src/game-server/monster.hpp b/src/game-server/monster.hpp
index 36dbbdc3..3f6db5c1 100644
--- a/src/game-server/monster.hpp
+++ b/src/game-server/monster.hpp
@@ -44,6 +44,24 @@ struct MonsterDrop
typedef std::vector< MonsterDrop > MonsterDrops;
/**
+ * Structure containing different attack types of a monster type
+ */
+struct MonsterAttack
+{
+ unsigned id;
+ int priority;
+ float damageFactor;
+ int element;
+ int type;
+ int preDelay;
+ int aftDelay;
+ int range;
+ int angle;
+};
+
+typedef std::vector< MonsterAttack *> MonsterAttacks;
+
+/**
* Class describing the characteristics of a generic monster.
*/
class MonsterClass
@@ -58,7 +76,8 @@ class MonsterClass
mAggressive(false),
mTrackRange(1),
mStrollRange(0),
- mMutation(0)
+ mMutation(0),
+ mAttackDistance(0)
{}
/**
@@ -106,6 +125,12 @@ class MonsterClass
void setMutation(unsigned factor) { mMutation = factor; } /**< sets mutation factor in percent*/
unsigned getMutation() const { return mMutation; } /**< gets mutation factor in percent*/
+ void setAttackDistance(unsigned distance) { mAttackDistance = distance; } /**< sets preferred combat distance in pixels*/
+ unsigned getAttackDistance() const { return mAttackDistance; } /**< gets preferred combat distance in pixels*/
+
+ void addAttack(MonsterAttack *type) { mAttacks.push_back(type); } /**< adds an attack to the monsters repertoire */
+ const MonsterAttacks &getAttacks() const { return mAttacks; } /**< gets all attacks of the monster */
+
/**
* Randomly selects a monster drop (may return NULL).
*/
@@ -122,6 +147,8 @@ class MonsterClass
unsigned mTrackRange; /**< Distance the monster tracks enemies in */
unsigned mStrollRange; /**< Distance the monster strolls around in when not fighting */
unsigned mMutation; /**< Mutation factor in percent*/
+ unsigned mAttackDistance;
+ MonsterAttacks mAttacks; /**< preferred combat distance in pixels*/
};
/**
@@ -205,12 +232,7 @@ class Monster : public Being
std::set<Character *> mLegalExpReceivers; /**< List of characters who are entitled to receive exp (killsteal protection)*/
int mAttackTime; /**< Delay until monster can attack */
- // TODO: the following vars should all be the same for all monsters of
- // the same type. So they should be stored in mSpecy to save memory
- int mAttackPreDelay; /**< time between decision to make an attack and performing the attack */
- int mAttackAftDelay; /**< time it takes to perform an attack */
- int mAttackRange; /**< range of the monsters attacks in pixel */
- int mAttackAngle; /**< angle of the monsters attacks in degree */
+ MonsterAttack *mCurrentAttack; /**<Attack the monster is currently performing */
std::list<AttackPosition> mAttackPositions; /**< set positions relative to target from which the monster can attack */
friend struct MonsterTargetEventDispatch;
diff --git a/src/game-server/monstermanager.cpp b/src/game-server/monstermanager.cpp
index 693cd53a..69ad5c08 100644
--- a/src/game-server/monstermanager.cpp
+++ b/src/game-server/monstermanager.cpp
@@ -196,6 +196,49 @@ void MonsterManager::reload()
}
monster->setTrackRange(XML::getProperty(subnode, "track-range", 1));
monster->setStrollRange(XML::getProperty(subnode, "stroll-range", 0) * 32);
+ monster->setAttackDistance(XML::getProperty(subnode, "attack-distance", 0));
+ }
+ else if (xmlStrEqual(subnode->name, BAD_CAST "attack"))
+ {
+ MonsterAttack *att = new MonsterAttack;
+ att->id = XML::getProperty(subnode, "id", 0);
+ att->priority = XML::getProperty(subnode, "priority", 1);
+ att->damageFactor = XML::getFloatProperty(subnode, "damage-factor", 1.0f);
+ att->preDelay = XML::getProperty(subnode, "pre-delay", 1);
+ att->aftDelay = XML::getProperty(subnode, "aft-delay", 0);
+ att->range = XML::getProperty(subnode, "range", 1);
+ att->angle = XML::getProperty(subnode, "angle", 1);
+ std::string sElement = XML::getProperty(subnode, "element", "neutral");
+ att->element = XML::elementFromString(sElement);
+ std::string sType = XML::getProperty(subnode, "type", "physical");
+ if (sType == "physical") {att->type = DAMAGE_PHYSICAL; }
+ else if (sType == "magical" || sType == "magic") {att->type = DAMAGE_MAGICAL; }
+ else if (sType == "other") {att->type = DAMAGE_OTHER; }
+ else { att->type = -1; }
+
+ if (att->id == 0)
+ {
+ LOG_WARN(monsterReferenceFile
+ <<": Attack without ID for monster #"
+ <<id<<" ("<<name<<") - attack ignored");
+ }
+ else if (att->element == ELEMENT_ILLEGAL)
+ {
+ LOG_WARN(monsterReferenceFile
+ <<": Attack with unknown element \""<<sElement<<"\" "
+ <<"for monster #"<<id<<" ("<<name<<") - attack ignored");
+ }
+ else if (att->type == -1)
+ {
+ LOG_WARN(monsterReferenceFile
+ <<": Attack with unknown type \""<<sType<<"\" "
+ <<"for monster #"<<id<<" ("<<name<<")");
+ }
+ else
+ {
+ monster->addAttack(att);
+ }
+
}
}
diff --git a/src/utils/xml.cpp b/src/utils/xml.cpp
index 41742d7e..f71e5bfd 100644
--- a/src/utils/xml.cpp
+++ b/src/utils/xml.cpp
@@ -39,6 +39,20 @@ int getProperty(xmlNodePtr node, char const *name, int def)
return def;
}
+double
+getFloatProperty(xmlNodePtr node, const char* name, double def)
+{
+ double &ret = def;
+
+ xmlChar *prop = xmlGetProp(node, BAD_CAST name);
+ if (prop) {
+ ret = atof((char*)prop);
+ xmlFree(prop);
+ }
+
+ return ret;
+}
+
std::string getProperty(xmlNodePtr node, char const *name, std::string const &def)
{
if (xmlChar *prop = xmlGetProp(node, BAD_CAST name))
@@ -50,4 +64,62 @@ std::string getProperty(xmlNodePtr node, char const *name, std::string const &de
return def;
}
+unsigned int elementFromString(std::string name)
+{
+ if (name=="neutral") return ELEMENT_NEUTRAL;
+ else if (name=="fire") return ELEMENT_FIRE;
+ else if (name=="water") return ELEMENT_WATER;
+ else if (name=="earth") return ELEMENT_EARTH;
+ else if (name=="air") return ELEMENT_AIR;
+ else if (name=="lightning") return ELEMENT_LIGHTNING;
+ else if (name=="metal") return ELEMENT_METAL;
+ else if (name=="wood") return ELEMENT_WOOD;
+ else if (name=="ice") return ELEMENT_ICE;
+ {
+ return ELEMENT_ILLEGAL;
+ }
+}
+
+ItemType itemTypeFromString (std::string name)
+{
+ if (name=="generic") return ITEM_UNUSABLE;
+ else if (name=="usable") return ITEM_USABLE;
+ else if (name=="equip-1hand") return ITEM_EQUIPMENT_ONE_HAND_WEAPON;
+ else if (name=="equip-2hand") return ITEM_EQUIPMENT_TWO_HANDS_WEAPON;
+ else if (name=="equip-torso") return ITEM_EQUIPMENT_TORSO;
+ else if (name=="equip-arms") return ITEM_EQUIPMENT_ARMS;
+ else if (name=="equip-head") return ITEM_EQUIPMENT_HEAD;
+ else if (name=="equip-legs") return ITEM_EQUIPMENT_LEGS;
+ else if (name=="equip-shield") return ITEM_EQUIPMENT_SHIELD;
+ else if (name=="equip-ring") return ITEM_EQUIPMENT_RING;
+ else if (name=="equip-necklace") return ITEM_EQUIPMENT_NECKLACE;
+ else if (name=="equip-feet") return ITEM_EQUIPMENT_FEET;
+ else if (name=="equip-ammo") return ITEM_EQUIPMENT_AMMO;
+ else if (name=="hairsprite") return ITEM_HAIRSPRITE;
+ else if (name=="racesprite") return ITEM_RACESPRITE;
+ else
+ {
+ return ITEM_UNKNOWN;
+ }
+}
+
+WeaponType weaponTypeFromString (std::string name)
+{
+ if (name=="knife") return WPNTYPE_KNIFE;
+ else if (name=="sword") return WPNTYPE_SWORD;
+ else if (name=="polearm") return WPNTYPE_POLEARM;
+ else if (name=="staff") return WPNTYPE_STAFF;
+ else if (name=="whip") return WPNTYPE_WHIP;
+ else if (name=="bow") return WPNTYPE_BOW;
+ else if (name=="shooting") return WPNTYPE_SHOOTING;
+ else if (name=="mace") return WPNTYPE_MACE;
+ else if (name=="axe") return WPNTYPE_AXE;
+ else if (name=="thrown") return WPNTYPE_THROWN;
+ else
+ {
+ return WPNTYPE_NONE;
+ }
+}
+
+
} // namespace XML
diff --git a/src/utils/xml.hpp b/src/utils/xml.hpp
index ace8d64d..d2ab62e7 100644
--- a/src/utils/xml.hpp
+++ b/src/utils/xml.hpp
@@ -27,6 +27,9 @@
#include <string>
#include <libxml/tree.h>
+#include "defines.h"
+#include "../game-server/item.hpp"
+
namespace XML
{
/**
@@ -38,6 +41,26 @@ namespace XML
* Gets a string property from an xmlNodePtr.
*/
std::string getProperty(xmlNodePtr node, char const *name, std::string const &def);
+
+ /**
+ * Gets an floating point property from an xmlNodePtr.
+ */
+ double
+ getFloatProperty(xmlNodePtr node, const char *name, double def);
+
+
+ /**
+ * Converts a string into an element number
+ */
+ unsigned int elementFromString(std::string name);
+ /**
+ * Converts a string into an ItemType number
+ */
+ ItemType itemTypeFromString (std::string name);
+ /**
+ * Converts a string into a weaponType number
+ */
+ WeaponType weaponTypeFromString (std::string name);
}
#define for_each_xml_child_node(var, parent) \