Advertisement
Guest User

Untitled

a guest
Mar 9th, 2019
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 38.51 KB | None | 0 0
  1. /**
  2. * The Forgotten Server - a free and open-source MMORPG server emulator
  3. * Copyright (C) 2016 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.  
  26. #include "creature.h"
  27. #include "combat.h"
  28. #include "game.h"
  29. #include "mailbox.h"
  30. #include "monster.h"
  31. #include "movement.h"
  32. #include "teleport.h"
  33. #include "trashholder.h"
  34.  
  35. extern Game g_game;
  36. extern MoveEvents* g_moveEvents;
  37.  
  38. StaticTile real_nullptr_tile(0xFFFF, 0xFFFF, 0xFF);
  39. Tile& Tile::nullptr_tile = real_nullptr_tile;
  40.  
  41. bool Tile::hasProperty(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(const Item* exclude, 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. size_t Tile::getCreatureCount() const
  105. {
  106. if (const CreatureVector* creatures = getCreatures()) {
  107. return creatures->size();
  108. }
  109. return 0;
  110. }
  111.  
  112. size_t Tile::getItemCount() const
  113. {
  114. if (const TileItemVector* items = getItemList()) {
  115. return items->size();
  116. }
  117. return 0;
  118. }
  119.  
  120. uint32_t Tile::getTopItemCount() const
  121. {
  122. if (const TileItemVector* items = getItemList()) {
  123. return items->getTopItemCount();
  124. }
  125. return 0;
  126. }
  127.  
  128. uint32_t Tile::getDownItemCount() const
  129. {
  130. if (const TileItemVector* items = getItemList()) {
  131. return items->getDownItemCount();
  132. }
  133. return 0;
  134. }
  135.  
  136. std::string Tile::getDescription(int32_t) const
  137. {
  138. return "You dont know why, but you cant see anything!";
  139. }
  140.  
  141. Teleport* Tile::getTeleportItem() const
  142. {
  143. if (!hasFlag(TILESTATE_TELEPORT)) {
  144. return nullptr;
  145. }
  146.  
  147. if (const TileItemVector* items = getItemList()) {
  148. for (auto it = items->rbegin(), end = items->rend(); it != end; ++it) {
  149. if ((*it)->getTeleport()) {
  150. return (*it)->getTeleport();
  151. }
  152. }
  153. }
  154. return nullptr;
  155. }
  156.  
  157. MagicField* Tile::getFieldItem() const
  158. {
  159. if (!hasFlag(TILESTATE_MAGICFIELD)) {
  160. return nullptr;
  161. }
  162.  
  163. if (ground && ground->getMagicField()) {
  164. return ground->getMagicField();
  165. }
  166.  
  167. if (const TileItemVector* items = getItemList()) {
  168. for (auto it = items->rbegin(), end = items->rend(); it != end; ++it) {
  169. if ((*it)->getMagicField()) {
  170. return (*it)->getMagicField();
  171. }
  172. }
  173. }
  174. return nullptr;
  175. }
  176.  
  177. TrashHolder* Tile::getTrashHolder() const
  178. {
  179. if (!hasFlag(TILESTATE_TRASHHOLDER)) {
  180. return nullptr;
  181. }
  182.  
  183. if (ground && ground->getTrashHolder()) {
  184. return ground->getTrashHolder();
  185. }
  186.  
  187. if (const TileItemVector* items = getItemList()) {
  188. for (auto it = items->rbegin(), end = items->rend(); it != end; ++it) {
  189. if ((*it)->getTrashHolder()) {
  190. return (*it)->getTrashHolder();
  191. }
  192. }
  193. }
  194. return nullptr;
  195. }
  196.  
  197. Mailbox* Tile::getMailbox() const
  198. {
  199. if (!hasFlag(TILESTATE_MAILBOX)) {
  200. return nullptr;
  201. }
  202.  
  203. if (ground && ground->getMailbox()) {
  204. return ground->getMailbox();
  205. }
  206.  
  207. if (const TileItemVector* items = getItemList()) {
  208. for (auto it = items->rbegin(), end = items->rend(); it != end; ++it) {
  209. if ((*it)->getMailbox()) {
  210. return (*it)->getMailbox();
  211. }
  212. }
  213. }
  214. return nullptr;
  215. }
  216.  
  217. BedItem* Tile::getBedItem() const
  218. {
  219. if (!hasFlag(TILESTATE_BED)) {
  220. return nullptr;
  221. }
  222.  
  223. if (ground && ground->getBed()) {
  224. return ground->getBed();
  225. }
  226.  
  227. if (const TileItemVector* items = getItemList()) {
  228. for (auto it = items->rbegin(), end = items->rend(); it != end; ++it) {
  229. if ((*it)->getBed()) {
  230. return (*it)->getBed();
  231. }
  232. }
  233. }
  234. return nullptr;
  235. }
  236.  
  237. Creature* Tile::getTopCreature() const
  238. {
  239. if (const CreatureVector* creatures = getCreatures()) {
  240. if (!creatures->empty()) {
  241. return *creatures->begin();
  242. }
  243. }
  244. return nullptr;
  245. }
  246.  
  247. const Creature* Tile::getBottomCreature() const
  248. {
  249. if (const CreatureVector* creatures = getCreatures()) {
  250. if (!creatures->empty()) {
  251. return *creatures->rbegin();
  252. }
  253. }
  254. return nullptr;
  255. }
  256.  
  257. Creature* Tile::getTopVisibleCreature(const Creature* creature) const
  258. {
  259. if (const CreatureVector* creatures = getCreatures()) {
  260. if (creature) {
  261. const Player* player = creature->getPlayer();
  262. if (player && player->isAccessPlayer()) {
  263. return getTopCreature();
  264. }
  265.  
  266. for (Creature* tileCreature : *creatures) {
  267. if (creature->canSeeCreature(tileCreature)) {
  268. return tileCreature;
  269. }
  270. }
  271. } else {
  272. for (Creature* tileCreature : *creatures) {
  273. if (!tileCreature->isInvisible()) {
  274. const Player* player = tileCreature->getPlayer();
  275. if (!player || !player->isInGhostMode()) {
  276. return tileCreature;
  277. }
  278. }
  279. }
  280. }
  281. }
  282. return nullptr;
  283. }
  284.  
  285. const Creature* Tile::getBottomVisibleCreature(const Creature* creature) const
  286. {
  287. if (const CreatureVector* creatures = getCreatures()) {
  288. if (creature) {
  289. const Player* player = creature->getPlayer();
  290. if (player && player->isAccessPlayer()) {
  291. return getBottomCreature();
  292. }
  293.  
  294. for (auto it = creatures->rbegin(), end = creatures->rend(); it != end; ++it) {
  295. if (creature->canSeeCreature(*it)) {
  296. return *it;
  297. }
  298. }
  299. } else {
  300. for (auto it = creatures->rbegin(), end = creatures->rend(); it != end; ++it) {
  301. if (!(*it)->isInvisible()) {
  302. const Player* player = (*it)->getPlayer();
  303. if (!player || !player->isInGhostMode()) {
  304. return *it;
  305. }
  306. }
  307. }
  308. }
  309. }
  310. return nullptr;
  311. }
  312.  
  313. Item* Tile::getTopDownItem() const
  314. {
  315. if (const TileItemVector* items = getItemList()) {
  316. return items->getTopDownItem();
  317. }
  318. return nullptr;
  319. }
  320.  
  321. Item* Tile::getTopTopItem() const
  322. {
  323. if (const TileItemVector* items = getItemList()) {
  324. return items->getTopTopItem();
  325. }
  326. return nullptr;
  327. }
  328.  
  329. Item* Tile::getItemByTopOrder(int32_t topOrder)
  330. {
  331. //topOrder:
  332. //1: borders
  333. //2: ladders, signs, splashes
  334. //3: doors etc
  335. //4: creatures
  336. if (TileItemVector* items = getItemList()) {
  337. for (auto it = ItemVector::const_reverse_iterator(items->getEndTopItem()), end = ItemVector::const_reverse_iterator(items->getBeginTopItem()); it != end; ++it) {
  338. if (Item::items[(*it)->getID()].alwaysOnTopOrder == topOrder) {
  339. return (*it);
  340. }
  341. }
  342. }
  343. return nullptr;
  344. }
  345.  
  346. Thing* Tile::getTopVisibleThing(const Creature* creature)
  347. {
  348. Thing* thing = getTopVisibleCreature(creature);
  349. if (thing) {
  350. return thing;
  351. }
  352.  
  353. TileItemVector* items = getItemList();
  354. if (items) {
  355. for (ItemVector::const_iterator it = items->getBeginDownItem(), end = items->getEndDownItem(); it != end; ++it) {
  356. const ItemType& iit = Item::items[(*it)->getID()];
  357. if (!iit.lookThrough) {
  358. return (*it);
  359. }
  360. }
  361.  
  362. for (auto it = ItemVector::const_reverse_iterator(items->getEndTopItem()), end = ItemVector::const_reverse_iterator(items->getBeginTopItem()); it != end; ++it) {
  363. const ItemType& iit = Item::items[(*it)->getID()];
  364. if (!iit.lookThrough) {
  365. return (*it);
  366. }
  367. }
  368. }
  369.  
  370. return ground;
  371. }
  372.  
  373. void Tile::onAddTileItem(Item* item)
  374. {
  375. setTileFlags(item);
  376.  
  377. const Position& cylinderMapPos = getPosition();
  378.  
  379. SpectatorVec list;
  380. g_game.map.getSpectators(list, cylinderMapPos, true);
  381.  
  382. //send to client
  383. for (Creature* spectator : list) {
  384. if (Player* tmpPlayer = spectator->getPlayer()) {
  385. tmpPlayer->sendAddTileItem(this, cylinderMapPos, item);
  386. }
  387. }
  388.  
  389. //event methods
  390. for (Creature* spectator : list) {
  391. spectator->onAddTileItem(this, cylinderMapPos);
  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. SpectatorVec list;
  400. g_game.map.getSpectators(list, cylinderMapPos, true);
  401.  
  402. //send to client
  403. for (Creature* spectator : list) {
  404. if (Player* tmpPlayer = spectator->getPlayer()) {
  405. tmpPlayer->sendUpdateTileItem(this, cylinderMapPos, newItem);
  406. }
  407. }
  408.  
  409. //event methods
  410. for (Creature* spectator : list) {
  411. spectator->onUpdateTileItem(this, cylinderMapPos, oldItem, oldType, newItem, newType);
  412. }
  413. }
  414.  
  415. void Tile::onRemoveTileItem(const SpectatorVec& list, const std::vector<int32_t>& oldStackPosVector, Item* item)
  416. {
  417. resetTileFlags(item);
  418.  
  419. const Position& cylinderMapPos = getPosition();
  420. const ItemType& iType = Item::items[item->getID()];
  421.  
  422. //send to client
  423. size_t i = 0;
  424. for (Creature* spectator : list) {
  425. if (Player* tmpPlayer = spectator->getPlayer()) {
  426. tmpPlayer->sendRemoveTileThing(cylinderMapPos, oldStackPosVector[i++]);
  427. }
  428. }
  429.  
  430. //event methods
  431. for (Creature* spectator : list) {
  432. spectator->onRemoveTileItem(this, cylinderMapPos, iType, item);
  433. }
  434. }
  435.  
  436. void Tile::onUpdateTile(const SpectatorVec& list)
  437. {
  438. const Position& cylinderMapPos = getPosition();
  439.  
  440. //send to clients
  441. for (Creature* spectator : list) {
  442. spectator->getPlayer()->sendUpdateTile(this, cylinderMapPos);
  443. }
  444. }
  445.  
  446. ReturnValue Tile::queryAdd(int32_t, const Thing& thing, uint32_t, uint32_t flags, Creature*) const
  447. {
  448. if (const Creature* creature = thing.getCreature()) {
  449. if (hasBitSet(FLAG_NOLIMIT, flags)) {
  450. return RETURNVALUE_NOERROR;
  451. }
  452.  
  453. if (hasBitSet(FLAG_PATHFINDING, flags) && hasFlag(TILESTATE_FLOORCHANGE | TILESTATE_TELEPORT)) {
  454. return RETURNVALUE_NOTPOSSIBLE;
  455. }
  456.  
  457. if (ground == nullptr) {
  458. return RETURNVALUE_NOTPOSSIBLE;
  459. }
  460.  
  461. if (const Monster* monster = creature->getMonster()) {
  462. if (hasFlag(TILESTATE_PROTECTIONZONE | TILESTATE_FLOORCHANGE | TILESTATE_TELEPORT)) {
  463. return RETURNVALUE_NOTPOSSIBLE;
  464. }
  465.  
  466. const CreatureVector* creatures = getCreatures();
  467. if (monster->canPushCreatures() && !monster->isSummon()) {
  468. if (creatures) {
  469. for (Creature* tileCreature : *creatures) {
  470. if (tileCreature->getPlayer() && tileCreature->getPlayer()->isInGhostMode()) {
  471. continue;
  472. }
  473.  
  474. const Monster* creatureMonster = tileCreature->getMonster();
  475. if (!creatureMonster || !tileCreature->isPushable() ||
  476. (creatureMonster->isSummon() && creatureMonster->getMaster()->getPlayer())) {
  477. return RETURNVALUE_NOTPOSSIBLE;
  478. }
  479. }
  480. }
  481. } else if (creatures && !creatures->empty()) {
  482. for (const Creature* tileCreature : *creatures) {
  483. if (!tileCreature->isInGhostMode()) {
  484. return RETURNVALUE_NOTENOUGHROOM;
  485. }
  486. }
  487. }
  488.  
  489. if (hasFlag(TILESTATE_IMMOVABLEBLOCKSOLID)) {
  490. return RETURNVALUE_NOTPOSSIBLE;
  491. }
  492.  
  493. if (hasBitSet(FLAG_PATHFINDING, flags) && hasFlag(TILESTATE_IMMOVABLENOFIELDBLOCKPATH)) {
  494. return RETURNVALUE_NOTPOSSIBLE;
  495. }
  496.  
  497. if (hasFlag(TILESTATE_BLOCKSOLID) || (hasBitSet(FLAG_PATHFINDING, flags) && hasFlag(TILESTATE_NOFIELDBLOCKPATH))) {
  498. if (!(monster->canPushItems() || hasBitSet(FLAG_IGNOREBLOCKITEM, flags))) {
  499. return RETURNVALUE_NOTPOSSIBLE;
  500. }
  501. }
  502.  
  503. MagicField* field = getFieldItem();
  504. if (field && !field->isBlocking()) {
  505. CombatType_t combatType = field->getCombatType();
  506.  
  507. //There is 3 options for a monster to enter a magic field
  508. //1) Monster is immune
  509. if (!monster->isImmune(combatType)) {
  510. //1) Monster is "strong" enough to handle the damage
  511. //2) Monster is already afflicated by this type of condition
  512. if (hasBitSet(FLAG_IGNOREFIELDDAMAGE, flags)) {
  513. if (!(monster->canPushItems() || monster->hasCondition(Combat::DamageToConditionType(combatType)))) {
  514. return RETURNVALUE_NOTPOSSIBLE;
  515. }
  516. } else {
  517. return RETURNVALUE_NOTPOSSIBLE;
  518. }
  519. }
  520. }
  521.  
  522. return RETURNVALUE_NOERROR;
  523. }
  524.  
  525. const CreatureVector* creatures = getCreatures();
  526. if (const Player* player = creature->getPlayer()) {
  527. if (creatures && !creatures->empty() && !hasBitSet(FLAG_IGNOREBLOCKCREATURE, flags) && !player->isAccessPlayer()) {
  528. return RETURNVALUE_NOTPOSSIBLE;
  529. }
  530.  
  531. if (player->getParent() == nullptr && hasFlag(TILESTATE_NOLOGOUT)) {
  532. //player is trying to login to a "no logout" tile
  533. return RETURNVALUE_NOTPOSSIBLE;
  534. }
  535.  
  536. const Tile* playerTile = player->getTile();
  537. if (playerTile && player->isPzLocked()) {
  538. if (!playerTile->hasFlag(TILESTATE_PVPZONE)) {
  539. //player is trying to enter a pvp zone while being pz-locked
  540. if (hasFlag(TILESTATE_PVPZONE)) {
  541. return RETURNVALUE_PLAYERISPZLOCKEDENTERPVPZONE;
  542. }
  543. } else if (!hasFlag(TILESTATE_PVPZONE)) {
  544. // player is trying to leave a pvp zone while being pz-locked
  545. return RETURNVALUE_PLAYERISPZLOCKEDLEAVEPVPZONE;
  546. }
  547.  
  548. if ((!playerTile->hasFlag(TILESTATE_NOPVPZONE) && hasFlag(TILESTATE_NOPVPZONE)) ||
  549. (!playerTile->hasFlag(TILESTATE_PROTECTIONZONE) && hasFlag(TILESTATE_PROTECTIONZONE))) {
  550. // player is trying to enter a non-pvp/protection zone while being pz-locked
  551. return RETURNVALUE_PLAYERISPZLOCKED;
  552. }
  553. }
  554. } else if (creatures && !creatures->empty() && !hasBitSet(FLAG_IGNOREBLOCKCREATURE, flags)) {
  555. for (const Creature* tileCreature : *creatures) {
  556. if (!tileCreature->isInGhostMode()) {
  557. return RETURNVALUE_NOTENOUGHROOM;
  558. }
  559. }
  560. }
  561.  
  562. if (!hasBitSet(FLAG_IGNOREBLOCKITEM, flags)) {
  563. //If the FLAG_IGNOREBLOCKITEM bit isn't set we dont have to iterate every single item
  564. if (hasFlag(TILESTATE_BLOCKSOLID)) {
  565. return RETURNVALUE_NOTENOUGHROOM;
  566. }
  567. } else {
  568. //FLAG_IGNOREBLOCKITEM is set
  569. if (ground) {
  570. const ItemType& iiType = Item::items[ground->getID()];
  571. if (iiType.blockSolid && (!iiType.moveable || ground->hasAttribute(ITEM_ATTRIBUTE_UNIQUEID))) {
  572. return RETURNVALUE_NOTPOSSIBLE;
  573. }
  574. }
  575.  
  576. if (const auto items = getItemList()) {
  577. for (const Item* item : *items) {
  578. const ItemType& iiType = Item::items[item->getID()];
  579. if (iiType.blockSolid && (!iiType.moveable || item->hasAttribute(ITEM_ATTRIBUTE_UNIQUEID))) {
  580. return RETURNVALUE_NOTPOSSIBLE;
  581. }
  582. }
  583. }
  584. }
  585. } else if (const Item* item = thing.getItem()) {
  586. const TileItemVector* items = getItemList();
  587. if (items && items->size() >= 0xFFFF) {
  588. return RETURNVALUE_NOTPOSSIBLE;
  589. }
  590.  
  591. if (hasBitSet(FLAG_NOLIMIT, flags)) {
  592. return RETURNVALUE_NOERROR;
  593. }
  594.  
  595. bool itemIsHangable = item->isHangable();
  596. if (ground == nullptr && !itemIsHangable) {
  597. return RETURNVALUE_NOTPOSSIBLE;
  598. }
  599.  
  600. const CreatureVector* creatures = getCreatures();
  601. if (creatures && !creatures->empty() && item->isBlocking() && !hasBitSet(FLAG_IGNOREBLOCKCREATURE, flags)) {
  602. for (const Creature* tileCreature : *creatures) {
  603. if (!tileCreature->isInGhostMode()) {
  604. return RETURNVALUE_NOTENOUGHROOM;
  605. }
  606. }
  607. }
  608.  
  609. if (itemIsHangable && hasFlag(TILESTATE_SUPPORTS_HANGABLE)) {
  610. if (items) {
  611. for (const Item* tileItem : *items) {
  612. if (tileItem->isHangable()) {
  613. return RETURNVALUE_NEEDEXCHANGE;
  614. }
  615. }
  616. }
  617. } else {
  618. if (ground) {
  619. const ItemType& iiType = Item::items[ground->getID()];
  620. if (iiType.blockSolid) {
  621. if (!iiType.allowPickupable || item->isMagicField() || item->isBlocking()) {
  622. if (!item->isPickupable()) {
  623. return RETURNVALUE_NOTENOUGHROOM;
  624. }
  625.  
  626. if (!iiType.hasHeight || iiType.pickupable || iiType.isBed()) {
  627. return RETURNVALUE_NOTENOUGHROOM;
  628. }
  629. }
  630. }
  631. }
  632.  
  633. if (items) {
  634. for (const Item* tileItem : *items) {
  635. const ItemType& iiType = Item::items[tileItem->getID()];
  636. if (!iiType.blockSolid) {
  637. continue;
  638. }
  639.  
  640. if (iiType.allowPickupable && !item->isMagicField() && !item->isBlocking()) {
  641. continue;
  642. }
  643.  
  644. if (!item->isPickupable()) {
  645. return RETURNVALUE_NOTENOUGHROOM;
  646. }
  647.  
  648. if (!iiType.hasHeight || iiType.pickupable || iiType.isBed()) {
  649. return RETURNVALUE_NOTENOUGHROOM;
  650. }
  651. }
  652. }
  653. }
  654. }
  655. return RETURNVALUE_NOERROR;
  656. }
  657.  
  658. ReturnValue Tile::queryMaxCount(int32_t, const Thing&, uint32_t count, uint32_t& maxQueryCount, uint32_t) const
  659. {
  660. maxQueryCount = std::max<uint32_t>(1, count);
  661. return RETURNVALUE_NOERROR;
  662. }
  663.  
  664. ReturnValue Tile::queryRemove(const Thing& thing, uint32_t count, uint32_t flags) const
  665. {
  666. int32_t index = getThingIndex(&thing);
  667. if (index == -1) {
  668. return RETURNVALUE_NOTPOSSIBLE;
  669. }
  670.  
  671. const Item* item = thing.getItem();
  672. if (item == nullptr) {
  673. return RETURNVALUE_NOTPOSSIBLE;
  674. }
  675.  
  676. if (count == 0 || (item->isStackable() && count > item->getItemCount())) {
  677. return RETURNVALUE_NOTPOSSIBLE;
  678. }
  679.  
  680. if (!item->isMoveable() && !hasBitSet(FLAG_IGNORENOTMOVEABLE, flags)) {
  681. return RETURNVALUE_NOTMOVEABLE;
  682. }
  683.  
  684. return RETURNVALUE_NOERROR;
  685. }
  686.  
  687. Tile* Tile::queryDestination(int32_t&, const Thing&, Item** destItem, uint32_t& flags)
  688. {
  689. Tile* destTile = nullptr;
  690. *destItem = nullptr;
  691.  
  692. if (hasFlag(TILESTATE_FLOORCHANGE_DOWN)) {
  693. uint16_t dx = tilePos.x;
  694. uint16_t dy = tilePos.y;
  695. uint8_t dz = tilePos.z + 1;
  696.  
  697. Tile* southDownTile = g_game.map.getTile(dx, dy - 1, dz);
  698. if (southDownTile && southDownTile->hasFlag(TILESTATE_FLOORCHANGE_SOUTH_ALT)) {
  699. dy -= 2;
  700. destTile = g_game.map.getTile(dx, dy, dz);
  701. } else {
  702. Tile* eastDownTile = g_game.map.getTile(dx - 1, dy, dz);
  703. if (eastDownTile && eastDownTile->hasFlag(TILESTATE_FLOORCHANGE_EAST_ALT)) {
  704. dx -= 2;
  705. destTile = g_game.map.getTile(dx, dy, dz);
  706. } else {
  707. Tile* downTile = g_game.map.getTile(dx, dy, dz);
  708. if (downTile) {
  709. if (downTile->hasFlag(TILESTATE_FLOORCHANGE_NORTH)) {
  710. ++dy;
  711. }
  712.  
  713. if (downTile->hasFlag(TILESTATE_FLOORCHANGE_SOUTH)) {
  714. --dy;
  715. }
  716.  
  717. if (downTile->hasFlag(TILESTATE_FLOORCHANGE_SOUTH_ALT)) {
  718. dy -= 2;
  719. }
  720.  
  721. if (downTile->hasFlag(TILESTATE_FLOORCHANGE_EAST)) {
  722. --dx;
  723. }
  724.  
  725. if (downTile->hasFlag(TILESTATE_FLOORCHANGE_EAST_ALT)) {
  726. dx -= 2;
  727. }
  728.  
  729. if (downTile->hasFlag(TILESTATE_FLOORCHANGE_WEST)) {
  730. ++dx;
  731. }
  732.  
  733. destTile = g_game.map.getTile(dx, dy, dz);
  734. }
  735. }
  736. }
  737. } else if (hasFlag(TILESTATE_FLOORCHANGE)) {
  738. uint16_t dx = tilePos.x;
  739. uint16_t dy = tilePos.y;
  740. uint8_t dz = tilePos.z - 1;
  741.  
  742. if (hasFlag(TILESTATE_FLOORCHANGE_NORTH)) {
  743. --dy;
  744. }
  745.  
  746. if (hasFlag(TILESTATE_FLOORCHANGE_SOUTH)) {
  747. ++dy;
  748. }
  749.  
  750. if (hasFlag(TILESTATE_FLOORCHANGE_EAST)) {
  751. ++dx;
  752. }
  753.  
  754. if (hasFlag(TILESTATE_FLOORCHANGE_WEST)) {
  755. --dx;
  756. }
  757.  
  758. if (hasFlag(TILESTATE_FLOORCHANGE_SOUTH_ALT)) {
  759. dy += 2;
  760. }
  761.  
  762. if (hasFlag(TILESTATE_FLOORCHANGE_EAST_ALT)) {
  763. dx += 2;
  764. }
  765.  
  766. destTile = g_game.map.getTile(dx, dy, dz);
  767. }
  768.  
  769. if (destTile == nullptr) {
  770. destTile = this;
  771. } else {
  772. flags |= FLAG_NOLIMIT; //Will ignore that there is blocking items/creatures
  773. }
  774.  
  775. if (destTile) {
  776. Thing* destThing = destTile->getTopDownItem();
  777. if (destThing) {
  778. *destItem = destThing->getItem();
  779. }
  780. }
  781. return destTile;
  782. }
  783.  
  784. void Tile::addThing(Thing* thing)
  785. {
  786. addThing(0, thing);
  787. }
  788.  
  789. void Tile::addThing(int32_t, Thing* thing)
  790. {
  791. Creature* creature = thing->getCreature();
  792. if (creature) {
  793. g_game.map.clearSpectatorCache();
  794. creature->setParent(this);
  795. CreatureVector* creatures = makeCreatures();
  796. creatures->insert(creatures->end(), creature);
  797. } else {
  798. Item* item = thing->getItem();
  799. if (item == nullptr) {
  800. return /*RETURNVALUE_NOTPOSSIBLE*/;
  801. }
  802.  
  803. TileItemVector* items = getItemList();
  804. if (items && items->size() >= 0xFFFF) {
  805. return /*RETURNVALUE_NOTPOSSIBLE*/;
  806. }
  807.  
  808. item->setParent(this);
  809.  
  810. const ItemType& itemType = Item::items[item->getID()];
  811. if (itemType.isGroundTile()) {
  812. if (ground == nullptr) {
  813. ground = item;
  814. onAddTileItem(item);
  815. } else {
  816. const ItemType& oldType = Item::items[ground->getID()];
  817.  
  818. Item* oldGround = ground;
  819. ground->setParent(nullptr);
  820. g_game.ReleaseItem(ground);
  821. ground = item;
  822. resetTileFlags(oldGround);
  823. setTileFlags(item);
  824. onUpdateTileItem(oldGround, oldType, item, itemType);
  825. postRemoveNotification(oldGround, nullptr, 0);
  826. }
  827. } else if (itemType.alwaysOnTop) {
  828. if (itemType.isSplash() && items) {
  829. //remove old splash if exists
  830. for (ItemVector::const_iterator it = items->getBeginTopItem(), end = items->getEndTopItem(); it != end; ++it) {
  831. Item* oldSplash = *it;
  832. if (!Item::items[oldSplash->getID()].isSplash()) {
  833. continue;
  834. }
  835.  
  836. removeThing(oldSplash, 1);
  837. oldSplash->setParent(nullptr);
  838. g_game.ReleaseItem(oldSplash);
  839. postRemoveNotification(oldSplash, nullptr, 0);
  840. break;
  841. }
  842. }
  843.  
  844. bool isInserted = false;
  845.  
  846. if (items) {
  847. for (auto it = items->getBeginTopItem(), end = items->getEndTopItem(); it != end; ++it) {
  848. //Note: this is different from internalAddThing
  849. if (itemType.alwaysOnTopOrder <= Item::items[(*it)->getID()].alwaysOnTopOrder) {
  850. items->insert(it, item);
  851. isInserted = true;
  852. break;
  853. }
  854. }
  855. } else {
  856. items = makeItemList();
  857. }
  858.  
  859. if (!isInserted) {
  860. items->push_back(item);
  861. }
  862.  
  863. onAddTileItem(item);
  864. } else {
  865. if (itemType.isMagicField()) {
  866. //remove old field item if exists
  867. if (items) {
  868. for (ItemVector::const_iterator it = items->getBeginDownItem(), end = items->getEndDownItem(); it != end; ++it) {
  869. MagicField* oldField = (*it)->getMagicField();
  870. if (oldField) {
  871. if (oldField->isReplaceable()) {
  872. removeThing(oldField, 1);
  873.  
  874. oldField->setParent(nullptr);
  875. g_game.ReleaseItem(oldField);
  876. postRemoveNotification(oldField, nullptr, 0);
  877. break;
  878. } else {
  879. //This magic field cannot be replaced.
  880. item->setParent(nullptr);
  881. g_game.ReleaseItem(item);
  882. return;
  883. }
  884. }
  885. }
  886. }
  887. }
  888.  
  889. items = makeItemList();
  890. items->insert(items->getBeginDownItem(), item);
  891. items->addDownItemCount(1);
  892. onAddTileItem(item);
  893. }
  894. }
  895. }
  896.  
  897. void Tile::updateThing(Thing* thing, uint16_t itemId, uint32_t count)
  898. {
  899. int32_t index = getThingIndex(thing);
  900. if (index == -1) {
  901. return /*RETURNVALUE_NOTPOSSIBLE*/;
  902. }
  903.  
  904. Item* item = thing->getItem();
  905. if (item == nullptr) {
  906. return /*RETURNVALUE_NOTPOSSIBLE*/;
  907. }
  908.  
  909. const ItemType& oldType = Item::items[item->getID()];
  910. const ItemType& newType = Item::items[itemId];
  911. resetTileFlags(item);
  912. item->setID(itemId);
  913. item->setSubType(count);
  914. setTileFlags(item);
  915. onUpdateTileItem(item, oldType, item, newType);
  916. }
  917.  
  918. void Tile::replaceThing(uint32_t index, Thing* thing)
  919. {
  920. int32_t pos = index;
  921.  
  922. Item* item = thing->getItem();
  923. if (item == nullptr) {
  924. return /*RETURNVALUE_NOTPOSSIBLE*/;
  925. }
  926.  
  927. Item* oldItem = nullptr;
  928. bool isInserted = false;
  929.  
  930. if (ground) {
  931. if (pos == 0) {
  932. oldItem = ground;
  933. ground = item;
  934. isInserted = true;
  935. }
  936.  
  937. --pos;
  938. }
  939.  
  940. TileItemVector* items = getItemList();
  941. if (items && !isInserted) {
  942. int32_t topItemSize = getTopItemCount();
  943. if (pos < topItemSize) {
  944. auto it = items->getBeginTopItem();
  945. it += pos;
  946.  
  947. oldItem = (*it);
  948. it = items->erase(it);
  949. items->insert(it, item);
  950. isInserted = true;
  951. }
  952.  
  953. pos -= topItemSize;
  954. }
  955.  
  956. CreatureVector* creatures = getCreatures();
  957. if (creatures) {
  958. if (!isInserted && pos < static_cast<int32_t>(creatures->size())) {
  959. return /*RETURNVALUE_NOTPOSSIBLE*/;
  960. }
  961.  
  962. pos -= static_cast<uint32_t>(creatures->size());
  963. }
  964.  
  965. if (items && !isInserted) {
  966. int32_t downItemSize = getDownItemCount();
  967. if (pos < downItemSize) {
  968. auto it = items->getBeginDownItem() + pos;
  969. oldItem = *it;
  970. it = items->erase(it);
  971. items->insert(it, item);
  972. isInserted = true;
  973. }
  974. }
  975.  
  976. if (isInserted) {
  977. item->setParent(this);
  978.  
  979. resetTileFlags(oldItem);
  980. setTileFlags(item);
  981. const ItemType& oldType = Item::items[oldItem->getID()];
  982. const ItemType& newType = Item::items[item->getID()];
  983. onUpdateTileItem(oldItem, oldType, item, newType);
  984.  
  985. oldItem->setParent(nullptr);
  986. return /*RETURNVALUE_NOERROR*/;
  987. }
  988. }
  989.  
  990. void Tile::removeThing(Thing* thing, uint32_t count)
  991. {
  992. Creature* creature = thing->getCreature();
  993. if (creature) {
  994. CreatureVector* creatures = getCreatures();
  995. if (creatures) {
  996. auto it = std::find(creatures->begin(), creatures->end(), thing);
  997. if (it != creatures->end()) {
  998. g_game.map.clearSpectatorCache();
  999. creatures->erase(it);
  1000. }
  1001. }
  1002. return;
  1003. }
  1004.  
  1005. Item* item = thing->getItem();
  1006. if (!item) {
  1007. return;
  1008. }
  1009.  
  1010. int32_t index = getThingIndex(item);
  1011. if (index == -1) {
  1012. return;
  1013. }
  1014.  
  1015. if (item == ground) {
  1016. ground->setParent(nullptr);
  1017. ground = nullptr;
  1018.  
  1019. SpectatorVec list;
  1020. g_game.map.getSpectators(list, getPosition(), true);
  1021. onRemoveTileItem(list, std::vector<int32_t>(list.size(), 0), item);
  1022. return;
  1023. }
  1024.  
  1025. TileItemVector* items = getItemList();
  1026. if (!items) {
  1027. return;
  1028. }
  1029.  
  1030. const ItemType& itemType = Item::items[item->getID()];
  1031. if (itemType.alwaysOnTop) {
  1032. auto it = std::find(items->getBeginTopItem(), items->getEndTopItem(), item);
  1033. if (it == items->getEndTopItem()) {
  1034. return;
  1035. }
  1036.  
  1037. std::vector<int32_t> oldStackPosVector;
  1038.  
  1039. SpectatorVec list;
  1040. g_game.map.getSpectators(list, getPosition(), true);
  1041. for (Creature* spectator : list) {
  1042. if (Player* tmpPlayer = spectator->getPlayer()) {
  1043. oldStackPosVector.push_back(getStackposOfItem(tmpPlayer, item));
  1044. }
  1045. }
  1046.  
  1047. item->setParent(nullptr);
  1048. items->erase(it);
  1049. onRemoveTileItem(list, oldStackPosVector, item);
  1050. } else {
  1051. auto it = std::find(items->getBeginDownItem(), items->getEndDownItem(), item);
  1052. if (it == items->getEndDownItem()) {
  1053. return;
  1054. }
  1055.  
  1056. if (itemType.stackable && count != item->getItemCount()) {
  1057. uint8_t newCount = static_cast<uint8_t>(std::max<int32_t>(0, static_cast<int32_t>(item->getItemCount() - count)));
  1058. item->setItemCount(newCount);
  1059. onUpdateTileItem(item, itemType, item, itemType);
  1060. } else {
  1061. std::vector<int32_t> oldStackPosVector;
  1062.  
  1063. SpectatorVec list;
  1064. g_game.map.getSpectators(list, getPosition(), true);
  1065. for (Creature* spectator : list) {
  1066. if (Player* tmpPlayer = spectator->getPlayer()) {
  1067. oldStackPosVector.push_back(getStackposOfItem(tmpPlayer, item));
  1068. }
  1069. }
  1070.  
  1071. item->setParent(nullptr);
  1072. items->erase(it);
  1073. items->addDownItemCount(-1);
  1074. onRemoveTileItem(list, oldStackPosVector, item);
  1075. }
  1076. }
  1077. }
  1078.  
  1079. void Tile::removeCreature(Creature* creature)
  1080. {
  1081. g_game.map.getQTNode(tilePos.x, tilePos.y)->removeCreature(creature);
  1082. removeThing(creature, 0);
  1083. }
  1084.  
  1085. int32_t Tile::getThingIndex(const Thing* thing) const
  1086. {
  1087. int32_t n = -1;
  1088. if (ground) {
  1089. if (ground == thing) {
  1090. return 0;
  1091. }
  1092. ++n;
  1093. }
  1094.  
  1095. const TileItemVector* items = getItemList();
  1096. if (items) {
  1097. const Item* item = thing->getItem();
  1098. if (item && item->isAlwaysOnTop()) {
  1099. for (auto it = items->getBeginTopItem(), end = items->getEndTopItem(); it != end; ++it) {
  1100. ++n;
  1101. if (*it == item) {
  1102. return n;
  1103. }
  1104. }
  1105. } else {
  1106. n += items->getTopItemCount();
  1107. }
  1108. }
  1109.  
  1110. if (const CreatureVector* creatures = getCreatures()) {
  1111. if (thing->getCreature()) {
  1112. for (Creature* creature : *creatures) {
  1113. ++n;
  1114. if (creature == thing) {
  1115. return n;
  1116. }
  1117. }
  1118. } else {
  1119. n += creatures->size();
  1120. }
  1121. }
  1122.  
  1123. if (items) {
  1124. const Item* item = thing->getItem();
  1125. if (item && !item->isAlwaysOnTop()) {
  1126. for (auto it = items->getBeginDownItem(), end = items->getEndDownItem(); it != end; ++it) {
  1127. ++n;
  1128. if (*it == item) {
  1129. return n;
  1130. }
  1131. }
  1132. }
  1133. }
  1134. return -1;
  1135. }
  1136.  
  1137. int32_t Tile::getClientIndexOfCreature(const Player* player, const Creature* creature) const
  1138. {
  1139. int32_t n;
  1140. if (ground) {
  1141. n = 1;
  1142. } else {
  1143. n = 0;
  1144. }
  1145.  
  1146. const TileItemVector* items = getItemList();
  1147. if (items) {
  1148. n += items->getTopItemCount();
  1149. }
  1150.  
  1151. if (const CreatureVector* creatures = getCreatures()) {
  1152. for (const Creature* c : boost::adaptors::reverse(*creatures)) {
  1153. if (c == creature) {
  1154. return n;
  1155. } else if (player->canSeeCreature(c)) {
  1156. ++n;
  1157. }
  1158. }
  1159. }
  1160. return -1;
  1161. }
  1162.  
  1163. int32_t Tile::getStackposOfCreature(const Player* player, const Creature* creature) const
  1164. {
  1165. int32_t n;
  1166. if (ground) {
  1167. n = 1;
  1168. } else {
  1169. n = 0;
  1170. }
  1171.  
  1172. const TileItemVector* items = getItemList();
  1173. if (items) {
  1174. n += items->getTopItemCount();
  1175. if (n >= 10) {
  1176. return -1;
  1177. }
  1178. }
  1179.  
  1180. if (const CreatureVector* creatures = getCreatures()) {
  1181. for (const Creature* c : boost::adaptors::reverse(*creatures)) {
  1182. if (c == creature) {
  1183. return n;
  1184. } else if (player->canSeeCreature(c)) {
  1185. if (++n >= 10) {
  1186. return -1;
  1187. }
  1188. }
  1189. }
  1190. }
  1191. return -1;
  1192. }
  1193.  
  1194. int32_t Tile::getStackposOfItem(const Player* player, const Item* item) const
  1195. {
  1196. int32_t n = 0;
  1197. if (ground) {
  1198. if (ground == item) {
  1199. return n;
  1200. }
  1201. ++n;
  1202. }
  1203.  
  1204. const TileItemVector* items = getItemList();
  1205. if (items) {
  1206. if (item->isAlwaysOnTop()) {
  1207. for (auto it = items->getBeginTopItem(), end = items->getEndTopItem(); it != end; ++it) {
  1208. if (*it == item) {
  1209. return n;
  1210. } else if (++n == 10) {
  1211. return -1;
  1212. }
  1213. }
  1214. } else {
  1215. n += items->getTopItemCount();
  1216. if (n >= 10) {
  1217. return -1;
  1218. }
  1219. }
  1220. }
  1221.  
  1222. if (const CreatureVector* creatures = getCreatures()) {
  1223. for (const Creature* creature : *creatures) {
  1224. if (player->canSeeCreature(creature)) {
  1225. if (++n >= 10) {
  1226. return -1;
  1227. }
  1228. }
  1229. }
  1230. }
  1231.  
  1232. if (items && !item->isAlwaysOnTop()) {
  1233. for (auto it = items->getBeginDownItem(), end = items->getEndDownItem(); it != end; ++it) {
  1234. if (*it == item) {
  1235. return n;
  1236. } else if (++n >= 10) {
  1237. return -1;
  1238. }
  1239. }
  1240. }
  1241. return -1;
  1242. }
  1243.  
  1244. size_t Tile::getFirstIndex() const
  1245. {
  1246. return 0;
  1247. }
  1248.  
  1249. size_t Tile::getLastIndex() const
  1250. {
  1251. return getThingCount();
  1252. }
  1253.  
  1254. uint32_t Tile::getItemTypeCount(uint16_t itemId, int32_t subType /*= -1*/) const
  1255. {
  1256. uint32_t count = 0;
  1257. if (ground && ground->getID() == itemId) {
  1258. count += Item::countByType(ground, subType);
  1259. }
  1260.  
  1261. const TileItemVector* items = getItemList();
  1262. if (items) {
  1263. for (const Item* item : *items) {
  1264. if (item->getID() == itemId) {
  1265. count += Item::countByType(item, subType);
  1266. }
  1267. }
  1268. }
  1269. return count;
  1270. }
  1271.  
  1272. Thing* Tile::getThing(size_t index) const
  1273. {
  1274. if (ground) {
  1275. if (index == 0) {
  1276. return ground;
  1277. }
  1278.  
  1279. --index;
  1280. }
  1281.  
  1282. const TileItemVector* items = getItemList();
  1283. if (items) {
  1284. uint32_t topItemSize = items->getTopItemCount();
  1285. if (index < topItemSize) {
  1286. return items->at(items->getDownItemCount() + index);
  1287. }
  1288. index -= topItemSize;
  1289. }
  1290.  
  1291. if (const CreatureVector* creatures = getCreatures()) {
  1292. if (index < creatures->size()) {
  1293. return (*creatures)[index];
  1294. }
  1295. index -= creatures->size();
  1296. }
  1297.  
  1298. if (items && index < items->getDownItemCount()) {
  1299. return items->at(index);
  1300. }
  1301. return nullptr;
  1302. }
  1303.  
  1304. void Tile::postAddNotification(Thing* thing, const Cylinder* oldParent, int32_t index, cylinderlink_t link /*= LINK_OWNER*/)
  1305. {
  1306. SpectatorVec list;
  1307. g_game.map.getSpectators(list, getPosition(), true, true);
  1308. for (Creature* spectator : list) {
  1309. spectator->getPlayer()->postAddNotification(thing, oldParent, index, LINK_NEAR);
  1310. }
  1311.  
  1312. //add a reference to this item, it may be deleted after being added (mailbox for example)
  1313. Creature* creature = thing->getCreature();
  1314. Item* item;
  1315. if (creature) {
  1316. creature->incrementReferenceCounter();
  1317. item = nullptr;
  1318. } else {
  1319. item = thing->getItem();
  1320. if (item) {
  1321. item->incrementReferenceCounter();
  1322. }
  1323. }
  1324.  
  1325. if (link == LINK_OWNER) {
  1326. if (hasFlag(TILESTATE_TELEPORT)) {
  1327. Teleport* teleport = getTeleportItem();
  1328. if (teleport) {
  1329. teleport->addThing(thing);
  1330. }
  1331. } else if (hasFlag(TILESTATE_TRASHHOLDER)) {
  1332. TrashHolder* trashholder = getTrashHolder();
  1333. if (trashholder) {
  1334. trashholder->addThing(thing);
  1335. }
  1336. } else if (hasFlag(TILESTATE_MAILBOX)) {
  1337. Mailbox* mailbox = getMailbox();
  1338. if (mailbox) {
  1339. mailbox->addThing(thing);
  1340. }
  1341. }
  1342.  
  1343. //calling movement scripts
  1344. if (creature) {
  1345. g_moveEvents->onCreatureMove(creature, this, oldParent ? oldParent->getPosition() : getPosition(), MOVE_EVENT_STEP_IN);
  1346. } else if (item) {
  1347. g_moveEvents->onItemMove(item, this, true);
  1348. }
  1349. }
  1350.  
  1351. //release the reference to this item onces we are finished
  1352. if (creature) {
  1353. g_game.ReleaseCreature(creature);
  1354. } else if (item) {
  1355. g_game.ReleaseItem(item);
  1356. }
  1357. }
  1358.  
  1359. void Tile::postRemoveNotification(Thing* thing, const Cylinder* newParent, int32_t index, cylinderlink_t)
  1360. {
  1361. SpectatorVec list;
  1362. g_game.map.getSpectators(list, getPosition(), true, true);
  1363.  
  1364. if (getThingCount() > 8) {
  1365. onUpdateTile(list);
  1366. }
  1367.  
  1368. for (Creature* spectator : list) {
  1369. spectator->getPlayer()->postRemoveNotification(thing, newParent, index, LINK_NEAR);
  1370. }
  1371.  
  1372. //calling movement scripts
  1373. Creature* creature = thing->getCreature();
  1374. if (creature) {
  1375. g_moveEvents->onCreatureMove(creature, this, getPosition(), MOVE_EVENT_STEP_OUT);
  1376. } else {
  1377. Item* item = thing->getItem();
  1378. if (item) {
  1379. g_moveEvents->onItemMove(item, this, false);
  1380. }
  1381. }
  1382. }
  1383.  
  1384. void Tile::internalAddThing(Thing* thing)
  1385. {
  1386. internalAddThing(0, thing);
  1387. }
  1388.  
  1389. void Tile::internalAddThing(uint32_t, Thing* thing)
  1390. {
  1391. thing->setParent(this);
  1392.  
  1393. Creature* creature = thing->getCreature();
  1394. if (creature) {
  1395. g_game.map.clearSpectatorCache();
  1396. CreatureVector* creatures = makeCreatures();
  1397. creatures->insert(creatures->begin(), creature);
  1398. } else {
  1399. Item* item = thing->getItem();
  1400. if (item == nullptr) {
  1401. return;
  1402. }
  1403.  
  1404. const ItemType& itemType = Item::items[item->getID()];
  1405. if (itemType.isGroundTile()) {
  1406. if (ground == nullptr) {
  1407. ground = item;
  1408. setTileFlags(item);
  1409. }
  1410. return;
  1411. }
  1412.  
  1413. TileItemVector* items = makeItemList();
  1414. if (items->size() >= 0xFFFF) {
  1415. return /*RETURNVALUE_NOTPOSSIBLE*/;
  1416. }
  1417.  
  1418. if (itemType.alwaysOnTop) {
  1419. bool isInserted = false;
  1420. for (auto it = items->getBeginTopItem(), end = items->getEndTopItem(); it != end; ++it) {
  1421. if (Item::items[(*it)->getID()].alwaysOnTopOrder > itemType.alwaysOnTopOrder) {
  1422. items->insert(it, item);
  1423. isInserted = true;
  1424. break;
  1425. }
  1426. }
  1427.  
  1428. if (!isInserted) {
  1429. items->push_back(item);
  1430. }
  1431. } else {
  1432. items->insert(items->getBeginDownItem(), item);
  1433. items->addDownItemCount(1);
  1434. }
  1435.  
  1436. setTileFlags(item);
  1437. }
  1438. }
  1439.  
  1440. void Tile::setTileFlags(const Item* item)
  1441. {
  1442. if (!hasFlag(TILESTATE_FLOORCHANGE)) {
  1443. const ItemType& it = Item::items[item->getID()];
  1444. if (it.floorChange != 0) {
  1445. setFlag(it.floorChange);
  1446. }
  1447. }
  1448.  
  1449. if (item->hasProperty(CONST_PROP_IMMOVABLEBLOCKSOLID)) {
  1450. setFlag(TILESTATE_IMMOVABLEBLOCKSOLID);
  1451. }
  1452.  
  1453. if (item->hasProperty(CONST_PROP_BLOCKPATH)) {
  1454. setFlag(TILESTATE_BLOCKPATH);
  1455. }
  1456.  
  1457. if (item->hasProperty(CONST_PROP_NOFIELDBLOCKPATH)) {
  1458. setFlag(TILESTATE_NOFIELDBLOCKPATH);
  1459. }
  1460.  
  1461. if (item->hasProperty(CONST_PROP_IMMOVABLENOFIELDBLOCKPATH)) {
  1462. setFlag(TILESTATE_IMMOVABLENOFIELDBLOCKPATH);
  1463. }
  1464.  
  1465. if (item->getTeleport()) {
  1466. setFlag(TILESTATE_TELEPORT);
  1467. }
  1468.  
  1469. if (item->getMagicField()) {
  1470. setFlag(TILESTATE_MAGICFIELD);
  1471. }
  1472.  
  1473. if (item->getMailbox()) {
  1474. setFlag(TILESTATE_MAILBOX);
  1475. }
  1476.  
  1477. if (item->getTrashHolder()) {
  1478. setFlag(TILESTATE_TRASHHOLDER);
  1479. }
  1480.  
  1481. if (item->hasProperty(CONST_PROP_BLOCKSOLID)) {
  1482. setFlag(TILESTATE_BLOCKSOLID);
  1483. }
  1484.  
  1485. if (item->getBed()) {
  1486. setFlag(TILESTATE_BED);
  1487. }
  1488.  
  1489. const Container* container = item->getContainer();
  1490. if (container && container->getDepotLocker()) {
  1491. setFlag(TILESTATE_DEPOT);
  1492. }
  1493.  
  1494. if (item->hasProperty(CONST_PROP_SUPPORTHANGABLE)) {
  1495. setFlag(TILESTATE_SUPPORTS_HANGABLE);
  1496. }
  1497. }
  1498.  
  1499. void Tile::resetTileFlags(const Item* item)
  1500. {
  1501. const ItemType& it = Item::items[item->getID()];
  1502. if (it.floorChange != 0) {
  1503. resetFlag(TILESTATE_FLOORCHANGE);
  1504. }
  1505.  
  1506. if (item->hasProperty(CONST_PROP_BLOCKSOLID) && !hasProperty(item, CONST_PROP_BLOCKSOLID)) {
  1507. resetFlag(TILESTATE_BLOCKSOLID);
  1508. }
  1509.  
  1510. if (item->hasProperty(CONST_PROP_IMMOVABLEBLOCKSOLID) && !hasProperty(item, CONST_PROP_IMMOVABLEBLOCKSOLID)) {
  1511. resetFlag(TILESTATE_IMMOVABLEBLOCKSOLID);
  1512. }
  1513.  
  1514. if (item->hasProperty(CONST_PROP_BLOCKPATH) && !hasProperty(item, CONST_PROP_BLOCKPATH)) {
  1515. resetFlag(TILESTATE_BLOCKPATH);
  1516. }
  1517.  
  1518. if (item->hasProperty(CONST_PROP_NOFIELDBLOCKPATH) && !hasProperty(item, CONST_PROP_NOFIELDBLOCKPATH)) {
  1519. resetFlag(TILESTATE_NOFIELDBLOCKPATH);
  1520. }
  1521.  
  1522. if (item->hasProperty(CONST_PROP_IMMOVABLEBLOCKPATH) && !hasProperty(item, CONST_PROP_IMMOVABLEBLOCKPATH)) {
  1523. resetFlag(TILESTATE_IMMOVABLEBLOCKPATH);
  1524. }
  1525.  
  1526. if (item->hasProperty(CONST_PROP_IMMOVABLENOFIELDBLOCKPATH) && !hasProperty(item, CONST_PROP_IMMOVABLENOFIELDBLOCKPATH)) {
  1527. resetFlag(TILESTATE_IMMOVABLENOFIELDBLOCKPATH);
  1528. }
  1529.  
  1530. if (item->getTeleport()) {
  1531. resetFlag(TILESTATE_TELEPORT);
  1532. }
  1533.  
  1534. if (item->getMagicField()) {
  1535. resetFlag(TILESTATE_MAGICFIELD);
  1536. }
  1537.  
  1538. if (item->getMailbox()) {
  1539. resetFlag(TILESTATE_MAILBOX);
  1540. }
  1541.  
  1542. if (item->getTrashHolder()) {
  1543. resetFlag(TILESTATE_TRASHHOLDER);
  1544. }
  1545.  
  1546. if (item->getBed()) {
  1547. resetFlag(TILESTATE_BED);
  1548. }
  1549.  
  1550. const Container* container = item->getContainer();
  1551. if (container && container->getDepotLocker()) {
  1552. resetFlag(TILESTATE_DEPOT);
  1553. }
  1554.  
  1555. if (item->hasProperty(CONST_PROP_SUPPORTHANGABLE)) {
  1556. resetFlag(TILESTATE_SUPPORTS_HANGABLE);
  1557. }
  1558. }
  1559.  
  1560. bool Tile::isMoveableBlocking() const
  1561. {
  1562. return !ground || hasFlag(TILESTATE_BLOCKSOLID);
  1563. }
  1564.  
  1565. Item* Tile::getUseItem() const
  1566. {
  1567. const TileItemVector* items = getItemList();
  1568. if (!items || items->size() == 0) {
  1569. return ground;
  1570. }
  1571.  
  1572. for (Item* item : boost::adaptors::reverse(*items)) {
  1573. if (Item::items[item->getID()].forceUse) {
  1574. return item;
  1575. }
  1576. }
  1577.  
  1578. Item* item = items->getTopDownItem();
  1579. if (!item) {
  1580. item = items->getTopTopItem();
  1581. }
  1582. return item;
  1583. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement