Advertisement
Guest User

Untitled

a guest
Nov 19th, 2016
129
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 50.75 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. #include <iostream>
  19. #include "tile.h"
  20. #include "housetile.h"
  21. #include "player.h"
  22. #include "creature.h"
  23. #include "teleport.h"
  24. #include "trashholder.h"
  25. #include "mailbox.h"
  26. #include "combat.h"
  27. #include "movement.h"
  28. #include "game.h"
  29. #include "configmanager.h"
  30. extern ConfigManager g_config;
  31. extern Game g_game;
  32. extern MoveEvents* g_moveEvents;
  33. StaticTile reallyNullTile(0xFFFF, 0xFFFF, 0xFFFF);
  34. Tile& Tile::nullTile = reallyNullTile;
  35. bool Tile::hasProperty(enum ITEMPROPERTY prop) const
  36. {
  37.     if(ground && ground->hasProperty(prop))
  38.         return true;
  39.     if(const TileItemVector* items = getItemList())
  40.     {
  41.         for(ItemVector::const_iterator it = items->begin(); it != items->end(); ++it)
  42.         {
  43.             if((*it)->hasProperty(prop))
  44.                 return true;
  45.         }
  46.     }
  47.     return false;
  48. }
  49. bool Tile::hasProperty(Item* exclude, enum ITEMPROPERTY prop) const
  50. {
  51.     assert(exclude);
  52.     if(ground && exclude != ground && ground->hasProperty(prop))
  53.         return true;
  54.     if(const TileItemVector* items = getItemList())
  55.     {
  56.         Item* item = NULL;
  57.         for(ItemVector::const_iterator it = items->begin(); it != items->end(); ++it)
  58.         {
  59.             if((item = (*it)) && item != exclude && item->hasProperty(prop))
  60.                 return true;
  61.         }
  62.     }
  63.     return false;
  64. }
  65. HouseTile* Tile::getHouseTile()
  66. {
  67.     if(isHouseTile())
  68.         return static_cast<HouseTile*>(this);
  69.     return NULL;
  70. }
  71. const HouseTile* Tile::getHouseTile() const
  72. {
  73.     if(isHouseTile())
  74.         return static_cast<const HouseTile*>(this);
  75.     return NULL;
  76. }
  77. bool Tile::hasHeight(uint32_t n) const
  78. {
  79.     uint32_t height = 0;
  80.     if(ground)
  81.     {
  82.         if(ground->hasProperty(HASHEIGHT))
  83.             ++height;
  84.         if(n == height)
  85.             return true;
  86.     }
  87.     if(const TileItemVector* items = getItemList())
  88.     {
  89.         for(ItemVector::const_iterator it = items->begin(); it != items->end(); ++it)
  90.         {
  91.             if((*it)->hasProperty(HASHEIGHT))
  92.                 ++height;
  93.             if(n == height)
  94.                 return true;
  95.         }
  96.     }
  97.     return false;
  98. }
  99. uint32_t Tile::getCreatureCount() const
  100. {
  101.     if(const CreatureVector* creatures = getCreatures())
  102.         return creatures->size();
  103.     return 0;
  104. }
  105. uint32_t Tile::getItemCount() const
  106. {
  107.     if(const TileItemVector* items = getItemList())
  108.         return (uint32_t)items->size();
  109.     return 0;
  110. }
  111. uint32_t Tile::getTopItemCount() const
  112. {
  113.     if(const TileItemVector* items = getItemList())
  114.         return items->getTopItemCount();
  115.     return 0;
  116. }
  117. uint32_t Tile::getDownItemCount() const
  118. {
  119.     if(const TileItemVector* items =getItemList())
  120.         return items->getDownItemCount();
  121.     return 0;
  122. }
  123. Teleport* Tile::getTeleportItem() const
  124. {
  125.     if(!hasFlag(TILESTATE_TELEPORT))
  126.         return NULL;
  127.     if(ground && ground->getTeleport())
  128.         return ground->getTeleport();
  129.     if(const TileItemVector* items = getItemList())
  130.     {
  131.         for(ItemVector::const_reverse_iterator it = items->rbegin(); it != items->rend(); ++it)
  132.         {
  133.             if((*it)->getTeleport())
  134.                 return (*it)->getTeleport();
  135.         }
  136.     }
  137.     return NULL;
  138. }
  139. MagicField* Tile::getFieldItem() const
  140. {
  141.     if(!hasFlag(TILESTATE_MAGICFIELD))
  142.         return NULL;
  143.     if(ground && ground->getMagicField())
  144.         return ground->getMagicField();
  145.     if(const TileItemVector* items = getItemList())
  146.     {
  147.         for(ItemVector::const_reverse_iterator it = items->rbegin(); it != items->rend(); ++it)
  148.         {
  149.             if((*it)->getMagicField())
  150.                 return (*it)->getMagicField();
  151.         }
  152.     }
  153.     return NULL;
  154. }
  155. TrashHolder* Tile::getTrashHolder() const
  156. {
  157.     if(!hasFlag(TILESTATE_TRASHHOLDER))
  158.         return NULL;
  159.     if(ground && ground->getTrashHolder())
  160.         return ground->getTrashHolder();
  161.     if(const TileItemVector* items = getItemList())
  162.     {
  163.         for(ItemVector::const_reverse_iterator it = items->rbegin(); it != items->rend(); ++it)
  164.         {
  165.             if((*it)->getTrashHolder())
  166.                 return (*it)->getTrashHolder();
  167.         }
  168.     }
  169.     return NULL;
  170. }
  171. Mailbox* Tile::getMailbox() const
  172. {
  173.     if(!hasFlag(TILESTATE_MAILBOX))
  174.         return NULL;
  175.     if(ground && ground->getMailbox())
  176.         return ground->getMailbox();
  177.     if(const TileItemVector* items = getItemList())
  178.     {
  179.         for(ItemVector::const_reverse_iterator it = items->rbegin(); it != items->rend(); ++it)
  180.         {
  181.             if((*it)->getMailbox())
  182.                 return (*it)->getMailbox();
  183.         }
  184.     }
  185.     return NULL;
  186. }
  187. BedItem* Tile::getBedItem() const
  188. {
  189.     if(!hasFlag(TILESTATE_BED))
  190.         return NULL;
  191.     if(ground && ground->getBed())
  192.         return ground->getBed();
  193.     if(const TileItemVector* items = getItemList())
  194.     {
  195.         for(ItemVector::const_reverse_iterator it = items->rbegin(); it != items->rend(); ++it)
  196.         {
  197.             if((*it)->getBed())
  198.                 return (*it)->getBed();
  199.         }
  200.     }
  201.     return NULL;
  202. }
  203. Creature* Tile::getTopCreature()
  204. {
  205.     if(CreatureVector* creatures = getCreatures())
  206.     {
  207.         if(!creatures->empty())
  208.             return *creatures->begin();
  209.     }
  210.     return NULL;
  211. }
  212. Item* Tile::getTopDownItem()
  213. {
  214.     if(TileItemVector* items = getItemList())
  215.     {
  216.         if(items->getDownItemCount() > 0)
  217.             return *items->getBeginDownItem();
  218.     }
  219.     return NULL;
  220. }
  221. Item* Tile::getTopTopItem()
  222. {
  223.     if(TileItemVector* items = getItemList())
  224.     {
  225.         if(items->getTopItemCount() > 0)
  226.             return *(items->getEndTopItem() - 1);
  227.     }
  228.     return NULL;
  229. }
  230. Item* Tile::getItemByTopOrder(uint32_t topOrder)
  231. {
  232.     if(TileItemVector* items = getItemList())
  233.     {
  234.         for(ItemVector::reverse_iterator it = ItemVector::reverse_iterator(items->getEndTopItem()),
  235.             end = ItemVector::reverse_iterator(items->getBeginTopItem()); it != end; ++it)
  236.         {
  237.             if(Item::items[(*it)->getID()].alwaysOnTopOrder == (int32_t)topOrder)
  238.                 return (*it);
  239.         }
  240.     }
  241.     return NULL;
  242. }
  243. Thing* Tile::getTopVisibleThing(const Creature* creature)
  244. {
  245.     if(Creature* _creature = getTopVisibleCreature(creature))
  246.         return _creature;
  247.     if(TileItemVector* items = getItemList())
  248.     {
  249.         for(ItemVector::iterator it = items->getBeginDownItem(); it != items->getEndDownItem(); ++it)
  250.         {
  251.             const ItemType& iit = Item::items[(*it)->getID()];
  252.             if(!iit.lookThrough)
  253.                 return *it;
  254.         }
  255.         for(ItemVector::reverse_iterator it = ItemVector::reverse_iterator(items->getEndTopItem()),
  256.             end = ItemVector::reverse_iterator(items->getBeginTopItem()); it != end; ++it)
  257.         {
  258.             const ItemType& iit = Item::items[(*it)->getID()];
  259.             if(!iit.lookThrough)
  260.                 return *it;
  261.         }
  262.     }
  263.     return ground;
  264. }
  265. Creature* Tile::getTopVisibleCreature(const Creature* creature)
  266. {
  267.     if(CreatureVector* creatures = getCreatures())
  268.     {
  269.         for(CreatureVector::iterator cit = creatures->begin(); cit != creatures->end(); ++cit)
  270.         {
  271.             if(creature->canSeeCreature(*cit))
  272.                 return (*cit);
  273.         }
  274.     }
  275.     return NULL;
  276. }
  277. const Creature* Tile::getTopVisibleCreature(const Creature* creature) const
  278. {
  279.     if(const CreatureVector* creatures = getCreatures())
  280.     {
  281.         for(CreatureVector::const_iterator cit = creatures->begin(); cit != creatures->end(); ++cit)
  282.         {
  283.             if(creature->canSeeCreature(*cit))
  284.                 return (*cit);
  285.         }
  286.     }
  287.     return NULL;
  288. }
  289. void Tile::onAddTileItem(Item* item)
  290. {
  291.     updateTileFlags(item, false);
  292.     const Position& cylinderMapPos = pos;
  293.     const SpectatorVec& list = g_game.getSpectators(cylinderMapPos);
  294.     SpectatorVec::const_iterator it;
  295.     //send to client
  296.     Player* tmpPlayer = NULL;
  297.     for(it = list.begin(); it != list.end(); ++it)
  298.     {
  299.         if((tmpPlayer = (*it)->getPlayer()))
  300.             tmpPlayer->sendAddTileItem(this, cylinderMapPos, item);
  301.     }
  302.     //event methods
  303.     for(it = list.begin(); it != list.end(); ++it)
  304.         (*it)->onAddTileItem(this, cylinderMapPos, item);
  305. }
  306. void Tile::onUpdateTileItem(Item* oldItem, const ItemType& oldType, Item* newItem, const ItemType& newType)
  307. {
  308.     const Position& cylinderMapPos = pos;
  309.     const SpectatorVec& list = g_game.getSpectators(cylinderMapPos);
  310.     SpectatorVec::const_iterator it;
  311.     //send to client
  312.     Player* tmpPlayer = NULL;
  313.     for(it = list.begin(); it != list.end(); ++it)
  314.     {
  315.         if((tmpPlayer = (*it)->getPlayer()))
  316.             tmpPlayer->sendUpdateTileItem(this, cylinderMapPos, oldItem, newItem);
  317.     }
  318.     //event methods
  319.     for(it = list.begin(); it != list.end(); ++it)
  320.         (*it)->onUpdateTileItem(this, cylinderMapPos, oldItem, oldType, newItem, newType);
  321. }
  322. void Tile::onRemoveTileItem(const SpectatorVec& list, std::vector<int32_t>& oldStackposVector, Item* item)
  323. {
  324.     updateTileFlags(item, true);
  325.     const Position& cylinderMapPos = pos;
  326.     const ItemType& iType = Item::items[item->getID()];
  327.     SpectatorVec::const_iterator it;
  328.     //send to client
  329.     Player* tmpPlayer = NULL;
  330.     uint32_t i = 0;
  331.     for(it = list.begin(); it != list.end(); ++it)
  332.     {
  333.         if((tmpPlayer = (*it)->getPlayer()))
  334.             tmpPlayer->sendRemoveTileItem(this, cylinderMapPos, oldStackposVector[i++], item);
  335.     }
  336.     //event methods
  337.     for(it = list.begin(); it != list.end(); ++it)
  338.         (*it)->onRemoveTileItem(this, cylinderMapPos, iType, item);
  339. }
  340. void Tile::onUpdateTile()
  341. {
  342.     const Position& cylinderMapPos = pos;
  343.     const SpectatorVec& list = g_game.getSpectators(cylinderMapPos);
  344.     SpectatorVec::const_iterator it;
  345.     //send to client
  346.     Player* tmpPlayer = NULL;
  347.     for(it = list.begin(); it != list.end(); ++it)
  348.     {
  349.         if((tmpPlayer = (*it)->getPlayer()))
  350.             tmpPlayer->sendUpdateTile(this, cylinderMapPos);
  351.     }
  352.     //event methods
  353.     for(it = list.begin(); it != list.end(); ++it)
  354.         (*it)->onUpdateTile(this, cylinderMapPos);
  355. }
  356. void Tile::moveCreature(Creature* actor, Creature* creature, Cylinder* toCylinder, bool forceTeleport/* = false*/)
  357. {
  358.     Tile* newTile = toCylinder->getTile();
  359.     SpectatorVec list;
  360.     SpectatorVec::iterator it;
  361.     g_game.getSpectators(list, pos, false, true);
  362.     Position newPos = newTile->getPosition();
  363.     g_game.getSpectators(list, newPos, true, true);
  364.     bool teleport = false;
  365.     if(forceTeleport || !newTile->ground || !Position::areInRange<1,1,0>(pos, newPos))
  366.         teleport = true;
  367.     std::vector<int32_t> oldStackposVector;
  368.     Player* tmpPlayer = NULL;
  369.     for(it = list.begin(); it != list.end(); ++it)
  370.     {
  371.         if((tmpPlayer = (*it)->getPlayer()))
  372.             oldStackposVector.push_back(getClientIndexOfThing(tmpPlayer, creature));
  373.     }
  374.     int32_t oldStackpos = __getIndexOfThing(creature);
  375.     //remove the creature
  376.     __removeThing(creature, 0);
  377.     //switch the node ownership
  378.     if(qt_node != newTile->qt_node)
  379.     {
  380.         qt_node->removeCreature(creature);
  381.         newTile->qt_node->addCreature(creature);
  382.     }
  383.     //add the creature
  384.     newTile->__addThing(actor, creature);
  385.     int32_t newStackpos = newTile->__getIndexOfThing(creature);
  386.     if(!teleport)
  387.     {
  388.         if(pos.y > newPos.y)
  389.             creature->setDirection(NORTH);
  390.         else if(pos.y < newPos.y)
  391.             creature->setDirection(SOUTH);
  392.         if(pos.x < newPos.x)
  393.             creature->setDirection(EAST);
  394.         else if(pos.x > newPos.x)
  395.             creature->setDirection(WEST);
  396.     }
  397.     //send to client
  398.     int32_t i = 0;
  399.     for(it = list.begin(); it != list.end(); ++it)
  400.     {
  401.         if((tmpPlayer = (*it)->getPlayer()))
  402.             tmpPlayer->sendCreatureMove(creature, newTile, newPos, this, pos, oldStackposVector[i++], teleport);
  403.     }
  404.     //event method
  405.     for(it = list.begin(); it != list.end(); ++it)
  406.         (*it)->onCreatureMove(creature, newTile, newPos, this, pos, teleport);
  407.     postRemoveNotification(actor, creature, toCylinder, oldStackpos, true);
  408.     newTile->postAddNotification(actor, creature, this, newStackpos);
  409. }
  410. ReturnValue Tile::__queryAdd(int32_t, const Thing* thing, uint32_t,
  411.     uint32_t flags) const
  412. {
  413.     const CreatureVector* creatures = getCreatures();
  414.     const TileItemVector* items = getItemList();
  415.     if(const Creature* creature = thing->getCreature())
  416.     {
  417.         if(hasBitSet(FLAG_NOLIMIT, flags))
  418.             return RET_NOERROR;
  419.         if(hasBitSet(FLAG_PATHFINDING, flags))
  420.         {
  421.             if(floorChange() || positionChange())
  422.                 return RET_NOTPOSSIBLE;
  423.         }
  424.         if(!ground)
  425.             return RET_NOTPOSSIBLE;
  426.         if(const Monster* monster = creature->getMonster())
  427.         {
  428.             if(hasFlag(TILESTATE_PROTECTIONZONE))
  429.                 return RET_NOTPOSSIBLE;
  430.             if(floorChange() || positionChange())
  431.                 return RET_NOTPOSSIBLE;
  432.             if(monster->canPushCreatures() && !monster->isSummon())
  433.             {
  434.                 if(creatures && !creatures->empty())
  435.                 {
  436.                     Creature* tmp = NULL;
  437.                     for(uint32_t i = 0; i < creatures->size(); ++i)
  438.                     {
  439.                         tmp = creatures->at(i);
  440.                         if(creature->canWalkthrough(tmp))
  441.                             continue;
  442.                         if(!tmp->getMonster() || !tmp->isPushable() || tmp->isPlayerSummon())
  443.                             return RET_NOTPOSSIBLE;
  444.                     }
  445.                 }
  446.             }
  447.             else if(creatures && !creatures->empty())
  448.             {
  449.                 for(CreatureVector::const_iterator cit = creatures->begin(); cit != creatures->end(); ++cit)
  450.                 {
  451.                     if(!creature->canWalkthrough(*cit))
  452.                         return RET_NOTENOUGHROOM; //NOTPOSSIBLE
  453.                 }
  454.             }
  455.             if(hasFlag(TILESTATE_IMMOVABLEBLOCKSOLID))
  456.                 return RET_NOTPOSSIBLE;
  457.             if(hasBitSet(FLAG_PATHFINDING, flags) && hasFlag(TILESTATE_IMMOVABLENOFIELDBLOCKPATH))
  458.                 return RET_NOTPOSSIBLE;
  459.             if((hasFlag(TILESTATE_BLOCKSOLID) || (hasBitSet(FLAG_PATHFINDING, flags) && hasFlag(TILESTATE_NOFIELDBLOCKPATH)))
  460.                 && (!(monster->canPushItems() || hasBitSet(FLAG_IGNOREBLOCKITEM, flags))))
  461.                 return RET_NOTPOSSIBLE;
  462.             if(!items) // Do not seek for fields if there are no items
  463.                 return RET_NOERROR;
  464.             MagicField* field = getFieldItem();
  465.             if(!field)
  466.                 return RET_NOERROR;
  467.             if(field->isBlocking(creature))
  468.                 return RET_NOTPOSSIBLE;
  469.             CombatType_t combatType = field->getCombatType();
  470.             //There is 3 options for a monster to enter a magic field
  471.             //1) Monster is immune
  472.             if(monster->isImmune(combatType))
  473.                 return RET_NOERROR;
  474.             //1) Monster is "strong" enough to handle the damage
  475.             //2) Monster is already afflicated by this type of condition
  476.             if(!hasBitSet(FLAG_IGNOREFIELDDAMAGE, flags))
  477.                 return RET_NOTPOSSIBLE;
  478.             return !monster->hasCondition(Combat::DamageToConditionType(combatType), -1, false)
  479.                 && !monster->canPushItems() ? RET_NOTPOSSIBLE : RET_NOERROR;
  480.         }
  481.         if(const Player* player = creature->getPlayer())
  482.         {
  483.             if(creatures && !creatures->empty() && !hasBitSet(FLAG_IGNOREBLOCKCREATURE, flags))
  484.             {
  485.                 for(CreatureVector::const_iterator cit = creatures->begin(); cit != creatures->end(); ++cit)
  486.                 {
  487.                     if(!creature->canWalkthrough(*cit))
  488.                         return RET_NOTENOUGHROOM; //NOTPOSSIBLE
  489.                 }
  490.             }
  491.             if(!player->getParent() && hasFlag(TILESTATE_NOLOGOUT)) //player is trying to login to a "no logout" tile
  492.                 return RET_NOTPOSSIBLE;
  493.             if(player->isPzLocked() && !player->getTile()->hasFlag(TILESTATE_HARDCOREZONE) && hasFlag(TILESTATE_HARDCOREZONE)) //player is trying to enter a pvp zone while being pz-locked
  494.                 return RET_PLAYERISPZLOCKEDENTERPVPZONE;
  495.             if(player->isPzLocked() && player->getTile()->hasFlag(TILESTATE_HARDCOREZONE) && !hasFlag(TILESTATE_HARDCOREZONE)) //player is trying to leave a pvp zone while being pz-locked
  496.                 return RET_PLAYERISPZLOCKEDLEAVEPVPZONE;
  497.             if(hasFlag(TILESTATE_OPTIONALZONE) && player->isPzLocked())
  498.                 return RET_PLAYERISPZLOCKED;
  499.             if(hasFlag(TILESTATE_PROTECTIONZONE) && player->isPzLocked())
  500.                 return RET_PLAYERISPZLOCKED;
  501.         }
  502.         else if(creatures && !creatures->empty() && !hasBitSet(FLAG_IGNOREBLOCKCREATURE, flags))
  503.         {
  504.             for(CreatureVector::const_iterator cit = creatures->begin(); cit != creatures->end(); ++cit)
  505.             {
  506.                 if(!creature->canWalkthrough(*cit))
  507.                     return RET_NOTENOUGHROOM; //NOTPOSSIBLE
  508.             }
  509.         }
  510.         if(items)
  511.         {
  512.             MagicField* field = getFieldItem();
  513.             if(field && field->isBlocking(creature))
  514.                 return RET_NOTPOSSIBLE;
  515.             if(hasBitSet(FLAG_IGNOREBLOCKITEM, flags)) //if the FLAG_IGNOREBLOCKITEM bit isn't set we dont have to iterate every single item
  516.             {
  517.                 //FLAG_IGNOREBLOCKITEM is set
  518.                 if(ground)
  519.                 {
  520.                     const ItemType& iType = Item::items[ground->getID()];
  521.                     if(ground->isBlocking(creature) && (!iType.moveable || (ground->isLoadedFromMap() &&
  522.                         (ground->getUniqueId() || (ground->getActionId() && ground->getContainer())))))
  523.                         return RET_NOTPOSSIBLE;
  524.                 }
  525.                 if(const TileItemVector* items = getItemList())
  526.                 {
  527.                     for(ItemVector::const_iterator it = items->begin(); it != items->end(); ++it)
  528.                     {
  529.                         const ItemType& iType = Item::items[(*it)->getID()];
  530.                         if((*it)->isBlocking(creature) && (!iType.moveable || ((*it)->isLoadedFromMap() &&
  531.                             ((*it)->getUniqueId() || ((*it)->getActionId() && (*it)->getContainer())))))
  532.                             return RET_NOTPOSSIBLE;
  533.                     }
  534.                 }
  535.             }
  536.             else if(hasFlag(TILESTATE_BLOCKSOLID))
  537.                 return RET_NOTPOSSIBLE;
  538.         }
  539.     }
  540.     else if(const Item* item = thing->getItem())
  541.     {
  542. #ifdef __DEBUG__
  543.         if(thing->getParent() == NULL && !hasBitSet(FLAG_NOLIMIT, flags))
  544.             std::clog << "[Notice - Tile::__queryAdd] thing->getParent() == NULL" << std::endl;
  545. #endif
  546.         if(items && items->size() >= 0xFFFF)
  547.             return RET_NOTPOSSIBLE;
  548.         if(hasBitSet(FLAG_NOLIMIT, flags))
  549.             return RET_NOERROR;
  550.         bool itemIsHangable = item->isHangable();
  551.         if(!ground && !itemIsHangable)
  552.             return RET_NOTPOSSIBLE;
  553.         if(creatures && !creatures->empty() && !hasBitSet(FLAG_IGNOREBLOCKCREATURE, flags))
  554.         {
  555.             for(CreatureVector::const_iterator cit = creatures->begin(); cit != creatures->end(); ++cit)
  556.             {
  557.                 if(!(*cit)->isGhost() && item->isBlocking(*cit))
  558.                     return RET_NOTENOUGHROOM; //NOTPOSSIBLE
  559.             }
  560.         }
  561.         const uint32_t itemLimit = g_config.getNumber(
  562.                 hasFlag(TILESTATE_PROTECTIONZONE) ? ConfigManager::PROTECTION_TILE_LIMIT : ConfigManager::TILE_LIMIT);
  563.         if(itemLimit && getThingCount() > itemLimit && !item->getMagicField())
  564.             return RET_TILEISFULL;
  565.         bool hasHangable = false, supportHangable = false;
  566.         if(items)
  567.         {
  568.             Thing* iThing = NULL;
  569.             for(uint32_t i = 0; i < getThingCount(); ++i)
  570.             {
  571.                 iThing = __getThing(i);
  572.                 if(const Item* iItem = iThing->getItem())
  573.                 {
  574.                     const ItemType& iType = Item::items[iItem->getID()];
  575.                     if(iType.isHangable)
  576.                         hasHangable = true;
  577.                     if(iType.isHorizontal || iType.isVertical)
  578.                         supportHangable = true;
  579.                     if(itemIsHangable && (iType.isHorizontal || iType.isVertical))
  580.                         continue;
  581.                     else if(iItem->isBlocking(NULL))
  582.                     {
  583.                         if(!item->isPickupable())
  584.                             return RET_NOTPOSSIBLE;
  585.                         if(iType.allowPickupable)
  586.                             continue;
  587.                         if(!iType.hasHeight || iType.pickupable || iType.isBed())
  588.                             return RET_NOTPOSSIBLE;
  589.                     }
  590.                 }
  591.             }
  592.         }
  593.         if(itemIsHangable && hasHangable && supportHangable)
  594.             return RET_NEEDEXCHANGE;
  595.     }
  596.     return RET_NOERROR;
  597. }
  598. ReturnValue Tile::__queryMaxCount(int32_t, const Thing*, uint32_t count, uint32_t& maxQueryCount,
  599.     uint32_t ) const
  600. {
  601.     maxQueryCount = std::max((uint32_t)1, count);
  602.     return RET_NOERROR;
  603. }
  604. ReturnValue Tile::__queryRemove(const Thing* thing, uint32_t count, uint32_t flags) const
  605. {
  606.     int32_t index = __getIndexOfThing(thing);
  607.     if(index == -1)
  608.         return RET_NOTPOSSIBLE;
  609.     const Item* item = thing->getItem();
  610.     if(!item || !count || (item->isStackable() && count > item->getItemCount())
  611.         || (!item->isMoveable() && !hasBitSet(FLAG_IGNORENOTMOVEABLE, flags)))
  612.         return RET_NOTPOSSIBLE;
  613.     return RET_NOERROR;
  614. }
  615. Cylinder* Tile::__queryDestination(int32_t&, const Thing*, Item** destItem,
  616.     uint32_t& flags)
  617. {
  618.     Tile* destTile = NULL;
  619.     *destItem = NULL;
  620.     Position _pos = pos;
  621.     if(floorChange(CHANGE_DOWN))
  622.     {
  623.         _pos.z++;
  624.         for(int32_t i = CHANGE_FIRST_EX; i < CHANGE_LAST; ++i)
  625.         {
  626.             Position __pos = _pos;
  627.             Tile* tmpTile = NULL;
  628.             switch(i)
  629.             {
  630.                 case CHANGE_NORTH_EX:
  631.                     __pos.y++;
  632.                     if((tmpTile = g_game.getTile(__pos)))
  633.                         __pos.y++;
  634.                     break;
  635.                 case CHANGE_SOUTH_EX:
  636.                     __pos.y--;
  637.                     if((tmpTile = g_game.getTile(__pos)))
  638.                         __pos.y--;
  639.                     break;
  640.                 case CHANGE_EAST_EX:
  641.                     __pos.x--;
  642.                     if((tmpTile = g_game.getTile(__pos)))
  643.                         __pos.x--;
  644.                     break;
  645.                 case CHANGE_WEST_EX:
  646.                     __pos.x++;
  647.                     if((tmpTile = g_game.getTile(__pos)))
  648.                         __pos.x++;
  649.                     break;
  650.                 default:
  651.                     break;
  652.             }
  653.             if(!tmpTile || !tmpTile->floorChange((FloorChange_t)i))
  654.                 continue;
  655.             destTile = g_game.getTile(__pos);
  656.             break;
  657.         }
  658.         if(!destTile)
  659.         {
  660.             if(Tile* downTile = g_game.getTile(_pos))
  661.             {
  662.                 if(downTile->floorChange(CHANGE_NORTH) || downTile->floorChange(CHANGE_NORTH_EX))
  663.                     _pos.y++;
  664.                 if(downTile->floorChange(CHANGE_SOUTH) || downTile->floorChange(CHANGE_SOUTH_EX))
  665.                     _pos.y--;
  666.                 if(downTile->floorChange(CHANGE_EAST) || downTile->floorChange(CHANGE_EAST_EX))
  667.                     _pos.x--;
  668.                 if(downTile->floorChange(CHANGE_WEST) || downTile->floorChange(CHANGE_WEST_EX))
  669.                     _pos.x++;
  670.                 destTile = g_game.getTile(_pos);
  671.             }
  672.         }
  673.     }
  674.     else if(floorChange())
  675.     {
  676.         _pos.z--;
  677.         if(floorChange(CHANGE_NORTH))
  678.             _pos.y--;
  679.         if(floorChange(CHANGE_SOUTH))
  680.             _pos.y++;
  681.         if(floorChange(CHANGE_EAST))
  682.             _pos.x++;
  683.         if(floorChange(CHANGE_WEST))
  684.             _pos.x--;
  685.         if(floorChange(CHANGE_NORTH_EX))
  686.             _pos.y -= 2;
  687.         if(floorChange(CHANGE_SOUTH_EX))
  688.             _pos.y += 2;
  689.         if(floorChange(CHANGE_EAST_EX))
  690.             _pos.x += 2;
  691.         if(floorChange(CHANGE_WEST_EX))
  692.             _pos.x -= 2;
  693.         destTile = g_game.getTile(_pos);
  694.     }
  695.     if(!destTile)
  696.         destTile = this;
  697.     else
  698.         flags |= FLAG_NOLIMIT; //will ignore that there is blocking items/creatures
  699.     if(destTile)
  700.     {
  701.         if(Item* item = destTile->getTopDownItem())
  702.             *destItem = item;
  703.     }
  704.     return destTile;
  705. }
  706. void Tile::__addThing(Creature* actor, int32_t, Thing* thing)
  707. {
  708.     if(Creature* creature = thing->getCreature())
  709.     {
  710.         g_game.clearSpectatorCache();
  711.         creature->setParent(this);
  712.         CreatureVector* creatures = makeCreatures();
  713.         creatures->insert(creatures->begin(), creature);
  714.         ++thingCount;
  715.         return;
  716.     }
  717.     Item* item = thing->getItem();
  718.     if(!item)
  719.     {
  720. #ifdef __DEBUG_MOVESYS__
  721.         std::clog << "[Failure - Tile::__addThing] item == NULL" << std::endl;
  722. #endif
  723.         return/* RET_NOTPOSSIBLE*/;
  724.     }
  725.     TileItemVector* items = getItemList();
  726.     if(items && items->size() >= 0xFFFF)
  727.         return/* RET_NOTPOSSIBLE*/;
  728.     if(g_config.getBool(ConfigManager::STORE_TRASH) && !hasFlag(TILESTATE_TRASHED))
  729.     {
  730.         g_game.addTrash(pos);
  731.         setFlag(TILESTATE_TRASHED);
  732.     }
  733.     item->setParent(this);
  734.     if(item->isGroundTile())
  735.     {
  736.         if(ground)
  737.         {
  738.             const ItemType& oldType = Item::items[ground->getID()];
  739.             int32_t oldGroundIndex = __getIndexOfThing(ground);
  740.             Item* oldGround = ground;
  741.             ground->setParent(NULL);
  742.             g_game.freeThing(ground);
  743.             ground = item;
  744.             updateTileFlags(oldGround, true);
  745.             updateTileFlags(item, false);
  746.             onUpdateTileItem(oldGround, oldType, item, Item::items[item->getID()]);
  747.             postRemoveNotification(actor, oldGround, NULL, oldGroundIndex, true);
  748.             onUpdateTile();
  749.         }
  750.         else
  751.         {
  752.             ground = item;
  753.             ++thingCount;
  754.             onAddTileItem(item);
  755.         }
  756.     }
  757.     else if(item->isAlwaysOnTop())
  758.     {
  759.         if(item->isSplash())
  760.         {
  761.             //remove old splash if exists
  762.             if(items)
  763.             {
  764.                 for(ItemVector::iterator it = items->getBeginTopItem(); it != items->getEndTopItem(); ++it)
  765.                 {
  766.                     if(!(*it)->isSplash())
  767.                         continue;
  768.                     int32_t oldSplashIndex = __getIndexOfThing(*it);
  769.                     Item* oldSplash = *it;
  770.                     __removeThing(oldSplash, 1);
  771.                     oldSplash->setParent(NULL);
  772.                     g_game.freeThing(oldSplash);
  773.                     postRemoveNotification(actor, oldSplash, NULL, oldSplashIndex, true);
  774.                     break;
  775.                 }
  776.             }
  777.         }
  778.         bool isInserted = false;
  779.         if(items)
  780.         {
  781.             for(ItemVector::iterator it = items->getBeginTopItem(); it != items->getEndTopItem(); ++it)
  782.             {
  783.                 //Note: this is different from internalAddThing
  784.                 if(Item::items[item->getID()].alwaysOnTopOrder > Item::items[(*it)->getID()].alwaysOnTopOrder)
  785.                     continue;
  786.                 items->insert(it, item);
  787.                 ++thingCount;
  788.                 isInserted = true;
  789.                 break;
  790.             }
  791.         }
  792.         else
  793.             items = makeItemList();
  794.         if(!isInserted)
  795.         {
  796.             items->push_back(item);
  797.             ++thingCount;
  798.         }
  799.         onAddTileItem(item);
  800.     }
  801.     else
  802.     {
  803.         if(item->isMagicField())
  804.         {
  805.             //remove old field item if exists
  806.             if(items)
  807.             {
  808.                 MagicField* oldField = NULL;
  809.                 for(ItemVector::iterator it = items->getBeginDownItem(); it != items->getEndDownItem(); ++it)
  810.                 {
  811.                     if(!(oldField = (*it)->getMagicField()))
  812.                         continue;
  813.                     if(oldField->isReplacable())
  814.                     {
  815.                         int32_t oldFieldIndex = __getIndexOfThing(*it);
  816.                         __removeThing(oldField, 1);
  817.                         oldField->setParent(NULL);
  818.                         g_game.freeThing(oldField);
  819.                         postRemoveNotification(actor, oldField, NULL, oldFieldIndex, true);
  820.                         break;
  821.                     }
  822.                     //This magic field cannot be replaced.
  823.                     item->setParent(NULL);
  824.                     g_game.freeThing(item);
  825.                     return;
  826.                 }
  827.             }
  828.         }
  829.         if(item->getID() == ITEM_WATERBALL_SPLASH && !hasFlag(TILESTATE_TRASHHOLDER))
  830.             item->setID(ITEM_WATERBALL);
  831.         items = makeItemList();
  832.         items->insert(items->getBeginDownItem(), item);
  833.         ++items->downItemCount;
  834.         ++thingCount;
  835.         onAddTileItem(item);
  836.     }
  837. }
  838. void Tile::__updateThing(Thing* thing, uint16_t itemId, uint32_t count)
  839. {
  840.     int32_t index = __getIndexOfThing(thing);
  841.     if(index == -1)
  842.     {
  843. #ifdef __DEBUG_MOVESYS__
  844.         std::clog << "[Failure - Tile::__updateThing] index == -1" << std::endl;
  845. #endif
  846.         return/* RET_NOTPOSSIBLE*/;
  847.     }
  848.     Item* item = thing->getItem();
  849.     if(!item)
  850.     {
  851. #ifdef __DEBUG_MOVESYS__
  852.         std::clog << "[Failure - Tile::__updateThing] item == NULL" << std::endl;
  853. #endif
  854.         return/* RET_NOTPOSSIBLE*/;
  855.     }
  856.     //Need to update it here too since the old and new item is the same
  857.     uint16_t oldId = item->getID();
  858.     updateTileFlags(item, true);
  859.     item->setID(itemId);
  860.     item->setSubType(count);
  861.     updateTileFlags(item, false);
  862.     onUpdateTileItem(item, Item::items[oldId], item, Item::items[itemId]);
  863. }
  864. void Tile::__replaceThing(uint32_t index, Thing* thing)
  865. {
  866.     Item* item = thing->getItem();
  867.     if(!item)
  868.     {
  869. #ifdef __DEBUG_MOVESYS__
  870.         std::clog << "[Failure - Tile::__replaceThing] item == NULL" << std::endl;
  871. #endif
  872.         return/* RET_NOTPOSSIBLE*/;
  873.     }
  874.     int32_t pos = index;
  875.     Item* oldItem = NULL;
  876.     if(ground)
  877.     {
  878.         if(!pos)
  879.         {
  880.             oldItem = ground;
  881.             ground = item;
  882.         }
  883.         --pos;
  884.     }
  885.     TileItemVector* items = NULL;
  886.     if(!oldItem)
  887.         items = getItemList();
  888.     if(items)
  889.     {
  890.         int32_t topItemSize = getTopItemCount();
  891.         if(pos < topItemSize)
  892.         {
  893.             ItemVector::iterator it = items->getBeginTopItem();
  894.             it += pos;
  895.             oldItem = (*it);
  896.             it = items->erase(it);
  897.             items->insert(it, item);
  898.         }
  899.         pos -= topItemSize;
  900.     }
  901.     if(!oldItem)
  902.     {
  903.         if(CreatureVector* creatures = getCreatures())
  904.         {
  905.             if(pos < (int32_t)creatures->size())
  906.             {
  907. #ifdef __DEBUG_MOVESYS__
  908.                 std::clog << "[Failure - Tile::__replaceThing] Update object is a creature" << std::endl;
  909. #endif
  910.                 return/* RET_NOTPOSSIBLE*/;
  911.             }
  912.             pos -= (uint32_t)creatures->size();
  913.         }
  914.     }
  915.     if(!oldItem && items)
  916.     {
  917.         int32_t downItemSize = getDownItemCount();
  918.         if(pos < downItemSize)
  919.         {
  920.             ItemVector::iterator it = items->begin();
  921.             it += pos;
  922.             pos = 0;
  923.             oldItem = (*it);
  924.             it = items->erase(it);
  925.             items->insert(it, item);
  926.         }
  927.     }
  928.     item->setParent(this);
  929.     if(oldItem)
  930.         updateTileFlags(oldItem, true);
  931.     updateTileFlags(item, false);
  932.     if(oldItem)
  933.     {
  934.         onUpdateTileItem(oldItem, Item::items[oldItem->getID()], item, Item::items[item->getID()]);
  935.         oldItem->setParent(NULL);
  936.         return/* RET_NOERROR*/;
  937.     }
  938. #ifdef __DEBUG_MOVESYS__
  939.     std::clog << "[Failure - Tile::__replaceThing] Update object not found" << std::endl;
  940. #endif
  941. }
  942. void Tile::__removeThing(Thing* thing, uint32_t count)
  943. {
  944.     Creature* creature = thing->getCreature();
  945.     if(creature)
  946.     {
  947.         if(CreatureVector* creatures = getCreatures())
  948.         {
  949.             CreatureVector::iterator it = std::find(creatures->begin(), creatures->end(), thing);
  950.             if(it == creatures->end())
  951.             {
  952. #ifdef __DEBUG_MOVESYS__
  953.                 std::clog << "[Failure - Tile::__removeThing] creature not found" << std::endl;
  954. #endif
  955.                 return/* RET_NOTPOSSIBLE*/;
  956.             }
  957.             g_game.clearSpectatorCache();
  958.             creatures->erase(it);
  959.             --thingCount;
  960.         }
  961. #ifdef __DEBUG_MOVESYS__
  962.         else
  963.             std::clog << "[Failure - Tile::__removeThing] creature not found" << std::endl;
  964. #endif
  965.         return;
  966.     }
  967.     Item* item = thing->getItem();
  968.     if(!item)
  969.     {
  970. #ifdef __DEBUG_MOVESYS__
  971.         std::clog << "[Failure - Tile::__removeThing] item == NULL" << std::endl;
  972. #endif
  973.         return/* RET_NOTPOSSIBLE*/;
  974.     }
  975.     int32_t index = __getIndexOfThing(item);
  976.     if(index == -1)
  977.     {
  978. #ifdef __DEBUG_MOVESYS__
  979.         std::clog << "[Failure - Tile::__removeThing] index == -1" << std::endl;
  980. #endif
  981.         return/* RET_NOTPOSSIBLE*/;
  982.     }
  983.     if(item == ground)
  984.     {
  985.         const SpectatorVec& list = g_game.getSpectators(pos);
  986.         std::vector<int32_t> oldStackposVector;
  987.         Player* tmpPlayer = NULL;
  988.         for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
  989.         {
  990.             if((tmpPlayer = (*it)->getPlayer()))
  991.                 oldStackposVector.push_back(getClientIndexOfThing(tmpPlayer, ground));
  992.         }
  993.         ground->setParent(NULL);
  994.         ground = NULL;
  995.         --thingCount;
  996.         onRemoveTileItem(list, oldStackposVector, item);
  997.         return/* RET_NOERROR*/;
  998.     }
  999.     TileItemVector* items = getItemList();
  1000.     if(!items)
  1001.         return;
  1002.     if(item->isAlwaysOnTop())
  1003.     {
  1004.         for(ItemVector::iterator it = items->getBeginTopItem(); it != items->getEndTopItem(); ++it)
  1005.         {
  1006.             if(*it != item)
  1007.                 continue;
  1008.             const SpectatorVec& list = g_game.getSpectators(pos);
  1009.             std::vector<int32_t> oldStackposVector;
  1010.             Player* tmpPlayer = NULL;
  1011.             for(SpectatorVec::const_iterator iit = list.begin(); iit != list.end(); ++iit)
  1012.             {
  1013.                 if((tmpPlayer = (*iit)->getPlayer()))
  1014.                     oldStackposVector.push_back(getClientIndexOfThing(tmpPlayer, *it));
  1015.             }
  1016.             (*it)->setParent(NULL);
  1017.             items->erase(it);
  1018.             --thingCount;
  1019.             onRemoveTileItem(list, oldStackposVector, item);
  1020.             return/* RET_NOERROR*/;
  1021.         }
  1022.     }
  1023.     else
  1024.     {
  1025.         for(ItemVector::iterator it = items->getBeginDownItem(); it != items->getEndDownItem(); ++it)
  1026.         {
  1027.             if((*it) != item)
  1028.                 continue;
  1029.             if(item->isStackable() && count != item->getItemCount())
  1030.             {
  1031.                 uint8_t newCount = (uint8_t)std::max((int32_t)0, (int32_t)(item->getItemCount() - count));
  1032.                 updateTileFlags(item, true);
  1033.                 item->setItemCount(newCount);
  1034.                 updateTileFlags(item, false);
  1035.                 const ItemType& it = Item::items[item->getID()];
  1036.                 onUpdateTileItem(item, it, item, it);
  1037.             }
  1038.             else
  1039.             {
  1040.                 const SpectatorVec& list = g_game.getSpectators(pos);
  1041.                 std::vector<int32_t> oldStackposVector;
  1042.                 Player* tmpPlayer = NULL;
  1043.                 for(SpectatorVec::const_iterator iit = list.begin(); iit != list.end(); ++iit)
  1044.                 {
  1045.                     if((tmpPlayer = (*iit)->getPlayer()))
  1046.                         oldStackposVector.push_back(getClientIndexOfThing(tmpPlayer, *it));
  1047.                 }
  1048.                 (*it)->setParent(NULL);
  1049.                 items->erase(it);
  1050.                 --items->downItemCount;
  1051.                 --thingCount;
  1052.                 onRemoveTileItem(list, oldStackposVector, item);
  1053.             }
  1054.             return/* RET_NOERROR*/;
  1055.         }
  1056.     }
  1057. #ifdef __DEBUG_MOVESYS__
  1058.     std::clog << "[Failure - Tile::__removeThing] thing not found" << std::endl;
  1059. #endif
  1060. }
  1061. int32_t Tile::getClientIndexOfThing(const Player* player, const Thing* thing) const
  1062. {
  1063.     if(ground && ground == thing)
  1064.         return 0;
  1065.     int32_t n = 0;
  1066.     if(!ground)
  1067.         n--;
  1068.     const TileItemVector* items = getItemList();
  1069.     if(items)
  1070.     {
  1071.         if(thing && thing->getItem())
  1072.         {
  1073.             for(ItemVector::const_iterator it = items->getBeginTopItem(); it != items->getEndTopItem(); ++it)
  1074.             {
  1075.                 ++n;
  1076.                 if((*it) == thing)
  1077.                     return n;
  1078.             }
  1079.         }
  1080.         else
  1081.             n += items->getTopItemCount();
  1082.     }
  1083.     if(const CreatureVector* creatures = getCreatures())
  1084.     {
  1085.         for(CreatureVector::const_reverse_iterator cit = creatures->rbegin(); cit != creatures->rend(); ++cit)
  1086.         {
  1087.             if((*cit) == thing)
  1088.                 return ++n;
  1089.             if(player->canSeeCreature(*cit))
  1090.                 ++n;
  1091.         }
  1092.     }
  1093.     if(items)
  1094.     {
  1095.         if(thing && thing->getItem())
  1096.         {
  1097.             for(ItemVector::const_iterator it = items->getBeginDownItem(); it != items->getEndDownItem(); ++it)
  1098.             {
  1099.                 ++n;
  1100.                 if((*it) == thing)
  1101.                     return n;
  1102.             }
  1103.         }
  1104.         else
  1105.             n += items->getDownItemCount();
  1106.     }
  1107.     return -1;
  1108. }
  1109. int32_t Tile::__getIndexOfThing(const Thing* thing) const
  1110. {
  1111.     if(ground && ground == thing)
  1112.         return 0;
  1113.     int32_t n = 0;
  1114.     if(!ground)
  1115.         n--;
  1116.     const TileItemVector* items = getItemList();
  1117.     if(items)
  1118.     {
  1119.         if(thing && thing->getItem())
  1120.         {
  1121.             for(ItemVector::const_iterator it = items->getBeginTopItem(); it != items->getEndTopItem(); ++it)
  1122.             {
  1123.                 ++n;
  1124.                 if((*it) == thing)
  1125.                     return n;
  1126.             }
  1127.         }
  1128.         else
  1129.             n += items->getTopItemCount();
  1130.     }
  1131.     if(const CreatureVector* creatures = getCreatures())
  1132.     {
  1133.         for(CreatureVector::const_iterator cit = creatures->begin(); cit != creatures->end(); ++cit)
  1134.         {
  1135.             ++n;
  1136.             if((*cit) == thing)
  1137.                 return n;
  1138.         }
  1139.     }
  1140.     if(items)
  1141.     {
  1142.         if(thing && thing->getItem())
  1143.         {
  1144.             for(ItemVector::const_iterator it = items->getBeginDownItem(); it != items->getEndDownItem(); ++it)
  1145.             {
  1146.                 ++n;
  1147.                 if((*it) == thing)
  1148.                     return n;
  1149.             }
  1150.         }
  1151.         else
  1152.             n += items->getDownItemCount();
  1153.     }
  1154.     return -1;
  1155. }
  1156. uint32_t Tile::__getItemTypeCount(uint16_t itemId, int32_t subType /*= -1*/) const
  1157. {
  1158.     uint32_t count = 0;
  1159.     Thing* thing = NULL;
  1160.     for(uint32_t i = 0; i < getThingCount(); ++i)
  1161.     {
  1162.         if(!(thing = __getThing(i)))
  1163.             continue;
  1164.         if(const Item* item = thing->getItem())
  1165.         {
  1166.             if(item->getID() == itemId)
  1167.                 count += Item::countByType(item, subType);
  1168.         }
  1169.     }
  1170.     return count;
  1171. }
  1172. Thing* Tile::__getThing(uint32_t index) const
  1173. {
  1174.     if(ground)
  1175.     {
  1176.         if(!index)
  1177.             return ground;
  1178.         --index;
  1179.     }
  1180.     const TileItemVector* items = getItemList();
  1181.     if(items)
  1182.     {
  1183.         uint32_t topItemSize = items->getTopItemCount();
  1184.         if(index < topItemSize)
  1185.             return items->at(items->downItemCount + index);
  1186.         index -= topItemSize;
  1187.     }
  1188.     if(const CreatureVector* creatures = getCreatures())
  1189.     {
  1190.         if(index < (uint32_t)creatures->size())
  1191.             return creatures->at(index);
  1192.         index -= (uint32_t)creatures->size();
  1193.     }
  1194.     if(items && index < items->getDownItemCount())
  1195.         return items->at(index);
  1196.     return NULL;
  1197. }
  1198. void Tile::postAddNotification(Creature* actor, Thing* thing, const Cylinder* oldParent,
  1199.     int32_t index, cylinderlink_t link/* = LINK_OWNER*/)
  1200. {
  1201.     const Position& cylinderMapPos = pos;
  1202.     const SpectatorVec& list = g_game.getSpectators(cylinderMapPos);
  1203.     SpectatorVec::const_iterator it;
  1204.     Player* tmpPlayer = NULL;
  1205.     for(it = list.begin(); it != list.end(); ++it)
  1206.     {
  1207.         if((tmpPlayer = (*it)->getPlayer()))
  1208.             tmpPlayer->postAddNotification(actor, thing, oldParent, index, LINK_NEAR);
  1209.     }
  1210.     //add a reference to this item, it may be deleted after being added (mailbox for example)
  1211.     thing->addRef();
  1212.     if(link == LINK_OWNER)
  1213.     {
  1214.         //calling movement scripts
  1215.         if(Creature* creature = thing->getCreature())
  1216.         {
  1217.             const Tile* fromTile = NULL;
  1218.             if(oldParent)
  1219.                 fromTile = oldParent->getTile();
  1220.             g_moveEvents->onCreatureMove(actor, creature, fromTile, this, true);
  1221.         }
  1222.         else if(Item* item = thing->getItem())
  1223.         {
  1224.             g_moveEvents->onAddTileItem(this, item);
  1225.             g_moveEvents->onItemMove(actor, item, this, true);
  1226.         }
  1227.         if(hasFlag(TILESTATE_TELEPORT))
  1228.         {
  1229.             if(Teleport* teleport = getTeleportItem())
  1230.                 teleport->__addThing(actor, thing);
  1231.         }
  1232.         else if(hasFlag(TILESTATE_TRASHHOLDER))
  1233.         {
  1234.             if(TrashHolder* trashHolder = getTrashHolder())
  1235.                 trashHolder->__addThing(actor, thing);
  1236.         }
  1237.         else if(hasFlag(TILESTATE_MAILBOX))
  1238.         {
  1239.             if(Mailbox* mailbox = getMailbox())
  1240.                 mailbox->__addThing(actor, thing);
  1241.         }
  1242.     }
  1243.     //release the reference to this item onces we are finished
  1244.     g_game.freeThing(thing);
  1245. }
  1246. void Tile::postRemoveNotification(Creature* actor, Thing* thing, const Cylinder* newParent,
  1247.     int32_t index, bool isCompleteRemoval, cylinderlink_t /*link = LINK_OWNER*/)
  1248. {
  1249.     const Position& cylinderMapPos = pos;
  1250.     const SpectatorVec& list = g_game.getSpectators(cylinderMapPos);
  1251.     SpectatorVec::const_iterator it;
  1252.     if(/*isCompleteRemoval && */getThingCount() > 8)
  1253.         onUpdateTile();
  1254.     Player* tmpPlayer = NULL;
  1255.     for(it = list.begin(); it != list.end(); ++it)
  1256.     {
  1257.         if((tmpPlayer = (*it)->getPlayer()))
  1258.             tmpPlayer->postRemoveNotification(actor, thing, newParent, index, isCompleteRemoval, LINK_NEAR);
  1259.     }
  1260.     //calling movement scripts
  1261.     if(Creature* creature = thing->getCreature())
  1262.     {
  1263.         const Tile* toTile = NULL;
  1264.         if(newParent)
  1265.             toTile = newParent->getTile();
  1266.         g_moveEvents->onCreatureMove(actor, creature, this, toTile, false);
  1267.     }
  1268.     else if(Item* item = thing->getItem())
  1269.     {
  1270.         g_moveEvents->onRemoveTileItem(this, item);
  1271.         g_moveEvents->onItemMove(actor, item, this, false);
  1272.     }
  1273. }
  1274. void Tile::__internalAddThing(uint32_t, Thing* thing)
  1275. {
  1276.     thing->setParent(this);
  1277.     if(Creature* creature = thing->getCreature())
  1278.     {
  1279.         g_game.clearSpectatorCache();
  1280.         CreatureVector* creatures = makeCreatures();
  1281.         creatures->insert(creatures->begin(), creature);
  1282.         ++thingCount;
  1283.         return;
  1284.     }
  1285.     Item* item = thing->getItem();
  1286.     if(!item)
  1287.         return;
  1288.     TileItemVector* items = makeItemList();
  1289.     if(items && items->size() >= 0xFFFF)
  1290.         return/* RET_NOTPOSSIBLE*/;
  1291.     if(item->isGroundTile())
  1292.     {
  1293.         if(!ground)
  1294.         {
  1295.             ground = item;
  1296.             ++thingCount;
  1297.         }
  1298.     }
  1299.     else if(item->isAlwaysOnTop())
  1300.     {
  1301.         bool isInserted = false;
  1302.         for(ItemVector::iterator it = items->getBeginTopItem(); it != items->getEndTopItem(); ++it)
  1303.         {
  1304.             if(Item::items[(*it)->getID()].alwaysOnTopOrder <= Item::items[item->getID()].alwaysOnTopOrder)
  1305.                 continue;
  1306.             items->insert(it, item);
  1307.             ++thingCount;
  1308.             isInserted = true;
  1309.             break;
  1310.         }
  1311.         if(!isInserted)
  1312.         {
  1313.             items->push_back(item);
  1314.             ++thingCount;
  1315.         }
  1316.     }
  1317.     else
  1318.     {
  1319.         items->insert(items->getBeginDownItem(), item);
  1320.         ++items->downItemCount;
  1321.         ++thingCount;
  1322.     }
  1323.     updateTileFlags(item, false);
  1324. }
  1325. void Tile::updateTileFlags(Item* item, bool remove)
  1326. {
  1327.     if(!remove)
  1328.     {
  1329.         if(!hasFlag(TILESTATE_FLOORCHANGE))
  1330.         {
  1331.             if(item->floorChange(CHANGE_DOWN))
  1332.             {
  1333.                 setFlag(TILESTATE_FLOORCHANGE);
  1334.                 setFlag(TILESTATE_FLOORCHANGE_DOWN);
  1335.             }
  1336.             if(item->floorChange(CHANGE_NORTH))
  1337.             {
  1338.                 setFlag(TILESTATE_FLOORCHANGE);
  1339.                 setFlag(TILESTATE_FLOORCHANGE_NORTH);
  1340.             }
  1341.             if(item->floorChange(CHANGE_SOUTH))
  1342.             {
  1343.                 setFlag(TILESTATE_FLOORCHANGE);
  1344.                 setFlag(TILESTATE_FLOORCHANGE_SOUTH);
  1345.             }
  1346.             if(item->floorChange(CHANGE_EAST))
  1347.             {
  1348.                 setFlag(TILESTATE_FLOORCHANGE);
  1349.                 setFlag(TILESTATE_FLOORCHANGE_EAST);
  1350.             }
  1351.             if(item->floorChange(CHANGE_WEST))
  1352.             {
  1353.                 setFlag(TILESTATE_FLOORCHANGE);
  1354.                 setFlag(TILESTATE_FLOORCHANGE_WEST);
  1355.             }
  1356.             if(item->floorChange(CHANGE_NORTH_EX))
  1357.             {
  1358.                 setFlag(TILESTATE_FLOORCHANGE);
  1359.                 setFlag(TILESTATE_FLOORCHANGE_NORTH_EX);
  1360.             }
  1361.             if(item->floorChange(CHANGE_SOUTH_EX))
  1362.             {
  1363.                 setFlag(TILESTATE_FLOORCHANGE);
  1364.                 setFlag(TILESTATE_FLOORCHANGE_SOUTH_EX);
  1365.             }
  1366.             if(item->floorChange(CHANGE_EAST_EX))
  1367.             {
  1368.                 setFlag(TILESTATE_FLOORCHANGE);
  1369.                 setFlag(TILESTATE_FLOORCHANGE_EAST_EX);
  1370.             }
  1371.             if(item->floorChange(CHANGE_WEST_EX))
  1372.             {
  1373.                 setFlag(TILESTATE_FLOORCHANGE);
  1374.                 setFlag(TILESTATE_FLOORCHANGE_WEST_EX);
  1375.             }
  1376.         }
  1377.         if(item->getTeleport())
  1378.             setFlag(TILESTATE_TELEPORT);
  1379.         if(item->getMagicField())
  1380.             setFlag(TILESTATE_MAGICFIELD);
  1381.         if(item->getMailbox())
  1382.             setFlag(TILESTATE_MAILBOX);
  1383.         if(item->getTrashHolder())
  1384.             setFlag(TILESTATE_TRASHHOLDER);
  1385.         if(item->getBed())
  1386.             setFlag(TILESTATE_BED);
  1387.         if(item->getContainer() && item->getContainer()->getDepot())
  1388.             setFlag(TILESTATE_DEPOT);
  1389.         if(item->hasProperty(BLOCKSOLID))
  1390.             setFlag(TILESTATE_BLOCKSOLID);
  1391.         if(item->hasProperty(IMMOVABLEBLOCKSOLID))
  1392.             setFlag(TILESTATE_IMMOVABLEBLOCKSOLID);
  1393.         if(item->hasProperty(BLOCKPATH))
  1394.             setFlag(TILESTATE_BLOCKPATH);
  1395.         if(item->hasProperty(NOFIELDBLOCKPATH))
  1396.             setFlag(TILESTATE_NOFIELDBLOCKPATH);
  1397.         if(item->hasProperty(IMMOVABLENOFIELDBLOCKPATH))
  1398.             setFlag(TILESTATE_IMMOVABLENOFIELDBLOCKPATH);
  1399.     }
  1400.     else
  1401.     {
  1402.         if(item->floorChange(CHANGE_DOWN))
  1403.         {
  1404.             resetFlag(TILESTATE_FLOORCHANGE);
  1405.             resetFlag(TILESTATE_FLOORCHANGE_DOWN);
  1406.         }
  1407.         if(item->floorChange(CHANGE_NORTH))
  1408.         {
  1409.             resetFlag(TILESTATE_FLOORCHANGE);
  1410.             resetFlag(TILESTATE_FLOORCHANGE_NORTH);
  1411.         }
  1412.         if(item->floorChange(CHANGE_SOUTH))
  1413.         {
  1414.             resetFlag(TILESTATE_FLOORCHANGE);
  1415.             resetFlag(TILESTATE_FLOORCHANGE_SOUTH);
  1416.         }
  1417.         if(item->floorChange(CHANGE_EAST))
  1418.         {
  1419.             resetFlag(TILESTATE_FLOORCHANGE);
  1420.             resetFlag(TILESTATE_FLOORCHANGE_EAST);
  1421.         }
  1422.         if(item->floorChange(CHANGE_WEST))
  1423.         {
  1424.             resetFlag(TILESTATE_FLOORCHANGE);
  1425.             resetFlag(TILESTATE_FLOORCHANGE_WEST);
  1426.         }
  1427.         if(item->floorChange(CHANGE_NORTH_EX))
  1428.         {
  1429.             resetFlag(TILESTATE_FLOORCHANGE);
  1430.             resetFlag(TILESTATE_FLOORCHANGE_NORTH_EX);
  1431.         }
  1432.         if(item->floorChange(CHANGE_SOUTH_EX))
  1433.         {
  1434.             resetFlag(TILESTATE_FLOORCHANGE);
  1435.             resetFlag(TILESTATE_FLOORCHANGE_SOUTH_EX);
  1436.         }
  1437.         if(item->floorChange(CHANGE_EAST_EX))
  1438.         {
  1439.             resetFlag(TILESTATE_FLOORCHANGE);
  1440.             resetFlag(TILESTATE_FLOORCHANGE_EAST_EX);
  1441.         }
  1442.         if(item->floorChange(CHANGE_WEST_EX))
  1443.         {
  1444.             resetFlag(TILESTATE_FLOORCHANGE);
  1445.             resetFlag(TILESTATE_FLOORCHANGE_WEST_EX);
  1446.         }
  1447.         if(item->getTeleport())
  1448.             resetFlag(TILESTATE_TELEPORT);
  1449.         if(item->getMagicField())
  1450.             resetFlag(TILESTATE_MAGICFIELD);
  1451.         if(item->getMailbox())
  1452.             resetFlag(TILESTATE_MAILBOX);
  1453.         if(item->getTrashHolder())
  1454.             resetFlag(TILESTATE_TRASHHOLDER);
  1455.         if(item->getBed())
  1456.             resetFlag(TILESTATE_BED);
  1457.         if(item->getContainer() && item->getContainer()->getDepot())
  1458.             resetFlag(TILESTATE_DEPOT);
  1459.         if(item->hasProperty(BLOCKSOLID) && !hasProperty(item, BLOCKSOLID))
  1460.             resetFlag(TILESTATE_BLOCKSOLID);
  1461.         if(item->hasProperty(IMMOVABLEBLOCKSOLID) && !hasProperty(item, IMMOVABLEBLOCKSOLID))
  1462.             resetFlag(TILESTATE_IMMOVABLEBLOCKSOLID);
  1463.         if(item->hasProperty(BLOCKPATH) && !hasProperty(item, BLOCKPATH))
  1464.             resetFlag(TILESTATE_BLOCKPATH);
  1465.         if(item->hasProperty(NOFIELDBLOCKPATH) && !hasProperty(item, NOFIELDBLOCKPATH))
  1466.             resetFlag(TILESTATE_NOFIELDBLOCKPATH);
  1467.         if(item->hasProperty(IMMOVABLEBLOCKPATH) && !hasProperty(item, IMMOVABLEBLOCKPATH))
  1468.             resetFlag(TILESTATE_IMMOVABLEBLOCKPATH);
  1469.         if(item->hasProperty(IMMOVABLENOFIELDBLOCKPATH) && !hasProperty(item, IMMOVABLENOFIELDBLOCKPATH))
  1470.             resetFlag(TILESTATE_IMMOVABLENOFIELDBLOCKPATH);
  1471.     }
  1472. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement