Advertisement
Guest User

tile.cpp

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