Advertisement
Guest User

Untitled

a guest
Apr 22nd, 2020
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 40.91 KB | None | 0 0
  1. /**
  2. * The Forgotten Server - a free and open-source MMORPG server emulator
  3. * Copyright (C) 2016 Mark Samman <mark.samman@gmail.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program; if not, write to the Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. */
  19.  
  20. #include "otpch.h"
  21.  
  22. #include "creature.h"
  23. #include "game.h"
  24. #include "monster.h"
  25. #include "configmanager.h"
  26. #include "scheduler.h"
  27.  
  28. double Creature::speedA = 857.36;
  29. double Creature::speedB = 261.29;
  30. double Creature::speedC = -4795.01;
  31.  
  32. extern Game g_game;
  33. extern ConfigManager g_config;
  34. extern CreatureEvents* g_creatureEvents;
  35.  
  36. Creature::Creature() :
  37. localMapCache(), isInternalRemoved(false)
  38. {
  39. referenceCounter = 0;
  40.  
  41. id = 0;
  42. _tile = nullptr;
  43. direction = DIRECTION_SOUTH;
  44. master = nullptr;
  45. lootDrop = true;
  46. skillLoss = true;
  47.  
  48. health = 1000;
  49. healthMax = 1000;
  50. mana = 0;
  51.  
  52. lastStep = 0;
  53. lastStepCost = 1;
  54. baseSpeed = 220;
  55. varSpeed = 0;
  56.  
  57. followCreature = nullptr;
  58. hasFollowPath = false;
  59. eventWalk = 0;
  60. cancelNextWalk = false;
  61. forceUpdateFollowPath = false;
  62. isMapLoaded = false;
  63. isUpdatingPath = false;
  64.  
  65. attackedCreature = nullptr;
  66.  
  67. lastHitCreature = 0;
  68. blockCount = 0;
  69. blockTicks = 0;
  70. walkUpdateTicks = 0;
  71. creatureCheck = false;
  72. inCheckCreaturesVector = false;
  73. scriptEventsBitField = 0;
  74.  
  75. hiddenHealth = false;
  76. noMove = false;
  77.  
  78. skull = SKULL_NONE;
  79.  
  80. onIdleStatus();
  81. }
  82.  
  83. Creature::~Creature()
  84. {
  85. for (Creature* summon : summons) {
  86. summon->setAttackedCreature(nullptr);
  87. summon->setMaster(nullptr);
  88. summon->decrementReferenceCounter();
  89. }
  90.  
  91. for (Condition* condition : conditions) {
  92. condition->endCondition(this);
  93. delete condition;
  94. }
  95. }
  96.  
  97. bool Creature::canSee(const Position& myPos, const Position& pos, int32_t viewRangeX, int32_t viewRangeY)
  98. {
  99. if (myPos.z <= 7) {
  100. //we are on ground level or above (7 -> 0)
  101. //view is from 7 -> 0
  102. if (pos.z > 7) {
  103. return false;
  104. }
  105. } else if (myPos.z >= 8) {
  106. //we are underground (8 -> 15)
  107. //view is +/- 2 from the floor we stand on
  108. if (Position::getDistanceZ(myPos, pos) > 2) {
  109. return false;
  110. }
  111. }
  112.  
  113. const int_fast32_t offsetz = myPos.getZ() - pos.getZ();
  114. return (pos.getX() >= myPos.getX() - viewRangeX + offsetz) && (pos.getX() <= myPos.getX() + viewRangeX + offsetz)
  115. && (pos.getY() >= myPos.getY() - viewRangeY + offsetz) && (pos.getY() <= myPos.getY() + viewRangeY + offsetz);
  116. }
  117.  
  118. bool Creature::canSee(const Position& pos) const
  119. {
  120. return canSee(getPosition(), pos, Map::maxViewportX, Map::maxViewportY);
  121. }
  122.  
  123. bool Creature::canSeeCreature(const Creature* creature) const
  124. {
  125. if (!canSeeInvisibility() && creature->isInvisible()) {
  126. return false;
  127. }
  128. return true;
  129. }
  130.  
  131. void Creature::setSkull(Skulls_t newSkull)
  132. {
  133. skull = newSkull;
  134. g_game.updateCreatureSkull(this);
  135. }
  136.  
  137. int64_t Creature::getTimeSinceLastMove() const
  138. {
  139. if (lastStep) {
  140. return OTSYS_TIME() - lastStep;
  141. }
  142. return std::numeric_limits<int64_t>::max();
  143. }
  144.  
  145. int32_t Creature::getWalkDelay(Direction dir) const
  146. {
  147. if (lastStep == 0) {
  148. return 0;
  149. }
  150.  
  151. int64_t ct = OTSYS_TIME();
  152. int64_t stepDuration = getStepDuration(dir);
  153. return stepDuration - (ct - lastStep);
  154. }
  155.  
  156. int32_t Creature::getWalkDelay() const
  157. {
  158. //Used for auto-walking
  159. if (lastStep == 0) {
  160. return 0;
  161. }
  162.  
  163. int64_t ct = OTSYS_TIME();
  164. int64_t stepDuration = getStepDuration() * lastStepCost;
  165. return stepDuration - (ct - lastStep);
  166. }
  167.  
  168. void Creature::onThink(uint32_t interval)
  169. {
  170. if (!isMapLoaded && useCacheMap()) {
  171. isMapLoaded = true;
  172. updateMapCache();
  173. }
  174.  
  175. if (followCreature && master != followCreature && !canSeeCreature(followCreature)) {
  176. onCreatureDisappear(followCreature, false);
  177. }
  178.  
  179. if (attackedCreature && master != attackedCreature && !canSeeCreature(attackedCreature)) {
  180. onCreatureDisappear(attackedCreature, false);
  181. }
  182.  
  183. blockTicks += interval;
  184. if (blockTicks >= 1000) {
  185. blockCount = std::min<uint32_t>(blockCount + 1, 2);
  186. blockTicks = 0;
  187. }
  188.  
  189. if (followCreature) {
  190. walkUpdateTicks += interval;
  191. if (forceUpdateFollowPath || walkUpdateTicks >= 2000) {
  192. walkUpdateTicks = 0;
  193. forceUpdateFollowPath = false;
  194. isUpdatingPath = true;
  195. }
  196. }
  197.  
  198. if (isUpdatingPath) {
  199. isUpdatingPath = false;
  200. goToFollowCreature();
  201. }
  202.  
  203. //scripting event - onThink
  204. const CreatureEventList& thinkEvents = getCreatureEvents(CREATURE_EVENT_THINK);
  205. for (CreatureEvent* thinkEvent : thinkEvents) {
  206. thinkEvent->executeOnThink(this, interval);
  207. }
  208. }
  209.  
  210. void Creature::onAttacking(uint32_t interval)
  211. {
  212. if (!attackedCreature) {
  213. return;
  214. }
  215.  
  216. onAttacked();
  217. attackedCreature->onAttacked();
  218.  
  219. if (g_game.isSightClear(getPosition(), attackedCreature->getPosition(), true)) {
  220. doAttacking(interval);
  221. }
  222. }
  223.  
  224. void Creature::onIdleStatus()
  225. {
  226. if (getHealth() > 0) {
  227. damageMap.clear();
  228. lastHitCreature = 0;
  229. }
  230. }
  231.  
  232. void Creature::onWalk()
  233. {
  234. if (getWalkDelay() <= 0) {
  235. Direction dir;
  236. uint32_t flags = FLAG_IGNOREFIELDDAMAGE;
  237. if (getNextStep(dir, flags)) {
  238. ReturnValue ret = canMove() ? g_game.internalMoveCreature(this, dir, flags) : RETURNVALUE_NOTPOSSIBLE;
  239. if (ret != RETURNVALUE_NOERROR) {
  240. if (Player* player = getPlayer()) {
  241. player->sendCancelMessage(ret);
  242. player->sendCancelWalk();
  243. }
  244.  
  245. forceUpdateFollowPath = true;
  246. }
  247. } else {
  248. if (listWalkDir.empty()) {
  249. onWalkComplete();
  250. }
  251.  
  252. stopEventWalk();
  253. }
  254. }
  255.  
  256. if (cancelNextWalk) {
  257. listWalkDir.clear();
  258. onWalkAborted();
  259. cancelNextWalk = false;
  260. }
  261.  
  262. if (eventWalk != 0) {
  263. eventWalk = 0;
  264. addEventWalk();
  265. }
  266. }
  267.  
  268. void Creature::onWalk(Direction& dir)
  269. {
  270. if (hasCondition(CONDITION_DRUNK)) {
  271. uint32_t r = uniform_random(0, 20);
  272. if (r <= DIRECTION_DIAGONAL_MASK) {
  273. if (r < DIRECTION_DIAGONAL_MASK) {
  274. dir = static_cast<Direction>(r);
  275. }
  276. g_game.internalCreatureSay(this, TALKTYPE_MONSTER_SAY, "Hicks!", false);
  277. }
  278. }
  279. }
  280.  
  281. bool Creature::getNextStep(Direction& dir, uint32_t&)
  282. {
  283. if (listWalkDir.empty()) {
  284. return false;
  285. }
  286.  
  287. dir = listWalkDir.front();
  288. listWalkDir.pop_front();
  289. onWalk(dir);
  290. return true;
  291. }
  292.  
  293. void Creature::startAutoWalk(const std::forward_list<Direction>& listDir)
  294. {
  295. listWalkDir = listDir;
  296.  
  297. size_t size = 0;
  298. for (auto it = listDir.begin(); it != listDir.end() && size <= 1; ++it) {
  299. size++;
  300. }
  301. addEventWalk(size == 1);
  302. }
  303.  
  304. void Creature::addEventWalk(bool firstStep)
  305. {
  306. cancelNextWalk = false;
  307.  
  308. if (getStepSpeed() <= 0) {
  309. return;
  310. }
  311.  
  312. if (eventWalk != 0) {
  313. return;
  314. }
  315.  
  316. int64_t ticks = getEventStepTicks(firstStep);
  317. if (ticks <= 0) {
  318. return;
  319. }
  320.  
  321. // Take first step right away, but still queue the next
  322. if (ticks == 1) {
  323. g_game.checkCreatureWalk(getID());
  324. }
  325.  
  326. eventWalk = g_scheduler.addEvent(createSchedulerTask(ticks, std::bind(&Game::checkCreatureWalk, &g_game, getID())));
  327. }
  328.  
  329. void Creature::stopEventWalk()
  330. {
  331. if (eventWalk != 0) {
  332. g_scheduler.stopEvent(eventWalk);
  333. eventWalk = 0;
  334. }
  335. }
  336.  
  337. void Creature::updateMapCache()
  338. {
  339. Tile* tile;
  340. const Position& myPos = getPosition();
  341. Position pos(0, 0, myPos.z);
  342.  
  343. for (int32_t y = -maxWalkCacheHeight; y <= maxWalkCacheHeight; ++y) {
  344. for (int32_t x = -maxWalkCacheWidth; x <= maxWalkCacheWidth; ++x) {
  345. pos.x = myPos.getX() + x;
  346. pos.y = myPos.getY() + y;
  347. tile = g_game.map.getTile(pos);
  348. updateTileCache(tile, pos);
  349. }
  350. }
  351. }
  352.  
  353. void Creature::updateTileCache(const Tile* tile, int32_t dx, int32_t dy)
  354. {
  355. if (std::abs(dx) <= maxWalkCacheWidth && std::abs(dy) <= maxWalkCacheHeight) {
  356. localMapCache[maxWalkCacheHeight + dy][maxWalkCacheWidth + dx] = tile && tile->queryAdd(0, *this, 1, FLAG_PATHFINDING | FLAG_IGNOREFIELDDAMAGE) == RETURNVALUE_NOERROR;
  357. }
  358. }
  359.  
  360. void Creature::updateTileCache(const Tile* tile, const Position& pos)
  361. {
  362. const Position& myPos = getPosition();
  363. if (pos.z == myPos.z) {
  364. int32_t dx = Position::getOffsetX(pos, myPos);
  365. int32_t dy = Position::getOffsetY(pos, myPos);
  366. updateTileCache(tile, dx, dy);
  367. }
  368. }
  369.  
  370. int32_t Creature::getWalkCache(const Position& pos) const
  371. {
  372. if (!useCacheMap()) {
  373. return 2;
  374. }
  375.  
  376. const Position& myPos = getPosition();
  377. if (myPos.z != pos.z) {
  378. return 0;
  379. }
  380.  
  381. if (pos == myPos) {
  382. return 1;
  383. }
  384.  
  385. int32_t dx = Position::getOffsetX(pos, myPos);
  386. if (std::abs(dx) <= maxWalkCacheWidth) {
  387. int32_t dy = Position::getOffsetY(pos, myPos);
  388. if (std::abs(dy) <= maxWalkCacheHeight) {
  389. if (localMapCache[maxWalkCacheHeight + dy][maxWalkCacheWidth + dx]) {
  390. return 1;
  391. } else {
  392. return 0;
  393. }
  394. }
  395. }
  396.  
  397. //out of range
  398. return 2;
  399. }
  400.  
  401. void Creature::onAddTileItem(const Tile* tile, const Position& pos)
  402. {
  403. if (isMapLoaded && pos.z == getPosition().z) {
  404. updateTileCache(tile, pos);
  405. }
  406. }
  407.  
  408. void Creature::onUpdateTileItem(const Tile* tile, const Position& pos, const Item*,
  409. const ItemType& oldType, const Item*, const ItemType& newType)
  410. {
  411. if (!isMapLoaded) {
  412. return;
  413. }
  414.  
  415. if (oldType.blockSolid || oldType.blockPathFind || newType.blockPathFind || newType.blockSolid) {
  416. if (pos.z == getPosition().z) {
  417. updateTileCache(tile, pos);
  418. }
  419. }
  420. }
  421.  
  422. void Creature::onRemoveTileItem(const Tile* tile, const Position& pos, const ItemType& iType, const Item*)
  423. {
  424. if (!isMapLoaded) {
  425. return;
  426. }
  427.  
  428. if (iType.blockSolid || iType.blockPathFind || iType.isGroundTile()) {
  429. if (pos.z == getPosition().z) {
  430. updateTileCache(tile, pos);
  431. }
  432. }
  433. }
  434.  
  435. void Creature::onCreatureAppear(Creature* creature, bool)
  436. {
  437. if (creature == this) {
  438. if (useCacheMap()) {
  439. isMapLoaded = true;
  440. updateMapCache();
  441. }
  442. } else if (isMapLoaded) {
  443. if (creature->getPosition().z == getPosition().z) {
  444. updateTileCache(creature->getTile(), creature->getPosition());
  445. }
  446. }
  447. }
  448.  
  449. void Creature::onRemoveCreature(Creature* creature, bool)
  450. {
  451. onCreatureDisappear(creature, true);
  452. if (creature == this) {
  453. if (master && !master->isRemoved()) {
  454. master->removeSummon(this);
  455. }
  456. } else if (isMapLoaded) {
  457. if (creature->getPosition().z == getPosition().z) {
  458. updateTileCache(creature->getTile(), creature->getPosition());
  459. }
  460. }
  461. }
  462.  
  463. void Creature::onCreatureDisappear(const Creature* creature, bool isLogout)
  464. {
  465. if (attackedCreature == creature) {
  466. setAttackedCreature(nullptr);
  467. onAttackedCreatureDisappear(isLogout);
  468. }
  469.  
  470. if (followCreature == creature) {
  471. setFollowCreature(nullptr);
  472. onFollowCreatureDisappear(isLogout);
  473. }
  474. }
  475.  
  476. void Creature::onChangeZone(ZoneType_t zone)
  477. {
  478. if (attackedCreature && zone == ZONE_PROTECTION) {
  479. onCreatureDisappear(attackedCreature, false);
  480. }
  481. }
  482.  
  483. void Creature::onAttackedCreatureChangeZone(ZoneType_t zone)
  484. {
  485. if (zone == ZONE_PROTECTION) {
  486. onCreatureDisappear(attackedCreature, false);
  487. }
  488. }
  489.  
  490. void Creature::onCreatureMove(Creature* creature, const Tile* newTile, const Position& newPos,
  491. const Tile* oldTile, const Position& oldPos, bool teleport)
  492. {
  493. if (creature == this) {
  494. lastStep = OTSYS_TIME();
  495. lastStepCost = 1;
  496.  
  497. if (!teleport) {
  498. if (oldPos.z != newPos.z) {
  499. //floor change extra cost
  500. lastStepCost = 2;
  501. } else if (Position::getDistanceX(newPos, oldPos) >= 1 && Position::getDistanceY(newPos, oldPos) >= 1) {
  502. //diagonal extra cost
  503. lastStepCost = 3;
  504. }
  505. } else {
  506. stopEventWalk();
  507. }
  508.  
  509. if (!summons.empty()) {
  510. //check if any of our summons is out of range (+/- 2 floors or 30 tiles away)
  511. std::forward_list<Creature*> despawnList;
  512. for (Creature* summon : summons) {
  513. const Position& pos = summon->getPosition();
  514. if (Position::getDistanceZ(newPos, pos) > 2 || (std::max<int32_t>(Position::getDistanceX(newPos, pos), Position::getDistanceY(newPos, pos)) > 30)) {
  515. despawnList.push_front(summon);
  516. }
  517. }
  518.  
  519. for (Creature* despawnCreature : despawnList) {
  520. g_game.removeCreature(despawnCreature, true);
  521. }
  522. }
  523.  
  524. if (newTile->getZone() != oldTile->getZone()) {
  525. onChangeZone(getZone());
  526. }
  527.  
  528. //update map cache
  529. if (isMapLoaded) {
  530. if (teleport || oldPos.z != newPos.z) {
  531. updateMapCache();
  532. } else {
  533. Tile* tile;
  534. const Position& myPos = getPosition();
  535. Position pos;
  536.  
  537. if (oldPos.y > newPos.y) { //north
  538. //shift y south
  539. for (int32_t y = mapWalkHeight - 1; --y >= 0;) {
  540. memcpy(localMapCache[y + 1], localMapCache[y], sizeof(localMapCache[y]));
  541. }
  542.  
  543. //update 0
  544. for (int32_t x = -maxWalkCacheWidth; x <= maxWalkCacheWidth; ++x) {
  545. tile = g_game.map.getTile(myPos.getX() + x, myPos.getY() - maxWalkCacheHeight, myPos.z);
  546. updateTileCache(tile, x, -maxWalkCacheHeight);
  547. }
  548. } else if (oldPos.y < newPos.y) { // south
  549. //shift y north
  550. for (int32_t y = 0; y <= mapWalkHeight - 2; ++y) {
  551. memcpy(localMapCache[y], localMapCache[y + 1], sizeof(localMapCache[y]));
  552. }
  553.  
  554. //update mapWalkHeight - 1
  555. for (int32_t x = -maxWalkCacheWidth; x <= maxWalkCacheWidth; ++x) {
  556. tile = g_game.map.getTile(myPos.getX() + x, myPos.getY() + maxWalkCacheHeight, myPos.z);
  557. updateTileCache(tile, x, maxWalkCacheHeight);
  558. }
  559. }
  560.  
  561. if (oldPos.x < newPos.x) { // east
  562. //shift y west
  563. int32_t starty = 0;
  564. int32_t endy = mapWalkHeight - 1;
  565. int32_t dy = Position::getDistanceY(oldPos, newPos);
  566.  
  567. if (dy < 0) {
  568. endy += dy;
  569. } else if (dy > 0) {
  570. starty = dy;
  571. }
  572.  
  573. for (int32_t y = starty; y <= endy; ++y) {
  574. for (int32_t x = 0; x <= mapWalkWidth - 2; ++x) {
  575. localMapCache[y][x] = localMapCache[y][x + 1];
  576. }
  577. }
  578.  
  579. //update mapWalkWidth - 1
  580. for (int32_t y = -maxWalkCacheHeight; y <= maxWalkCacheHeight; ++y) {
  581. tile = g_game.map.getTile(myPos.x + maxWalkCacheWidth, myPos.y + y, myPos.z);
  582. updateTileCache(tile, maxWalkCacheWidth, y);
  583. }
  584. } else if (oldPos.x > newPos.x) { // west
  585. //shift y east
  586. int32_t starty = 0;
  587. int32_t endy = mapWalkHeight - 1;
  588. int32_t dy = Position::getDistanceY(oldPos, newPos);
  589.  
  590. if (dy < 0) {
  591. endy += dy;
  592. } else if (dy > 0) {
  593. starty = dy;
  594. }
  595.  
  596. for (int32_t y = starty; y <= endy; ++y) {
  597. for (int32_t x = mapWalkWidth - 1; --x >= 0;) {
  598. localMapCache[y][x + 1] = localMapCache[y][x];
  599. }
  600. }
  601.  
  602. //update 0
  603. for (int32_t y = -maxWalkCacheHeight; y <= maxWalkCacheHeight; ++y) {
  604. tile = g_game.map.getTile(myPos.x - maxWalkCacheWidth, myPos.y + y, myPos.z);
  605. updateTileCache(tile, -maxWalkCacheWidth, y);
  606. }
  607. }
  608.  
  609. updateTileCache(oldTile, oldPos);
  610. }
  611. }
  612. } else {
  613. if (isMapLoaded) {
  614. const Position& myPos = getPosition();
  615.  
  616. if (newPos.z == myPos.z) {
  617. updateTileCache(newTile, newPos);
  618. }
  619.  
  620. if (oldPos.z == myPos.z) {
  621. updateTileCache(oldTile, oldPos);
  622. }
  623. }
  624. }
  625.  
  626. if (creature == followCreature || (creature == this && followCreature)) {
  627. if (hasFollowPath) {
  628. isUpdatingPath = true;
  629. }
  630.  
  631. if (newPos.z != oldPos.z || !canSee(followCreature->getPosition())) {
  632. onCreatureDisappear(followCreature, false);
  633. }
  634. }
  635.  
  636. if (creature == attackedCreature || (creature == this && attackedCreature)) {
  637. if (newPos.z != oldPos.z || !canSee(attackedCreature->getPosition())) {
  638. onCreatureDisappear(attackedCreature, false);
  639. } else {
  640. if (hasExtraSwing()) {
  641. //our target is moving lets see if we can get in hit
  642. g_dispatcher.addTask(createTask(std::bind(&Game::checkCreatureAttack, &g_game, getID())));
  643. }
  644.  
  645. if (newTile->getZone() != oldTile->getZone()) {
  646. onAttackedCreatureChangeZone(attackedCreature->getZone());
  647. }
  648. }
  649. }
  650. }
  651.  
  652. void Creature::onDeath()
  653. {
  654. bool lastHitUnjustified = false;
  655. bool mostDamageUnjustified = false;
  656. Creature* _lastHitCreature = g_game.getCreatureByID(lastHitCreature);
  657. Creature* lastHitCreatureMaster;
  658. if (_lastHitCreature) {
  659. lastHitUnjustified = _lastHitCreature->onKilledCreature(this);
  660. lastHitCreatureMaster = _lastHitCreature->getMaster();
  661. } else {
  662. lastHitCreatureMaster = nullptr;
  663. }
  664.  
  665. Creature* mostDamageCreature = nullptr;
  666.  
  667. const int64_t timeNow = OTSYS_TIME();
  668. const uint32_t inFightTicks = g_config.getNumber(ConfigManager::PZ_LOCKED);
  669. int32_t mostDamage = 0;
  670. std::map<Creature*, uint64_t> experienceMap;
  671. for (const auto& it : damageMap) {
  672. if (Creature* attacker = g_game.getCreatureByID(it.first)) {
  673. CountBlock_t cb = it.second;
  674. if ((cb.total > mostDamage && (timeNow - cb.ticks <= inFightTicks))) {
  675. mostDamage = cb.total;
  676. mostDamageCreature = attacker;
  677. }
  678.  
  679. if (attacker != this) {
  680. uint64_t gainExp = getGainedExperience(attacker);
  681. if (Player* player = attacker->getPlayer()) {
  682. Party* party = player->getParty();
  683. if (party && party->getLeader() && party->isSharedExperienceActive() && party->isSharedExperienceEnabled()) {
  684. attacker = party->getLeader();
  685. }
  686. }
  687.  
  688. auto tmpIt = experienceMap.find(attacker);
  689. if (tmpIt == experienceMap.end()) {
  690. experienceMap[attacker] = gainExp;
  691. } else {
  692. tmpIt->second += gainExp;
  693. }
  694. }
  695. }
  696. }
  697.  
  698. for (const auto& it : experienceMap) {
  699. it.first->onGainExperience(it.second, this);
  700. }
  701.  
  702. if (mostDamageCreature) {
  703. if (mostDamageCreature != _lastHitCreature && mostDamageCreature != lastHitCreatureMaster) {
  704. Creature* mostDamageCreatureMaster = mostDamageCreature->getMaster();
  705. if (_lastHitCreature != mostDamageCreatureMaster && (lastHitCreatureMaster == nullptr || mostDamageCreatureMaster != lastHitCreatureMaster)) {
  706. mostDamageUnjustified = mostDamageCreature->onKilledCreature(this, false);
  707. }
  708. }
  709. }
  710.  
  711. bool droppedCorpse = dropCorpse(_lastHitCreature, mostDamageCreature, lastHitUnjustified, mostDamageUnjustified);
  712. death(_lastHitCreature);
  713.  
  714. if (master) {
  715. master->removeSummon(this);
  716. }
  717.  
  718. if (droppedCorpse) {
  719. g_game.removeCreature(this, false);
  720. }
  721. }
  722.  
  723. bool Creature::dropCorpse(Creature* _lastHitCreature, Creature* mostDamageCreature, bool lastHitUnjustified, bool mostDamageUnjustified)
  724. {
  725. if (!lootDrop && getMonster()) {
  726. if (master) {
  727. //scripting event - onDeath
  728. const CreatureEventList& deathEvents = getCreatureEvents(CREATURE_EVENT_DEATH);
  729. for (CreatureEvent* deathEvent : deathEvents) {
  730. deathEvent->executeOnDeath(this, nullptr, _lastHitCreature, mostDamageCreature, lastHitUnjustified, mostDamageUnjustified);
  731. }
  732. }
  733.  
  734. g_game.addMagicEffect(getPosition(), CONST_ME_POFF);
  735. } else {
  736. Item* splash;
  737. switch (getRace()) {
  738. case RACE_VENOM:
  739. splash = Item::CreateItem(ITEM_FULLSPLASH, FLUID_GREEN);
  740. break;
  741.  
  742. case RACE_BLOOD:
  743. splash = Item::CreateItem(ITEM_FULLSPLASH, FLUID_BLOOD);
  744. break;
  745.  
  746. default:
  747. splash = nullptr;
  748. break;
  749. }
  750.  
  751. Tile* tile = getTile();
  752.  
  753. if (splash) {
  754. g_game.internalAddItem(tile, splash, INDEX_WHEREEVER, FLAG_NOLIMIT);
  755. g_game.startDecay(splash);
  756. }
  757.  
  758. Item* corpse = getCorpse(_lastHitCreature, mostDamageCreature);
  759. if (corpse) {
  760. g_game.internalAddItem(tile, corpse, INDEX_WHEREEVER, FLAG_NOLIMIT);
  761. g_game.startDecay(corpse);
  762. }
  763.  
  764. //scripting event - onDeath
  765. for (CreatureEvent* deathEvent : getCreatureEvents(CREATURE_EVENT_DEATH)) {
  766. deathEvent->executeOnDeath(this, corpse, _lastHitCreature, mostDamageCreature, lastHitUnjustified, mostDamageUnjustified);
  767. }
  768.  
  769. if (corpse) {
  770. dropLoot(corpse->getContainer(), _lastHitCreature);
  771. }
  772. }
  773.  
  774. return true;
  775. }
  776.  
  777. bool Creature::hasBeenAttacked(uint32_t attackerId)
  778. {
  779. auto it = damageMap.find(attackerId);
  780. if (it == damageMap.end()) {
  781. return false;
  782. }
  783. return (OTSYS_TIME() - it->second.ticks) <= g_config.getNumber(ConfigManager::PZ_LOCKED);
  784. }
  785.  
  786. Item* Creature::getCorpse(Creature*, Creature*)
  787. {
  788. return Item::CreateItem(getLookCorpse());
  789. }
  790.  
  791. void Creature::changeHealth(int32_t healthChange, bool sendHealthChange/* = true*/)
  792. {
  793. int32_t oldHealth = health;
  794.  
  795. if (healthChange > 0) {
  796. health += std::min<int32_t>(healthChange, getMaxHealth() - health);
  797. } else {
  798. health = std::max<int32_t>(0, health + healthChange);
  799. }
  800.  
  801. if (sendHealthChange && oldHealth != health) {
  802. g_game.addCreatureHealth(this);
  803. }
  804. }
  805.  
  806. void Creature::changeMana(int32_t manaChange)
  807. {
  808. if (manaChange > 0) {
  809. mana += std::min<int32_t>(manaChange, getMaxMana() - mana);
  810. } else {
  811. mana = std::max<int32_t>(0, mana + manaChange);
  812. }
  813. }
  814.  
  815. void Creature::gainHealth(Creature* healer, int32_t healthGain)
  816. {
  817. changeHealth(healthGain);
  818. if (healer) {
  819. healer->onTargetCreatureGainHealth(this, healthGain);
  820. }
  821. }
  822.  
  823. void Creature::drainHealth(Creature* attacker, int32_t damage)
  824. {
  825. changeHealth(-damage, false);
  826.  
  827. if (attacker) {
  828. attacker->onAttackedCreatureDrainHealth(this, damage);
  829. }
  830. }
  831.  
  832. void Creature::drainMana(Creature* attacker, int32_t manaLoss)
  833. {
  834. onAttacked();
  835. changeMana(-manaLoss);
  836.  
  837. if (attacker) {
  838. addDamagePoints(attacker, manaLoss);
  839. }
  840. }
  841.  
  842. BlockType_t Creature::blockHit(Creature* attacker, CombatType_t combatType, int32_t& damage,
  843. bool checkDefense /* = false */, bool checkArmor /* = false */, bool /* field = false */)
  844. {
  845. BlockType_t blockType = BLOCK_NONE;
  846.  
  847. if (isImmune(combatType)) {
  848. damage = 0;
  849. blockType = BLOCK_IMMUNITY;
  850. } else if (checkDefense || checkArmor) {
  851. bool hasDefense = false;
  852.  
  853. if (blockCount > 0) {
  854. --blockCount;
  855. hasDefense = true;
  856. }
  857.  
  858. if (checkDefense && hasDefense) {
  859. int32_t defense = getDefense();
  860. damage -= uniform_random(defense / 2, defense);
  861. if (damage <= 0) {
  862. damage = 0;
  863. blockType = BLOCK_DEFENSE;
  864. checkArmor = false;
  865. }
  866. }
  867.  
  868. if (checkArmor) {
  869. int32_t armorValue = getArmor();
  870. if (armorValue > 1) {
  871. double armorFormula = armorValue * 0.475;
  872. int32_t armorReduction = static_cast<int32_t>(std::ceil(armorFormula));
  873. damage -= uniform_random(
  874. armorReduction,
  875. armorReduction + static_cast<int32_t>(std::floor(armorFormula))
  876. );
  877. } else if (armorValue == 1) {
  878. --damage;
  879. }
  880.  
  881. if (damage <= 0) {
  882. damage = 0;
  883. blockType = BLOCK_ARMOR;
  884. }
  885. }
  886.  
  887. if (hasDefense && blockType != BLOCK_NONE) {
  888. onBlockHit();
  889. }
  890. }
  891.  
  892. if (attacker) {
  893. attacker->onAttackedCreature(this);
  894. attacker->onAttackedCreatureBlockHit(blockType);
  895. }
  896.  
  897. onAttacked();
  898. return blockType;
  899. }
  900.  
  901. bool Creature::setAttackedCreature(Creature* creature)
  902. {
  903. if (creature) {
  904. const Position& creaturePos = creature->getPosition();
  905. if (creaturePos.z != getPosition().z || !canSee(creaturePos)) {
  906. attackedCreature = nullptr;
  907. return false;
  908. }
  909.  
  910. attackedCreature = creature;
  911. onAttackedCreature(attackedCreature);
  912. attackedCreature->onAttacked();
  913. } else {
  914. attackedCreature = nullptr;
  915. }
  916.  
  917. for (Creature* summon : summons) {
  918. summon->setAttackedCreature(creature);
  919. }
  920. return true;
  921. }
  922.  
  923. void Creature::getPathSearchParams(const Creature*, FindPathParams& fpp) const
  924. {
  925. fpp.fullPathSearch = !hasFollowPath;
  926. fpp.clearSight = true;
  927. fpp.maxSearchDist = 12;
  928. fpp.minTargetDist = 1;
  929. fpp.maxTargetDist = 1;
  930. }
  931.  
  932. void Creature::goToFollowCreature()
  933. {
  934. if (followCreature) {
  935. FindPathParams fpp;
  936. getPathSearchParams(followCreature, fpp);
  937.  
  938. Monster* monster = getMonster();
  939. if (monster && !monster->getMaster() && (monster->isFleeing() || fpp.maxTargetDist > 1)) {
  940. Direction dir = DIRECTION_NONE;
  941.  
  942. if (monster->isFleeing()) {
  943. monster->getDistanceStep(followCreature->getPosition(), dir, true);
  944. } else { //maxTargetDist > 1
  945. if (!monster->getDistanceStep(followCreature->getPosition(), dir)) {
  946. // if we can't get anything then let the A* calculate
  947. listWalkDir.clear();
  948. if (getPathTo(followCreature->getPosition(), listWalkDir, fpp)) {
  949. hasFollowPath = true;
  950. startAutoWalk(listWalkDir);
  951. } else {
  952. hasFollowPath = false;
  953. }
  954. return;
  955. }
  956. }
  957.  
  958. if (dir != DIRECTION_NONE) {
  959. listWalkDir.clear();
  960. listWalkDir.push_front(dir);
  961.  
  962. hasFollowPath = true;
  963. startAutoWalk(listWalkDir);
  964. }
  965. } else {
  966. listWalkDir.clear();
  967. if (getPathTo(followCreature->getPosition(), listWalkDir, fpp)) {
  968. hasFollowPath = true;
  969. startAutoWalk(listWalkDir);
  970. } else {
  971. hasFollowPath = false;
  972. }
  973. }
  974. }
  975.  
  976. onFollowCreatureComplete(followCreature);
  977. }
  978.  
  979. bool Creature::setFollowCreature(Creature* creature)
  980. {
  981. if (creature) {
  982. if (followCreature == creature) {
  983. return true;
  984. }
  985.  
  986. const Position& creaturePos = creature->getPosition();
  987. if (creaturePos.z != getPosition().z || !canSee(creaturePos)) {
  988. followCreature = nullptr;
  989. return false;
  990. }
  991.  
  992. if (!listWalkDir.empty()) {
  993. listWalkDir.clear();
  994. onWalkAborted();
  995. }
  996.  
  997. hasFollowPath = false;
  998. forceUpdateFollowPath = false;
  999. followCreature = creature;
  1000. isUpdatingPath = true;
  1001. } else {
  1002. isUpdatingPath = false;
  1003. followCreature = nullptr;
  1004. }
  1005.  
  1006. onFollowCreature(creature);
  1007. return true;
  1008. }
  1009.  
  1010. double Creature::getDamageRatio(Creature* attacker) const
  1011. {
  1012. uint32_t totalDamage = 0;
  1013. uint32_t attackerDamage = 0;
  1014.  
  1015. for (const auto& it : damageMap) {
  1016. const CountBlock_t& cb = it.second;
  1017. totalDamage += cb.total;
  1018. if (it.first == attacker->getID()) {
  1019. attackerDamage += cb.total;
  1020. }
  1021. }
  1022.  
  1023. if (totalDamage == 0) {
  1024. return 0;
  1025. }
  1026.  
  1027. return (static_cast<double>(attackerDamage) / totalDamage);
  1028. }
  1029.  
  1030. uint64_t Creature::getGainedExperience(Creature* attacker) const
  1031. {
  1032. return std::floor(getDamageRatio(attacker) * getLostExperience());
  1033. }
  1034.  
  1035. void Creature::addDamagePoints(Creature* attacker, int32_t damagePoints)
  1036. {
  1037. if (damagePoints <= 0) {
  1038. return;
  1039. }
  1040.  
  1041. uint32_t attackerId = attacker->id;
  1042.  
  1043. auto it = damageMap.find(attackerId);
  1044. if (it == damageMap.end()) {
  1045. CountBlock_t cb;
  1046. cb.ticks = OTSYS_TIME();
  1047. cb.total = damagePoints;
  1048. damageMap[attackerId] = cb;
  1049. } else {
  1050. it->second.total += damagePoints;
  1051. it->second.ticks = OTSYS_TIME();
  1052. }
  1053.  
  1054. lastHitCreature = attackerId;
  1055. }
  1056.  
  1057. void Creature::onAddCondition(ConditionType_t type)
  1058. {
  1059. if (type == CONDITION_PARALYZE && hasCondition(CONDITION_HASTE)) {
  1060. removeCondition(CONDITION_HASTE);
  1061. } else if (type == CONDITION_HASTE && hasCondition(CONDITION_PARALYZE)) {
  1062. removeCondition(CONDITION_PARALYZE);
  1063. }
  1064. }
  1065.  
  1066. void Creature::onAddCombatCondition(ConditionType_t)
  1067. {
  1068. //
  1069. }
  1070.  
  1071. void Creature::onEndCondition(ConditionType_t)
  1072. {
  1073. //
  1074. }
  1075.  
  1076. void Creature::onTickCondition(ConditionType_t type, bool& bRemove)
  1077. {
  1078. const MagicField* field = getTile()->getFieldItem();
  1079. if (!field) {
  1080. return;
  1081. }
  1082.  
  1083. switch (type) {
  1084. case CONDITION_FIRE:
  1085. bRemove = (field->getCombatType() != COMBAT_FIREDAMAGE);
  1086. break;
  1087. case CONDITION_ENERGY:
  1088. bRemove = (field->getCombatType() != COMBAT_ENERGYDAMAGE);
  1089. break;
  1090. case CONDITION_POISON:
  1091. bRemove = (field->getCombatType() != COMBAT_EARTHDAMAGE);
  1092. break;
  1093. case CONDITION_FREEZING:
  1094. bRemove = (field->getCombatType() != COMBAT_ICEDAMAGE);
  1095. break;
  1096. case CONDITION_DAZZLED:
  1097. bRemove = (field->getCombatType() != COMBAT_HOLYDAMAGE);
  1098. break;
  1099. case CONDITION_CURSED:
  1100. bRemove = (field->getCombatType() != COMBAT_DEATHDAMAGE);
  1101. break;
  1102. case CONDITION_DROWN:
  1103. bRemove = (field->getCombatType() != COMBAT_DROWNDAMAGE);
  1104. break;
  1105. case CONDITION_BLEEDING:
  1106. bRemove = (field->getCombatType() != COMBAT_PHYSICALDAMAGE);
  1107. break;
  1108. default:
  1109. break;
  1110. }
  1111. }
  1112.  
  1113. void Creature::onCombatRemoveCondition(Condition* condition)
  1114. {
  1115. removeCondition(condition);
  1116. }
  1117.  
  1118. void Creature::onAttacked()
  1119. {
  1120. //
  1121. }
  1122.  
  1123. void Creature::onAttackedCreatureDrainHealth(Creature* target, int32_t points)
  1124. {
  1125. target->addDamagePoints(this, points);
  1126. }
  1127.  
  1128. bool Creature::onKilledCreature(Creature* target, bool)
  1129. {
  1130. if (master) {
  1131. master->onKilledCreature(target);
  1132. }
  1133.  
  1134. //scripting event - onKill
  1135. const CreatureEventList& killEvents = getCreatureEvents(CREATURE_EVENT_KILL);
  1136. for (CreatureEvent* killEvent : killEvents) {
  1137. killEvent->executeOnKill(this, target);
  1138. }
  1139. return false;
  1140. }
  1141.  
  1142. void Creature::onGainExperience(uint64_t gainExp, Creature* target)
  1143. TextMessage message(MESSAGE_EXPERIENCE_OTHERS, ucfirst(getNameDescription()) + " gained " + std::to_string(gainExp) + (gainExp != 1 ? " experience points." : " experience point."));
  1144. static constexpr std::array<TextColor_t, 12> colors = {
  1145. TEXTCOLOR_BLUE,
  1146. TEXTCOLOR_LIGHTGREEN,
  1147. TEXTCOLOR_LIGHTBLUE,
  1148. TEXTCOLOR_MAYABLUE,
  1149. TEXTCOLOR_DARKRED,
  1150. TEXTCOLOR_LIGHTGREY,
  1151. TEXTCOLOR_SKYBLUE,
  1152. TEXTCOLOR_PURPLE,
  1153. TEXTCOLOR_RED,
  1154. TEXTCOLOR_ORANGE,
  1155. TEXTCOLOR_YELLOW,
  1156. TEXTCOLOR_WHITE_EXP,
  1157. };
  1158. message.position = position;
  1159. message.primary.color = colors[uniform_random(0, colors.size() - 1)];
  1160. message.primary.value = gainExp;
  1161. {
  1162. if (gainExp == 0 || !master) {
  1163. return;
  1164. }
  1165.  
  1166. gainExp /= 2;
  1167. master->onGainExperience(gainExp, target);
  1168.  
  1169. std::ostringstream strExp;
  1170. strExp << gainExp;
  1171. g_game.addAnimatedText(strExp.str(), _position, TEXTCOLOR_WHITE_EXP);
  1172. }
  1173.  
  1174.  
  1175.  
  1176. void Creature::addSummon(Creature* creature)
  1177. {
  1178. creature->setDropLoot(false);
  1179. creature->setLossSkill(false);
  1180. creature->setMaster(this);
  1181. creature->incrementReferenceCounter();
  1182. summons.push_back(creature);
  1183. }
  1184.  
  1185. void Creature::removeSummon(Creature* creature)
  1186. {
  1187. auto cit = std::find(summons.begin(), summons.end(), creature);
  1188. if (cit != summons.end()) {
  1189. creature->setDropLoot(false);
  1190. creature->setLossSkill(true);
  1191. creature->setMaster(nullptr);
  1192. creature->decrementReferenceCounter();
  1193. summons.erase(cit);
  1194. }
  1195. }
  1196.  
  1197. bool Creature::addCondition(Condition* condition, bool force/* = false*/)
  1198. {
  1199. if (condition == nullptr) {
  1200. return false;
  1201. }
  1202.  
  1203. if (!force && condition->getType() == CONDITION_HASTE && hasCondition(CONDITION_PARALYZE)) {
  1204. int64_t walkDelay = getWalkDelay();
  1205. if (walkDelay > 0) {
  1206. g_scheduler.addEvent(createSchedulerTask(walkDelay, std::bind(&Game::forceAddCondition, &g_game, getID(), condition)));
  1207. return false;
  1208. }
  1209. }
  1210.  
  1211. Condition* prevCond = getCondition(condition->getType(), condition->getId(), condition->getSubId());
  1212. if (prevCond) {
  1213. prevCond->addCondition(this, condition);
  1214. delete condition;
  1215. return true;
  1216. }
  1217.  
  1218. if (condition->startCondition(this)) {
  1219. conditions.push_back(condition);
  1220. onAddCondition(condition->getType());
  1221. return true;
  1222. }
  1223.  
  1224. delete condition;
  1225. return false;
  1226. }
  1227.  
  1228. bool Creature::addCombatCondition(Condition* condition)
  1229. {
  1230. //Caution: condition variable could be deleted after the call to addCondition
  1231. ConditionType_t type = condition->getType();
  1232.  
  1233. if (!addCondition(condition)) {
  1234. return false;
  1235. }
  1236.  
  1237. onAddCombatCondition(type);
  1238. return true;
  1239. }
  1240.  
  1241. void Creature::removeCondition(ConditionType_t type, bool force/* = false*/)
  1242. {
  1243. auto it = conditions.begin(), end = conditions.end();
  1244. while (it != end) {
  1245. Condition* condition = *it;
  1246. if (condition->getType() != type) {
  1247. ++it;
  1248. continue;
  1249. }
  1250.  
  1251. if (!force && type == CONDITION_PARALYZE) {
  1252. int64_t walkDelay = getWalkDelay();
  1253. if (walkDelay > 0) {
  1254. g_scheduler.addEvent(createSchedulerTask(walkDelay, std::bind(&Game::forceRemoveCondition, &g_game, getID(), type)));
  1255. return;
  1256. }
  1257. }
  1258.  
  1259. it = conditions.erase(it);
  1260.  
  1261. condition->endCondition(this);
  1262. delete condition;
  1263.  
  1264. onEndCondition(type);
  1265. }
  1266. }
  1267.  
  1268. void Creature::removeCondition(ConditionType_t type, ConditionId_t conditionId, bool force/* = false*/)
  1269. {
  1270. auto it = conditions.begin(), end = conditions.end();
  1271. while (it != end) {
  1272. Condition* condition = *it;
  1273. if (condition->getType() != type || condition->getId() != conditionId) {
  1274. ++it;
  1275. continue;
  1276. }
  1277.  
  1278. if (!force && type == CONDITION_PARALYZE) {
  1279. int64_t walkDelay = getWalkDelay();
  1280. if (walkDelay > 0) {
  1281. g_scheduler.addEvent(createSchedulerTask(walkDelay, std::bind(&Game::forceRemoveCondition, &g_game, getID(), type)));
  1282. return;
  1283. }
  1284. }
  1285.  
  1286. it = conditions.erase(it);
  1287.  
  1288. condition->endCondition(this);
  1289. delete condition;
  1290.  
  1291. onEndCondition(type);
  1292. }
  1293. }
  1294.  
  1295. void Creature::removeCombatCondition(ConditionType_t type)
  1296. {
  1297. std::vector<Condition*> removeConditions;
  1298. for (Condition* condition : conditions) {
  1299. if (condition->getType() == type) {
  1300. removeConditions.push_back(condition);
  1301. }
  1302. }
  1303.  
  1304. for (Condition* condition : removeConditions) {
  1305. onCombatRemoveCondition(condition);
  1306. }
  1307. }
  1308.  
  1309. void Creature::removeCondition(Condition* condition, bool force/* = false*/)
  1310. {
  1311. auto it = std::find(conditions.begin(), conditions.end(), condition);
  1312. if (it == conditions.end()) {
  1313. return;
  1314. }
  1315.  
  1316. if (!force && condition->getType() == CONDITION_PARALYZE) {
  1317. int64_t walkDelay = getWalkDelay();
  1318. if (walkDelay > 0) {
  1319. g_scheduler.addEvent(createSchedulerTask(walkDelay, std::bind(&Game::forceRemoveCondition, &g_game, getID(), condition->getType())));
  1320. return;
  1321. }
  1322. }
  1323.  
  1324. conditions.erase(it);
  1325.  
  1326. condition->endCondition(this);
  1327. onEndCondition(condition->getType());
  1328. delete condition;
  1329. }
  1330.  
  1331. Condition* Creature::getCondition(ConditionType_t type) const
  1332. {
  1333. for (Condition* condition : conditions) {
  1334. if (condition->getType() == type) {
  1335. return condition;
  1336. }
  1337. }
  1338. return nullptr;
  1339. }
  1340.  
  1341. Condition* Creature::getCondition(ConditionType_t type, ConditionId_t conditionId, uint32_t subId/* = 0*/) const
  1342. {
  1343. for (Condition* condition : conditions) {
  1344. if (condition->getType() == type && condition->getId() == conditionId && condition->getSubId() == subId) {
  1345. return condition;
  1346. }
  1347. }
  1348. return nullptr;
  1349. }
  1350.  
  1351. void Creature::executeConditions(uint32_t interval)
  1352. {
  1353. auto it = conditions.begin(), end = conditions.end();
  1354. while (it != end) {
  1355. Condition* condition = *it;
  1356. if (!condition->executeCondition(this, interval)) {
  1357. ConditionType_t type = condition->getType();
  1358.  
  1359. it = conditions.erase(it);
  1360.  
  1361. condition->endCondition(this);
  1362. delete condition;
  1363.  
  1364. onEndCondition(type);
  1365. } else {
  1366. ++it;
  1367. }
  1368. }
  1369. }
  1370.  
  1371. bool Creature::hasCondition(ConditionType_t type, uint32_t subId/* = 0*/) const
  1372. {
  1373. if (isSuppress(type)) {
  1374. return false;
  1375. }
  1376.  
  1377. int64_t timeNow = OTSYS_TIME();
  1378. for (Condition* condition : conditions) {
  1379. if (condition->getType() != type || condition->getSubId() != subId) {
  1380. continue;
  1381. }
  1382.  
  1383. if (condition->getEndTime() >= timeNow) {
  1384. return true;
  1385. }
  1386. }
  1387. return false;
  1388. }
  1389.  
  1390. bool Creature::isImmune(CombatType_t type) const
  1391. {
  1392. return hasBitSet(static_cast<uint32_t>(type), getDamageImmunities());
  1393. }
  1394.  
  1395. bool Creature::isImmune(ConditionType_t type) const
  1396. {
  1397. return hasBitSet(static_cast<uint32_t>(type), getConditionImmunities());
  1398. }
  1399.  
  1400. bool Creature::isSuppress(ConditionType_t type) const
  1401. {
  1402. return hasBitSet(static_cast<uint32_t>(type), getConditionSuppressions());
  1403. }
  1404.  
  1405. int64_t Creature::getStepDuration(Direction dir) const
  1406. {
  1407. int64_t stepDuration = getStepDuration();
  1408. if ((dir & DIRECTION_DIAGONAL_MASK) != 0) {
  1409. stepDuration *= 3;
  1410. }
  1411. return stepDuration;
  1412. }
  1413.  
  1414. int64_t Creature::getStepDuration() const
  1415. {
  1416. if (isRemoved()) {
  1417. return 0;
  1418. }
  1419.  
  1420. uint32_t calculatedStepSpeed;
  1421. uint32_t groundSpeed;
  1422.  
  1423. int32_t stepSpeed = getStepSpeed();
  1424. if (stepSpeed > -Creature::speedB) {
  1425. calculatedStepSpeed = floor((Creature::speedA * log((stepSpeed / 2) + Creature::speedB) + Creature::speedC) + 0.5);
  1426. if (calculatedStepSpeed <= 0) {
  1427. calculatedStepSpeed = 1;
  1428. }
  1429. } else {
  1430. calculatedStepSpeed = 1;
  1431. }
  1432.  
  1433. Item* ground = _tile->getGround();
  1434. if (ground) {
  1435. groundSpeed = Item::items[ground->getID()].speed;
  1436. if (groundSpeed == 0) {
  1437. groundSpeed = 150;
  1438. }
  1439. } else {
  1440. groundSpeed = 150;
  1441. }
  1442.  
  1443. double duration = std::floor(1000 * groundSpeed / calculatedStepSpeed);
  1444. int64_t stepDuration = std::ceil(duration / 50) * 50;
  1445.  
  1446. const Monster* monster = getMonster();
  1447. if (monster && monster->isTargetNearby() && !monster->isFleeing() && !monster->getMaster()) {
  1448. stepDuration *= 2;
  1449. }
  1450.  
  1451. return stepDuration;
  1452. }
  1453.  
  1454. int64_t Creature::getEventStepTicks(bool onlyDelay) const
  1455. {
  1456. int64_t ret = getWalkDelay();
  1457. if (ret <= 0) {
  1458. int64_t stepDuration = getStepDuration();
  1459. if (onlyDelay && stepDuration > 0) {
  1460. ret = 1;
  1461. } else {
  1462. ret = stepDuration * lastStepCost;
  1463. }
  1464. }
  1465. return ret;
  1466. }
  1467.  
  1468. void Creature::getCreatureLight(LightInfo& light) const
  1469. {
  1470. light = internalLight;
  1471. }
  1472.  
  1473. void Creature::setNormalCreatureLight()
  1474. {
  1475. internalLight.level = 0;
  1476. internalLight.color = 0;
  1477. }
  1478.  
  1479. bool Creature::registerCreatureEvent(const std::string& name)
  1480. {
  1481. CreatureEvent* event = g_creatureEvents->getEventByName(name);
  1482. if (!event) {
  1483. return false;
  1484. }
  1485.  
  1486. CreatureEventType_t type = event->getEventType();
  1487. if (hasEventRegistered(type)) {
  1488. for (CreatureEvent* creatureEvent : eventsList) {
  1489. if (creatureEvent == event) {
  1490. return false;
  1491. }
  1492. }
  1493. } else {
  1494. scriptEventsBitField |= static_cast<uint32_t>(1) << type;
  1495. }
  1496.  
  1497. eventsList.push_back(event);
  1498. return true;
  1499. }
  1500.  
  1501. bool Creature::unregisterCreatureEvent(const std::string& name)
  1502. {
  1503. CreatureEvent* event = g_creatureEvents->getEventByName(name);
  1504. if (!event) {
  1505. return false;
  1506. }
  1507.  
  1508. CreatureEventType_t type = event->getEventType();
  1509. if (!hasEventRegistered(type)) {
  1510. return false;
  1511. }
  1512.  
  1513. bool resetTypeBit = true;
  1514.  
  1515. auto it = eventsList.begin(), end = eventsList.end();
  1516. while (it != end) {
  1517. CreatureEvent* curEvent = *it;
  1518. if (curEvent == event) {
  1519. it = eventsList.erase(it);
  1520. continue;
  1521. }
  1522.  
  1523. if (curEvent->getEventType() == type) {
  1524. resetTypeBit = false;
  1525. }
  1526. ++it;
  1527. }
  1528.  
  1529. if (resetTypeBit) {
  1530. scriptEventsBitField &= ~(static_cast<uint32_t>(1) << type);
  1531. }
  1532. return true;
  1533. }
  1534.  
  1535. CreatureEventList Creature::getCreatureEvents(CreatureEventType_t type)
  1536. {
  1537. CreatureEventList tmpEventList;
  1538.  
  1539. if (!hasEventRegistered(type)) {
  1540. return tmpEventList;
  1541. }
  1542.  
  1543. for (CreatureEvent* creatureEvent : eventsList) {
  1544. if (creatureEvent->getEventType() == type) {
  1545. tmpEventList.push_back(creatureEvent);
  1546. }
  1547. }
  1548.  
  1549. return tmpEventList;
  1550. }
  1551.  
  1552. bool FrozenPathingConditionCall::isInRange(const Position& startPos, const Position& testPos,
  1553. const FindPathParams& fpp) const
  1554. {
  1555. if (fpp.fullPathSearch) {
  1556. if (testPos.x > targetPos.x + fpp.maxTargetDist) {
  1557. return false;
  1558. }
  1559.  
  1560. if (testPos.x < targetPos.x - fpp.maxTargetDist) {
  1561. return false;
  1562. }
  1563.  
  1564. if (testPos.y > targetPos.y + fpp.maxTargetDist) {
  1565. return false;
  1566. }
  1567.  
  1568. if (testPos.y < targetPos.y - fpp.maxTargetDist) {
  1569. return false;
  1570. }
  1571. } else {
  1572. int_fast32_t dx = Position::getOffsetX(startPos, targetPos);
  1573.  
  1574. int32_t dxMax = (dx >= 0 ? fpp.maxTargetDist : 0);
  1575. if (testPos.x > targetPos.x + dxMax) {
  1576. return false;
  1577. }
  1578.  
  1579. int32_t dxMin = (dx <= 0 ? fpp.maxTargetDist : 0);
  1580. if (testPos.x < targetPos.x - dxMin) {
  1581. return false;
  1582. }
  1583.  
  1584. int_fast32_t dy = Position::getOffsetY(startPos, targetPos);
  1585.  
  1586. int32_t dyMax = (dy >= 0 ? fpp.maxTargetDist : 0);
  1587. if (testPos.y > targetPos.y + dyMax) {
  1588. return false;
  1589. }
  1590.  
  1591. int32_t dyMin = (dy <= 0 ? fpp.maxTargetDist : 0);
  1592. if (testPos.y < targetPos.y - dyMin) {
  1593. return false;
  1594. }
  1595. }
  1596. return true;
  1597. }
  1598.  
  1599. bool FrozenPathingConditionCall::operator()(const Position& startPos, const Position& testPos,
  1600. const FindPathParams& fpp, int32_t& bestMatchDist) const
  1601. {
  1602. if (!isInRange(startPos, testPos, fpp)) {
  1603. return false;
  1604. }
  1605.  
  1606. if (fpp.clearSight && !g_game.isSightClear(testPos, targetPos, true)) {
  1607. return false;
  1608. }
  1609.  
  1610. int32_t testDist = std::max<int32_t>(Position::getDistanceX(targetPos, testPos), Position::getDistanceY(targetPos, testPos));
  1611. if (fpp.maxTargetDist == 1) {
  1612. if (testDist < fpp.minTargetDist || testDist > fpp.maxTargetDist) {
  1613. return false;
  1614. }
  1615.  
  1616. return true;
  1617. } else if (testDist <= fpp.maxTargetDist) {
  1618. if (testDist < fpp.minTargetDist) {
  1619. return false;
  1620. }
  1621.  
  1622. if (testDist == fpp.maxTargetDist) {
  1623. bestMatchDist = 0;
  1624. return true;
  1625. } else if (testDist > bestMatchDist) {
  1626. //not quite what we want, but the best so far
  1627. bestMatchDist = testDist;
  1628. return true;
  1629. }
  1630. }
  1631. return false;
  1632. }
  1633.  
  1634. bool Creature::isInvisible() const
  1635. {
  1636. return std::find_if(conditions.begin(), conditions.end(), [] (const Condition* condition) {
  1637. return condition->getType() == CONDITION_INVISIBLE;
  1638. }) != conditions.end();
  1639. }
  1640.  
  1641. bool Creature::getPathTo(const Position& targetPos, std::forward_list<Direction>& dirList, const FindPathParams& fpp) const
  1642. {
  1643. return g_game.map.getPathMatching(*this, dirList, FrozenPathingConditionCall(targetPos), fpp);
  1644. }
  1645.  
  1646. bool Creature::getPathTo(const Position& targetPos, std::forward_list<Direction>& dirList, int32_t minTargetDist, int32_t maxTargetDist, bool fullPathSearch /*= true*/, bool clearSight /*= true*/, int32_t maxSearchDist /*= 0*/) const
  1647. {
  1648. FindPathParams fpp;
  1649. fpp.fullPathSearch = fullPathSearch;
  1650. fpp.maxSearchDist = maxSearchDist;
  1651. fpp.clearSight = clearSight;
  1652. fpp.minTargetDist = minTargetDist;
  1653. fpp.maxTargetDist = maxTargetDist;
  1654. return getPathTo(targetPos, dirList, fpp);
  1655. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement