Guest User

Untitled

a guest
Jul 2nd, 2016
43
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 40.11 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.  
  19. #include "monster.h"
  20. #include "spawn.h"
  21. #include "monsters.h"
  22.  
  23. #include "spells.h"
  24. #include "combat.h"
  25.  
  26. #include "configmanager.h"
  27. #include "game.h"
  28. #include <boost/algorithm/string/replace.hpp>
  29.  
  30. extern Game g_game;
  31. extern ConfigManager g_config;
  32. extern Monsters g_monsters;
  33.  
  34. AutoList<Monster>Monster::autoList;
  35. #ifdef __ENABLE_SERVER_DIAGNOSTIC__
  36. uint32_t Monster::monsterCount = 0;
  37. #endif
  38.  
  39. Monster* Monster::createMonster(MonsterType* mType)
  40. {
  41. return new Monster(mType);
  42. }
  43.  
  44. Monster* Monster::createMonster(const std::string& name)
  45. {
  46. MonsterType* mType = g_monsters.getMonsterType(name);
  47. if(!mType)
  48. return NULL;
  49.  
  50. mType->name = name;
  51. mType->realName = name;
  52.  
  53.  
  54. //-- sistema de shiny respawn
  55.  
  56. mType->codenome = "";
  57. mType->exists = false;
  58.  
  59. std::string findText[] = {"Shiny", "Elite", "Elder", "shiny", "elite", "elder"};
  60. for(int i = 0; i < 6; i++){
  61. if(mType->name.find(findText[i]) != std::string::npos){
  62. mType->codenome = findText[i];
  63. mType->exists = true;
  64. break;
  65. }
  66. }
  67.  
  68.  
  69. if (mType->exists) {
  70. mType->realName = mType->name;
  71. std::string newName = mType->name;
  72. std::string from = mType->codenome + " ";
  73. std::string to = "";
  74. size_t start_pos = 0;
  75. while((start_pos = newName.find(from, start_pos)) != std::string::npos) {
  76. newName.replace(start_pos, from.length(), to);
  77. start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
  78. }
  79. mType->name = newName;
  80. }
  81.  
  82.  
  83. return createMonster(mType);
  84. }
  85.  
  86. Monster* Monster::createMonsterNick(const std::string& name, const std::string& nick)
  87. {
  88. MonsterType* mType = g_monsters.getMonsterType(name);
  89. if(!mType)
  90. return NULL;
  91.  
  92. mType->name = nick;
  93. mType->realName = name;
  94. return createMonster(mType);
  95. }
  96.  
  97. Monster::Monster(MonsterType* _mType):
  98. Creature()
  99. {
  100. isIdle = true;
  101. nick = _mType->name;
  102. name = _mType->realName;
  103.  
  104. isMasterInRange = false;
  105. teleportToMaster = false;
  106.  
  107. mType = _mType;
  108.  
  109. spawn = NULL;
  110. raid = NULL;
  111. defaultOutfit = mType->outfit;
  112. currentOutfit = mType->outfit;
  113.  
  114. double multiplier = g_config.getDouble(ConfigManager::RATE_MONSTER_HEALTH);
  115. health = (int32_t)(mType->health * multiplier);
  116. healthMax = (int32_t)(mType->healthMax * multiplier);
  117.  
  118. baseSpeed = mType->baseSpeed;
  119. internalLight.level = mType->lightLevel;
  120. internalLight.color = mType->lightColor;
  121. setSkull(mType->skull);
  122. setShield(mType->partyShield);
  123.  
  124. hideName = mType->hideName, hideHealth = mType->hideHealth;
  125.  
  126. minCombatValue = 0;
  127. maxCombatValue = 0;
  128.  
  129. targetTicks = 0;
  130. targetChangeTicks = 0;
  131. targetChangeCooldown = 0;
  132. attackTicks = 0;
  133. defenseTicks = 0;
  134. yellTicks = 0;
  135. extraMeleeAttack = false;
  136. //setStorage(510, mType->name);
  137.  
  138.  
  139. // register creature events
  140. for(StringVec::iterator it = mType->scriptList.begin(); it != mType->scriptList.end(); ++it)
  141. {
  142. if(!registerCreatureEvent(*it))
  143. std::cout << "[Warning - Monster::Monster] Unknown event name - " << *it << std::endl;
  144. }
  145.  
  146. #ifdef __ENABLE_SERVER_DIAGNOSTIC__
  147. monsterCount++;
  148. #endif
  149. }
  150.  
  151. Monster::~Monster()
  152. {
  153. clearTargetList();
  154. clearFriendList();
  155. #ifdef __ENABLE_SERVER_DIAGNOSTIC__
  156.  
  157. monsterCount--;
  158. #endif
  159. if(raid)
  160. {
  161. raid->unRef();
  162. raid = NULL;
  163. }
  164. }
  165.  
  166. void Monster::onAttackedCreature(Creature* target)
  167. {
  168. Creature::onAttackedCreature(target);
  169. if(isSummon())
  170. getMaster()->onSummonAttackedCreature(this, target);
  171. }
  172.  
  173. void Monster::onAttackedCreatureDisappear(bool isLogout)
  174. {
  175. #ifdef __DEBUG__
  176. std::cout << "Attacked creature disappeared." << std::endl;
  177. #endif
  178. attackTicks = 0;
  179. extraMeleeAttack = true;
  180. }
  181.  
  182. void Monster::onAttackedCreatureDrain(Creature* target, int32_t points)
  183. {
  184. Creature::onAttackedCreatureDrain(target, points);
  185. if(isSummon())
  186. getMaster()->onSummonAttackedCreatureDrain(this, target, points);
  187. }
  188.  
  189. void Monster::onCreatureAppear(const Creature* creature)
  190. {
  191. Creature::onCreatureAppear(creature);
  192. if(creature == this)
  193. {
  194. //We just spawned lets look around to see who is there.
  195. if(isSummon())
  196. isMasterInRange = canSee(getMaster()->getPosition());
  197.  
  198. setStorage(510, mType->realName); // sistema de shiny nomes 2.0
  199.  
  200. CreatureEventList spawn = getCreatureEvents(CREATURE_EVENT_SPAWN);
  201. for(CreatureEventList::iterator it = spawn.begin(); it != spawn.end(); ++it)
  202.  
  203. (*it)->executeOnSpawn(this);
  204.  
  205.  
  206. updateTargetList();
  207. updateIdleStatus();
  208. }
  209. else
  210. onCreatureEnter(const_cast<Creature*>(creature));
  211. }
  212.  
  213. void Monster::onCreatureDisappear(const Creature* creature, bool isLogout)
  214. {
  215. Creature::onCreatureDisappear(creature, isLogout);
  216. if(creature == this)
  217. {
  218. if(spawn)
  219. spawn->startEvent();
  220.  
  221. setIdle(true);
  222. }
  223. else
  224. onCreatureLeave(const_cast<Creature*>(creature));
  225. }
  226.  
  227. void Monster::onCreatureMove(const Creature* creature, const Tile* newTile, const Position& newPos,
  228. const Tile* oldTile, const Position& oldPos, bool teleport)
  229. {
  230. Creature::onCreatureMove(creature, newTile, newPos, oldTile, oldPos, teleport);
  231. if(creature == this)
  232. {
  233. if(isSummon())
  234. isMasterInRange = canSee(getMaster()->getPosition());
  235.  
  236. updateTargetList();
  237. updateIdleStatus();
  238. }
  239. else
  240. {
  241. bool canSeeNewPos = canSee(newPos), canSeeOldPos = canSee(oldPos);
  242. if(canSeeNewPos && !canSeeOldPos)
  243. onCreatureEnter(const_cast<Creature*>(creature));
  244. else if(!canSeeNewPos && canSeeOldPos)
  245. onCreatureLeave(const_cast<Creature*>(creature));
  246.  
  247. if(isSummon() && getMaster() == creature && canSeeNewPos) //Turn the summon on again
  248. isMasterInRange = true;
  249.  
  250. updateIdleStatus();
  251. if(!followCreature && !isSummon() && isOpponent(creature)) //we have no target lets try pick this one
  252. selectTarget(const_cast<Creature*>(creature));
  253. }
  254. }
  255.  
  256. void Monster::updateTargetList()
  257. {
  258. CreatureList::iterator it;
  259. for(it = friendList.begin(); it != friendList.end();)
  260. {
  261. if((*it)->getHealth() <= 0 || !canSee((*it)->getPosition()))
  262. {
  263. (*it)->unRef();
  264. it = friendList.erase(it);
  265. }
  266. else
  267. ++it;
  268. }
  269.  
  270. for(it = targetList.begin(); it != targetList.end();)
  271. {
  272. if((*it)->getHealth() <= 0 || !canSee((*it)->getPosition()))
  273. {
  274. (*it)->unRef();
  275. it = targetList.erase(it);
  276. }
  277. else
  278. ++it;
  279. }
  280.  
  281. const SpectatorVec& list = g_game.getSpectators(getPosition());
  282. for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
  283. {
  284. if((*it) != this && canSee((*it)->getPosition()))
  285. onCreatureFound(*it);
  286. }
  287. }
  288.  
  289. void Monster::clearTargetList()
  290. {
  291. for(CreatureList::iterator it = targetList.begin(); it != targetList.end(); ++it)
  292. (*it)->unRef();
  293.  
  294. targetList.clear();
  295. }
  296.  
  297. void Monster::clearFriendList()
  298. {
  299. for(CreatureList::iterator it = friendList.begin(); it != friendList.end(); ++it)
  300. (*it)->unRef();
  301.  
  302. friendList.clear();
  303. }
  304.  
  305. void Monster::onCreatureFound(Creature* creature, bool pushFront /*= false*/)
  306. {
  307. if(isFriend(creature))
  308. {
  309. assert(creature != this);
  310. if(std::find(friendList.begin(), friendList.end(), creature) == friendList.end())
  311. {
  312. creature->addRef();
  313. friendList.push_back(creature);
  314. }
  315. }
  316.  
  317. if(isOpponent(creature))
  318. {
  319. assert(creature != this);
  320. if(std::find(targetList.begin(), targetList.end(), creature) == targetList.end())
  321. {
  322. creature->addRef();
  323. if(pushFront)
  324. targetList.push_front(creature);
  325. else
  326. targetList.push_back(creature);
  327. }
  328. }
  329.  
  330. updateIdleStatus();
  331. }
  332.  
  333. void Monster::onCreatureEnter(Creature* creature)
  334. {
  335. if(getMaster() == creature) //Turn the summon on again
  336. {
  337. isMasterInRange = true;
  338. updateIdleStatus();
  339. }
  340.  
  341. onCreatureFound(creature, true);
  342. }
  343.  
  344. bool Monster::isFriend(const Creature* creature)
  345. {
  346. if(!isSummon() || !getMaster()->getPlayer())
  347. return creature->getMonster() && !creature->isSummon();
  348.  
  349. const Player* tmpPlayer = NULL;
  350. if(creature->getPlayer())
  351. tmpPlayer = creature->getPlayer();
  352. else if(creature->getMaster() && creature->getMaster()->getPlayer())
  353. tmpPlayer = creature->getMaster()->getPlayer();
  354.  
  355. const Player* masterPlayer = getMaster()->getPlayer();
  356. return tmpPlayer && (tmpPlayer == getMaster() || masterPlayer->isPartner(tmpPlayer));
  357. }
  358.  
  359. bool Monster::isOpponent(const Creature* creature)
  360. {
  361. return (isSummon() && getMaster()->getPlayer() && creature != getMaster()) || ((creature->getPlayer()
  362. && !creature->getPlayer()->hasFlag(PlayerFlag_IgnoredByMonsters)) ||
  363. (creature->getMaster() && creature->getMaster()->getPlayer()));
  364. }
  365.  
  366. bool Monster::doTeleportToMaster()
  367. {
  368. const Position& tmp = getPosition();
  369. if(g_game.internalTeleport(this, g_game.getClosestFreeTile(this,
  370. getMaster()->getPosition(), true), false) != RET_NOERROR)
  371. return false;
  372.  
  373. //g_game.addMagicEffect(tmp, MAGIC_EFFECT_POFF);
  374. //g_game.addMagicEffect(getPosition(), MAGIC_EFFECT_SOUND_YELLOW);
  375. return true;
  376. }
  377.  
  378. void Monster::onCreatureLeave(Creature* creature)
  379. {
  380. #ifdef __DEBUG__
  381. std::cout << "onCreatureLeave - " << creature->getName() << std::endl;
  382. #endif
  383. if(isSummon() && getMaster() == creature)
  384. {
  385. if(!g_config.getBool(ConfigManager::TELEPORT_SUMMONS) && (!getMaster()->getPlayer()
  386. || !g_config.getBool(ConfigManager::TELEPORT_PLAYER_SUMMONS)))
  387. {
  388. //Turn the monster off until its master comes back
  389. isMasterInRange = false;
  390. updateIdleStatus();
  391. }
  392. else if(!doTeleportToMaster())
  393. teleportToMaster = true;
  394. }
  395.  
  396. //update friendList
  397. if(isFriend(creature))
  398. {
  399. CreatureList::iterator it = std::find(friendList.begin(), friendList.end(), creature);
  400. if(it != friendList.end())
  401. {
  402. (*it)->unRef();
  403. friendList.erase(it);
  404. }
  405. #ifdef __DEBUG__
  406. else
  407. std::cout << "Monster: " << creature->getName() << " not found in the friendList." << std::endl;
  408. #endif
  409. }
  410.  
  411. //update targetList
  412. if(isOpponent(creature))
  413. {
  414. CreatureList::iterator it = std::find(targetList.begin(), targetList.end(), creature);
  415. if(it != targetList.end())
  416. {
  417. (*it)->unRef();
  418. targetList.erase(it);
  419. if(targetList.empty())
  420. updateIdleStatus();
  421. }
  422. #ifdef __DEBUG__
  423. else
  424. std::cout << "Player: " << creature->getName() << " not found in the targetList." << std::endl;
  425. #endif
  426. }
  427. }
  428.  
  429. bool Monster::searchTarget(TargetSearchType_t searchType /*= TARGETSEARCH_DEFAULT*/)
  430. {
  431. #ifdef __DEBUG__
  432. std::cout << "Searching target... " << std::endl;
  433. #endif
  434.  
  435. std::list<Creature*> resultList;
  436. const Position& myPos = getPosition();
  437. for(CreatureList::iterator it = targetList.begin(); it != targetList.end(); ++it)
  438. {
  439. if(followCreature != (*it) && isTarget(*it) && (searchType == TARGETSEARCH_RANDOM
  440. || canUseAttack(myPos, *it)))
  441. resultList.push_back(*it);
  442. }
  443.  
  444. switch(searchType)
  445. {
  446. case TARGETSEARCH_NEAREST:
  447. {
  448. Creature* target = NULL;
  449. int32_t range = -1; // aqui
  450.  
  451. for(CreatureList::iterator it = resultList.begin(); it != resultList.end(); ++it)
  452. {
  453. int32_t tmp = std::max(std::abs(myPos.x - (*it)->getPosition().x),
  454. std::abs(myPos.y - (*it)->getPosition().y));
  455. if(range >= 0 && tmp >= range)
  456. continue;
  457.  
  458. target = *it;
  459. range = tmp;
  460. }
  461.  
  462. if(target && selectTarget(target))
  463. return target;
  464.  
  465. break;
  466. }
  467. default:
  468. {
  469. if(!resultList.empty())
  470. {
  471. CreatureList::iterator it = resultList.begin();
  472. std::advance(it, random_range(0, resultList.size() - 1));
  473. #ifdef __DEBUG__
  474.  
  475. std::cout << "Selecting target " << (*it)->getName() << std::endl;
  476. #endif
  477. return selectTarget(*it);
  478. }
  479.  
  480. if(searchType == TARGETSEARCH_ATTACKRANGE)
  481. return false;
  482.  
  483. break;
  484. }
  485. }
  486.  
  487.  
  488. //lets just pick the first target in the list
  489. for(CreatureList::iterator it = targetList.begin(); it != targetList.end(); ++it)
  490. {
  491. if(followCreature == (*it) || !selectTarget(*it))
  492. continue;
  493.  
  494. #ifdef __DEBUG__
  495. std::cout << "Selecting target " << (*it)->getName() << std::endl;
  496. #endif
  497. return true;
  498. }
  499.  
  500. return false;
  501. }
  502.  
  503. void Monster::onFollowCreatureComplete(const Creature* creature)
  504. {
  505. if(!creature)
  506. return;
  507.  
  508. CreatureList::iterator it = std::find(targetList.begin(), targetList.end(), creature);
  509. if(it != targetList.end())
  510. {
  511. Creature* target = (*it);
  512. targetList.erase(it);
  513.  
  514. if(hasFollowPath) //push target we have found a path to the front
  515. targetList.push_front(target);
  516. else if(!isSummon()) //push target we have not found a path to the back
  517. targetList.push_back(target);
  518. else //Since we removed the creature from the targetList (and not put it back) we have to release it too
  519. target->unRef();
  520. }
  521. }
  522.  
  523. BlockType_t Monster::blockHit(Creature* attacker, CombatType_t combatType, int32_t& damage,
  524. bool checkDefense/* = false*/, bool checkArmor/* = false*/)
  525. {
  526. BlockType_t blockType = Creature::blockHit(attacker, combatType, damage, checkDefense, checkArmor);
  527. if(!damage)
  528. return blockType;
  529.  
  530. int32_t elementMod = 0;
  531. ElementMap::iterator it = mType->elementMap.find(combatType);
  532. if(it != mType->elementMap.end())
  533. elementMod = it->second;
  534.  
  535. if(!elementMod)
  536. return blockType;
  537.  
  538. damage = (int32_t)std::ceil(damage * ((float)(100 - elementMod) / 100));
  539. if(damage > 0)
  540. return blockType;
  541.  
  542. damage = 0;
  543. blockType = BLOCK_DEFENSE;
  544. return blockType;
  545. }
  546.  
  547. bool Monster::isTarget(Creature* creature)
  548. {
  549. return (!creature->isRemoved() && creature->isAttackable() && creature->getZone() != ZONE_PROTECTION
  550. && canSeeCreature(creature) && creature->getPosition().z == getPosition().z);
  551. }
  552.  
  553. bool Monster::selectTarget(Creature* creature)
  554. {
  555. #ifdef __DEBUG__
  556. std::cout << "Selecting target... " << std::endl;
  557. #endif
  558. if(!isTarget(creature))
  559. return false;
  560.  
  561. CreatureList::iterator it = std::find(targetList.begin(), targetList.end(), creature);
  562. if(it == targetList.end())
  563. {
  564. //Target not found in our target list.
  565. #ifdef __DEBUG__
  566. std::cout << "Target not found in targetList." << std::endl;
  567. #endif
  568. return false;
  569. }
  570. if (isPassive() && !hasBeenAttacked(creature->getID())) {
  571. return false;
  572. }
  573. if(!isHostile() && getHealth() == getMaxHealth() && !isSummon() && !isTarget(creature))
  574. {
  575. return false;
  576. }
  577.  
  578. if((isHostile() || isSummon() || !isHostile() && getHealth() != getMaxHealth() || isPassive() && isTarget(creature)) && setAttackedCreature(creature) && !isSummon())
  579. Dispatcher::getInstance().addTask(createTask(
  580. boost::bind(&Game::checkCreatureAttack, &g_game, getID())));
  581.  
  582. return setFollowCreature(creature, true);
  583. }
  584.  
  585.  
  586. void Monster::setIdle(bool _idle)
  587. {
  588. if(isRemoved() || getHealth() <= 0)
  589. return;
  590.  
  591. isIdle = _idle;
  592. if(isIdle)
  593. {
  594. onIdleStatus();
  595. clearTargetList();
  596. clearFriendList();
  597. g_game.removeCreatureCheck(this);
  598. }
  599. else
  600. g_game.addCreatureCheck(this);
  601. }
  602.  
  603. void Monster::updateIdleStatus()
  604. {
  605. bool idle = false;
  606. if(conditions.empty())
  607. {
  608. if(isSummon())
  609. {
  610. if((!isMasterInRange && !teleportToMaster) || (getMaster()->getMonster() && getMaster()->getMonster()->getIdleStatus()))
  611. idle = true;
  612. }
  613. else if(targetList.empty())
  614. idle = true;
  615. }
  616.  
  617. setIdle(idle);
  618. }
  619.  
  620. void Monster::onAddCondition(ConditionType_t type, bool hadCondition)
  621. {
  622. Creature::onAddCondition(type, hadCondition);
  623. //the walkCache need to be updated if the monster becomes "resistent" to the damage, see Tile::__queryAdd()
  624. if(type == CONDITION_FIRE || type == CONDITION_ENERGY || type == CONDITION_POISON)
  625. updateMapCache();
  626.  
  627. updateIdleStatus();
  628. }
  629.  
  630. void Monster::onEndCondition(ConditionType_t type)
  631. {
  632. Creature::onEndCondition(type);
  633. //the walkCache need to be updated if the monster loose the "resistent" to the damage, see Tile::__queryAdd()
  634. if(type == CONDITION_FIRE || type == CONDITION_ENERGY || type == CONDITION_POISON)
  635. updateMapCache();
  636.  
  637. updateIdleStatus();
  638. }
  639.  
  640. void Monster::onThink(uint32_t interval)
  641.  
  642. {
  643. Creature::onThink(interval);
  644. if(despawn())
  645. {
  646. g_game.removeCreature(this, true);
  647. setIdle(true);
  648. return;
  649. }
  650.  
  651. updateIdleStatus();
  652. if(isIdle)
  653. return;
  654.  
  655. if(teleportToMaster && doTeleportToMaster())
  656. teleportToMaster = false;
  657.  
  658. addEventWalk();
  659.  
  660. if(getMaster()){
  661. if(getPosition().z != getMaster()->getPosition().z){
  662. g_game.internalTeleport(this, getMaster()->getPosition(), false);
  663. //g_game.addMagicEffect(getPosition(), MAGIC_EFFECT_SOUND_YELLOW);
  664. }
  665. }
  666.  
  667. if(isSummon())
  668. {
  669. if(!attackedCreature)
  670. {
  671. std::string strValue;
  672. if(getMaster() && getMaster()->getAttackedCreature()) //This happens if the monster is summoned during combat
  673. selectTarget(getMaster()->getAttackedCreature());
  674. else{
  675. setFollowCreature((getMaster()->getStorage(500, strValue) && strValue != "-1") ? NULL : getMaster());
  676. }
  677.  
  678. }
  679. else if(attackedCreature == this)
  680. setFollowCreature(NULL);
  681. else if(followCreature != attackedCreature) //This happens just after a master orders an attack, so lets follow it aswell.
  682. setFollowCreature(attackedCreature);
  683. }
  684. else if(!targetList.empty())
  685. {
  686. if(!followCreature || !hasFollowPath)
  687. searchTarget();
  688. else if(isFleeing() && attackedCreature && !canUseAttack(getPosition(), attackedCreature))
  689. searchTarget(TARGETSEARCH_ATTACKRANGE);
  690. }
  691.  
  692. onThinkTarget(interval);
  693. onThinkYell(interval);
  694. onThinkDefense(interval);
  695. }
  696.  
  697. void Monster::setAttackSpeed(uint32_t interval)
  698. {
  699. attackTicks = interval;
  700. std::cout << "Deu" << std::endl;
  701. }
  702.  
  703. void Monster::doAttacking(uint32_t interval)
  704. {
  705. if(!attackedCreature || (isSummon() && attackedCreature == this))
  706. return; // aqui
  707.  
  708. const Position& myPos = getPosition();
  709. const Position& targetPos = attackedCreature->getPosition();
  710.  
  711. FindPathParams fpp;
  712.  
  713. fpp.fullPathSearch = true;
  714. fpp.maxSearchDist = -1;
  715. fpp.minTargetDist = 0;
  716. fpp.maxTargetDist = 1;
  717.  
  718. std::string valueString;
  719. std::list<Direction> dirList;
  720. if(attackedCreature->getPlayer()){
  721. if(Creature* summon = attackedCreature->pushBackSummonOne())
  722. selectTarget(summon);
  723. }
  724.  
  725. /*
  726. if(!g_game.getPathToEx(this, targetPos, dirList, fpp) && attackedCreature->isSummon()){
  727. selectTarget(attackedCreature->getMaster());
  728.  
  729. std::string strValue; int32_t value;
  730. if(getStorage(8085, strValue))
  731. {
  732. value = atoi(strValue.c_str());
  733. }
  734. if(value == 0)
  735. g_game.addAnimatedText(getPosition(), 215, "GRRR!");
  736.  
  737. setStorage(8085, "2");
  738. }
  739.  
  740. if(attackedCreature->getPlayer()){
  741. if(Creature* summon = attackedCreature->pushBackSummonOne()){
  742. if(g_game.getPathToEx(this, summon->getPosition(), dirList, fpp)){
  743. selectTarget(summon);
  744. std::string strValue, playerStor; int32_t value, value2;
  745. if(getStorage(8085, strValue))
  746. {
  747. value = atoi(strValue.c_str());
  748. }
  749. if(value == 2)
  750. g_game.addAnimatedText(getPosition(), 215, "Hmpf");
  751.  
  752.  
  753. setStorage(8085, "0");
  754. }
  755. }else
  756. setStorage(8085, "1");
  757. }
  758. */
  759.  
  760. bool updateLook = true, outOfRange = true;
  761. resetTicks = interval;
  762. attackTicks += interval;
  763.  
  764.  
  765. for(SpellList::iterator it = mType->spellAttackList.begin(); it != mType->spellAttackList.end(); ++it)
  766. {
  767. if(it->isMelee && isFleeing())
  768. continue;
  769.  
  770. bool inRange = false;
  771. if(canUseSpell(myPos, targetPos, *it, interval, inRange))
  772. {
  773. if(it->chance >= (uint32_t)random_range(1, 100))
  774. {
  775. if(updateLook)
  776. {
  777. updateLookDirection();
  778. updateLook = false;
  779. }
  780.  
  781. double multiplier;
  782. if(maxCombatValue > 0) //defense
  783. multiplier = g_config.getDouble(ConfigManager::RATE_MONSTER_DEFENSE);
  784. else //attack
  785. multiplier = g_config.getDouble(ConfigManager::RATE_MONSTER_ATTACK);
  786.  
  787. minCombatValue = (int32_t)(it->minCombatValue * multiplier);
  788. maxCombatValue = (int32_t)(it->maxCombatValue * multiplier);
  789.  
  790. it->spell->castSpell(this, attackedCreature);
  791. if(it->isMelee)
  792. extraMeleeAttack = false;
  793. #ifdef __DEBUG__
  794. static uint64_t prevTicks = OTSYS_TIME();
  795. std::cout << "doAttacking ticks: " << OTSYS_TIME() - prevTicks << std::endl;
  796. prevTicks = OTSYS_TIME();
  797. #endif
  798. }
  799. }
  800.  
  801. if(inRange)
  802. outOfRange = false;
  803. else if(it->isMelee) //melee swing out of reach
  804. extraMeleeAttack = true;
  805. }
  806.  
  807. if(updateLook)
  808. updateLookDirection();
  809.  
  810. if(resetTicks)
  811. attackTicks = 0;
  812. }
  813.  
  814.  
  815.  
  816. bool Monster::canUseAttack(const Position& pos, const Creature* target) const
  817. {
  818. const Position& targetPos = target->getPosition();
  819. for(SpellList::iterator it = mType->spellAttackList.begin(); it != mType->spellAttackList.end(); ++it)
  820. {
  821. if((*it).range != 0 && std::max(std::abs(pos.x - targetPos.x), std::abs(pos.y - targetPos.y)) <= (int32_t)(*it).range)
  822. return g_game.isSightClear(pos, targetPos, true);
  823. }
  824.  
  825. return false;
  826. }
  827.  
  828. bool Monster::canUseSpell(const Position& pos, const Position& targetPos,
  829. const spellBlock_t& sb, uint32_t interval, bool& inRange)
  830. {
  831. inRange = true;
  832. if(!sb.isMelee || !extraMeleeAttack)
  833. {
  834. if(sb.speed > attackTicks)
  835. {
  836. resetTicks = false;
  837. return false;
  838. }
  839.  
  840. if(attackTicks % sb.speed >= interval) //already used this spell for this round
  841. return false;
  842. }
  843.  
  844. if(!sb.range || std::max(std::abs(pos.x - targetPos.x), std::abs(pos.y - targetPos.y)) <= (int32_t)sb.range)
  845. return true;
  846.  
  847. inRange = false;
  848. return false;
  849. }
  850.  
  851. void Monster::onThinkTarget(uint32_t interval)
  852. {
  853.  
  854. if((isSummon() || mType->changeTargetSpeed <= 0))
  855. return;
  856.  
  857. bool canChangeTarget = true;
  858. if(targetChangeCooldown > 0)
  859. {
  860. targetChangeCooldown -= interval;
  861. if(targetChangeCooldown <= 0)
  862. {
  863. targetChangeCooldown = 0;
  864. targetChangeTicks = (uint32_t)mType->changeTargetSpeed;
  865. }
  866. else
  867. canChangeTarget = false;
  868. }
  869.  
  870. if(!canChangeTarget)
  871. return;
  872.  
  873. targetChangeTicks += interval;
  874. if(targetChangeTicks < (uint32_t)mType->changeTargetSpeed)
  875. return;
  876.  
  877. targetChangeTicks = 0;
  878. targetChangeCooldown = (uint32_t)mType->changeTargetSpeed;
  879. if(mType->changeTargetChance < random_range(1, 100))
  880. return;
  881.  
  882. std::string strValue;
  883. int32_t value;
  884. if(getStorage(502, strValue))
  885. {
  886. value = atoi(strValue.c_str());
  887. }
  888. if(mType->targetDistance <= 1 && value == -1)
  889. searchTarget(TARGETSEARCH_RANDOM);
  890. else
  891. searchTarget(TARGETSEARCH_NEAREST);
  892.  
  893.  
  894. }
  895.  
  896. void Monster::onThinkDefense(uint32_t interval)
  897. {
  898. resetTicks = true;
  899. defenseTicks += interval;
  900. for(SpellList::iterator it = mType->spellDefenseList.begin(); it != mType->spellDefenseList.end(); ++it)
  901. {
  902. if(it->speed > defenseTicks)
  903. {
  904. if(resetTicks)
  905. resetTicks = false;
  906.  
  907. continue;
  908. }
  909.  
  910. if(defenseTicks % it->speed >= interval) //already used this spell for this round
  911. continue;
  912.  
  913. if((it->chance >= (uint32_t)random_range(1, 100)))
  914. {
  915. minCombatValue = it->minCombatValue;
  916. maxCombatValue = it->maxCombatValue;
  917. it->spell->castSpell(this, this);
  918. }
  919. }
  920.  
  921. if(!isSummon())
  922. {
  923. if(mType->maxSummons < 0 || (int32_t)summons.size() < mType->maxSummons)
  924. {
  925. for(SummonList::iterator it = mType->summonList.begin(); it != mType->summonList.end(); ++it)
  926. {
  927. if((int32_t)summons.size() >= mType->maxSummons)
  928. break;
  929.  
  930. if(it->interval > defenseTicks)
  931. {
  932. if(resetTicks)
  933. resetTicks = false;
  934.  
  935. continue;
  936. }
  937.  
  938. if(defenseTicks % it->interval >= interval)
  939. continue;
  940.  
  941. uint32_t typeCount = 0;
  942. for(CreatureList::iterator cit = summons.begin(); cit != summons.end(); ++cit)
  943. {
  944. if(!(*cit)->isRemoved() && (*cit)->getMonster() &&
  945. (*cit)->getMonster()->getName() == it->name)
  946. typeCount++;
  947. }
  948.  
  949. if(typeCount >= it->amount)
  950. continue;
  951.  
  952. if((it->chance >= (uint32_t)random_range(1, 100)))
  953. {
  954. if(Monster* summon = Monster::createMonster(it->name))
  955. {
  956. addSummon(summon);
  957. if(!g_game.placeCreature(summon, getPosition()))
  958. removeSummon(summon);
  959. }
  960. }
  961. }
  962. }
  963. }
  964.  
  965. if(resetTicks)
  966. defenseTicks = 0;
  967. }
  968.  
  969. void Monster::onThinkYell(uint32_t interval)
  970. {
  971. if(mType->yellSpeedTicks <= 0)
  972. return;
  973.  
  974. yellTicks += interval;
  975. if(yellTicks < mType->yellSpeedTicks)
  976. return;
  977.  
  978. yellTicks = 0;
  979. if(mType->voiceVector.empty() || (mType->yellChance < (uint32_t)random_range(1, 100)))
  980. return;
  981.  
  982. const voiceBlock_t& vb = mType->voiceVector[random_range(0, mType->voiceVector.size() - 1)];
  983. if(vb.yellText)
  984. g_game.internalCreatureSay(this, SPEAK_MONSTER_YELL, vb.text, false);
  985. else
  986. g_game.internalCreatureSay(this, SPEAK_MONSTER_SAY, vb.text, false);
  987. }
  988.  
  989. bool Monster::pushItem(Item* item, int32_t radius)
  990. {
  991. const Position& centerPos = item->getPosition();
  992. PairVector pairVector;
  993. pairVector.push_back(PositionPair(-1, -1));
  994. pairVector.push_back(PositionPair(-1, 0));
  995. pairVector.push_back(PositionPair(-1, 1));
  996. pairVector.push_back(PositionPair(0, -1));
  997. pairVector.push_back(PositionPair(0, 1));
  998. pairVector.push_back(PositionPair(1, -1));
  999. pairVector.push_back(PositionPair(1, 0));
  1000. pairVector.push_back(PositionPair(1, 1));
  1001.  
  1002. std::random_shuffle(pairVector.begin(), pairVector.end());
  1003. Position tryPos;
  1004. for(int32_t n = 1; n <= radius; ++n)
  1005. {
  1006. for(PairVector::iterator it = pairVector.begin(); it != pairVector.end(); ++it)
  1007. {
  1008. int32_t dx = it->first * n, dy = it->second * n;
  1009. tryPos = centerPos;
  1010.  
  1011. tryPos.x = tryPos.x + dx;
  1012. tryPos.y = tryPos.y + dy;
  1013.  
  1014. Tile* tile = g_game.getTile(tryPos);
  1015. if(tile && g_game.canThrowObjectTo(centerPos, tryPos) && g_game.internalMoveItem(this, item->getParent(),
  1016. tile, INDEX_WHEREEVER, item, item->getItemCount(), NULL) == RET_NOERROR)
  1017. return true;
  1018. }
  1019. }
  1020.  
  1021. return false;
  1022. }
  1023.  
  1024. void Monster::pushItems(Tile* tile)
  1025. {
  1026. TileItemVector* items = tile->getItemList();
  1027. if(!items)
  1028. return;
  1029.  
  1030. //We cannot use iterators here since we can push the item to another tile
  1031. //which will invalidate the iterator.
  1032. //start from the end to minimize the amount of traffic
  1033. int32_t moveCount = 0, removeCount = 0, downItemsSize = tile->getDownItemCount();
  1034. Item* item = NULL;
  1035. for(int32_t i = downItemsSize - 1; i >= 0; --i)
  1036. {
  1037. assert(i >= 0 && i < downItemsSize);
  1038. if((item = items->at(i)) && item->hasProperty(MOVEABLE) &&
  1039. (item->hasProperty(BLOCKPATH) || item->hasProperty(BLOCKSOLID)))
  1040. {
  1041. if(moveCount < 20 && pushItem(item, 1))
  1042. moveCount++;
  1043. else if(g_game.internalRemoveItem(this, item) == RET_NOERROR)
  1044. ++removeCount;
  1045. }
  1046. }
  1047.  
  1048. //if(removeCount > 0)
  1049. //g_game.addMagicEffect(tile->getPosition(), MAGIC_EFFECT_SOUND_YELLOW);
  1050. }
  1051.  
  1052. bool Monster::pushCreature(Creature* creature)
  1053. {
  1054. DirVector dirVector;
  1055. dirVector.push_back(NORTH);
  1056. dirVector.push_back(SOUTH);
  1057. dirVector.push_back(WEST);
  1058. dirVector.push_back(EAST);
  1059.  
  1060. std::random_shuffle(dirVector.begin(), dirVector.end());
  1061. Position monsterPos = creature->getPosition();
  1062.  
  1063. Tile* tile = NULL;
  1064. for(DirVector::iterator it = dirVector.begin(); it != dirVector.end(); ++it)
  1065. {
  1066. if((tile = g_game.getTile(Spells::getCasterPosition(creature, (*it)))) && !tile->hasProperty(
  1067. BLOCKPATH) && g_game.internalMoveCreature(creature, (*it)) == RET_NOERROR)
  1068. return true;
  1069. }
  1070.  
  1071. return false;
  1072. }
  1073.  
  1074. void Monster::pushCreatures(Tile* tile)
  1075. {
  1076. CreatureVector* creatures = tile->getCreatures();
  1077. if(!creatures)
  1078. return;
  1079.  
  1080. bool effect = false;
  1081. Monster* monster = NULL;
  1082. for(uint32_t i = 0; i < creatures->size();)
  1083. {
  1084. if((monster = creatures->at(i)->getMonster()) && monster->isPushable())
  1085. {
  1086. if(pushCreature(monster))
  1087. continue;
  1088.  
  1089. monster->setDropLoot(LOOT_DROP_NONE);
  1090. monster->changeHealth(-monster->getHealth());
  1091. if(!effect)
  1092. effect = true;
  1093. }
  1094.  
  1095. ++i;
  1096. }
  1097.  
  1098. }
  1099.  
  1100. bool Monster::getNextStep(Direction& dir, uint32_t& flags)
  1101. {
  1102. if(isIdle || getHealth() <= 0)
  1103. {
  1104. //we dont have anyone watching might aswell stop walking
  1105. eventWalk = 0;
  1106. return false;
  1107. }
  1108.  
  1109. bool result = false;
  1110. if((!followCreature || !hasFollowPath) && !isSummon())
  1111. {
  1112. if(followCreature || getTimeSinceLastMove() > 1000) //choose a random direction
  1113. result = getRandomStep(getPosition(), dir);
  1114. }
  1115. else if(isSummon() || followCreature)
  1116. {
  1117. result = Creature::getNextStep(dir, flags);
  1118. if(!result)
  1119. {
  1120. //target dancing
  1121. if(attackedCreature && attackedCreature == followCreature)
  1122. {
  1123. if(isFleeing())
  1124. result = getDanceStep(getPosition(), dir, false, false);
  1125. else if(mType->staticAttackChance < (uint32_t)random_range(1, 100))
  1126. result = getDanceStep(getPosition(), dir);
  1127. }
  1128. }
  1129. else
  1130. flags |= FLAG_PATHFINDING;
  1131. }
  1132.  
  1133. if(result && (canPushItems() || canPushCreatures()))
  1134. {
  1135. if(Tile* tile = g_game.getTile(Spells::getCasterPosition(this, dir)))
  1136. {
  1137. if(canPushItems())
  1138. pushItems(tile);
  1139.  
  1140. if(canPushCreatures())
  1141. pushCreatures(tile);
  1142. }
  1143. #ifdef __DEBUG__
  1144. else
  1145. std::cout << "[Warning - Monster::getNextStep] no tile found." << std::endl;
  1146. #endif
  1147. }
  1148.  
  1149. return result;
  1150. }
  1151.  
  1152. bool Monster::getRandomStep(const Position& creaturePos, Direction& dir)
  1153. {
  1154. DirVector dirVector;
  1155. dirVector.push_back(NORTH);
  1156. dirVector.push_back(SOUTH);
  1157. dirVector.push_back(WEST);
  1158. dirVector.push_back(EAST);
  1159.  
  1160. std::random_shuffle(dirVector.begin(), dirVector.end());
  1161. for(DirVector::iterator it = dirVector.begin(); it != dirVector.end(); ++it)
  1162. {
  1163. if(!canWalkTo(creaturePos, *it))
  1164. continue;
  1165.  
  1166. dir = *it;
  1167. return true;
  1168. }
  1169.  
  1170. return false;
  1171. }
  1172.  
  1173. bool Monster::getDanceStep(const Position& creaturePos, Direction& dir, bool keepAttack /*= true*/, bool keepDistance /*= true*/)
  1174. {
  1175. assert(attackedCreature);
  1176. bool canDoAttackNow = canUseAttack(creaturePos, attackedCreature);
  1177. const Position& centerPos = attackedCreature->getPosition();
  1178.  
  1179. uint32_t tmpDist, centerToDist = std::max(std::abs(creaturePos.x - centerPos.x), std::abs(creaturePos.y - centerPos.y));
  1180. DirVector dirVector;
  1181. if(!keepDistance || creaturePos.y - centerPos.y >= 0)
  1182. {
  1183. tmpDist = std::max(std::abs((creaturePos.x) - centerPos.x), std::abs((creaturePos.y - 1) - centerPos.y));
  1184. if(tmpDist == centerToDist && canWalkTo(creaturePos, NORTH))
  1185. {
  1186. bool result = true;
  1187. if(keepAttack)
  1188. result = (!canDoAttackNow || canUseAttack(Position(creaturePos.x, creaturePos.y - 1, creaturePos.z), attackedCreature));
  1189.  
  1190. if(result)
  1191. dirVector.push_back(NORTH);
  1192. }
  1193. }
  1194.  
  1195. if(!keepDistance || creaturePos.y - centerPos.y <= 0)
  1196. {
  1197. tmpDist = std::max(std::abs((creaturePos.x) - centerPos.x), std::abs((creaturePos.y + 1) - centerPos.y));
  1198. if(tmpDist == centerToDist && canWalkTo(creaturePos, SOUTH))
  1199. {
  1200. bool result = true;
  1201. if(keepAttack)
  1202. result = (!canDoAttackNow || canUseAttack(Position(creaturePos.x, creaturePos.y + 1, creaturePos.z), attackedCreature));
  1203.  
  1204. if(result)
  1205. dirVector.push_back(SOUTH);
  1206. }
  1207. }
  1208.  
  1209. if(!keepDistance || creaturePos.x - centerPos.x >= 0)
  1210. {
  1211. tmpDist = std::max(std::abs((creaturePos.x + 1) - centerPos.x), std::abs((creaturePos.y) - centerPos.y));
  1212. if(tmpDist == centerToDist && canWalkTo(creaturePos, EAST))
  1213. {
  1214. bool result = true;
  1215. if(keepAttack)
  1216. result = (!canDoAttackNow || canUseAttack(Position(creaturePos.x + 1, creaturePos.y, creaturePos.z), attackedCreature));
  1217.  
  1218. if(result)
  1219. dirVector.push_back(EAST);
  1220. }
  1221. }
  1222.  
  1223. if(!keepDistance || creaturePos.x - centerPos.x <= 0)
  1224. {
  1225. tmpDist = std::max(std::abs((creaturePos.x - 1) - centerPos.x), std::abs((creaturePos.y) - centerPos.y));
  1226. if(tmpDist == centerToDist && canWalkTo(creaturePos, WEST))
  1227. {
  1228. bool result = true;
  1229. if(keepAttack)
  1230. result = (!canDoAttackNow || canUseAttack(Position(creaturePos.x - 1, creaturePos.y, creaturePos.z), attackedCreature));
  1231.  
  1232. if(result)
  1233. dirVector.push_back(WEST);
  1234. }
  1235. }
  1236.  
  1237. if(dirVector.empty())
  1238. return false;
  1239.  
  1240. std::random_shuffle(dirVector.begin(), dirVector.end());
  1241. dir = dirVector[random_range(0, dirVector.size() - 1)];
  1242. return true;
  1243. }
  1244.  
  1245. bool Monster::isInSpawnRange(const Position& toPos)
  1246. {
  1247. return masterRadius == -1 || !inDespawnRange(toPos);
  1248. }
  1249.  
  1250. bool Monster::canWalkTo(Position pos, Direction dir)
  1251. {
  1252. if(getNoMove())
  1253. return false;
  1254.  
  1255. switch(dir)
  1256. {
  1257. case NORTH:
  1258. pos.y += -1;
  1259. break;
  1260. case WEST:
  1261. pos.x += -1;
  1262. break;
  1263. case EAST:
  1264. pos.x += 1;
  1265. break;
  1266. case SOUTH:
  1267. pos.y += 1;
  1268. break;
  1269. default:
  1270. break;
  1271. }
  1272.  
  1273. if(!isInSpawnRange(pos) || !getWalkCache(pos))
  1274. return false;
  1275.  
  1276. Tile* tile = g_game.getTile(pos);
  1277. if(!tile || getTile()->isSwimmingPool(false) != tile->isSwimmingPool(false)) // prevent monsters entering/exiting to swimming pool
  1278. return false;
  1279.  
  1280. return !tile->getTopVisibleCreature(this) && tile->__queryAdd(
  1281. 0, this, 1, FLAG_PATHFINDING) == RET_NOERROR;
  1282. }
  1283.  
  1284. bool Monster::onDeath()
  1285. {
  1286. if(!Creature::onDeath())
  1287. return false;
  1288.  
  1289. destroySummons();
  1290. clearTargetList();
  1291. clearFriendList();
  1292.  
  1293. setAttackedCreature(NULL);
  1294. onIdleStatus();
  1295. if(raid)
  1296. {
  1297. raid->unRef();
  1298. raid = NULL;
  1299. }
  1300.  
  1301. g_game.removeCreature(this, false);
  1302. return true;
  1303. }
  1304.  
  1305. Item* Monster::createCorpse(DeathList deathList)
  1306. {
  1307. Item* corpse = Creature::createCorpse(deathList);
  1308. uint8_t effect = 36;
  1309. if(isSummon())
  1310. {
  1311. return NULL;
  1312. }
  1313.  
  1314. if(!corpse)
  1315. return NULL;
  1316.  
  1317. if(mType->corpseUnique)
  1318. corpse->setUniqueId(mType->corpseUnique);
  1319.  
  1320. if(mType->corpseAction)
  1321. corpse->setActionId(mType->corpseAction);
  1322.  
  1323. DeathEntry ownerEntry = deathList[0];
  1324. if(ownerEntry.isNameKill())
  1325. return corpse;
  1326.  
  1327. Creature* owner = ownerEntry.getKillerCreature();
  1328. if(!owner)
  1329. return corpse;
  1330.  
  1331. uint32_t ownerId = 0;
  1332. if(owner->getPlayer())
  1333. ownerId = owner->getID();
  1334. else if(owner->getMaster() && owner->getPlayerMaster())
  1335. ownerId = owner->getMaster()->getID();
  1336.  
  1337. if(ownerId)
  1338. corpse->setCorpseOwner(ownerId);
  1339.  
  1340. return corpse;
  1341. }
  1342.  
  1343. bool Monster::inDespawnRange(const Position& pos)
  1344. {
  1345. if(!spawn || mType->isLureable)
  1346. return false;
  1347.  
  1348. int32_t radius = g_config.getNumber(ConfigManager::DEFAULT_DESPAWNRADIUS);
  1349. if(!radius)
  1350. return false;
  1351.  
  1352. if(!Spawns::getInstance()->isInZone(masterPosition, radius, pos))
  1353. return true;
  1354.  
  1355. int32_t range = g_config.getNumber(ConfigManager::DEFAULT_DESPAWNRANGE);
  1356. if(!range)
  1357. return false;
  1358.  
  1359. return std::abs(pos.z - masterPosition.z) > range;
  1360. }
  1361.  
  1362. bool Monster::despawn()
  1363. {
  1364. return inDespawnRange(getPosition());
  1365. }
  1366.  
  1367. bool Monster::getCombatValues(int32_t& min, int32_t& max)
  1368. {
  1369. if(!minCombatValue && !maxCombatValue)
  1370. return false;
  1371.  
  1372. double multiplier;
  1373. if(maxCombatValue > 0) //defense
  1374. multiplier = g_config.getDouble(ConfigManager::RATE_MONSTER_DEFENSE);
  1375. else //attack
  1376. multiplier = g_config.getDouble(ConfigManager::RATE_MONSTER_ATTACK);
  1377.  
  1378. min = (int32_t)(minCombatValue * multiplier);
  1379. max = (int32_t)(maxCombatValue * multiplier);
  1380. return true;
  1381. }
  1382.  
  1383. void Monster::updateLookDirection()
  1384. {
  1385. Direction newDir = getDirection();
  1386. if(attackedCreature)
  1387. {
  1388. const Position& pos = getPosition();
  1389. const Position& attackedCreaturePos = attackedCreature->getPosition();
  1390.  
  1391. int32_t dx = attackedCreaturePos.x - pos.x, dy = attackedCreaturePos.y - pos.y;
  1392. if(std::abs(dx) > std::abs(dy))
  1393. {
  1394. //look EAST/WEST
  1395. if(dx < 0)
  1396. newDir = WEST;
  1397. else
  1398. newDir = EAST;
  1399. }
  1400. else if(std::abs(dx) < std::abs(dy))
  1401. {
  1402. //look NORTH/SOUTH
  1403. if(dy < 0)
  1404. newDir = NORTH;
  1405. else
  1406. newDir = SOUTH;
  1407. }
  1408. else if(dx < 0 && dy < 0)
  1409. {
  1410. if(getDirection() == SOUTH)
  1411. newDir = WEST;
  1412. else if(getDirection() == EAST)
  1413. newDir = NORTH;
  1414. }
  1415. else if(dx < 0 && dy > 0)
  1416. {
  1417. if(getDirection() == NORTH)
  1418. newDir = WEST;
  1419. else if(getDirection() == EAST)
  1420. newDir = SOUTH;
  1421. }
  1422. else if(dx > 0 && dy < 0)
  1423. {
  1424. if(getDirection() == SOUTH)
  1425. newDir = EAST;
  1426. else if(getDirection() == WEST)
  1427. newDir = NORTH;
  1428. }
  1429. else if(getDirection() == NORTH)
  1430. newDir = EAST;
  1431. else if(getDirection() == WEST)
  1432. newDir = SOUTH;
  1433. }
  1434.  
  1435. g_game.internalCreatureTurn(this, newDir);
  1436. }
  1437.  
  1438. void Monster::dropLoot(Container* corpse)
  1439. {
  1440. if(corpse && lootDrop == LOOT_DROP_FULL)
  1441. mType->dropLoot(corpse);
  1442. }
  1443.  
  1444. bool Monster::isImmune(CombatType_t type) const
  1445. {
  1446. ElementMap::const_iterator it = mType->elementMap.find(type);
  1447. if(it == mType->elementMap.end())
  1448. return Creature::isImmune(type);
  1449.  
  1450. return it->second >= 100;
  1451. }
  1452.  
  1453. void Monster::setNormalCreatureLight()
  1454. {
  1455. internalLight.level = mType->lightLevel;
  1456. internalLight.color = mType->lightColor;
  1457. }
  1458.  
  1459. void Monster::drainHealth(Creature* attacker, CombatType_t combatType, int32_t damage)
  1460. {
  1461. Creature::drainHealth(attacker, combatType, damage);
  1462. //if(isInvisible())
  1463. //removeCondition(CONDITION_INVISIBLE);
  1464. }
  1465.  
  1466. void Monster::changeHealth(int32_t healthChange)
  1467. {
  1468. //In case a player with ignore flag set attacks the monster
  1469. setIdle(false);
  1470. Creature::changeHealth(healthChange);
  1471. }
  1472.  
  1473. bool Monster::challengeCreature(Creature* creature)
  1474. {
  1475. if(isSummon() || !selectTarget(creature))
  1476. return false;
  1477.  
  1478. targetChangeCooldown = 8000;
  1479. targetChangeTicks = 0;
  1480. return true;
  1481. }
  1482.  
  1483. bool Monster::convinceCreature(Creature* creature)
  1484. {
  1485. Player* player = creature->getPlayer();
  1486. if(player && !player->hasFlag(PlayerFlag_CanConvinceAll) && !mType->isConvinceable)
  1487. return false;
  1488.  
  1489. Creature* oldMaster = NULL;
  1490. if(isSummon())
  1491. oldMaster = getMaster();
  1492.  
  1493. if(oldMaster)
  1494. {
  1495. if(oldMaster->getPlayer() || oldMaster == creature)
  1496. return false;
  1497.  
  1498. oldMaster->removeSummon(this);
  1499. }
  1500.  
  1501. setFollowCreature(NULL);
  1502. setAttackedCreature(NULL);
  1503. destroySummons();
  1504.  
  1505. creature->addSummon(this);
  1506. updateTargetList();
  1507. updateIdleStatus();
  1508.  
  1509. //Notify surrounding about the change
  1510. SpectatorVec list;
  1511. g_game.getSpectators(list, getPosition(), false, true);
  1512. g_game.getSpectators(list, creature->getPosition(), true, true);
  1513.  
  1514. isMasterInRange = true;
  1515. for(SpectatorVec::iterator it = list.begin(); it != list.end(); ++it)
  1516. (*it)->onCreatureConvinced(creature, this);
  1517.  
  1518. if(spawn)
  1519. {
  1520. spawn->removeMonster(this);
  1521. spawn = NULL;
  1522. masterRadius = -1;
  1523. }
  1524.  
  1525. if(raid)
  1526. {
  1527. raid->unRef();
  1528. raid = NULL;
  1529. }
  1530.  
  1531. return true;
  1532. }
  1533.  
  1534. void Monster::onCreatureConvinced(const Creature* convincer, const Creature* creature)
  1535. {
  1536. if(convincer == this || (!isFriend(creature) && !isOpponent(creature)))
  1537. return;
  1538.  
  1539. updateTargetList();
  1540. updateIdleStatus();
  1541. }
  1542.  
  1543. void Monster::getPathSearchParams(const Creature* creature, FindPathParams& fpp) const
  1544. {
  1545. Creature::getPathSearchParams(creature, fpp);
  1546.  
  1547. fpp.clearSight = false;
  1548.  
  1549. fpp.minTargetDist = 1;
  1550. fpp.maxTargetDist = mType->targetDistance; //aqui
  1551. std::string strValue;
  1552. int32_t value;
  1553. if(getStorage(502, strValue))
  1554. {
  1555. value = atoi(strValue.c_str());
  1556. fpp.maxTargetDist = value;
  1557. }
  1558. if(isSummon())
  1559. {
  1560. if(getMaster() == creature)
  1561. {
  1562. fpp.maxTargetDist = 2;
  1563. fpp.fullPathSearch = true;
  1564. }
  1565. else if(mType->targetDistance <= 1)
  1566. fpp.fullPathSearch = true;
  1567. else
  1568. fpp.fullPathSearch = !canUseAttack(getPosition(), creature);
  1569. }
  1570. else if(isFleeing())
  1571. {
  1572. //Distance should be higher than the client view range (Map::maxClientViewportX/Map::maxClientViewportY)
  1573. fpp.maxTargetDist = Map::maxViewportX;
  1574. fpp.fullPathSearch = false;
  1575. fpp.keepDistance = true;
  1576. }
  1577. else if(mType->targetDistance <= 1)
  1578. fpp.fullPathSearch = true;
  1579. else
  1580. fpp.fullPathSearch = !canUseAttack(getPosition(), creature);
  1581. }
Add Comment
Please, Sign In to add comment