Advertisement
Guest User

blabla

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