Advertisement
Guest User

Untitled

a guest
Jul 2nd, 2016
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 40.33 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.  
  571. if(!isHostile() && getHealth() == getMaxHealth() && !isSummon() && !isTarget(creature) && isPassive())
  572. {
  573. return false;
  574. }
  575. if(isTarget(creature) && !isHostile() && !isSummon())
  576. {
  577. Dispatcher::getInstance().addTask(createTask(
  578. boost::bind(&Game::checkCreatureAttack, &g_game, getID())));
  579. return setFollowCreature(creature, true);
  580. }
  581.  
  582. if((isHostile() || !isPassive() || isSummon() || !isHostile() && getHealth() != getMaxHealth() && isPassive() || !isHostile() && isPassive() && isTarget(creature)) && setAttackedCreature(creature) && !isSummon())
  583. Dispatcher::getInstance().addTask(createTask(
  584. boost::bind(&Game::checkCreatureAttack, &g_game, getID())));
  585.  
  586. return setFollowCreature(creature, true);
  587. }
  588.  
  589.  
  590. void Monster::setIdle(bool _idle)
  591. {
  592. if(isRemoved() || getHealth() <= 0)
  593. return;
  594.  
  595. isIdle = _idle;
  596. if(isIdle)
  597. {
  598. onIdleStatus();
  599. clearTargetList();
  600. clearFriendList();
  601. g_game.removeCreatureCheck(this);
  602. }
  603. else
  604. g_game.addCreatureCheck(this);
  605. }
  606.  
  607. void Monster::updateIdleStatus()
  608. {
  609. bool idle = false;
  610. if(conditions.empty())
  611. {
  612. if(isSummon())
  613. {
  614. if((!isMasterInRange && !teleportToMaster) || (getMaster()->getMonster() && getMaster()->getMonster()->getIdleStatus()))
  615. idle = true;
  616. }
  617. else if(targetList.empty())
  618. idle = true;
  619. }
  620.  
  621. setIdle(idle);
  622. }
  623.  
  624. void Monster::onAddCondition(ConditionType_t type, bool hadCondition)
  625. {
  626. Creature::onAddCondition(type, hadCondition);
  627. //the walkCache need to be updated if the monster becomes "resistent" to the damage, see Tile::__queryAdd()
  628. if(type == CONDITION_FIRE || type == CONDITION_ENERGY || type == CONDITION_POISON)
  629. updateMapCache();
  630.  
  631. updateIdleStatus();
  632. }
  633.  
  634. void Monster::onEndCondition(ConditionType_t type)
  635. {
  636. Creature::onEndCondition(type);
  637. //the walkCache need to be updated if the monster loose the "resistent" to the damage, see Tile::__queryAdd()
  638. if(type == CONDITION_FIRE || type == CONDITION_ENERGY || type == CONDITION_POISON)
  639. updateMapCache();
  640.  
  641. updateIdleStatus();
  642. }
  643.  
  644. void Monster::onThink(uint32_t interval)
  645.  
  646. {
  647. Creature::onThink(interval);
  648. if(despawn())
  649. {
  650. g_game.removeCreature(this, true);
  651. setIdle(true);
  652. return;
  653. }
  654.  
  655. updateIdleStatus();
  656. if(isIdle)
  657. return;
  658.  
  659. if(teleportToMaster && doTeleportToMaster())
  660. teleportToMaster = false;
  661.  
  662. addEventWalk();
  663.  
  664. if(getMaster()){
  665. if(getPosition().z != getMaster()->getPosition().z){
  666. g_game.internalTeleport(this, getMaster()->getPosition(), false);
  667. //g_game.addMagicEffect(getPosition(), MAGIC_EFFECT_SOUND_YELLOW);
  668. }
  669. }
  670.  
  671. if(isSummon())
  672. {
  673. if(!attackedCreature)
  674. {
  675. std::string strValue;
  676. if(getMaster() && getMaster()->getAttackedCreature()) //This happens if the monster is summoned during combat
  677. selectTarget(getMaster()->getAttackedCreature());
  678. else{
  679. setFollowCreature((getMaster()->getStorage(500, strValue) && strValue != "-1") ? NULL : getMaster());
  680. }
  681.  
  682. }
  683. else if(attackedCreature == this)
  684. setFollowCreature(NULL);
  685. else if(followCreature != attackedCreature) //This happens just after a master orders an attack, so lets follow it aswell.
  686. setFollowCreature(attackedCreature);
  687. }
  688. else if(!targetList.empty())
  689. {
  690. if(!followCreature || !hasFollowPath)
  691. searchTarget();
  692. else if(isFleeing() && attackedCreature && !canUseAttack(getPosition(), attackedCreature))
  693. searchTarget(TARGETSEARCH_ATTACKRANGE);
  694. }
  695.  
  696. onThinkTarget(interval);
  697. onThinkYell(interval);
  698. onThinkDefense(interval);
  699. }
  700.  
  701. void Monster::setAttackSpeed(uint32_t interval)
  702. {
  703. attackTicks = interval;
  704. std::cout << "Deu" << std::endl;
  705. }
  706.  
  707. void Monster::doAttacking(uint32_t interval)
  708. {
  709. if(!attackedCreature || (isSummon() && attackedCreature == this))
  710. return; // aqui
  711.  
  712. const Position& myPos = getPosition();
  713. const Position& targetPos = attackedCreature->getPosition();
  714.  
  715. FindPathParams fpp;
  716.  
  717. fpp.fullPathSearch = true;
  718. fpp.maxSearchDist = -1;
  719. fpp.minTargetDist = 0;
  720. fpp.maxTargetDist = 1;
  721.  
  722. std::string valueString;
  723. std::list<Direction> dirList;
  724. if(attackedCreature->getPlayer()){
  725. if(Creature* summon = attackedCreature->pushBackSummonOne())
  726. selectTarget(summon);
  727. }
  728.  
  729. /*
  730. if(!g_game.getPathToEx(this, targetPos, dirList, fpp) && attackedCreature->isSummon()){
  731. selectTarget(attackedCreature->getMaster());
  732.  
  733. std::string strValue; int32_t value;
  734. if(getStorage(8085, strValue))
  735. {
  736. value = atoi(strValue.c_str());
  737. }
  738. if(value == 0)
  739. g_game.addAnimatedText(getPosition(), 215, "GRRR!");
  740.  
  741. setStorage(8085, "2");
  742. }
  743.  
  744. if(attackedCreature->getPlayer()){
  745. if(Creature* summon = attackedCreature->pushBackSummonOne()){
  746. if(g_game.getPathToEx(this, summon->getPosition(), dirList, fpp)){
  747. selectTarget(summon);
  748. std::string strValue, playerStor; int32_t value, value2;
  749. if(getStorage(8085, strValue))
  750. {
  751. value = atoi(strValue.c_str());
  752. }
  753. if(value == 2)
  754. g_game.addAnimatedText(getPosition(), 215, "Hmpf");
  755.  
  756.  
  757. setStorage(8085, "0");
  758. }
  759. }else
  760. setStorage(8085, "1");
  761. }
  762. */
  763.  
  764. bool updateLook = true, outOfRange = true;
  765. resetTicks = interval;
  766. attackTicks += interval;
  767.  
  768.  
  769. for(SpellList::iterator it = mType->spellAttackList.begin(); it != mType->spellAttackList.end(); ++it)
  770. {
  771. if(it->isMelee && isFleeing())
  772. continue;
  773.  
  774. bool inRange = false;
  775. if(canUseSpell(myPos, targetPos, *it, interval, inRange))
  776. {
  777. if(it->chance >= (uint32_t)random_range(1, 100))
  778. {
  779. if(updateLook)
  780. {
  781. updateLookDirection();
  782. updateLook = false;
  783. }
  784.  
  785. double multiplier;
  786. if(maxCombatValue > 0) //defense
  787. multiplier = g_config.getDouble(ConfigManager::RATE_MONSTER_DEFENSE);
  788. else //attack
  789. multiplier = g_config.getDouble(ConfigManager::RATE_MONSTER_ATTACK);
  790.  
  791. minCombatValue = (int32_t)(it->minCombatValue * multiplier);
  792. maxCombatValue = (int32_t)(it->maxCombatValue * multiplier);
  793.  
  794. it->spell->castSpell(this, attackedCreature);
  795. if(it->isMelee)
  796. extraMeleeAttack = false;
  797. #ifdef __DEBUG__
  798. static uint64_t prevTicks = OTSYS_TIME();
  799. std::cout << "doAttacking ticks: " << OTSYS_TIME() - prevTicks << std::endl;
  800. prevTicks = OTSYS_TIME();
  801. #endif
  802. }
  803. }
  804.  
  805. if(inRange)
  806. outOfRange = false;
  807. else if(it->isMelee) //melee swing out of reach
  808. extraMeleeAttack = true;
  809. }
  810.  
  811. if(updateLook)
  812. updateLookDirection();
  813.  
  814. if(resetTicks)
  815. attackTicks = 0;
  816. }
  817.  
  818.  
  819.  
  820. bool Monster::canUseAttack(const Position& pos, const Creature* target) const
  821. {
  822. const Position& targetPos = target->getPosition();
  823. for(SpellList::iterator it = mType->spellAttackList.begin(); it != mType->spellAttackList.end(); ++it)
  824. {
  825. if((*it).range != 0 && std::max(std::abs(pos.x - targetPos.x), std::abs(pos.y - targetPos.y)) <= (int32_t)(*it).range)
  826. return g_game.isSightClear(pos, targetPos, true);
  827. }
  828.  
  829. return false;
  830. }
  831.  
  832. bool Monster::canUseSpell(const Position& pos, const Position& targetPos,
  833. const spellBlock_t& sb, uint32_t interval, bool& inRange)
  834. {
  835. inRange = true;
  836. if(!sb.isMelee || !extraMeleeAttack)
  837. {
  838. if(sb.speed > attackTicks)
  839. {
  840. resetTicks = false;
  841. return false;
  842. }
  843.  
  844. if(attackTicks % sb.speed >= interval) //already used this spell for this round
  845. return false;
  846. }
  847.  
  848. if(!sb.range || std::max(std::abs(pos.x - targetPos.x), std::abs(pos.y - targetPos.y)) <= (int32_t)sb.range)
  849. return true;
  850.  
  851. inRange = false;
  852. return false;
  853. }
  854.  
  855. void Monster::onThinkTarget(uint32_t interval)
  856. {
  857.  
  858. if((isSummon() || mType->changeTargetSpeed <= 0))
  859. return;
  860.  
  861. bool canChangeTarget = true;
  862. if(targetChangeCooldown > 0)
  863. {
  864. targetChangeCooldown -= interval;
  865. if(targetChangeCooldown <= 0)
  866. {
  867. targetChangeCooldown = 0;
  868. targetChangeTicks = (uint32_t)mType->changeTargetSpeed;
  869. }
  870. else
  871. canChangeTarget = false;
  872. }
  873.  
  874. if(!canChangeTarget)
  875. return;
  876.  
  877. targetChangeTicks += interval;
  878. if(targetChangeTicks < (uint32_t)mType->changeTargetSpeed)
  879. return;
  880.  
  881. targetChangeTicks = 0;
  882. targetChangeCooldown = (uint32_t)mType->changeTargetSpeed;
  883. if(mType->changeTargetChance < random_range(1, 100))
  884. return;
  885.  
  886. std::string strValue;
  887. int32_t value;
  888. if(getStorage(502, strValue))
  889. {
  890. value = atoi(strValue.c_str());
  891. }
  892. if(mType->targetDistance <= 1 && value == -1)
  893. searchTarget(TARGETSEARCH_RANDOM);
  894. else
  895. searchTarget(TARGETSEARCH_NEAREST);
  896.  
  897.  
  898. }
  899.  
  900. void Monster::onThinkDefense(uint32_t interval)
  901. {
  902. resetTicks = true;
  903. defenseTicks += interval;
  904. for(SpellList::iterator it = mType->spellDefenseList.begin(); it != mType->spellDefenseList.end(); ++it)
  905. {
  906. if(it->speed > defenseTicks)
  907. {
  908. if(resetTicks)
  909. resetTicks = false;
  910.  
  911. continue;
  912. }
  913.  
  914. if(defenseTicks % it->speed >= interval) //already used this spell for this round
  915. continue;
  916.  
  917. if((it->chance >= (uint32_t)random_range(1, 100)))
  918. {
  919. minCombatValue = it->minCombatValue;
  920. maxCombatValue = it->maxCombatValue;
  921. it->spell->castSpell(this, this);
  922. }
  923. }
  924.  
  925. if(!isSummon())
  926. {
  927. if(mType->maxSummons < 0 || (int32_t)summons.size() < mType->maxSummons)
  928. {
  929. for(SummonList::iterator it = mType->summonList.begin(); it != mType->summonList.end(); ++it)
  930. {
  931. if((int32_t)summons.size() >= mType->maxSummons)
  932. break;
  933.  
  934. if(it->interval > defenseTicks)
  935. {
  936. if(resetTicks)
  937. resetTicks = false;
  938.  
  939. continue;
  940. }
  941.  
  942. if(defenseTicks % it->interval >= interval)
  943. continue;
  944.  
  945. uint32_t typeCount = 0;
  946. for(CreatureList::iterator cit = summons.begin(); cit != summons.end(); ++cit)
  947. {
  948. if(!(*cit)->isRemoved() && (*cit)->getMonster() &&
  949. (*cit)->getMonster()->getName() == it->name)
  950. typeCount++;
  951. }
  952.  
  953. if(typeCount >= it->amount)
  954. continue;
  955.  
  956. if((it->chance >= (uint32_t)random_range(1, 100)))
  957. {
  958. if(Monster* summon = Monster::createMonster(it->name))
  959. {
  960. addSummon(summon);
  961. if(!g_game.placeCreature(summon, getPosition()))
  962. removeSummon(summon);
  963. }
  964. }
  965. }
  966. }
  967. }
  968.  
  969. if(resetTicks)
  970. defenseTicks = 0;
  971. }
  972.  
  973. void Monster::onThinkYell(uint32_t interval)
  974. {
  975. if(mType->yellSpeedTicks <= 0)
  976. return;
  977.  
  978. yellTicks += interval;
  979. if(yellTicks < mType->yellSpeedTicks)
  980. return;
  981.  
  982. yellTicks = 0;
  983. if(mType->voiceVector.empty() || (mType->yellChance < (uint32_t)random_range(1, 100)))
  984. return;
  985.  
  986. const voiceBlock_t& vb = mType->voiceVector[random_range(0, mType->voiceVector.size() - 1)];
  987. if(vb.yellText)
  988. g_game.internalCreatureSay(this, SPEAK_MONSTER_YELL, vb.text, false);
  989. else
  990. g_game.internalCreatureSay(this, SPEAK_MONSTER_SAY, vb.text, false);
  991. }
  992.  
  993. bool Monster::pushItem(Item* item, int32_t radius)
  994. {
  995. const Position& centerPos = item->getPosition();
  996. PairVector pairVector;
  997. pairVector.push_back(PositionPair(-1, -1));
  998. pairVector.push_back(PositionPair(-1, 0));
  999. pairVector.push_back(PositionPair(-1, 1));
  1000. pairVector.push_back(PositionPair(0, -1));
  1001. pairVector.push_back(PositionPair(0, 1));
  1002. pairVector.push_back(PositionPair(1, -1));
  1003. pairVector.push_back(PositionPair(1, 0));
  1004. pairVector.push_back(PositionPair(1, 1));
  1005.  
  1006. std::random_shuffle(pairVector.begin(), pairVector.end());
  1007. Position tryPos;
  1008. for(int32_t n = 1; n <= radius; ++n)
  1009. {
  1010. for(PairVector::iterator it = pairVector.begin(); it != pairVector.end(); ++it)
  1011. {
  1012. int32_t dx = it->first * n, dy = it->second * n;
  1013. tryPos = centerPos;
  1014.  
  1015. tryPos.x = tryPos.x + dx;
  1016. tryPos.y = tryPos.y + dy;
  1017.  
  1018. Tile* tile = g_game.getTile(tryPos);
  1019. if(tile && g_game.canThrowObjectTo(centerPos, tryPos) && g_game.internalMoveItem(this, item->getParent(),
  1020. tile, INDEX_WHEREEVER, item, item->getItemCount(), NULL) == RET_NOERROR)
  1021. return true;
  1022. }
  1023. }
  1024.  
  1025. return false;
  1026. }
  1027.  
  1028. void Monster::pushItems(Tile* tile)
  1029. {
  1030. TileItemVector* items = tile->getItemList();
  1031. if(!items)
  1032. return;
  1033.  
  1034. //We cannot use iterators here since we can push the item to another tile
  1035. //which will invalidate the iterator.
  1036. //start from the end to minimize the amount of traffic
  1037. int32_t moveCount = 0, removeCount = 0, downItemsSize = tile->getDownItemCount();
  1038. Item* item = NULL;
  1039. for(int32_t i = downItemsSize - 1; i >= 0; --i)
  1040. {
  1041. assert(i >= 0 && i < downItemsSize);
  1042. if((item = items->at(i)) && item->hasProperty(MOVEABLE) &&
  1043. (item->hasProperty(BLOCKPATH) || item->hasProperty(BLOCKSOLID)))
  1044. {
  1045. if(moveCount < 20 && pushItem(item, 1))
  1046. moveCount++;
  1047. else if(g_game.internalRemoveItem(this, item) == RET_NOERROR)
  1048. ++removeCount;
  1049. }
  1050. }
  1051.  
  1052. //if(removeCount > 0)
  1053. //g_game.addMagicEffect(tile->getPosition(), MAGIC_EFFECT_SOUND_YELLOW);
  1054. }
  1055.  
  1056. bool Monster::pushCreature(Creature* creature)
  1057. {
  1058. DirVector dirVector;
  1059. dirVector.push_back(NORTH);
  1060. dirVector.push_back(SOUTH);
  1061. dirVector.push_back(WEST);
  1062. dirVector.push_back(EAST);
  1063.  
  1064. std::random_shuffle(dirVector.begin(), dirVector.end());
  1065. Position monsterPos = creature->getPosition();
  1066.  
  1067. Tile* tile = NULL;
  1068. for(DirVector::iterator it = dirVector.begin(); it != dirVector.end(); ++it)
  1069. {
  1070. if((tile = g_game.getTile(Spells::getCasterPosition(creature, (*it)))) && !tile->hasProperty(
  1071. BLOCKPATH) && g_game.internalMoveCreature(creature, (*it)) == RET_NOERROR)
  1072. return true;
  1073. }
  1074.  
  1075. return false;
  1076. }
  1077.  
  1078. void Monster::pushCreatures(Tile* tile)
  1079. {
  1080. CreatureVector* creatures = tile->getCreatures();
  1081. if(!creatures)
  1082. return;
  1083.  
  1084. bool effect = false;
  1085. Monster* monster = NULL;
  1086. for(uint32_t i = 0; i < creatures->size();)
  1087. {
  1088. if((monster = creatures->at(i)->getMonster()) && monster->isPushable())
  1089. {
  1090. if(pushCreature(monster))
  1091. continue;
  1092.  
  1093. monster->setDropLoot(LOOT_DROP_NONE);
  1094. monster->changeHealth(-monster->getHealth());
  1095. if(!effect)
  1096. effect = true;
  1097. }
  1098.  
  1099. ++i;
  1100. }
  1101.  
  1102. }
  1103.  
  1104. bool Monster::getNextStep(Direction& dir, uint32_t& flags)
  1105. {
  1106. if(isIdle || getHealth() <= 0)
  1107. {
  1108. //we dont have anyone watching might aswell stop walking
  1109. eventWalk = 0;
  1110. return false;
  1111. }
  1112.  
  1113. bool result = false;
  1114. if((!followCreature || !hasFollowPath) && !isSummon())
  1115. {
  1116. if(followCreature || getTimeSinceLastMove() > 1000) //choose a random direction
  1117. result = getRandomStep(getPosition(), dir);
  1118. }
  1119. else if(isSummon() || followCreature)
  1120. {
  1121. result = Creature::getNextStep(dir, flags);
  1122. if(!result)
  1123. {
  1124. //target dancing
  1125. if(attackedCreature && attackedCreature == followCreature)
  1126. {
  1127. if(isFleeing())
  1128. result = getDanceStep(getPosition(), dir, false, false);
  1129. else if(mType->staticAttackChance < (uint32_t)random_range(1, 100))
  1130. result = getDanceStep(getPosition(), dir);
  1131. }
  1132. }
  1133. else
  1134. flags |= FLAG_PATHFINDING;
  1135. }
  1136.  
  1137. if(result && (canPushItems() || canPushCreatures()))
  1138. {
  1139. if(Tile* tile = g_game.getTile(Spells::getCasterPosition(this, dir)))
  1140. {
  1141. if(canPushItems())
  1142. pushItems(tile);
  1143.  
  1144. if(canPushCreatures())
  1145. pushCreatures(tile);
  1146. }
  1147. #ifdef __DEBUG__
  1148. else
  1149. std::cout << "[Warning - Monster::getNextStep] no tile found." << std::endl;
  1150. #endif
  1151. }
  1152.  
  1153. return result;
  1154. }
  1155.  
  1156. bool Monster::getRandomStep(const Position& creaturePos, Direction& dir)
  1157. {
  1158. DirVector dirVector;
  1159. dirVector.push_back(NORTH);
  1160. dirVector.push_back(SOUTH);
  1161. dirVector.push_back(WEST);
  1162. dirVector.push_back(EAST);
  1163.  
  1164. std::random_shuffle(dirVector.begin(), dirVector.end());
  1165. for(DirVector::iterator it = dirVector.begin(); it != dirVector.end(); ++it)
  1166. {
  1167. if(!canWalkTo(creaturePos, *it))
  1168. continue;
  1169.  
  1170. dir = *it;
  1171. return true;
  1172. }
  1173.  
  1174. return false;
  1175. }
  1176.  
  1177. bool Monster::getDanceStep(const Position& creaturePos, Direction& dir, bool keepAttack /*= true*/, bool keepDistance /*= true*/)
  1178. {
  1179. assert(attackedCreature);
  1180. bool canDoAttackNow = canUseAttack(creaturePos, attackedCreature);
  1181. const Position& centerPos = attackedCreature->getPosition();
  1182.  
  1183. uint32_t tmpDist, centerToDist = std::max(std::abs(creaturePos.x - centerPos.x), std::abs(creaturePos.y - centerPos.y));
  1184. DirVector dirVector;
  1185. if(!keepDistance || creaturePos.y - centerPos.y >= 0)
  1186. {
  1187. tmpDist = std::max(std::abs((creaturePos.x) - centerPos.x), std::abs((creaturePos.y - 1) - centerPos.y));
  1188. if(tmpDist == centerToDist && canWalkTo(creaturePos, NORTH))
  1189. {
  1190. bool result = true;
  1191. if(keepAttack)
  1192. result = (!canDoAttackNow || canUseAttack(Position(creaturePos.x, creaturePos.y - 1, creaturePos.z), attackedCreature));
  1193.  
  1194. if(result)
  1195. dirVector.push_back(NORTH);
  1196. }
  1197. }
  1198.  
  1199. if(!keepDistance || creaturePos.y - centerPos.y <= 0)
  1200. {
  1201. tmpDist = std::max(std::abs((creaturePos.x) - centerPos.x), std::abs((creaturePos.y + 1) - centerPos.y));
  1202. if(tmpDist == centerToDist && canWalkTo(creaturePos, SOUTH))
  1203. {
  1204. bool result = true;
  1205. if(keepAttack)
  1206. result = (!canDoAttackNow || canUseAttack(Position(creaturePos.x, creaturePos.y + 1, creaturePos.z), attackedCreature));
  1207.  
  1208. if(result)
  1209. dirVector.push_back(SOUTH);
  1210. }
  1211. }
  1212.  
  1213. if(!keepDistance || creaturePos.x - centerPos.x >= 0)
  1214. {
  1215. tmpDist = std::max(std::abs((creaturePos.x + 1) - centerPos.x), std::abs((creaturePos.y) - centerPos.y));
  1216. if(tmpDist == centerToDist && canWalkTo(creaturePos, EAST))
  1217. {
  1218. bool result = true;
  1219. if(keepAttack)
  1220. result = (!canDoAttackNow || canUseAttack(Position(creaturePos.x + 1, creaturePos.y, creaturePos.z), attackedCreature));
  1221.  
  1222. if(result)
  1223. dirVector.push_back(EAST);
  1224. }
  1225. }
  1226.  
  1227. if(!keepDistance || creaturePos.x - centerPos.x <= 0)
  1228. {
  1229. tmpDist = std::max(std::abs((creaturePos.x - 1) - centerPos.x), std::abs((creaturePos.y) - centerPos.y));
  1230. if(tmpDist == centerToDist && canWalkTo(creaturePos, WEST))
  1231. {
  1232. bool result = true;
  1233. if(keepAttack)
  1234. result = (!canDoAttackNow || canUseAttack(Position(creaturePos.x - 1, creaturePos.y, creaturePos.z), attackedCreature));
  1235.  
  1236. if(result)
  1237. dirVector.push_back(WEST);
  1238. }
  1239. }
  1240.  
  1241. if(dirVector.empty())
  1242. return false;
  1243.  
  1244. std::random_shuffle(dirVector.begin(), dirVector.end());
  1245. dir = dirVector[random_range(0, dirVector.size() - 1)];
  1246. return true;
  1247. }
  1248.  
  1249. bool Monster::isInSpawnRange(const Position& toPos)
  1250. {
  1251. return masterRadius == -1 || !inDespawnRange(toPos);
  1252. }
  1253.  
  1254. bool Monster::canWalkTo(Position pos, Direction dir)
  1255. {
  1256. if(getNoMove())
  1257. return false;
  1258.  
  1259. switch(dir)
  1260. {
  1261. case NORTH:
  1262. pos.y += -1;
  1263. break;
  1264. case WEST:
  1265. pos.x += -1;
  1266. break;
  1267. case EAST:
  1268. pos.x += 1;
  1269. break;
  1270. case SOUTH:
  1271. pos.y += 1;
  1272. break;
  1273. default:
  1274. break;
  1275. }
  1276.  
  1277. if(!isInSpawnRange(pos) || !getWalkCache(pos))
  1278. return false;
  1279.  
  1280. Tile* tile = g_game.getTile(pos);
  1281. if(!tile || getTile()->isSwimmingPool(false) != tile->isSwimmingPool(false)) // prevent monsters entering/exiting to swimming pool
  1282. return false;
  1283.  
  1284. return !tile->getTopVisibleCreature(this) && tile->__queryAdd(
  1285. 0, this, 1, FLAG_PATHFINDING) == RET_NOERROR;
  1286. }
  1287.  
  1288. bool Monster::onDeath()
  1289. {
  1290. if(!Creature::onDeath())
  1291. return false;
  1292.  
  1293. destroySummons();
  1294. clearTargetList();
  1295. clearFriendList();
  1296.  
  1297. setAttackedCreature(NULL);
  1298. onIdleStatus();
  1299. if(raid)
  1300. {
  1301. raid->unRef();
  1302. raid = NULL;
  1303. }
  1304.  
  1305. g_game.removeCreature(this, false);
  1306. return true;
  1307. }
  1308.  
  1309. Item* Monster::createCorpse(DeathList deathList)
  1310. {
  1311. Item* corpse = Creature::createCorpse(deathList);
  1312. uint8_t effect = 36;
  1313. if(isSummon())
  1314. {
  1315. return NULL;
  1316. }
  1317.  
  1318. if(!corpse)
  1319. return NULL;
  1320.  
  1321. if(mType->corpseUnique)
  1322. corpse->setUniqueId(mType->corpseUnique);
  1323.  
  1324. if(mType->corpseAction)
  1325. corpse->setActionId(mType->corpseAction);
  1326.  
  1327. DeathEntry ownerEntry = deathList[0];
  1328. if(ownerEntry.isNameKill())
  1329. return corpse;
  1330.  
  1331. Creature* owner = ownerEntry.getKillerCreature();
  1332. if(!owner)
  1333. return corpse;
  1334.  
  1335. uint32_t ownerId = 0;
  1336. if(owner->getPlayer())
  1337. ownerId = owner->getID();
  1338. else if(owner->getMaster() && owner->getPlayerMaster())
  1339. ownerId = owner->getMaster()->getID();
  1340.  
  1341. if(ownerId)
  1342. corpse->setCorpseOwner(ownerId);
  1343.  
  1344. return corpse;
  1345. }
  1346.  
  1347. bool Monster::inDespawnRange(const Position& pos)
  1348. {
  1349. if(!spawn || mType->isLureable)
  1350. return false;
  1351.  
  1352. int32_t radius = g_config.getNumber(ConfigManager::DEFAULT_DESPAWNRADIUS);
  1353. if(!radius)
  1354. return false;
  1355.  
  1356. if(!Spawns::getInstance()->isInZone(masterPosition, radius, pos))
  1357. return true;
  1358.  
  1359. int32_t range = g_config.getNumber(ConfigManager::DEFAULT_DESPAWNRANGE);
  1360. if(!range)
  1361. return false;
  1362.  
  1363. return std::abs(pos.z - masterPosition.z) > range;
  1364. }
  1365.  
  1366. bool Monster::despawn()
  1367. {
  1368. return inDespawnRange(getPosition());
  1369. }
  1370.  
  1371. bool Monster::getCombatValues(int32_t& min, int32_t& max)
  1372. {
  1373. if(!minCombatValue && !maxCombatValue)
  1374. return false;
  1375.  
  1376. double multiplier;
  1377. if(maxCombatValue > 0) //defense
  1378. multiplier = g_config.getDouble(ConfigManager::RATE_MONSTER_DEFENSE);
  1379. else //attack
  1380. multiplier = g_config.getDouble(ConfigManager::RATE_MONSTER_ATTACK);
  1381.  
  1382. min = (int32_t)(minCombatValue * multiplier);
  1383. max = (int32_t)(maxCombatValue * multiplier);
  1384. return true;
  1385. }
  1386.  
  1387. void Monster::updateLookDirection()
  1388. {
  1389. Direction newDir = getDirection();
  1390. if(attackedCreature)
  1391. {
  1392. const Position& pos = getPosition();
  1393. const Position& attackedCreaturePos = attackedCreature->getPosition();
  1394.  
  1395. int32_t dx = attackedCreaturePos.x - pos.x, dy = attackedCreaturePos.y - pos.y;
  1396. if(std::abs(dx) > std::abs(dy))
  1397. {
  1398. //look EAST/WEST
  1399. if(dx < 0)
  1400. newDir = WEST;
  1401. else
  1402. newDir = EAST;
  1403. }
  1404. else if(std::abs(dx) < std::abs(dy))
  1405. {
  1406. //look NORTH/SOUTH
  1407. if(dy < 0)
  1408. newDir = NORTH;
  1409. else
  1410. newDir = SOUTH;
  1411. }
  1412. else if(dx < 0 && dy < 0)
  1413. {
  1414. if(getDirection() == SOUTH)
  1415. newDir = WEST;
  1416. else if(getDirection() == EAST)
  1417. newDir = NORTH;
  1418. }
  1419. else if(dx < 0 && dy > 0)
  1420. {
  1421. if(getDirection() == NORTH)
  1422. newDir = WEST;
  1423. else if(getDirection() == EAST)
  1424. newDir = SOUTH;
  1425. }
  1426. else if(dx > 0 && dy < 0)
  1427. {
  1428. if(getDirection() == SOUTH)
  1429. newDir = EAST;
  1430. else if(getDirection() == WEST)
  1431. newDir = NORTH;
  1432. }
  1433. else if(getDirection() == NORTH)
  1434. newDir = EAST;
  1435. else if(getDirection() == WEST)
  1436. newDir = SOUTH;
  1437. }
  1438.  
  1439. g_game.internalCreatureTurn(this, newDir);
  1440. }
  1441.  
  1442. void Monster::dropLoot(Container* corpse)
  1443. {
  1444. if(corpse && lootDrop == LOOT_DROP_FULL)
  1445. mType->dropLoot(corpse);
  1446. }
  1447.  
  1448. bool Monster::isImmune(CombatType_t type) const
  1449. {
  1450. ElementMap::const_iterator it = mType->elementMap.find(type);
  1451. if(it == mType->elementMap.end())
  1452. return Creature::isImmune(type);
  1453.  
  1454. return it->second >= 100;
  1455. }
  1456.  
  1457. void Monster::setNormalCreatureLight()
  1458. {
  1459. internalLight.level = mType->lightLevel;
  1460. internalLight.color = mType->lightColor;
  1461. }
  1462.  
  1463. void Monster::drainHealth(Creature* attacker, CombatType_t combatType, int32_t damage)
  1464. {
  1465. Creature::drainHealth(attacker, combatType, damage);
  1466. //if(isInvisible())
  1467. //removeCondition(CONDITION_INVISIBLE);
  1468. }
  1469.  
  1470. void Monster::changeHealth(int32_t healthChange)
  1471. {
  1472. //In case a player with ignore flag set attacks the monster
  1473. setIdle(false);
  1474. Creature::changeHealth(healthChange);
  1475. }
  1476.  
  1477. bool Monster::challengeCreature(Creature* creature)
  1478. {
  1479. if(isSummon() || !selectTarget(creature))
  1480. return false;
  1481.  
  1482. targetChangeCooldown = 8000;
  1483. targetChangeTicks = 0;
  1484. return true;
  1485. }
  1486.  
  1487. bool Monster::convinceCreature(Creature* creature)
  1488. {
  1489. Player* player = creature->getPlayer();
  1490. if(player && !player->hasFlag(PlayerFlag_CanConvinceAll) && !mType->isConvinceable)
  1491. return false;
  1492.  
  1493. Creature* oldMaster = NULL;
  1494. if(isSummon())
  1495. oldMaster = getMaster();
  1496.  
  1497. if(oldMaster)
  1498. {
  1499. if(oldMaster->getPlayer() || oldMaster == creature)
  1500. return false;
  1501.  
  1502. oldMaster->removeSummon(this);
  1503. }
  1504.  
  1505. setFollowCreature(NULL);
  1506. setAttackedCreature(NULL);
  1507. destroySummons();
  1508.  
  1509. creature->addSummon(this);
  1510. updateTargetList();
  1511. updateIdleStatus();
  1512.  
  1513. //Notify surrounding about the change
  1514. SpectatorVec list;
  1515. g_game.getSpectators(list, getPosition(), false, true);
  1516. g_game.getSpectators(list, creature->getPosition(), true, true);
  1517.  
  1518. isMasterInRange = true;
  1519. for(SpectatorVec::iterator it = list.begin(); it != list.end(); ++it)
  1520. (*it)->onCreatureConvinced(creature, this);
  1521.  
  1522. if(spawn)
  1523. {
  1524. spawn->removeMonster(this);
  1525. spawn = NULL;
  1526. masterRadius = -1;
  1527. }
  1528.  
  1529. if(raid)
  1530. {
  1531. raid->unRef();
  1532. raid = NULL;
  1533. }
  1534.  
  1535. return true;
  1536. }
  1537.  
  1538. void Monster::onCreatureConvinced(const Creature* convincer, const Creature* creature)
  1539. {
  1540. if(convincer == this || (!isFriend(creature) && !isOpponent(creature)))
  1541. return;
  1542.  
  1543. updateTargetList();
  1544. updateIdleStatus();
  1545. }
  1546.  
  1547. void Monster::getPathSearchParams(const Creature* creature, FindPathParams& fpp) const
  1548. {
  1549. Creature::getPathSearchParams(creature, fpp);
  1550.  
  1551. fpp.clearSight = false;
  1552.  
  1553. fpp.minTargetDist = 1;
  1554. fpp.maxTargetDist = mType->targetDistance; //aqui
  1555. std::string strValue;
  1556. int32_t value;
  1557. if(getStorage(502, strValue))
  1558. {
  1559. value = atoi(strValue.c_str());
  1560. fpp.maxTargetDist = value;
  1561. }
  1562. if(isSummon())
  1563. {
  1564. if(getMaster() == creature)
  1565. {
  1566. fpp.maxTargetDist = 2;
  1567. fpp.fullPathSearch = true;
  1568. }
  1569. else if(mType->targetDistance <= 1)
  1570. fpp.fullPathSearch = true;
  1571. else
  1572. fpp.fullPathSearch = !canUseAttack(getPosition(), creature);
  1573. }
  1574. else if(isFleeing())
  1575. {
  1576. //Distance should be higher than the client view range (Map::maxClientViewportX/Map::maxClientViewportY)
  1577. fpp.maxTargetDist = Map::maxViewportX;
  1578. fpp.fullPathSearch = false;
  1579. fpp.keepDistance = true;
  1580. }
  1581. else if(mType->targetDistance <= 1)
  1582. fpp.fullPathSearch = true;
  1583. else
  1584. fpp.fullPathSearch = !canUseAttack(getPosition(), creature);
  1585. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement