Advertisement
Guest User

Untitled

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