Oskar1121

Untitled

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