Advertisement
Prawdziwynrtn

Untitled

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