Advertisement
Guest User

creature.cpp

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