Guest User

Untitled

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