Advertisement
Guest User

Untitled

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