00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <map>
00023
00024 #include "game-server/monstermanager.hpp"
00025
00026 #include "defines.h"
00027 #include "game-server/attackzone.hpp"
00028 #include "game-server/itemmanager.hpp"
00029 #include "game-server/monster.hpp"
00030 #include "game-server/resourcemanager.hpp"
00031 #include "utils/logger.h"
00032 #include "utils/xml.hpp"
00033
00034 typedef std::map< int, MonsterClass * > MonsterClasses;
00035 static MonsterClasses monsterClasses;
00036 static std::string monsterReferenceFile;
00037
00038 Element elementFromString (const std::string &name)
00039 {
00040 static std::map<const std::string, Element> table;
00041
00042 if (table.empty())
00043 {
00044 table["neutral"] = ELEMENT_NEUTRAL;
00045 table["fire"] = ELEMENT_FIRE;
00046 table["water"] = ELEMENT_WATER;
00047 table["earth"] = ELEMENT_EARTH;
00048 table["air"] = ELEMENT_AIR;
00049 table["lightning"] = ELEMENT_LIGHTNING;
00050 table["metal"] = ELEMENT_METAL;
00051 table["wood"] = ELEMENT_WOOD;
00052 table["ice"] = ELEMENT_ICE;
00053 }
00054
00055 std::map<const std::string, Element>::iterator val = table.find(name);
00056
00057 return val == table.end() ? ELEMENT_ILLEGAL : (*val).second;
00058 }
00059
00060 void MonsterManager::initialize(const std::string &file)
00061 {
00062 monsterReferenceFile = file;
00063 reload();
00064 }
00065
00066 void MonsterManager::reload()
00067 {
00068 int size;
00069 char *data = ResourceManager::loadFile(monsterReferenceFile, size);
00070
00071 if (!data) {
00072 LOG_ERROR("Monster Manager: Could not find "
00073 << monsterReferenceFile << "!");
00074 free(data);
00075 return;
00076 }
00077
00078 xmlDocPtr doc = xmlParseMemory(data, size);
00079 free(data);
00080
00081 if (!doc)
00082 {
00083 LOG_ERROR("Monster Manager: Error while parsing monster database ("
00084 << monsterReferenceFile << ")!");
00085 return;
00086 }
00087
00088 xmlNodePtr node = xmlDocGetRootElement(doc);
00089 if (!node || !xmlStrEqual(node->name, BAD_CAST "monsters"))
00090 {
00091 LOG_ERROR("Monster Manager: " << monsterReferenceFile
00092 << " is not a valid database file!");
00093 xmlFreeDoc(doc);
00094 return;
00095 }
00096
00097 LOG_INFO("Loading monster reference...");
00098 int nbMonsters = 0;
00099 for (node = node->xmlChildrenNode; node != NULL; node = node->next)
00100 {
00101 if (!xmlStrEqual(node->name, BAD_CAST "monster"))
00102 {
00103 continue;
00104 }
00105
00106 int id = XML::getProperty(node, "id", -1);
00107 std::string name = XML::getProperty(node, "name", "unnamed");
00108
00109 if (id == -1)
00110 {
00111 LOG_WARN("Monster Manager: There is a monster ("<<name<<") without ID in "
00112 << monsterReferenceFile << "! It has been ignored.");
00113 continue;
00114 }
00115
00116 MonsterClass *monster;
00117 MonsterClasses::iterator i = monsterClasses.find(id);
00118 if (i == monsterClasses.end())
00119 {
00120 monster = new MonsterClass(id);
00121 monsterClasses[id] = monster;
00122 }
00123 else
00124 {
00125 monster = i->second;
00126 }
00127
00128 MonsterDrops drops;
00129 bool attributesSet = false;
00130 bool behaviorSet = false;
00131
00132 for (xmlNodePtr subnode = node->xmlChildrenNode; subnode != NULL;
00133 subnode = subnode->next)
00134 {
00135 if (xmlStrEqual(subnode->name, BAD_CAST "drop"))
00136 {
00137 MonsterDrop drop;
00138 drop.item = ItemManager::getItem(XML::getProperty(subnode, "item", 0));
00139 drop.probability = XML::getProperty(subnode, "percent", 0) * 100;
00140 if (drop.item && drop.probability)
00141 {
00142 drops.push_back(drop);
00143 }
00144 }
00145 else if (xmlStrEqual(subnode->name, BAD_CAST "attributes"))
00146 {
00147 attributesSet = true;
00148 monster->setAttribute(BASE_ATTR_HP,
00149 XML::getProperty(subnode, "hp", -1));
00150 monster->setAttribute(BASE_ATTR_PHY_ATK_MIN,
00151 XML::getProperty(subnode, "attack-min", -1));
00152 monster->setAttribute(BASE_ATTR_PHY_ATK_DELTA,
00153 XML::getProperty(subnode, "attack-delta", -1));
00154 monster->setAttribute(BASE_ATTR_MAG_ATK,
00155 XML::getProperty(subnode, "attack-magic", -1));
00156 monster->setAttribute(BASE_ATTR_EVADE,
00157 XML::getProperty(subnode, "evade", -1));
00158 monster->setAttribute(BASE_ATTR_HIT,
00159 XML::getProperty(subnode, "hit", -1));
00160 monster->setAttribute(BASE_ATTR_PHY_RES,
00161 XML::getProperty(subnode, "physical-defence", -1));
00162 monster->setAttribute(BASE_ATTR_MAG_RES,
00163 XML::getProperty(subnode, "magical-defence", -1));
00164 monster->setSize(XML::getProperty(subnode, "size", 0));
00165 int speed = (XML::getProperty(subnode, "speed", 0));
00166 monster->setMutation(XML::getProperty(subnode, "mutation", 0));
00167
00168
00169
00170 if (monster->getMutation() > 99)
00171 {
00172 LOG_WARN(monsterReferenceFile
00173 <<": Mutation of monster #"<<id
00174 <<" more than 99% - ignored");
00175 monster->setMutation(0);
00176 }
00177
00178 bool attributesComplete = true;
00179 for (int i = BASE_ATTR_BEGIN; i < BASE_ATTR_END; i++)
00180 {
00181 if (monster->getAttribute(i) == -1)
00182 {
00183 attributesComplete = false;
00184 monster->setAttribute(i, 0);
00185 }
00186 }
00187 if (monster->getSize() == 0)
00188 {
00189 monster->setSize(16);
00190 attributesComplete = false;
00191 }
00192 if (speed == 0)
00193 {
00194 speed = 1;
00195 attributesComplete = false;
00196 }
00197
00198 if (!attributesComplete) LOG_WARN(monsterReferenceFile
00199 <<": Attributes incomplete for monster #"<<id);
00200
00201
00202
00203 monster->setSpeed(32000/speed);
00204
00205 }
00206 else if (xmlStrEqual(subnode->name, BAD_CAST "exp"))
00207 {
00208 xmlChar *exp = subnode->xmlChildrenNode->content;
00209 monster->setExp(atoi((const char*)exp));
00210 }
00211 else if (xmlStrEqual(subnode->name, BAD_CAST "behavior"))
00212 {
00213 behaviorSet = true;
00214 if (XML::getProperty(subnode, "aggressive", "") == "true")
00215 {
00216 monster->setAggressive(true);
00217 }
00218 monster->setTrackRange(XML::getProperty(subnode, "track-range", 1));
00219 monster->setStrollRange(XML::getProperty(subnode, "stroll-range", 0) * 32);
00220 monster->setAttackDistance(XML::getProperty(subnode, "attack-distance", 0));
00221 }
00222 else if (xmlStrEqual(subnode->name, BAD_CAST "attack"))
00223 {
00224 MonsterAttack *att = new MonsterAttack;
00225 AttackZone attackZone;
00226 att->id = XML::getProperty(subnode, "id", 0);
00227 att->priority = XML::getProperty(subnode, "priority", 1);
00228 att->damageFactor = XML::getFloatProperty(subnode, "damage-factor", 1.0f);
00229 att->preDelay = XML::getProperty(subnode, "pre-delay", 1);
00230 att->aftDelay = XML::getProperty(subnode, "aft-delay", 0);
00231 attackZone.multiTarget = true;
00232 attackZone.shape = ATTZONESHAPE_CONE;
00233 attackZone.range = XML::getProperty(subnode, "range", 1);
00234 attackZone.angle = XML::getProperty(subnode, "angle", 1);
00235 att->attackZone = attackZone;
00236 std::string sElement = XML::getProperty(subnode, "element", "neutral");
00237 att->element = elementFromString(sElement);
00238 std::string sType = XML::getProperty(subnode, "type", "physical");
00239 if (sType == "physical") {att->type = DAMAGE_PHYSICAL; }
00240 else if (sType == "magical" || sType == "magic") {att->type = DAMAGE_MAGICAL; }
00241 else if (sType == "other") {att->type = DAMAGE_OTHER; }
00242 else { att->type = -1; }
00243
00244 if (att->id == 0)
00245 {
00246 LOG_WARN(monsterReferenceFile
00247 <<": Attack without ID for monster #"
00248 <<id<<" ("<<name<<") - attack ignored");
00249 }
00250 else if (att->element == ELEMENT_ILLEGAL)
00251 {
00252 LOG_WARN(monsterReferenceFile
00253 <<": Attack with unknown element \""<<sElement<<"\" "
00254 <<"for monster #"<<id<<" ("<<name<<") - attack ignored");
00255 }
00256 else if (att->type == -1)
00257 {
00258 LOG_WARN(monsterReferenceFile
00259 <<": Attack with unknown type \""<<sType<<"\" "
00260 <<"for monster #"<<id<<" ("<<name<<")");
00261 }
00262 else
00263 {
00264 monster->addAttack(att);
00265 }
00266
00267 }
00268 }
00269
00270 monster->setDrops(drops);
00271 if (!attributesSet) LOG_WARN(monsterReferenceFile
00272 <<": No attributes defined for monster #"
00273 <<id<<" ("<<name<<")");
00274 if (!behaviorSet) LOG_WARN(monsterReferenceFile
00275 <<": No behavior defined for monster #"
00276 <<id<<" ("<<name<<")");
00277 if (monster->getExp() == -1)
00278 {
00279 LOG_WARN(monsterReferenceFile
00280 <<": No experience defined for monster #"
00281 <<id<<" ("<<name<<")");
00282 monster->setExp(0);
00283 }
00284 ++nbMonsters;
00285 }
00286
00287 LOG_INFO("Loaded " << nbMonsters << " monsters from "
00288 << monsterReferenceFile << '.');
00289
00290 xmlFreeDoc(doc);
00291 }
00292
00293 void MonsterManager::deinitialize()
00294 {
00295 for (MonsterClasses::iterator i = monsterClasses.begin(),
00296 i_end = monsterClasses.end(); i != i_end; ++i)
00297 {
00298 delete i->second;
00299 }
00300 monsterClasses.clear();
00301 }
00302
00303 MonsterClass *MonsterManager::getMonster(int id)
00304 {
00305 MonsterClasses::const_iterator i = monsterClasses.find(id);
00306 return i != monsterClasses.end() ? i->second : NULL;
00307 }