Advertisement
Guest User

a

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