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 #include <set>
00024
00025 #include "game-server/itemmanager.hpp"
00026
00027 #include "defines.h"
00028 #include "game-server/attackzone.hpp"
00029 #include "game-server/item.hpp"
00030 #include "game-server/resourcemanager.hpp"
00031 #include "scripting/script.hpp"
00032 #include "utils/logger.h"
00033 #include "utils/xml.hpp"
00034
00035 #include <sstream>
00036
00037 typedef std::map< int, ItemClass * > ItemClasses;
00038 static ItemClasses itemClasses;
00039 static std::string itemReferenceFile;
00040 static unsigned int itemDatabaseVersion = 0;
00042 void ItemManager::initialize(const std::string &file)
00043 {
00044 itemReferenceFile = file;
00045 reload();
00046 }
00047
00048 void ItemManager::reload()
00049 {
00050 int size;
00051 char *data = ResourceManager::loadFile(itemReferenceFile, size);
00052
00053 if (!data) {
00054 LOG_ERROR("Item Manager: Could not find " << itemReferenceFile << "!");
00055 free(data);
00056 return;
00057 }
00058
00059 xmlDocPtr doc = xmlParseMemory(data, size);
00060 free(data);
00061
00062 if (!doc)
00063 {
00064 LOG_ERROR("Item Manager: Error while parsing item database ("
00065 << itemReferenceFile << ")!");
00066 return;
00067 }
00068
00069 xmlNodePtr node = xmlDocGetRootElement(doc);
00070 if (!node || !xmlStrEqual(node->name, BAD_CAST "items"))
00071 {
00072 LOG_ERROR("Item Manager: " << itemReferenceFile
00073 << " is not a valid database file!");
00074 xmlFreeDoc(doc);
00075 return;
00076 }
00077
00078 LOG_INFO("Loading item reference...");
00079 unsigned nbItems = 0;
00080 for (node = node->xmlChildrenNode; node != NULL; node = node->next)
00081 {
00082
00083
00084
00085 if (xmlStrEqual(node->name, BAD_CAST "version"))
00086 {
00087 std::string revision = XML::getProperty(node, "revision", std::string());
00088 itemDatabaseVersion = atoi(revision.c_str());
00089
00090 LOG_INFO("Loading item database version " << itemDatabaseVersion);
00091 continue;
00092 }
00093
00094 if (!xmlStrEqual(node->name, BAD_CAST "item"))
00095 {
00096 continue;
00097 }
00098
00099 int id = XML::getProperty(node, "id", 0);
00100 if (id == 0)
00101 {
00102 LOG_WARN("Item Manager: An (ignored) item has no ID in "
00103 << itemReferenceFile << "!");
00104 continue;
00105 }
00106
00107 std::string sItemType = XML::getProperty(node, "type", "");
00108 ItemType itemType = itemTypeFromString(sItemType);
00109
00110 if (itemType == ITEM_UNKNOWN)
00111 {
00112 LOG_WARN(itemReferenceFile<<": Unknown item type \""<<sItemType
00113 <<"\" for item #"<<id<<" - treating it as \"generic\"");
00114 itemType = ITEM_UNUSABLE;
00115 }
00116
00117 if (itemType == ITEM_HAIRSPRITE || itemType == ITEM_RACESPRITE)
00118 {
00119 continue;
00120 }
00121
00122 ItemClass *item;
00123 ItemClasses::iterator i = itemClasses.find(id);
00124 if (i == itemClasses.end())
00125 {
00126 item = new ItemClass(id, itemType);
00127 itemClasses[id] = item;
00128 }
00129 else
00130 {
00131 item = i->second;
00132 }
00133
00134 int weight = XML::getProperty(node, "weight", 0);
00135 int value = XML::getProperty(node, "value", 0);
00136 int maxPerSlot = XML::getProperty(node, "max-per-slot", 0);
00137 int sprite = XML::getProperty(node, "sprite_id", 0);
00138 std::string scriptFile = XML::getProperty(node, "script", "");
00139 std::string attackShape = XML::getProperty(node, "attack-shape", "cone");
00140 std::string attackTarget = XML::getProperty(node, "attack-target", "multi");
00141 int attackRange = XML::getProperty(node, "attack-range", 32);
00142 int attackAngle = XML::getProperty(node, "attack-angle", 90);
00143
00144 ItemModifiers modifiers;
00145 if (itemType == ITEM_EQUIPMENT_ONE_HAND_WEAPON ||
00146 itemType == ITEM_EQUIPMENT_TWO_HANDS_WEAPON)
00147 {
00148 std::string sWeaponType = XML::getProperty(node, "weapon-type", "");
00149 WeaponType weaponType = weaponTypeFromString(sWeaponType);
00150 if (weaponType == WPNTYPE_NONE)
00151 {
00152 LOG_WARN(itemReferenceFile<<": Unknown weapon type \""
00153 <<sWeaponType<<"\" for item #"<<id<<" - treating it as generic item");
00154 itemType = ITEM_UNUSABLE;
00155 }
00156 modifiers.setValue(MOD_WEAPON_TYPE, weaponType);
00157 modifiers.setValue(MOD_WEAPON_RANGE, XML::getProperty(node, "range", 0));
00158 modifiers.setValue(MOD_ELEMENT_TYPE, XML::getProperty(node, "element", 0));
00159 }
00160 modifiers.setValue(MOD_LIFETIME, XML::getProperty(node, "lifetime", 0) * 10);
00161
00162 modifiers.setAttributeValue(BASE_ATTR_PHY_ATK_MIN, XML::getProperty(node, "attack-min", 0));
00163 modifiers.setAttributeValue(BASE_ATTR_PHY_ATK_DELTA, XML::getProperty(node, "attack-delta", 0));
00164 modifiers.setAttributeValue(BASE_ATTR_HP, XML::getProperty(node, "hp", 0));
00165 modifiers.setAttributeValue(BASE_ATTR_PHY_RES, XML::getProperty(node, "defense", 0));
00166 modifiers.setAttributeValue(CHAR_ATTR_STRENGTH, XML::getProperty(node, "strength", 0));
00167 modifiers.setAttributeValue(CHAR_ATTR_AGILITY, XML::getProperty(node, "agility", 0));
00168 modifiers.setAttributeValue(CHAR_ATTR_DEXTERITY, XML::getProperty(node, "dexterity", 0));
00169 modifiers.setAttributeValue(CHAR_ATTR_VITALITY, XML::getProperty(node, "vitality", 0));
00170 modifiers.setAttributeValue(CHAR_ATTR_INTELLIGENCE, XML::getProperty(node, "intelligence", 0));
00171 modifiers.setAttributeValue(CHAR_ATTR_WILLPOWER, XML::getProperty(node, "willpower", 0));
00172
00173 if (maxPerSlot == 0)
00174 {
00175
00176
00177 maxPerSlot = 1;
00178 }
00179
00180 if (itemType > ITEM_USABLE && itemType < ITEM_EQUIPMENT_AMMO &&
00181 maxPerSlot != 1)
00182 {
00183 LOG_WARN("Item Manager: Setting max-per-slot property to 1 for "
00184 "equipment " << id << " in " << itemReferenceFile << '.');
00185 maxPerSlot = 1;
00186 }
00187
00188 if (weight == 0)
00189 {
00190 LOG_WARN("Item Manager: Missing weight for item "
00191 << id << " in " << itemReferenceFile << '.');
00192 weight = 1;
00193 }
00194
00195
00196 if (scriptFile != "")
00197 {
00198 std::stringstream filename;
00199 filename << "scripts/items/" << scriptFile;
00200 if (ResourceManager::exists(filename.str()))
00201 {
00202 LOG_INFO("Loading item script: " << filename.str());
00203 Script *s = Script::create("lua");
00204 s->loadFile(filename.str());
00205 item->setScript(s);
00206 } else {
00207 LOG_WARN("Could not find script file \"" << filename.str() << "\" for item #"<<id);
00208 }
00209 }
00210
00211 item->setWeight(weight);
00212 item->setCost(value);
00213 item->setMaxPerSlot(maxPerSlot);
00214 item->setModifiers(modifiers);
00215 item->setSpriteID(sprite ? sprite : id);
00216 ++nbItems;
00217
00218 if (itemType == ITEM_EQUIPMENT_ONE_HAND_WEAPON ||
00219 itemType == ITEM_EQUIPMENT_TWO_HANDS_WEAPON)
00220 {
00221 AttackZone *zone = new AttackZone;
00222
00223 if (attackShape == "cone")
00224 {
00225 zone->shape = ATTZONESHAPE_CONE;
00226 }
00227 else
00228 {
00229 LOG_WARN("Item Manager: Unknown attack zone shape \"" << attackShape
00230 <<"\" for weapon " << id << " in " << itemReferenceFile << '.');
00231 zone->shape = ATTZONESHAPE_CONE;
00232 }
00233
00234 if (attackTarget == "multi")
00235 {
00236 zone->multiTarget = true;
00237 }
00238 else if (attackTarget == "single")
00239 {
00240 zone->multiTarget = false;
00241 }
00242 else
00243 {
00244 LOG_WARN("Item Manager: Unknown target mode \"" << attackTarget
00245 <<"\" for weapon " << id << " in " << itemReferenceFile << '.');
00246 zone->multiTarget = true;
00247 }
00248 zone->range = attackRange;
00249 zone->angle = attackAngle;
00250
00251 item->setAttackZone(zone);
00252 }
00253
00254 LOG_DEBUG("Item: ID: " << id << ", itemType: " << itemType
00255 << ", weight: " << weight << ", value: " << value <<
00256 ", script: " << scriptFile << ", maxPerSlot: " << maxPerSlot << ".");
00257 }
00258
00259 LOG_INFO("Loaded " << nbItems << " items from "
00260 << itemReferenceFile << ".");
00261
00262 xmlFreeDoc(doc);
00263 }
00264
00265 void ItemManager::deinitialize()
00266 {
00267 for (ItemClasses::iterator i = itemClasses.begin(), i_end = itemClasses.end(); i != i_end; ++i)
00268 {
00269 delete i->second;
00270 }
00271 itemClasses.clear();
00272 }
00273
00274 ItemClass *ItemManager::getItem(int itemId)
00275 {
00276 ItemClasses::const_iterator i = itemClasses.find(itemId);
00277 return i != itemClasses.end() ? i->second : NULL;
00278 }
00279
00280 unsigned int ItemManager::GetDatabaseVersion(void)
00281 {
00282 return itemDatabaseVersion;
00283 }