Advertisement
Guest User

monsters.cpp

a guest
Oct 18th, 2017
276
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 48.55 KB | None | 0 0
  1. ////////////////////////////////////////////////////////////////////////
  2. // OpenTibia - an opensource roleplaying game
  3. ////////////////////////////////////////////////////////////////////////
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. ////////////////////////////////////////////////////////////////////////
  17. #include "otpch.h"
  18. #include <libxml/xmlmemory.h>
  19. #include <libxml/parser.h>
  20.  
  21. #include "monsters.h"
  22. #include "tools.h"
  23. #include "monster.h"
  24.  
  25. #include "luascript.h"
  26. #include "container.h"
  27. #include "weapons.h"
  28.  
  29. #include "spells.h"
  30. #include "combat.h"
  31.  
  32. #include "configmanager.h"
  33. #include "game.h"
  34.  
  35. extern Game g_game;
  36. extern Spells* g_spells;
  37. extern Monsters g_monsters;
  38. extern ConfigManager g_config;
  39.  
  40. void MonsterType::reset()
  41. {
  42. canPushItems = canPushCreatures = isSummonable = isIllusionable = isConvinceable = isLureable = isWalkable = hideName = hideHealth = false;
  43. pushable = isAttackable = isHostile = true;
  44.  
  45. outfit.lookHead = outfit.lookBody = outfit.lookLegs = outfit.lookFeet = outfit.lookType = outfit.lookTypeEx = outfit.lookAddons = 0;
  46. runAwayHealth = manaCost = lightLevel = lightColor = yellSpeedTicks = yellChance = changeTargetSpeed = changeTargetChance = 0;
  47. experience = defense = armor = lookCorpse = corpseUnique = corpseAction = conditionImmunities = damageImmunities = 0;
  48.  
  49. maxSummons = -1;
  50. targetDistance = 1;
  51. staticAttackChance = 95;
  52. health = healthMax = 100;
  53. baseSpeed = 200;
  54.  
  55. race = RACE_BLOOD;
  56. skull = SKULL_NONE;
  57. partyShield = SHIELD_NONE;
  58. guildEmblem = EMBLEM_NONE;
  59. lootMessage = LOOTMSG_IGNORE;
  60.  
  61. for(SpellList::iterator it = spellAttackList.begin(); it != spellAttackList.end(); ++it)
  62. {
  63. if(!it->combatSpell)
  64. continue;
  65.  
  66. delete it->spell;
  67. it->spell = NULL;
  68. }
  69.  
  70. spellAttackList.clear();
  71. for(SpellList::iterator it = spellDefenseList.begin(); it != spellDefenseList.end(); ++it)
  72. {
  73. if(!it->combatSpell)
  74. continue;
  75.  
  76. delete it->spell;
  77. it->spell = NULL;
  78. }
  79.  
  80. spellDefenseList.clear();
  81. summonList.clear();
  82. scriptList.clear();
  83.  
  84. voiceVector.clear();
  85. lootItems.clear();
  86. elementMap.clear();
  87. }
  88.  
  89. uint16_t Monsters::getLootRandom()
  90. {
  91. return (uint16_t)std::ceil((double)random_range(0, MAX_LOOTCHANCE) / g_config.getDouble(ConfigManager::RATE_LOOT));
  92. }
  93.  
  94. void MonsterType::dropLoot(Container* corpse)
  95. {
  96. Item* tmpItem = NULL;
  97. for(LootItems::const_iterator it = lootItems.begin(); it != lootItems.end() && !corpse->full(); ++it)
  98. {
  99. if((tmpItem = createLoot(*it)))
  100. {
  101. if(Container* container = tmpItem->getContainer())
  102. {
  103. if(createChildLoot(container, (*it)))
  104. corpse->__internalAddThing(tmpItem);
  105. else
  106. delete container;
  107. }
  108. else
  109. corpse->__internalAddThing(tmpItem);
  110. }
  111. }
  112.  
  113. corpse->__startDecaying();
  114. uint32_t ownerId = corpse->getCorpseOwner();
  115. if(!ownerId)
  116. return;
  117.  
  118. Player* owner = g_game.getPlayerByGuid(ownerId);
  119. if(!owner)
  120. return;
  121.  
  122. LootMessage_t message = lootMessage;
  123. if(message == LOOTMSG_IGNORE)
  124. message = (LootMessage_t)g_config.getNumber(ConfigManager::LOOT_MESSAGE);
  125.  
  126. if(message < LOOTMSG_PLAYER)
  127. return;
  128.  
  129. std::stringstream ss;
  130. ss << "Loot of " << nameDescription << ": " << corpse->getContentDescription() << ".";
  131. if(owner->getParty() && message > LOOTMSG_PLAYER)
  132. owner->getParty()->broadcastMessage((MessageClasses)g_config.getNumber(ConfigManager::LOOT_MESSAGE_TYPE), ss.str());
  133. else if(message == LOOTMSG_PLAYER || message == LOOTMSG_BOTH)
  134. owner->sendTextMessage((MessageClasses)g_config.getNumber(ConfigManager::LOOT_MESSAGE_TYPE), ss.str());
  135. }
  136.  
  137. Item* MonsterType::createLoot(const LootBlock& lootBlock)
  138. {
  139. uint16_t item = lootBlock.ids[0], random = Monsters::getLootRandom();
  140. if(lootBlock.ids.size() > 1)
  141. item = lootBlock.ids[random_range((size_t)0, lootBlock.ids.size() - 1)];
  142.  
  143. Item* tmpItem = NULL;
  144. if(Item::items[item].stackable)
  145. {
  146. if(random < lootBlock.chance)
  147. tmpItem = Item::CreateItem(item, (random % lootBlock.count + 1));
  148. }
  149. else if(random < lootBlock.chance)
  150. tmpItem = Item::CreateItem(item, 0);
  151.  
  152. if(!tmpItem)
  153. return NULL;
  154.  
  155. if(lootBlock.subType != -1)
  156. tmpItem->setSubType(lootBlock.subType);
  157.  
  158. if(lootBlock.actionId != -1)
  159. tmpItem->setActionId(lootBlock.actionId, false);
  160.  
  161. if(lootBlock.uniqueId != -1)
  162. tmpItem->setUniqueId(lootBlock.uniqueId);
  163.  
  164. if(!lootBlock.text.empty())
  165. tmpItem->setText(lootBlock.text);
  166.  
  167. return tmpItem;
  168. }
  169.  
  170. bool MonsterType::createChildLoot(Container* parent, const LootBlock& lootBlock)
  171. {
  172. LootItems::const_iterator it = lootBlock.childLoot.begin();
  173. if(it == lootBlock.childLoot.end())
  174. return true;
  175.  
  176. Item* tmpItem = NULL;
  177. for(; it != lootBlock.childLoot.end() && !parent->full(); ++it)
  178. {
  179. if((tmpItem = createLoot(*it)))
  180. {
  181. if(Container* container = tmpItem->getContainer())
  182. {
  183. if(createChildLoot(container, (*it)))
  184. parent->__internalAddThing(container);
  185. else
  186. delete container;
  187. }
  188. else
  189. parent->__internalAddThing(tmpItem);
  190. }
  191. }
  192.  
  193. return !parent->empty();
  194. }
  195.  
  196. bool Monsters::loadFromXml(bool reloading /*= false*/)
  197. {
  198. loaded = false;
  199. xmlDocPtr doc = xmlParseFile(getFilePath(FILE_TYPE_OTHER, "monster/monsters.xml").c_str());
  200. if(!doc)
  201. {
  202. std::clog << "[Warning - Monsters::loadFromXml] Cannot load monsters file." << std::endl;
  203. std::clog << getLastXMLError() << std::endl;
  204. return false;
  205. }
  206.  
  207. xmlNodePtr p, root = xmlDocGetRootElement(doc);
  208. if(xmlStrcmp(root->name,(const xmlChar*)"monsters"))
  209. {
  210. std::clog << "[Error - Monsters::loadFromXml] Malformed monsters file." << std::endl;
  211. xmlFreeDoc(doc);
  212. return false;
  213. }
  214.  
  215. p = root->children;
  216. while(p)
  217. {
  218. if(p->type != XML_ELEMENT_NODE)
  219. {
  220. p = p->next;
  221. continue;
  222. }
  223.  
  224. if(xmlStrcmp(p->name, (const xmlChar*)"monster"))
  225. {
  226. std::clog << "[Warning - Monsters::loadFromXml] Unknown node name (" << p->name << ")." << std::endl;
  227. p = p->next;
  228. continue;
  229. }
  230.  
  231. std::string file, name;
  232. if(readXMLString(p, "file", file) && readXMLString(p, "name", name))
  233. {
  234. file = getFilePath(FILE_TYPE_OTHER, "monster/" + file);
  235. loadMonster(file, name, reloading);
  236. }
  237.  
  238. p = p->next;
  239. }
  240.  
  241. xmlFreeDoc(doc);
  242. loaded = true;
  243. return loaded;
  244. }
  245.  
  246. ConditionDamage* Monsters::getDamageCondition(ConditionType_t conditionType,
  247. int32_t maxDamage, int32_t minDamage, int32_t startDamage, uint32_t tickInterval)
  248. {
  249. if(ConditionDamage* condition = dynamic_cast<ConditionDamage*>(Condition::createCondition(CONDITIONID_COMBAT, conditionType, 0)))
  250. {
  251. condition->setParam(CONDITIONPARAM_TICKINTERVAL, tickInterval);
  252. condition->setParam(CONDITIONPARAM_MINVALUE, minDamage);
  253. condition->setParam(CONDITIONPARAM_MAXVALUE, maxDamage);
  254. condition->setParam(CONDITIONPARAM_STARTVALUE, startDamage);
  255. condition->setParam(CONDITIONPARAM_DELAYED, 1);
  256. return condition;
  257. }
  258.  
  259. return NULL;
  260. }
  261.  
  262. bool Monsters::deserializeSpell(xmlNodePtr node, spellBlock_t& sb, const std::string& description)
  263. {
  264. sb.range = sb.minCombatValue = sb.maxCombatValue = 0;
  265. sb.combatSpell = sb.isMelee = false;
  266. sb.chance = 100;
  267. sb.speed = 2000;
  268.  
  269. std::string name, scriptName;
  270. bool isScripted = false;
  271. if(readXMLString(node, "script", scriptName))
  272. isScripted = true;
  273. else if(!readXMLString(node, "name", name))
  274. return false;
  275.  
  276. int32_t intValue;
  277. std::string strValue;
  278. if(readXMLInteger(node, "speed", intValue) || readXMLInteger(node, "interval", intValue))
  279. sb.speed = std::max(1, intValue);
  280.  
  281. if(readXMLInteger(node, "chance", intValue))
  282. {
  283. if(intValue < 0 || intValue > 100)
  284. intValue = 100;
  285.  
  286. sb.chance = intValue;
  287. }
  288.  
  289. if(readXMLInteger(node, "range", intValue))
  290. {
  291. if(intValue < 0)
  292. intValue = 0;
  293.  
  294. if(intValue > Map::maxViewportX * 2)
  295. intValue = Map::maxViewportX * 2;
  296.  
  297. sb.range = intValue;
  298. }
  299.  
  300. if(readXMLInteger(node, "min", intValue))
  301. sb.minCombatValue = intValue;
  302.  
  303. if(readXMLInteger(node, "max", intValue))
  304. sb.maxCombatValue = intValue;
  305.  
  306. //normalize values
  307. if(std::abs(sb.minCombatValue) > std::abs(sb.maxCombatValue))
  308. std::swap(sb.minCombatValue, sb.maxCombatValue);
  309.  
  310. if((sb.spell = g_spells->getSpellByName(name)))
  311. return true;
  312.  
  313. CombatSpell* combatSpell = NULL;
  314. bool needTarget = false, needDirection = false;
  315. if(isScripted)
  316. {
  317. if(readXMLString(node, "direction", strValue))
  318. needDirection = booleanString(strValue);
  319.  
  320. if(readXMLString(node, "target", strValue))
  321. needTarget = booleanString(strValue);
  322.  
  323. combatSpell = new CombatSpell(NULL, needTarget, needDirection);
  324. if(!combatSpell->loadScript(getFilePath(FILE_TYPE_OTHER, g_spells->getScriptBaseName() + "/scripts/" + scriptName), true))
  325. {
  326. delete combatSpell;
  327. return false;
  328. }
  329.  
  330. if(!combatSpell->loadScriptCombat())
  331. {
  332. delete combatSpell;
  333. return false;
  334.  
  335. }
  336.  
  337. combatSpell->getCombat()->setPlayerCombatValues(FORMULA_VALUE, sb.minCombatValue, 0, sb.maxCombatValue, 0, 0, 0, 0, 0, 0, 0);
  338. }
  339. else
  340. {
  341. Combat* combat = new Combat;
  342. sb.combatSpell = true;
  343. if(readXMLInteger(node, "length", intValue))
  344. {
  345. int32_t length = intValue;
  346. if(length > 0)
  347. {
  348. int32_t spread = 3;
  349. //need direction spell
  350. if(readXMLInteger(node, "spread", intValue))
  351. spread = std::max(0, intValue);
  352.  
  353. CombatArea* area = new CombatArea();
  354. area->setupArea(length, spread);
  355.  
  356. combat->setArea(area);
  357. needDirection = true;
  358. }
  359. }
  360.  
  361. if(readXMLInteger(node, "radius", intValue))
  362. {
  363. int32_t radius = intValue;
  364. //target spell
  365. if(readXMLInteger(node, "target", intValue))
  366. needTarget = (intValue != 0);
  367.  
  368. CombatArea* area = new CombatArea();
  369. area->setupArea(radius);
  370. combat->setArea(area);
  371. }
  372.  
  373. std::string tmpName = asLowerCaseString(name);
  374. if(tmpName == "melee" || tmpName == "distance")
  375. {
  376. int32_t attack = 0, skill = 0;
  377. if(readXMLInteger(node, "attack", attack) && readXMLInteger(node, "skill", skill))
  378. {
  379. sb.minCombatValue = 0;
  380. sb.maxCombatValue = -Weapons::getMaxMeleeDamage(skill, attack);
  381. }
  382.  
  383. uint32_t tickInterval = 10000;
  384. ConditionType_t conditionType = CONDITION_NONE;
  385. if(readXMLInteger(node, "physical", intValue))
  386. conditionType = CONDITION_PHYSICAL;
  387. else if(readXMLInteger(node, "fire", intValue))
  388. conditionType = CONDITION_FIRE;
  389. else if(readXMLInteger(node, "energy", intValue))
  390. conditionType = CONDITION_ENERGY;
  391. else if(readXMLInteger(node, "earth", intValue))
  392. conditionType = CONDITION_POISON;
  393. else if(readXMLInteger(node, "freeze", intValue))
  394. conditionType = CONDITION_FREEZING;
  395. else if(readXMLInteger(node, "dazzle", intValue))
  396. conditionType = CONDITION_DAZZLED;
  397. else if(readXMLInteger(node, "curse", intValue))
  398. conditionType = CONDITION_CURSED;
  399. else if(readXMLInteger(node, "drown", intValue))
  400. {
  401. conditionType = CONDITION_DROWN;
  402. tickInterval = 5000;
  403. }
  404. else if(readXMLInteger(node, "poison", intValue))
  405. {
  406. conditionType = CONDITION_POISON;
  407. tickInterval = 5000;
  408. }
  409.  
  410. uint32_t damage = std::abs(intValue);
  411. if(readXMLInteger(node, "tick", intValue) && intValue > 0)
  412. tickInterval = intValue;
  413.  
  414. if(conditionType != CONDITION_NONE)
  415. {
  416. Condition* condition = getDamageCondition(conditionType, damage, damage, 0, tickInterval);
  417. if(condition)
  418. combat->setCondition(condition);
  419. }
  420.  
  421. sb.isMelee = true;
  422. sb.range = 1;
  423.  
  424. combat->setParam(COMBATPARAM_COMBATTYPE, COMBAT_PHYSICALDAMAGE);
  425. combat->setParam(COMBATPARAM_BLOCKEDBYSHIELD, 1);
  426. combat->setParam(COMBATPARAM_BLOCKEDBYARMOR, 1);
  427. }
  428. else if(tmpName == "physical")
  429. {
  430. combat->setParam(COMBATPARAM_COMBATTYPE, COMBAT_PHYSICALDAMAGE);
  431. combat->setParam(COMBATPARAM_BLOCKEDBYARMOR, 1);
  432. }
  433. else if(tmpName == "drown")
  434. combat->setParam(COMBATPARAM_COMBATTYPE, COMBAT_DROWNDAMAGE);
  435. else if(tmpName == "fire")
  436. combat->setParam(COMBATPARAM_COMBATTYPE, COMBAT_FIREDAMAGE);
  437. else if(tmpName == "energy")
  438. combat->setParam(COMBATPARAM_COMBATTYPE, COMBAT_ENERGYDAMAGE);
  439. else if(tmpName == "poison" || tmpName == "earth")
  440. combat->setParam(COMBATPARAM_COMBATTYPE, COMBAT_EARTHDAMAGE);
  441. else if(tmpName == "ice")
  442. combat->setParam(COMBATPARAM_COMBATTYPE, COMBAT_ICEDAMAGE);
  443. else if(tmpName == "holy")
  444. combat->setParam(COMBATPARAM_COMBATTYPE, COMBAT_HOLYDAMAGE);
  445. else if(tmpName == "death")
  446. combat->setParam(COMBATPARAM_COMBATTYPE, COMBAT_DEATHDAMAGE);
  447. else if(tmpName == "lifedrain")
  448. combat->setParam(COMBATPARAM_COMBATTYPE, COMBAT_LIFEDRAIN);
  449. else if(tmpName == "manadrain")
  450. combat->setParam(COMBATPARAM_COMBATTYPE, COMBAT_MANADRAIN);
  451. else if(tmpName == "healing")
  452. {
  453. bool aggressive = false;
  454. if(readXMLInteger(node, "self", intValue))
  455. aggressive = intValue;
  456.  
  457. combat->setParam(COMBATPARAM_COMBATTYPE, COMBAT_HEALING);
  458. combat->setParam(COMBATPARAM_AGGRESSIVE, aggressive);
  459. }
  460. else if(tmpName == "undefined")
  461. combat->setParam(COMBATPARAM_COMBATTYPE, COMBAT_UNDEFINEDDAMAGE);
  462. else if(tmpName == "speed")
  463. {
  464. int32_t speedChange = 0, duration = 10000;
  465. if(readXMLInteger(node, "duration", intValue))
  466. duration = intValue;
  467.  
  468. enum Aggressive {
  469. NO,
  470. YES,
  471. AUTO
  472. } aggressive = AUTO;
  473. if(readXMLInteger(node, "self", intValue))
  474. aggressive = (Aggressive)intValue;
  475.  
  476. if(readXMLInteger(node, "speedchange", intValue))
  477. speedChange = std::max(-1000, intValue); //cant be slower than 100%
  478.  
  479. std::vector<Outfit_t> outfits;
  480. for(xmlNodePtr tmpNode = node->children; tmpNode; tmpNode = tmpNode->next)
  481. {
  482. if(xmlStrcmp(tmpNode->name,(const xmlChar*)"outfit"))
  483. continue;
  484.  
  485. if(readXMLInteger(tmpNode, "type", intValue))
  486. {
  487. Outfit_t outfit;
  488. outfit.lookType = intValue;
  489. if(readXMLInteger(tmpNode, "head", intValue))
  490. outfit.lookHead = intValue;
  491.  
  492. if(readXMLInteger(tmpNode, "body", intValue))
  493. outfit.lookBody = intValue;
  494.  
  495. if(readXMLInteger(tmpNode, "legs", intValue))
  496. outfit.lookLegs = intValue;
  497.  
  498. if(readXMLInteger(tmpNode, "feet", intValue))
  499. outfit.lookFeet = intValue;
  500.  
  501. if(readXMLInteger(tmpNode, "addons", intValue))
  502. outfit.lookAddons = intValue;
  503.  
  504. outfits.push_back(outfit);
  505. }
  506.  
  507. if(readXMLInteger(tmpNode, "typeex", intValue) || readXMLInteger(tmpNode, "item", intValue))
  508. {
  509. Outfit_t outfit;
  510. outfit.lookTypeEx = intValue;
  511. outfits.push_back(outfit);
  512. }
  513.  
  514. if(readXMLString(tmpNode, "monster", strValue))
  515. {
  516. if(MonsterType* mType = g_monsters.getMonsterType(strValue))
  517. outfits.push_back(mType->outfit);
  518. }
  519. }
  520.  
  521. ConditionType_t conditionType = CONDITION_PARALYZE;
  522. if(speedChange > 0)
  523. {
  524. conditionType = CONDITION_HASTE;
  525. if(aggressive == AUTO)
  526. aggressive = NO;
  527. }
  528. else if(aggressive == AUTO)
  529. aggressive = YES;
  530.  
  531. if(ConditionSpeed* condition = dynamic_cast<ConditionSpeed*>(Condition::createCondition(
  532. CONDITIONID_COMBAT, conditionType, duration)))
  533. {
  534. condition->setFormulaVars((speedChange / 1000.), 0, (speedChange / 1000.), 0);
  535. if(!outfits.empty())
  536. condition->setOutfits(outfits);
  537.  
  538. combat->setCondition(condition);
  539. combat->setParam(COMBATPARAM_AGGRESSIVE, aggressive);
  540. }
  541. }
  542. else if(tmpName == "outfit")
  543. {
  544. std::vector<Outfit_t> outfits;
  545. for(xmlNodePtr tmpNode = node->children; tmpNode; tmpNode = tmpNode->next)
  546. {
  547. if(xmlStrcmp(tmpNode->name,(const xmlChar*)"outfit"))
  548. continue;
  549.  
  550. if(readXMLInteger(tmpNode, "type", intValue))
  551. {
  552. Outfit_t outfit;
  553. outfit.lookType = intValue;
  554. if(readXMLInteger(tmpNode, "head", intValue))
  555. outfit.lookHead = intValue;
  556.  
  557. if(readXMLInteger(tmpNode, "body", intValue))
  558. outfit.lookBody = intValue;
  559.  
  560. if(readXMLInteger(tmpNode, "legs", intValue))
  561. outfit.lookLegs = intValue;
  562.  
  563. if(readXMLInteger(tmpNode, "feet", intValue))
  564. outfit.lookFeet = intValue;
  565.  
  566. if(readXMLInteger(tmpNode, "addons", intValue))
  567. outfit.lookAddons = intValue;
  568.  
  569. outfits.push_back(outfit);
  570. }
  571.  
  572. if(readXMLInteger(tmpNode, "typeex", intValue) || readXMLInteger(tmpNode, "item", intValue))
  573. {
  574. Outfit_t outfit;
  575. outfit.lookTypeEx = intValue;
  576. outfits.push_back(outfit);
  577. }
  578.  
  579. if(readXMLString(tmpNode, "monster", strValue))
  580. {
  581. if(MonsterType* mType = g_monsters.getMonsterType(strValue))
  582. outfits.push_back(mType->outfit);
  583. }
  584. }
  585.  
  586. if(outfits.empty())
  587. {
  588. if(readXMLInteger(node, "type", intValue))
  589. {
  590. Outfit_t outfit;
  591. outfit.lookType = intValue;
  592. if(readXMLInteger(node, "head", intValue))
  593. outfit.lookHead = intValue;
  594.  
  595. if(readXMLInteger(node, "body", intValue))
  596. outfit.lookBody = intValue;
  597.  
  598. if(readXMLInteger(node, "legs", intValue))
  599. outfit.lookLegs = intValue;
  600.  
  601. if(readXMLInteger(node, "feet", intValue))
  602. outfit.lookFeet = intValue;
  603.  
  604. if(readXMLInteger(node, "addons", intValue))
  605. outfit.lookAddons = intValue;
  606.  
  607. outfits.push_back(outfit);
  608. }
  609.  
  610. if(readXMLInteger(node, "typeex", intValue) || readXMLInteger(node, "item", intValue))
  611. {
  612. Outfit_t outfit;
  613. outfit.lookTypeEx = intValue;
  614. outfits.push_back(outfit);
  615. }
  616.  
  617. if(readXMLString(node, "monster", strValue))
  618. {
  619. if(MonsterType* mType = g_monsters.getMonsterType(strValue))
  620. outfits.push_back(mType->outfit);
  621. }
  622. }
  623.  
  624. if(!outfits.empty())
  625. {
  626. int32_t duration = 10000;
  627. if(readXMLInteger(node, "duration", intValue))
  628. duration = intValue;
  629.  
  630. bool aggressive = false;
  631. if(readXMLInteger(node, "self", intValue))
  632. aggressive = intValue;
  633.  
  634. if(ConditionOutfit* condition = dynamic_cast<ConditionOutfit*>(Condition::createCondition(
  635. CONDITIONID_COMBAT, CONDITION_OUTFIT, duration)))
  636. {
  637. condition->setOutfits(outfits);
  638. combat->setCondition(condition);
  639. combat->setParam(COMBATPARAM_AGGRESSIVE, aggressive);
  640. }
  641. }
  642. }
  643. else if(tmpName == "invisible")
  644. {
  645. int32_t duration = 10000;
  646. if(readXMLInteger(node, "duration", intValue))
  647. duration = intValue;
  648.  
  649. bool aggressive = false;
  650. if(readXMLInteger(node, "self", intValue))
  651. aggressive = intValue;
  652.  
  653. if(Condition* condition = Condition::createCondition(CONDITIONID_COMBAT, CONDITION_INVISIBLE, duration))
  654. {
  655. combat->setParam(COMBATPARAM_AGGRESSIVE, aggressive);
  656. combat->setCondition(condition);
  657. }
  658. }
  659. else if(tmpName == "drunk")
  660. {
  661. int32_t duration = 10000;
  662. if(readXMLInteger(node, "duration", intValue))
  663. duration = intValue;
  664.  
  665. if(Condition* condition = Condition::createCondition(CONDITIONID_COMBAT, CONDITION_DRUNK, duration))
  666. combat->setCondition(condition);
  667. }
  668. else if(tmpName == "skills" || tmpName == "attributes")
  669. {
  670. uint32_t duration = 10000, subId = 0;
  671. if(readXMLInteger(node, "duration", intValue))
  672. duration = intValue;
  673.  
  674. if(readXMLInteger(node, "subid", intValue))
  675. subId = intValue;
  676.  
  677. intValue = 0;
  678. ConditionParam_t param = CONDITIONPARAM_BUFF; //to know was it loaded
  679. if(readXMLInteger(node, "melee", intValue))
  680. param = CONDITIONPARAM_SKILL_MELEE;
  681. else if(readXMLInteger(node, "fist", intValue))
  682. param = CONDITIONPARAM_SKILL_FIST;
  683. else if(readXMLInteger(node, "club", intValue))
  684. param = CONDITIONPARAM_SKILL_CLUB;
  685. else if(readXMLInteger(node, "axe", intValue))
  686. param = CONDITIONPARAM_SKILL_AXE;
  687. else if(readXMLInteger(node, "sword", intValue))
  688. param = CONDITIONPARAM_SKILL_SWORD;
  689. else if(readXMLInteger(node, "distance", intValue) || readXMLInteger(node, "dist", intValue))
  690. param = CONDITIONPARAM_SKILL_DISTANCE;
  691. else if(readXMLInteger(node, "shielding", intValue) || readXMLInteger(node, "shield", intValue))
  692. param = CONDITIONPARAM_SKILL_SHIELD;
  693. else if(readXMLInteger(node, "fishing", intValue) || readXMLInteger(node, "fish", intValue))
  694. param = CONDITIONPARAM_SKILL_FISHING;
  695. else if(readXMLInteger(node, "meleePercent", intValue))
  696. param = CONDITIONPARAM_SKILL_MELEEPERCENT;
  697. else if(readXMLInteger(node, "fistPercent", intValue))
  698. param = CONDITIONPARAM_SKILL_FISTPERCENT;
  699. else if(readXMLInteger(node, "clubPercent", intValue))
  700. param = CONDITIONPARAM_SKILL_CLUBPERCENT;
  701. else if(readXMLInteger(node, "axePercent", intValue))
  702. param = CONDITIONPARAM_SKILL_AXEPERCENT;
  703. else if(readXMLInteger(node, "swordPercent", intValue))
  704. param = CONDITIONPARAM_SKILL_SWORDPERCENT;
  705. else if(readXMLInteger(node, "distancePercent", intValue) || readXMLInteger(node, "distPercent", intValue))
  706. param = CONDITIONPARAM_SKILL_DISTANCEPERCENT;
  707. else if(readXMLInteger(node, "shieldingPercent", intValue) || readXMLInteger(node, "shieldPercent", intValue))
  708. param = CONDITIONPARAM_SKILL_SHIELDPERCENT;
  709. else if(readXMLInteger(node, "fishingPercent", intValue) || readXMLInteger(node, "fishPercent", intValue))
  710. param = CONDITIONPARAM_SKILL_FISHINGPERCENT;
  711. else if(readXMLInteger(node, "maxhealth", intValue))
  712. param = CONDITIONPARAM_STAT_MAXHEALTHPERCENT;
  713. else if(readXMLInteger(node, "maxmana", intValue))
  714. param = CONDITIONPARAM_STAT_MAXMANAPERCENT;
  715. else if(readXMLInteger(node, "soul", intValue))
  716. param = CONDITIONPARAM_STAT_SOULPERCENT;
  717. else if(readXMLInteger(node, "magiclevel", intValue) || readXMLInteger(node, "maglevel", intValue))
  718. param = CONDITIONPARAM_STAT_MAGICLEVELPERCENT;
  719. else if(readXMLInteger(node, "maxhealthPercent", intValue))
  720. param = CONDITIONPARAM_STAT_MAXHEALTHPERCENT;
  721. else if(readXMLInteger(node, "maxmanaPercent", intValue))
  722. param = CONDITIONPARAM_STAT_MAXMANAPERCENT;
  723. else if(readXMLInteger(node, "soulPercent", intValue))
  724. param = CONDITIONPARAM_STAT_SOULPERCENT;
  725. else if(readXMLInteger(node, "magiclevelPercent", intValue) || readXMLInteger(node, "maglevelPercent", intValue))
  726. param = CONDITIONPARAM_STAT_MAGICLEVELPERCENT;
  727.  
  728. if(param != CONDITIONPARAM_BUFF)
  729. {
  730. if(ConditionAttributes* condition = dynamic_cast<ConditionAttributes*>(Condition::createCondition(
  731. CONDITIONID_COMBAT, CONDITION_ATTRIBUTES, duration, false, subId)))
  732. {
  733. condition->setParam(param, intValue);
  734. combat->setCondition(condition);
  735. }
  736. }
  737. }
  738. else if(tmpName == "firefield")
  739. combat->setParam(COMBATPARAM_CREATEITEM, 1492);
  740. else if(tmpName == "poisonfield")
  741. combat->setParam(COMBATPARAM_CREATEITEM, 1496);
  742. else if(tmpName == "energyfield")
  743. combat->setParam(COMBATPARAM_CREATEITEM, 1495);
  744. else if(tmpName == "firecondition" || tmpName == "energycondition" || tmpName == "drowncondition" ||
  745. tmpName == "poisoncondition" || tmpName == "earthcondition" || tmpName == "freezecondition" ||
  746. tmpName == "cursecondition" || tmpName == "dazzlecondition")
  747. {
  748. ConditionType_t conditionType = CONDITION_NONE;
  749. uint32_t tickInterval = 2000;
  750. if(tmpName == "physicalcondition")
  751. {
  752. conditionType = CONDITION_PHYSICAL;
  753. tickInterval = 5000;
  754. }
  755. else if(tmpName == "firecondition")
  756. {
  757. conditionType = CONDITION_FIRE;
  758. tickInterval = 10000;
  759. }
  760. else if(tmpName == "energycondition")
  761. {
  762. conditionType = CONDITION_ENERGY;
  763. tickInterval = 10000;
  764. }
  765. else if(tmpName == "earthcondition")
  766. {
  767. conditionType = CONDITION_POISON;
  768. tickInterval = 10000;
  769. }
  770. else if(tmpName == "freezecondition")
  771. {
  772. conditionType = CONDITION_FREEZING;
  773. tickInterval = 10000;
  774. }
  775. else if(tmpName == "cursecondition")
  776. {
  777. conditionType = CONDITION_CURSED;
  778. tickInterval = 10000;
  779. }
  780. else if(tmpName == "dazzlecondition")
  781. {
  782. conditionType = CONDITION_DAZZLED;
  783. tickInterval = 10000;
  784. }
  785. else if(tmpName == "drowncondition")
  786. {
  787. conditionType = CONDITION_DROWN;
  788. tickInterval = 5000;
  789. }
  790. else if(tmpName == "poisoncondition")
  791. {
  792. conditionType = CONDITION_POISON;
  793. tickInterval = 5000;
  794. }
  795.  
  796. if(readXMLInteger(node, "tick", intValue) && intValue > 0)
  797. tickInterval = intValue;
  798.  
  799. int32_t startDamage = 0, minDamage = std::abs(sb.minCombatValue), maxDamage = std::abs(sb.maxCombatValue);
  800. if(readXMLInteger(node, "start", intValue))
  801. startDamage = std::max(std::abs(intValue), minDamage);
  802.  
  803. if(Condition* condition = getDamageCondition(conditionType, maxDamage, minDamage, startDamage, tickInterval))
  804. combat->setCondition(condition);
  805. }
  806. else if(tmpName == "strength")
  807. {
  808. //TODO: monster extra strength
  809. }
  810. else if(tmpName == "effect")
  811. {/*show some effect and bye bye!*/}
  812. else
  813. {
  814. delete combat;
  815. std::clog << "[Error - Monsters::deserializeSpell] " << description << " - Unknown spell name: " << name << std::endl;
  816. return false;
  817. }
  818.  
  819. combat->setPlayerCombatValues(FORMULA_VALUE, sb.minCombatValue, 0, sb.maxCombatValue, 0, 0, 0, 0, 0, 0, 0);
  820. combatSpell = new CombatSpell(combat, needTarget, needDirection);
  821.  
  822. xmlNodePtr attributeNode = node->children;
  823. while(attributeNode)
  824. {
  825. if(!xmlStrcmp(attributeNode->name, (const xmlChar*)"attribute"))
  826. {
  827. if(readXMLString(attributeNode, "key", strValue))
  828. {
  829. std::string tmpStrValue = asLowerCaseString(strValue);
  830. if(tmpStrValue == "shooteffect")
  831. {
  832. if(readXMLString(attributeNode, "value", strValue))
  833. {
  834. ShootEffect_t shoot = getShootType(strValue);
  835. if(shoot != SHOOT_EFFECT_UNKNOWN)
  836. combat->setParam(COMBATPARAM_DISTANCEEFFECT, shoot);
  837. else
  838. std::clog << "[Warning - Monsters::deserializeSpell] " << description << " - Unknown shootEffect: " << strValue << std::endl;
  839. }
  840. }
  841. else if(tmpStrValue == "areaeffect")
  842. {
  843. if(readXMLString(attributeNode, "value", strValue))
  844. {
  845. MagicEffect_t effect = getMagicEffect(strValue);
  846. if(effect != MAGIC_EFFECT_UNKNOWN)
  847. combat->setParam(COMBATPARAM_EFFECT, effect);
  848. else
  849. std::clog << "[Warning - Monsters::deserializeSpell] " << description << " - Unknown areaEffect: " << strValue << std::endl;
  850. }
  851. }
  852. else
  853. std::clog << "[Warning - Monsters::deserializeSpells] Effect type \"" << strValue << "\" does not exist." << std::endl;
  854. }
  855. }
  856. attributeNode = attributeNode->next;
  857. }
  858. }
  859.  
  860. sb.spell = combatSpell;
  861. return true;
  862. }
  863.  
  864. #define SHOW_XML_WARNING(desc) std::clog << "[Warning - Monsters::loadMonster] " << desc << ". (" << file << ")" << std::endl;
  865. #define SHOW_XML_ERROR(desc) std::clog << "[Error - Monsters::loadMonster] " << desc << ". (" << file << ")" << std::endl;
  866.  
  867. bool Monsters::loadMonster(const std::string& file, const std::string& monsterName, bool reloading/* = false*/)
  868. {
  869. if(getIdByName(monsterName) && !reloading)
  870. {
  871. std::clog << "[Warning - Monsters::loadMonster] Duplicate registered monster with name: " << monsterName << std::endl;
  872. return true;
  873. }
  874.  
  875. bool monsterLoad, new_mType = true;
  876. MonsterType* mType = NULL;
  877. if(reloading)
  878. {
  879. uint32_t id = getIdByName(monsterName);
  880. if(id != 0)
  881. {
  882. mType = getMonsterType(id);
  883. if(mType != NULL)
  884. {
  885. new_mType = false;
  886. mType->reset();
  887. }
  888. }
  889. }
  890.  
  891. if(new_mType)
  892. mType = new MonsterType();
  893.  
  894. xmlDocPtr doc = xmlParseFile(file.c_str());
  895. if(!doc)
  896. {
  897. std::clog << "[Warning - Monsters::loadMonster] Cannot load monster (" << monsterName << ") file (" << file << ")." << std::endl;
  898. std::clog << getLastXMLError() << std::endl;
  899. return false;
  900. }
  901.  
  902. monsterLoad = true;
  903. xmlNodePtr p, root = xmlDocGetRootElement(doc);
  904. if(xmlStrcmp(root->name,(const xmlChar*)"monster"))
  905. {
  906. std::clog << "[Error - Monsters::loadMonster] Malformed monster (" << monsterName << ") file (" << file << ")." << std::endl;
  907. xmlFreeDoc(doc);
  908. return false;
  909. }
  910.  
  911. int32_t intValue;
  912. std::string strValue;
  913. if(readXMLString(root, "name", strValue))
  914. mType->name = strValue;
  915. else
  916. monsterLoad = false;
  917.  
  918. if(readXMLString(root, "nameDescription", strValue))
  919. mType->nameDescription = strValue;
  920. else
  921. {
  922. mType->nameDescription = "a " + mType->name;
  923. toLowerCaseString(mType->nameDescription);
  924. }
  925.  
  926. if(readXMLString(root, "race", strValue))
  927. {
  928. std::string tmpStrValue = asLowerCaseString(strValue);
  929. if(tmpStrValue == "venom" || atoi(strValue.c_str()) == 1)
  930. mType->race = RACE_VENOM;
  931. else if(tmpStrValue == "blood" || atoi(strValue.c_str()) == 2)
  932. mType->race = RACE_BLOOD;
  933. else if(tmpStrValue == "undead" || atoi(strValue.c_str()) == 3)
  934. mType->race = RACE_UNDEAD;
  935. else if(tmpStrValue == "fire" || atoi(strValue.c_str()) == 4)
  936. mType->race = RACE_FIRE;
  937. else if(tmpStrValue == "energy" || atoi(strValue.c_str()) == 5)
  938. mType->race = RACE_ENERGY;
  939. else
  940. SHOW_XML_WARNING("Unknown race type " << strValue);
  941. }
  942.  
  943. if(readXMLInteger(root, "experience", intValue))
  944. mType->experience = intValue;
  945.  
  946. if(readXMLInteger(root, "speed", intValue))
  947. mType->baseSpeed = intValue;
  948.  
  949. if(readXMLInteger(root, "manacost", intValue))
  950. mType->manaCost = intValue;
  951.  
  952. if(readXMLString(root, "skull", strValue))
  953. mType->skull = getSkulls(strValue);
  954.  
  955. if(readXMLString(root, "shield", strValue))
  956. mType->partyShield = getShields(strValue);
  957.  
  958. if(readXMLString(root, "emblem", strValue))
  959. mType->guildEmblem = getEmblems(strValue);
  960.  
  961. p = root->children;
  962. while(p && monsterLoad)
  963. {
  964. if(p->type != XML_ELEMENT_NODE)
  965. {
  966. p = p->next;
  967. continue;
  968. }
  969.  
  970. if(!xmlStrcmp(p->name, (const xmlChar*)"health"))
  971. {
  972. if(readXMLInteger(p, "now", intValue))
  973. mType->health = intValue;
  974. else
  975. {
  976. SHOW_XML_ERROR("Missing health.now");
  977. monsterLoad = false;
  978. }
  979.  
  980. if(readXMLInteger(p, "max", intValue))
  981. mType->healthMax = intValue;
  982. else
  983. {
  984. SHOW_XML_ERROR("Missing health.max");
  985. monsterLoad = false;
  986. }
  987. }
  988. else if(!xmlStrcmp(p->name, (const xmlChar*)"flags"))
  989. {
  990. xmlNodePtr tmpNode = p->children;
  991. while(tmpNode)
  992. {
  993. if(xmlStrcmp(tmpNode->name, (const xmlChar*)"flag") == 0)
  994. {
  995. if(readXMLString(tmpNode, "summonable", strValue))
  996. mType->isSummonable = booleanString(strValue);
  997.  
  998. if(readXMLString(tmpNode, "attackable", strValue))
  999. mType->isAttackable = booleanString(strValue);
  1000.  
  1001. if(readXMLString(tmpNode, "hostile", strValue))
  1002. mType->isHostile = booleanString(strValue);
  1003.  
  1004. if(readXMLString(tmpNode, "illusionable", strValue))
  1005. mType->isIllusionable = booleanString(strValue);
  1006.  
  1007. if(readXMLString(tmpNode, "convinceable", strValue))
  1008. mType->isConvinceable = booleanString(strValue);
  1009.  
  1010. if(readXMLString(tmpNode, "pushable", strValue))
  1011. mType->pushable = booleanString(strValue);
  1012.  
  1013. if(readXMLString(tmpNode, "canpushitems", strValue))
  1014. mType->canPushItems = booleanString(strValue);
  1015.  
  1016. if(readXMLString(tmpNode, "canpushcreatures", strValue))
  1017. mType->canPushCreatures = booleanString(strValue);
  1018.  
  1019. if(readXMLString(tmpNode, "hidename", strValue))
  1020. mType->hideName = booleanString(strValue);
  1021.  
  1022. if(readXMLString(tmpNode, "hidehealth", strValue))
  1023. mType->hideHealth = booleanString(strValue);
  1024.  
  1025. if(readXMLInteger(tmpNode, "lootmessage", intValue))
  1026. mType->lootMessage = (LootMessage_t)intValue;
  1027.  
  1028. if(readXMLInteger(tmpNode, "staticattack", intValue))
  1029. {
  1030. if(intValue < 0 || intValue > 100)
  1031. {
  1032. SHOW_XML_WARNING("staticattack lower than 0 or greater than 100");
  1033. intValue = 0;
  1034. }
  1035.  
  1036. mType->staticAttackChance = intValue;
  1037. }
  1038.  
  1039. if(readXMLInteger(tmpNode, "lightlevel", intValue))
  1040. mType->lightLevel = intValue;
  1041.  
  1042. if(readXMLInteger(tmpNode, "lightcolor", intValue))
  1043. mType->lightColor = intValue;
  1044.  
  1045. if(readXMLInteger(tmpNode, "targetdistance", intValue))
  1046. {
  1047. if(intValue > Map::maxViewportX)
  1048. SHOW_XML_WARNING("targetdistance greater than maxViewportX");
  1049.  
  1050. mType->targetDistance = std::max(1, intValue);
  1051. }
  1052.  
  1053. if(readXMLInteger(tmpNode, "runonhealth", intValue))
  1054. mType->runAwayHealth = intValue;
  1055.  
  1056. if(readXMLString(tmpNode, "lureable", strValue))
  1057. mType->isLureable = booleanString(strValue);
  1058.  
  1059. if(readXMLString(tmpNode, "walkable", strValue))
  1060. mType->isWalkable = booleanString(strValue);
  1061.  
  1062. if(readXMLString(tmpNode, "skull", strValue))
  1063. mType->skull = getSkulls(strValue);
  1064.  
  1065. if(readXMLString(tmpNode, "shield", strValue))
  1066. mType->partyShield = getShields(strValue);
  1067.  
  1068. if(readXMLString(tmpNode, "emblem", strValue))
  1069. mType->guildEmblem = getEmblems(strValue);
  1070. }
  1071.  
  1072. tmpNode = tmpNode->next;
  1073. }
  1074.  
  1075. //if a monster can push creatures, it should not be pushable
  1076. if(mType->canPushCreatures && mType->pushable)
  1077. mType->pushable = false;
  1078. }
  1079. else if(!xmlStrcmp(p->name, (const xmlChar*)"targetchange"))
  1080. {
  1081. if(readXMLInteger(p, "speed", intValue) || readXMLInteger(p, "interval", intValue))
  1082. mType->changeTargetSpeed = std::max(1, intValue);
  1083. else
  1084. SHOW_XML_WARNING("Missing targetchange.speed");
  1085.  
  1086. if(readXMLInteger(p, "chance", intValue))
  1087. mType->changeTargetChance = intValue;
  1088. else
  1089. SHOW_XML_WARNING("Missing targetchange.chance");
  1090. }
  1091. else if(!xmlStrcmp(p->name, (const xmlChar*)"strategy"))
  1092. {
  1093. if(readXMLInteger(p, "attack", intValue)) {}
  1094. //mType->attackStrength = intValue;
  1095.  
  1096. if(readXMLInteger(p, "defense", intValue)) {}
  1097. //mType->defenseStrength = intValue;
  1098. }
  1099. else if(!xmlStrcmp(p->name, (const xmlChar*)"look"))
  1100. {
  1101. if(readXMLInteger(p, "type", intValue))
  1102. {
  1103. mType->outfit.lookType = intValue;
  1104. if(readXMLInteger(p, "head", intValue))
  1105. mType->outfit.lookHead = intValue;
  1106.  
  1107. if(readXMLInteger(p, "body", intValue))
  1108. mType->outfit.lookBody = intValue;
  1109.  
  1110. if(readXMLInteger(p, "legs", intValue))
  1111. mType->outfit.lookLegs = intValue;
  1112.  
  1113. if(readXMLInteger(p, "feet", intValue))
  1114. mType->outfit.lookFeet = intValue;
  1115.  
  1116. if(readXMLInteger(p, "addons", intValue))
  1117. mType->outfit.lookAddons = intValue;
  1118. }
  1119. else if(readXMLInteger(p, "typeex", intValue))
  1120. mType->outfit.lookTypeEx = intValue;
  1121. else
  1122. SHOW_XML_WARNING("Missing look type/typeex");
  1123.  
  1124. if(readXMLInteger(p, "corpse", intValue))
  1125. mType->lookCorpse = intValue;
  1126.  
  1127. if(readXMLInteger(p, "corpseUniqueId", intValue) || readXMLInteger(p, "corpseUid", intValue))
  1128. mType->corpseUnique = intValue;
  1129.  
  1130. if(readXMLInteger(p, "corpseActionId", intValue) || readXMLInteger(p, "corpseAid", intValue))
  1131. mType->corpseAction = intValue;
  1132. }
  1133. else if(!xmlStrcmp(p->name, (const xmlChar*)"attacks"))
  1134. {
  1135. xmlNodePtr tmpNode = p->children;
  1136. while(tmpNode)
  1137. {
  1138. if(!xmlStrcmp(tmpNode->name, (const xmlChar*)"attack"))
  1139. {
  1140. spellBlock_t sb;
  1141. if(deserializeSpell(tmpNode, sb, monsterName))
  1142. mType->spellAttackList.push_back(sb);
  1143. else
  1144. SHOW_XML_WARNING("Cant load spell");
  1145. }
  1146.  
  1147. tmpNode = tmpNode->next;
  1148. }
  1149. }
  1150. else if(!xmlStrcmp(p->name, (const xmlChar*)"defenses"))
  1151. {
  1152. if(readXMLInteger(p, "defense", intValue))
  1153. mType->defense = intValue;
  1154.  
  1155. if(readXMLInteger(p, "armor", intValue))
  1156. mType->armor = intValue;
  1157.  
  1158. xmlNodePtr tmpNode = p->children;
  1159. while(tmpNode)
  1160. {
  1161. if(!xmlStrcmp(tmpNode->name, (const xmlChar*)"defense"))
  1162. {
  1163. spellBlock_t sb;
  1164. if(deserializeSpell(tmpNode, sb, monsterName))
  1165. mType->spellDefenseList.push_back(sb);
  1166. else
  1167. SHOW_XML_WARNING("Cant load spell");
  1168. }
  1169.  
  1170. tmpNode = tmpNode->next;
  1171. }
  1172. }
  1173. else if(!xmlStrcmp(p->name, (const xmlChar*)"immunities"))
  1174. {
  1175. xmlNodePtr tmpNode = p->children;
  1176. while(tmpNode)
  1177. {
  1178. if(!xmlStrcmp(tmpNode->name, (const xmlChar*)"immunity"))
  1179. {
  1180. if(readXMLString(tmpNode, "name", strValue))
  1181. {
  1182. std::string tmpStrValue = asLowerCaseString(strValue);
  1183. if(tmpStrValue == "physical")
  1184. {
  1185. mType->damageImmunities |= COMBAT_PHYSICALDAMAGE;
  1186. mType->conditionImmunities |= CONDITION_PHYSICAL;
  1187. }
  1188. else if(tmpStrValue == "energy")
  1189. {
  1190. mType->damageImmunities |= COMBAT_ENERGYDAMAGE;
  1191. mType->conditionImmunities |= CONDITION_ENERGY;
  1192. }
  1193. else if(tmpStrValue == "fire")
  1194. {
  1195. mType->damageImmunities |= COMBAT_FIREDAMAGE;
  1196. mType->conditionImmunities |= CONDITION_FIRE;
  1197. }
  1198. else if(tmpStrValue == "poison" || tmpStrValue == "earth")
  1199. {
  1200. mType->damageImmunities |= COMBAT_EARTHDAMAGE;
  1201. mType->conditionImmunities |= CONDITION_POISON;
  1202. }
  1203. else if(tmpStrValue == "ice")
  1204. {
  1205. mType->damageImmunities |= COMBAT_ICEDAMAGE;
  1206. mType->conditionImmunities |= CONDITION_FREEZING;
  1207. }
  1208. else if(tmpStrValue == "holy")
  1209. {
  1210. mType->damageImmunities |= COMBAT_HOLYDAMAGE;
  1211. mType->conditionImmunities |= CONDITION_DAZZLED;
  1212. }
  1213. else if(tmpStrValue == "death")
  1214. {
  1215. mType->damageImmunities |= COMBAT_DEATHDAMAGE;
  1216. mType->conditionImmunities |= CONDITION_CURSED;
  1217. }
  1218. else if(tmpStrValue == "drown")
  1219. {
  1220. mType->damageImmunities |= COMBAT_DROWNDAMAGE;
  1221. mType->conditionImmunities |= CONDITION_DROWN;
  1222. }
  1223. else if(tmpStrValue == "lifedrain")
  1224. mType->damageImmunities |= COMBAT_LIFEDRAIN;
  1225. else if(tmpStrValue == "manadrain")
  1226. mType->damageImmunities |= COMBAT_MANADRAIN;
  1227. else if(tmpStrValue == "paralyze")
  1228. mType->conditionImmunities |= CONDITION_PARALYZE;
  1229. else if(tmpStrValue == "outfit")
  1230. mType->conditionImmunities |= CONDITION_OUTFIT;
  1231. else if(tmpStrValue == "drunk")
  1232. mType->conditionImmunities |= CONDITION_DRUNK;
  1233. else if(tmpStrValue == "invisible")
  1234. mType->conditionImmunities |= CONDITION_INVISIBLE;
  1235. else
  1236. SHOW_XML_WARNING("Unknown immunity name " << strValue);
  1237. }
  1238. else if(readXMLString(tmpNode, "physical", strValue) && booleanString(strValue))
  1239. {
  1240. mType->damageImmunities |= COMBAT_PHYSICALDAMAGE;
  1241. //mType->conditionImmunities |= CONDITION_PHYSICAL;
  1242. }
  1243. else if(readXMLString(tmpNode, "energy", strValue) && booleanString(strValue))
  1244. {
  1245. mType->damageImmunities |= COMBAT_ENERGYDAMAGE;
  1246. mType->conditionImmunities |= CONDITION_ENERGY;
  1247. }
  1248. else if(readXMLString(tmpNode, "fire", strValue) && booleanString(strValue))
  1249. {
  1250. mType->damageImmunities |= COMBAT_FIREDAMAGE;
  1251. mType->conditionImmunities |= CONDITION_FIRE;
  1252. }
  1253. else if((readXMLString(tmpNode, "poison", strValue) || readXMLString(tmpNode, "earth", strValue))
  1254. && booleanString(strValue))
  1255. {
  1256. mType->damageImmunities |= COMBAT_EARTHDAMAGE;
  1257. mType->conditionImmunities |= CONDITION_POISON;
  1258. }
  1259. else if(readXMLString(tmpNode, "drown", strValue) && booleanString(strValue))
  1260. {
  1261. mType->damageImmunities |= COMBAT_DROWNDAMAGE;
  1262. mType->conditionImmunities |= CONDITION_DROWN;
  1263. }
  1264. else if(readXMLString(tmpNode, "ice", strValue) && booleanString(strValue))
  1265. {
  1266. mType->damageImmunities |= COMBAT_ICEDAMAGE;
  1267. mType->conditionImmunities |= CONDITION_FREEZING;
  1268. }
  1269. else if(readXMLString(tmpNode, "holy", strValue) && booleanString(strValue))
  1270. {
  1271. mType->damageImmunities |= COMBAT_HOLYDAMAGE;
  1272. mType->conditionImmunities |= CONDITION_DAZZLED;
  1273. }
  1274. else if(readXMLString(tmpNode, "death", strValue) && booleanString(strValue))
  1275. {
  1276. mType->damageImmunities |= COMBAT_DEATHDAMAGE;
  1277. mType->conditionImmunities |= CONDITION_CURSED;
  1278. }
  1279. else if(readXMLString(tmpNode, "lifedrain", strValue) && booleanString(strValue))
  1280. mType->damageImmunities |= COMBAT_LIFEDRAIN;
  1281. else if(readXMLString(tmpNode, "manadrain", strValue) && booleanString(strValue))
  1282. mType->damageImmunities |= COMBAT_LIFEDRAIN;
  1283. else if(readXMLString(tmpNode, "paralyze", strValue) && booleanString(strValue))
  1284. mType->conditionImmunities |= CONDITION_PARALYZE;
  1285. else if(readXMLString(tmpNode, "outfit", strValue) && booleanString(strValue))
  1286. mType->conditionImmunities |= CONDITION_OUTFIT;
  1287. else if(readXMLString(tmpNode, "drunk", strValue) && booleanString(strValue))
  1288. mType->conditionImmunities |= CONDITION_DRUNK;
  1289. else if(readXMLString(tmpNode, "invisible", strValue) && booleanString(strValue))
  1290. mType->conditionImmunities |= CONDITION_INVISIBLE;
  1291. }
  1292.  
  1293. tmpNode = tmpNode->next;
  1294. }
  1295. }
  1296. else if(!xmlStrcmp(p->name, (const xmlChar*)"voices"))
  1297. {
  1298. if(readXMLInteger(p, "speed", intValue) || readXMLInteger(p, "interval", intValue))
  1299. mType->yellSpeedTicks = intValue;
  1300. else
  1301. SHOW_XML_WARNING("Missing voices.speed");
  1302.  
  1303. if(readXMLInteger(p, "chance", intValue))
  1304. mType->yellChance = intValue;
  1305. else
  1306. SHOW_XML_WARNING("Missing voices.chance");
  1307.  
  1308. xmlNodePtr tmpNode = p->children;
  1309. while(tmpNode)
  1310. {
  1311. if(!xmlStrcmp(tmpNode->name, (const xmlChar*)"voice"))
  1312. {
  1313. voiceBlock_t vb;
  1314. vb.text = "";
  1315. vb.yellText = false;
  1316.  
  1317. if(readXMLString(tmpNode, "sentence", strValue))
  1318. vb.text = strValue;
  1319. else
  1320. SHOW_XML_WARNING("Missing voice.sentence");
  1321.  
  1322. if(readXMLString(tmpNode, "yell", strValue))
  1323. vb.yellText = booleanString(strValue);
  1324.  
  1325. mType->voiceVector.push_back(vb);
  1326. }
  1327.  
  1328. tmpNode = tmpNode->next;
  1329. }
  1330. }
  1331. else if(!xmlStrcmp(p->name, (const xmlChar*)"loot"))
  1332. {
  1333. xmlNodePtr tmpNode = p->children;
  1334. while(tmpNode)
  1335. {
  1336. if(tmpNode->type != XML_ELEMENT_NODE)
  1337. {
  1338. tmpNode = tmpNode->next;
  1339. continue;
  1340. }
  1341.  
  1342. LootBlock rootBlock;
  1343. if(loadLoot(tmpNode, rootBlock))
  1344. mType->lootItems.push_back(rootBlock);
  1345. else
  1346. SHOW_XML_WARNING("Cant load loot");
  1347.  
  1348. tmpNode = tmpNode->next;
  1349. }
  1350. }
  1351. else if(!xmlStrcmp(p->name, (const xmlChar*)"elements"))
  1352. {
  1353. xmlNodePtr tmpNode = p->children;
  1354. while(tmpNode)
  1355. {
  1356. if(!xmlStrcmp(tmpNode->name, (const xmlChar*)"element"))
  1357. {
  1358. if(readXMLInteger(tmpNode, "firePercent", intValue))
  1359. mType->elementMap[COMBAT_FIREDAMAGE] = intValue;
  1360. else if(readXMLInteger(tmpNode, "energyPercent", intValue))
  1361. mType->elementMap[COMBAT_ENERGYDAMAGE] = intValue;
  1362. else if(readXMLInteger(tmpNode, "icePercent", intValue))
  1363. mType->elementMap[COMBAT_ICEDAMAGE] = intValue;
  1364. else if(readXMLInteger(tmpNode, "poisonPercent", intValue) || readXMLInteger(tmpNode, "earthPercent", intValue))
  1365. mType->elementMap[COMBAT_EARTHDAMAGE] = intValue;
  1366. else if(readXMLInteger(tmpNode, "holyPercent", intValue))
  1367. mType->elementMap[COMBAT_HOLYDAMAGE] = intValue;
  1368. else if(readXMLInteger(tmpNode, "deathPercent", intValue))
  1369. mType->elementMap[COMBAT_DEATHDAMAGE] = intValue;
  1370. else if(readXMLInteger(tmpNode, "drownPercent", intValue))
  1371. mType->elementMap[COMBAT_DROWNDAMAGE] = intValue;
  1372. else if(readXMLInteger(tmpNode, "physicalPercent", intValue))
  1373. mType->elementMap[COMBAT_PHYSICALDAMAGE] = intValue;
  1374. else if(readXMLInteger(tmpNode, "lifeDrainPercent", intValue))
  1375. mType->elementMap[COMBAT_LIFEDRAIN] = intValue;
  1376. else if(readXMLInteger(tmpNode, "manaDrainPercent", intValue))
  1377. mType->elementMap[COMBAT_MANADRAIN] = intValue;
  1378. else if(readXMLInteger(tmpNode, "healingPercent", intValue))
  1379. mType->elementMap[COMBAT_HEALING] = intValue;
  1380. else if(readXMLInteger(tmpNode, "undefinedPercent", intValue))
  1381. mType->elementMap[COMBAT_UNDEFINEDDAMAGE] = intValue;
  1382. }
  1383.  
  1384. tmpNode = tmpNode->next;
  1385. }
  1386. }
  1387. else if(!xmlStrcmp(p->name, (const xmlChar*)"summons"))
  1388. {
  1389. if(readXMLInteger(p, "maxSummons", intValue) || readXMLInteger(p, "max", intValue))
  1390. mType->maxSummons = intValue;
  1391.  
  1392. xmlNodePtr tmpNode = p->children;
  1393. while(tmpNode)
  1394. {
  1395. if(!xmlStrcmp(tmpNode->name, (const xmlChar*)"summon"))
  1396. {
  1397. uint32_t chance = 100, interval = 1000, amount = 1;
  1398. if(readXMLInteger(tmpNode, "speed", intValue) || readXMLInteger(tmpNode, "interval", intValue))
  1399. interval = intValue;
  1400.  
  1401. if(readXMLInteger(tmpNode, "chance", intValue))
  1402. chance = intValue;
  1403.  
  1404. if(readXMLInteger(tmpNode, "amount", intValue) || readXMLInteger(tmpNode, "max", intValue))
  1405. amount = intValue;
  1406.  
  1407. if(readXMLString(tmpNode, "name", strValue))
  1408. {
  1409. summonBlock_t sb;
  1410. sb.name = strValue;
  1411. sb.interval = interval;
  1412. sb.chance = chance;
  1413. sb.amount = amount;
  1414.  
  1415. mType->summonList.push_back(sb);
  1416. }
  1417. else
  1418. SHOW_XML_WARNING("Missing summon.name");
  1419. }
  1420.  
  1421. tmpNode = tmpNode->next;
  1422. }
  1423. }
  1424. else if(!xmlStrcmp(p->name, (const xmlChar*)"script"))
  1425. {
  1426. xmlNodePtr tmpNode = p->children;
  1427. while(tmpNode)
  1428. {
  1429. if(!xmlStrcmp(tmpNode->name, (const xmlChar*)"event"))
  1430. {
  1431. if(readXMLString(tmpNode, "name", strValue))
  1432. mType->scriptList.push_back(strValue);
  1433. else
  1434. SHOW_XML_WARNING("Missing name for script event");
  1435. }
  1436.  
  1437. tmpNode = tmpNode->next;
  1438. }
  1439. }
  1440. else
  1441. SHOW_XML_WARNING("Unknown attribute type - " << p->name);
  1442.  
  1443. p = p->next;
  1444. }
  1445.  
  1446. xmlFreeDoc(doc);
  1447. if(monsterLoad)
  1448. {
  1449. static uint32_t id = 0;
  1450. if(new_mType)
  1451. {
  1452. id++;
  1453. monsterNames[asLowerCaseString(monsterName)] = id;
  1454. monsters[id] = mType;
  1455. }
  1456.  
  1457. return true;
  1458. }
  1459.  
  1460. if(new_mType)
  1461. delete mType;
  1462.  
  1463. return false;
  1464. }
  1465.  
  1466. bool Monsters::loadLoot(xmlNodePtr node, LootBlock& lootBlock)
  1467. {
  1468. std::string strValue;
  1469. if(readXMLString(node, "id", strValue) || readXMLString(node, "ids", strValue))
  1470. {
  1471. IntegerVec idsVec;
  1472. parseIntegerVec(strValue, idsVec);
  1473. for(IntegerVec::iterator it = idsVec.begin(); it != idsVec.end(); ++it)
  1474. {
  1475. lootBlock.ids.push_back(*it);
  1476. if(Item::items[(*it)].isContainer())
  1477. loadChildLoot(node, lootBlock);
  1478. }
  1479. }
  1480. else if(readXMLString(node, "name", strValue) || readXMLString(node, "names", strValue))
  1481. {
  1482. StringVec names = explodeString(strValue, ";");
  1483. for(StringVec::iterator it = names.begin(); it != names.end(); ++it)
  1484. {
  1485. uint16_t tmp = Item::items.getItemIdByName(strValue);
  1486. if(!tmp)
  1487. continue;
  1488.  
  1489. lootBlock.ids.push_back(tmp);
  1490. if(Item::items[tmp].isContainer())
  1491. loadChildLoot(node, lootBlock);
  1492. }
  1493. }
  1494.  
  1495. if(lootBlock.ids.empty())
  1496. return false;
  1497.  
  1498. int32_t intValue;
  1499. if(readXMLInteger(node, "count", intValue) || readXMLInteger(node, "countmax", intValue))
  1500. lootBlock.count = std::max(1, std::min(100, intValue));
  1501. else
  1502. lootBlock.count = 1;
  1503.  
  1504. if(readXMLInteger(node, "chance", intValue) || readXMLInteger(node, "chance1", intValue))
  1505. lootBlock.chance = std::min(MAX_LOOTCHANCE, intValue);
  1506. else
  1507. lootBlock.chance = MAX_LOOTCHANCE;
  1508.  
  1509. if(readXMLInteger(node, "subtype", intValue) || readXMLInteger(node, "subType", intValue))
  1510. lootBlock.subType = intValue;
  1511.  
  1512. if(readXMLInteger(node, "actionId", intValue) || readXMLInteger(node, "actionid", intValue)
  1513. || readXMLInteger(node, "aid", intValue))
  1514. lootBlock.actionId = intValue;
  1515.  
  1516. if(readXMLInteger(node, "uniqueId", intValue) || readXMLInteger(node, "uniqueid", intValue)
  1517. || readXMLInteger(node, "uid", intValue))
  1518. lootBlock.uniqueId = intValue;
  1519.  
  1520. if(readXMLString(node, "text", strValue))
  1521. lootBlock.text = strValue;
  1522.  
  1523. return true;
  1524. }
  1525.  
  1526. bool Monsters::loadChildLoot(xmlNodePtr node, LootBlock& parentBlock)
  1527. {
  1528. if(!node)
  1529. return false;
  1530.  
  1531. xmlNodePtr p = node->children, insideNode;
  1532. while(p)
  1533. {
  1534. if(!xmlStrcmp(p->name, (const xmlChar*)"inside"))
  1535. {
  1536. insideNode = p->children;
  1537. while(insideNode)
  1538. {
  1539. LootBlock childBlock;
  1540. if(loadLoot(insideNode, childBlock))
  1541. parentBlock.childLoot.push_back(childBlock);
  1542.  
  1543. insideNode = insideNode->next;
  1544. }
  1545.  
  1546. p = p->next;
  1547. continue;
  1548. }
  1549.  
  1550. LootBlock childBlock;
  1551. if(loadLoot(p, childBlock))
  1552. parentBlock.childLoot.push_back(childBlock);
  1553.  
  1554. p = p->next;
  1555. }
  1556.  
  1557. return true;
  1558. }
  1559.  
  1560. MonsterType* Monsters::getMonsterType(const std::string& name)
  1561. {
  1562. uint32_t mId = getIdByName(name);
  1563. if(mId != 0)
  1564. return getMonsterType(mId);
  1565.  
  1566. return NULL;
  1567. }
  1568.  
  1569. MonsterType* Monsters::getMonsterType(uint32_t mid)
  1570. {
  1571. MonsterMap::iterator it = monsters.find(mid);
  1572. if(it != monsters.end())
  1573. return it->second;
  1574.  
  1575. return NULL;
  1576. }
  1577.  
  1578. uint32_t Monsters::getIdByName(const std::string& name)
  1579. {
  1580. std::string tmp = name;
  1581. MonsterNameMap::iterator it = monsterNames.find(asLowerCaseString(tmp));
  1582. if(it != monsterNames.end())
  1583. return it->second;
  1584.  
  1585. return 0;
  1586. }
  1587.  
  1588. Monsters::~Monsters()
  1589. {
  1590. loaded = false;
  1591. for(MonsterMap::iterator it = monsters.begin(); it != monsters.end(); it++)
  1592. delete it->second;
  1593. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement