Advertisement
Guest User

Untitled

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