Advertisement
Guest User

Untitled

a guest
May 20th, 2019
74
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 29.83 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 "iomap.h"
  23. #include "iomapserialize.h"
  24. #include "combat.h"
  25. #include "creature.h"
  26. #include "game.h"
  27.  
  28. extern Game g_game;
  29.  
  30. bool Map::loadMap(const std::string& identifier, bool loadHouses)
  31. {
  32. IOMap loader;
  33. if (!loader.loadMap(this, identifier)) {
  34. std::cout << "[Fatal - Map::loadMap] " << loader.getLastErrorString() << std::endl;
  35. return false;
  36. }
  37.  
  38. if (!IOMap::loadSpawns(this)) {
  39. std::cout << "[Warning - Map::loadMap] Failed to load spawn data." << std::endl;
  40. }
  41.  
  42. if (loadHouses) {
  43. if (!IOMap::loadHouses(this)) {
  44. std::cout << "[Warning - Map::loadMap] Failed to load house data." << std::endl;
  45. }
  46.  
  47. IOMapSerialize::loadHouseInfo();
  48. IOMapSerialize::loadHouseItems(this);
  49. }
  50. return true;
  51. }
  52.  
  53. bool Map::save()
  54. {
  55. bool saved = false;
  56. for (uint32_t tries = 0; tries < 3; tries++) {
  57. if (IOMapSerialize::saveHouseInfo()) {
  58. saved = true;
  59. break;
  60. }
  61. }
  62.  
  63. if (!saved) {
  64. return false;
  65. }
  66.  
  67. saved = false;
  68. for (uint32_t tries = 0; tries < 3; tries++) {
  69. if (IOMapSerialize::saveHouseItems()) {
  70. saved = true;
  71. break;
  72. }
  73. }
  74. return saved;
  75. }
  76.  
  77. Tile* Map::getTile(uint16_t x, uint16_t y, uint8_t z) const
  78. {
  79. if (z >= MAP_MAX_LAYERS) {
  80. return nullptr;
  81. }
  82.  
  83. const QTreeLeafNode* leaf = QTreeNode::getLeafStatic<const QTreeLeafNode*, const QTreeNode*>(&root, x, y);
  84. if (!leaf) {
  85. return nullptr;
  86. }
  87.  
  88. const Floor* floor = leaf->getFloor(z);
  89. if (!floor) {
  90. return nullptr;
  91. }
  92. return floor->tiles[x & FLOOR_MASK][y & FLOOR_MASK];
  93. }
  94.  
  95. void Map::setTile(uint16_t x, uint16_t y, uint8_t z, Tile* newTile)
  96. {
  97. if (z >= MAP_MAX_LAYERS) {
  98. std::cout << "ERROR: Attempt to set tile on invalid coordinate " << Position(x, y, z) << "!" << std::endl;
  99. return;
  100. }
  101.  
  102. QTreeLeafNode::newLeaf = false;
  103. QTreeLeafNode* leaf = root.createLeaf(x, y, 15);
  104.  
  105. if (QTreeLeafNode::newLeaf) {
  106. //update north
  107. QTreeLeafNode* northLeaf = root.getLeaf(x, y - FLOOR_SIZE);
  108. if (northLeaf) {
  109. northLeaf->leafS = leaf;
  110. }
  111.  
  112. //update west leaf
  113. QTreeLeafNode* westLeaf = root.getLeaf(x - FLOOR_SIZE, y);
  114. if (westLeaf) {
  115. westLeaf->leafE = leaf;
  116. }
  117.  
  118. //update south
  119. QTreeLeafNode* southLeaf = root.getLeaf(x, y + FLOOR_SIZE);
  120. if (southLeaf) {
  121. leaf->leafS = southLeaf;
  122. }
  123.  
  124. //update east
  125. QTreeLeafNode* eastLeaf = root.getLeaf(x + FLOOR_SIZE, y);
  126. if (eastLeaf) {
  127. leaf->leafE = eastLeaf;
  128. }
  129. }
  130.  
  131. Floor* floor = leaf->createFloor(z);
  132. uint32_t offsetX = x & FLOOR_MASK;
  133. uint32_t offsetY = y & FLOOR_MASK;
  134.  
  135. Tile*& tile = floor->tiles[offsetX][offsetY];
  136. if (tile) {
  137. TileItemVector* items = newTile->getItemList();
  138. if (items) {
  139. for (auto it = items->rbegin(), end = items->rend(); it != end; ++it) {
  140. tile->addThing(*it);
  141. }
  142. items->clear();
  143. }
  144.  
  145. Item* ground = newTile->getGround();
  146. if (ground) {
  147. tile->addThing(ground);
  148. newTile->setGround(nullptr);
  149. }
  150. delete newTile;
  151. } else {
  152. tile = newTile;
  153. }
  154. }
  155.  
  156. bool Map::placeCreature(const Position& centerPos, Creature* creature, bool extendedPos/* = false*/, bool forceLogin/* = false*/)
  157. {
  158. bool foundTile;
  159. bool placeInPZ;
  160.  
  161. Tile* tile = getTile(centerPos.x, centerPos.y, centerPos.z);
  162. if (tile) {
  163. placeInPZ = tile->hasFlag(TILESTATE_PROTECTIONZONE);
  164. ReturnValue ret = tile->queryAdd(0, *creature, 1, FLAG_IGNOREBLOCKITEM);
  165. foundTile = forceLogin || ret == RETURNVALUE_NOERROR || ret == RETURNVALUE_PLAYERISNOTINVITED;
  166. } else {
  167. placeInPZ = false;
  168. foundTile = false;
  169. }
  170.  
  171. if (!foundTile) {
  172. static std::vector<std::pair<int32_t, int32_t>> extendedRelList {
  173. {0, -2},
  174. {-1, -1}, {0, -1}, {1, -1},
  175. {-2, 0}, {-1, 0}, {1, 0}, {2, 0},
  176. {-1, 1}, {0, 1}, {1, 1},
  177. {0, 2}
  178. };
  179.  
  180. static std::vector<std::pair<int32_t, int32_t>> normalRelList {
  181. {-1, -1}, {0, -1}, {1, -1},
  182. {-1, 0}, {1, 0},
  183. {-1, 1}, {0, 1}, {1, 1}
  184. };
  185.  
  186. std::vector<std::pair<int32_t, int32_t>>& relList = (extendedPos ? extendedRelList : normalRelList);
  187.  
  188. if (extendedPos) {
  189. std::shuffle(relList.begin(), relList.begin() + 4, getRandomGenerator());
  190. std::shuffle(relList.begin() + 4, relList.end(), getRandomGenerator());
  191. } else {
  192. std::shuffle(relList.begin(), relList.end(), getRandomGenerator());
  193. }
  194.  
  195. for (const auto& it : relList) {
  196. Position tryPos(centerPos.x + it.first, centerPos.y + it.second, centerPos.z);
  197.  
  198. tile = getTile(tryPos.x, tryPos.y, tryPos.z);
  199. if (!tile || (placeInPZ && !tile->hasFlag(TILESTATE_PROTECTIONZONE))) {
  200. continue;
  201. }
  202.  
  203. if (tile->queryAdd(0, *creature, 1, 0) == RETURNVALUE_NOERROR) {
  204. if (!extendedPos || isSightClear(centerPos, tryPos, false)) {
  205. foundTile = true;
  206. break;
  207. }
  208. }
  209. }
  210.  
  211. if (!foundTile) {
  212. return false;
  213. }
  214. }
  215.  
  216. int32_t index = 0;
  217. uint32_t flags = 0;
  218. Item* toItem = nullptr;
  219.  
  220. Cylinder* toCylinder = tile->queryDestination(index, *creature, &toItem, flags);
  221. toCylinder->internalAddThing(creature);
  222.  
  223. const Position& dest = toCylinder->getPosition();
  224. getQTNode(dest.x, dest.y)->addCreature(creature);
  225. return true;
  226. }
  227.  
  228. void Map::moveCreature(Creature& creature, Tile& newTile, bool forceTeleport/* = false*/)
  229. {
  230. Tile& oldTile = *creature.getTile();
  231.  
  232. Position oldPos = oldTile.getPosition();
  233. Position newPos = newTile.getPosition();
  234.  
  235. bool teleport = forceTeleport || !newTile.getGround() || !Position::areInRange<1, 1, 0>(oldPos, newPos);
  236.  
  237. SpectatorVec list;
  238. getSpectators(list, oldPos, true);
  239. getSpectators(list, newPos, true);
  240.  
  241. std::vector<int32_t> oldStackPosVector;
  242. for (Creature* spectator : list) {
  243. if (Player* tmpPlayer = spectator->getPlayer()) {
  244. if (tmpPlayer->canSeeCreature(&creature)) {
  245. oldStackPosVector.push_back(oldTile.getClientIndexOfCreature(tmpPlayer, &creature));
  246. } else {
  247. oldStackPosVector.push_back(-1);
  248. }
  249. }
  250. }
  251.  
  252. //remove the creature
  253. oldTile.removeThing(&creature, 0);
  254.  
  255. QTreeLeafNode* leaf = getQTNode(oldPos.x, oldPos.y);
  256. QTreeLeafNode* new_leaf = getQTNode(newPos.x, newPos.y);
  257.  
  258. // Switch the node ownership
  259. if (leaf != new_leaf) {
  260. leaf->removeCreature(&creature);
  261. new_leaf->addCreature(&creature);
  262. }
  263.  
  264. //add the creature
  265. newTile.addThing(&creature);
  266.  
  267. if (!teleport) {
  268. if (oldPos.y > newPos.y) {
  269. creature.setDirection(DIRECTION_NORTH);
  270. } else if (oldPos.y < newPos.y) {
  271. creature.setDirection(DIRECTION_SOUTH);
  272. }
  273.  
  274. if (oldPos.x < newPos.x) {
  275. creature.setDirection(DIRECTION_EAST);
  276. } else if (oldPos.x > newPos.x) {
  277. creature.setDirection(DIRECTION_WEST);
  278. }
  279. }
  280.  
  281. //send to client
  282. size_t i = 0;
  283. for (Creature* spectator : list) {
  284. if (Player* tmpPlayer = spectator->getPlayer()) {
  285. //Use the correct stackpos
  286. int32_t stackpos = oldStackPosVector[i++];
  287. if (stackpos != -1) {
  288. tmpPlayer->sendCreatureMove(&creature, newPos, newTile.getStackposOfCreature(tmpPlayer, &creature), oldPos, stackpos, teleport);
  289. }
  290. }
  291. }
  292.  
  293. //event method
  294. for (Creature* spectator : list) {
  295. spectator->onCreatureMove(&creature, &newTile, newPos, &oldTile, oldPos, teleport);
  296. }
  297.  
  298. oldTile.postRemoveNotification(&creature, &newTile, 0);
  299. newTile.postAddNotification(&creature, &oldTile, 0);
  300. }
  301.  
  302. void Map::getSpectatorsInternal(SpectatorVec& list, const Position& centerPos, int32_t minRangeX, int32_t maxRangeX, int32_t minRangeY, int32_t maxRangeY, int32_t minRangeZ, int32_t maxRangeZ, bool onlyPlayers) const
  303. {
  304. int_fast16_t min_y = centerPos.y + minRangeY;
  305. int_fast16_t min_x = centerPos.x + minRangeX;
  306. int_fast16_t max_y = centerPos.y + maxRangeY;
  307. int_fast16_t max_x = centerPos.x + maxRangeX;
  308.  
  309. int32_t minoffset = centerPos.getZ() - maxRangeZ;
  310. uint16_t x1 = std::min<uint32_t>(0xFFFF, std::max<int32_t>(0, (min_x + minoffset)));
  311. uint16_t y1 = std::min<uint32_t>(0xFFFF, std::max<int32_t>(0, (min_y + minoffset)));
  312.  
  313. int32_t maxoffset = centerPos.getZ() - minRangeZ;
  314. uint16_t x2 = std::min<uint32_t>(0xFFFF, std::max<int32_t>(0, (max_x + maxoffset)));
  315. uint16_t y2 = std::min<uint32_t>(0xFFFF, std::max<int32_t>(0, (max_y + maxoffset)));
  316.  
  317. int32_t startx1 = x1 - (x1 % FLOOR_SIZE);
  318. int32_t starty1 = y1 - (y1 % FLOOR_SIZE);
  319. int32_t endx2 = x2 - (x2 % FLOOR_SIZE);
  320. int32_t endy2 = y2 - (y2 % FLOOR_SIZE);
  321.  
  322. const QTreeLeafNode* startLeaf = QTreeNode::getLeafStatic<const QTreeLeafNode*, const QTreeNode*>(&root, startx1, starty1);
  323. const QTreeLeafNode* leafS = startLeaf;
  324. const QTreeLeafNode* leafE;
  325.  
  326. for (int_fast32_t ny = starty1; ny <= endy2; ny += FLOOR_SIZE) {
  327. leafE = leafS;
  328. for (int_fast32_t nx = startx1; nx <= endx2; nx += FLOOR_SIZE) {
  329. if (leafE) {
  330. const CreatureVector& node_list = (onlyPlayers ? leafE->player_list : leafE->creature_list);
  331. CreatureVector::const_iterator node_iter = node_list.begin();
  332. CreatureVector::const_iterator node_end = node_list.end();
  333. if (node_iter != node_end) {
  334. do {
  335. Creature* creature = *node_iter;
  336.  
  337. const Position& cpos = creature->getPosition();
  338. if (cpos.z < minRangeZ || cpos.z > maxRangeZ) {
  339. continue;
  340. }
  341.  
  342. int_fast16_t offsetZ = Position::getOffsetZ(centerPos, cpos);
  343. if (cpos.y < (min_y + offsetZ) || cpos.y > (max_y + offsetZ)) {
  344. continue;
  345. }
  346.  
  347. if (cpos.x < (min_x + offsetZ) || cpos.x > (max_x + offsetZ)) {
  348. continue;
  349. }
  350.  
  351. list.insert(creature);
  352. } while (++node_iter != node_end);
  353. }
  354. leafE = leafE->leafE;
  355. } else {
  356. leafE = QTreeNode::getLeafStatic<const QTreeLeafNode*, const QTreeNode*>(&root, nx + FLOOR_SIZE, ny);
  357. }
  358. }
  359.  
  360. if (leafS) {
  361. leafS = leafS->leafS;
  362. } else {
  363. leafS = QTreeNode::getLeafStatic<const QTreeLeafNode*, const QTreeNode*>(&root, startx1, ny + FLOOR_SIZE);
  364. }
  365. }
  366. }
  367.  
  368. void Map::getSpectators(SpectatorVec& list, const Position& centerPos, bool multifloor /*= false*/, bool onlyPlayers /*= false*/, int32_t minRangeX /*= 0*/, int32_t maxRangeX /*= 0*/, int32_t minRangeY /*= 0*/, int32_t maxRangeY /*= 0*/)
  369. {
  370. if (centerPos.z >= MAP_MAX_LAYERS) {
  371. return;
  372. }
  373.  
  374. bool foundCache = false;
  375. bool cacheResult = false;
  376.  
  377. minRangeX = (minRangeX == 0 ? -maxViewportX : -minRangeX);
  378. maxRangeX = (maxRangeX == 0 ? maxViewportX : maxRangeX);
  379. minRangeY = (minRangeY == 0 ? -maxViewportY : -minRangeY);
  380. maxRangeY = (maxRangeY == 0 ? maxViewportY : maxRangeY);
  381.  
  382. if (minRangeX == -maxViewportX && maxRangeX == maxViewportX && minRangeY == -maxViewportY && maxRangeY == maxViewportY && multifloor) {
  383. if (onlyPlayers) {
  384. auto it = playersSpectatorCache.find(centerPos);
  385. if (it != playersSpectatorCache.end()) {
  386. if (!list.empty()) {
  387. const SpectatorVec& cachedList = it->second;
  388. list.insert(cachedList.begin(), cachedList.end());
  389. } else {
  390. list = it->second;
  391. }
  392.  
  393. foundCache = true;
  394. }
  395. }
  396.  
  397. if (!foundCache) {
  398. auto it = spectatorCache.find(centerPos);
  399. if (it != spectatorCache.end()) {
  400. if (!onlyPlayers) {
  401. if (!list.empty()) {
  402. const SpectatorVec& cachedList = it->second;
  403. list.insert(cachedList.begin(), cachedList.end());
  404. } else {
  405. list = it->second;
  406. }
  407. } else {
  408. const SpectatorVec& cachedList = it->second;
  409. for (Creature* spectator : cachedList) {
  410. if (spectator->getPlayer()) {
  411. list.insert(spectator);
  412. }
  413. }
  414. }
  415.  
  416. foundCache = true;
  417. } else {
  418. cacheResult = true;
  419. }
  420. }
  421. }
  422.  
  423. if (!foundCache) {
  424. int32_t minRangeZ;
  425. int32_t maxRangeZ;
  426.  
  427. if (multifloor) {
  428. if (centerPos.z > 7) {
  429. //underground
  430.  
  431. //8->15
  432. minRangeZ = std::max<int32_t>(centerPos.getZ() - 2, 0);
  433. maxRangeZ = std::min<int32_t>(centerPos.getZ() + 2, MAP_MAX_LAYERS - 1);
  434. } else if (centerPos.z == 6) {
  435. minRangeZ = 0;
  436. maxRangeZ = 8;
  437. } else if (centerPos.z == 7) {
  438. minRangeZ = 0;
  439. maxRangeZ = 9;
  440. } else {
  441. minRangeZ = 0;
  442. maxRangeZ = 7;
  443. }
  444. } else {
  445. minRangeZ = centerPos.z;
  446. maxRangeZ = centerPos.z;
  447. }
  448.  
  449. getSpectatorsInternal(list, centerPos, minRangeX, maxRangeX, minRangeY, maxRangeY, minRangeZ, maxRangeZ, onlyPlayers);
  450.  
  451. if (cacheResult) {
  452. if (onlyPlayers) {
  453. playersSpectatorCache[centerPos] = list;
  454. } else {
  455. spectatorCache[centerPos] = list;
  456. }
  457. }
  458. }
  459. }
  460.  
  461. void Map::clearSpectatorCache()
  462. {
  463. spectatorCache.clear();
  464. playersSpectatorCache.clear();
  465. }
  466.  
  467. bool Map::canThrowObjectTo(const Position& fromPos, const Position& toPos, bool checkLineOfSight /*= true*/,
  468. int32_t rangex /*= Map::maxClientViewportX*/, int32_t rangey /*= Map::maxClientViewportY*/,
  469. MapPathFinding_t path/*= MAPPATH_RUNE*/) const
  470. {
  471. //z checks
  472. //underground 8->15
  473. //ground level and above 7->0
  474. if((fromPos.z >= 8 && toPos.z < 8) || (toPos.z >= 8 &&
  475. fromPos.z < 8) || fromPos.z - fromPos.z > 2)
  476. return false;
  477.  
  478. int32_t deltax = std::abs(fromPos.x - toPos.x), deltay = std::abs(
  479. fromPos.y - toPos.y), deltaz = std::abs(fromPos.z - toPos.z);
  480. if(deltax - deltaz > rangex || deltay - deltaz > rangey)
  481. return false;
  482.  
  483. if(!checkLineOfSight)
  484. return true;
  485.  
  486. return isSightClear(fromPos, toPos, false, path);
  487. }
  488.  
  489. bool Map::checkSightLine(const Position fromPos, const Position toPos) const
  490. {
  491. Position start(fromPos.z > toPos.z ? toPos : fromPos);
  492. Position destination(fromPos.z > toPos.z ? fromPos : toPos);
  493.  
  494. const int8_t mx = start.x < destination.x ? 1 : start.x == destination.x ? 0 : -1;
  495. const int8_t my = start.y < destination.y ? 1 : start.y == destination.y ? 0 : -1;
  496.  
  497. int32_t A = Position::getOffsetY(destination, start);
  498. int32_t B = Position::getOffsetX(start, destination);
  499. int32_t C = -(A * destination.x + B * destination.y);
  500.  
  501. int32_t move_x = std::abs(start.x - destination.x),
  502. move_y = std::abs(start.y - destination.y);
  503.  
  504. uint16_t countX = move_y != 0 ? std::max(0, (move_x - 1) / move_y) : 0,
  505. countY = move_x != 0 ? std::max(0, (move_y - 1) / move_x) : 0;
  506.  
  507. int16_t check = 0;
  508. while(start.x != destination.x || start.y != destination.y)
  509. {
  510. bool useDefault = false, checkAlgorithm = true;
  511. if(check <= 1)
  512. {
  513. if(check == 0 && A < 0 && B > 0)
  514. {
  515. // north west -1, -1
  516. if(start.y != destination.y)
  517. start.y += my;
  518.  
  519. if(start.x != destination.x)
  520. start.x += mx;
  521.  
  522. checkAlgorithm = false;
  523. }
  524. else if(A > 0 && B > 0)
  525. {
  526. // south west 1, 1
  527. if(move_y > move_x)
  528. {
  529. if(start.x != destination.x)
  530. start.x += mx;
  531.  
  532. if(start.y != destination.y)
  533. start.y += my;
  534.  
  535. checkAlgorithm = false;
  536. }
  537. }
  538. else if(check == 0 && A < 0 && B < 0)
  539. {
  540. // north east -1, -1
  541. if(move_x > move_y)
  542. {
  543. if(start.x != destination.x)
  544. start.x += mx;
  545.  
  546. if(start.y != destination.y)
  547. start.y += my;
  548.  
  549. checkAlgorithm = false;
  550. }
  551. }
  552. }
  553.  
  554. ++check;
  555. if(checkAlgorithm)
  556. {
  557. if(move_x > move_y)
  558. {
  559. if(check <= countX)
  560. {
  561. if(start.x != destination.x)
  562. start.x += mx;
  563. }
  564. else if(check == countX + 1)
  565. {
  566. if(start.x != destination.x)
  567. start.x += mx;
  568.  
  569. if(move_x <= move_y + 1)
  570. {
  571. if(start.y != destination.y)
  572. start.y += my;
  573. }
  574.  
  575. // check = 1;
  576. }
  577. else
  578. useDefault = true;
  579. }
  580. else if(move_y > move_x)
  581. {
  582. if(check <= countY)
  583. {
  584. if(start.y != destination.y)
  585. start.y += my;
  586. }
  587. else if(check == countY + 1)
  588. {
  589. if(start.x != destination.x)
  590. start.x += mx;
  591.  
  592. if(start.y != destination.y)
  593. start.y += my;
  594.  
  595. // check = 1;
  596. }
  597. else
  598. useDefault = true;
  599. }
  600. else
  601. {
  602. if(start.x != destination.x)
  603. start.x += mx;
  604.  
  605. if(start.y != destination.y)
  606. start.y += my;
  607. }
  608. }
  609.  
  610. if(useDefault)
  611. {
  612. int32_t move_hor = std::abs(A * (start.x + mx) + B * (start.y) + C);
  613. int32_t move_ver = std::abs(A * (start.x) + B * (start.y + my) + C);
  614. int32_t move_cross = std::abs(A * (start.x + mx) + B * (start.y + my) + C);
  615.  
  616. if(start.y != destination.y && (start.x == destination.x || move_hor > move_ver || move_hor > move_cross))
  617. start.y += my;
  618.  
  619. if(start.x != destination.x && (start.y == destination.y || move_ver > move_hor || move_ver > move_cross))
  620. start.x += mx;
  621. }
  622.  
  623. // g_game.addMagicEffect(start, MAGIC_EFFECT_CARNIPHILA, false);
  624.  
  625. const Tile* tile = const_cast<Map*>(this)->getTile(start);
  626. if(tile && (tile->hasProperty(BLOCKPROJECTILE) || tile->hasSpecialDoors(ignoreDoors)))
  627. return false;
  628. }
  629.  
  630. // now we need to perform a jump between floors to see if everything is clear (literally)
  631. while(start.z != destination.z)
  632. {
  633. const Tile* tile = const_cast<Map*>(this)->getTile(start.x, start.y, start.z);
  634. if(tile && tile->m_ground)
  635. return false;
  636.  
  637. start.z++;
  638. }
  639.  
  640. return true;
  641. }
  642.  
  643. bool Map::isSightClear(const Position& fromPos, const Position& toPos, bool floorCheck, MapPathFinding_t path/*= MAPPATH_RUNE*/) const
  644. {
  645. if(floorCheck && fromPos.z != toPos.z)
  646. return false;
  647.  
  648. // Cast two converging rays and see if either yields a result.
  649. if(path == MAPPATH_RUNE)
  650. return checkSightLine(fromPos, toPos, true);
  651. else if(!checkSightLine(fromPos, toPos))
  652. {
  653. const Tile* tile = const_cast<Map*>(this)->getTile(fromPos.x, fromPos.y, fromPos.z - 1);
  654. if(tile && tile->m_ground)
  655. return false;
  656.  
  657. if(fromPos.z > 0 && path == MAPPATH_ITEM)
  658. {
  659. if(checkSightLine(fromPos, Position(fromPos.x, fromPos.y, fromPos.z - 1)) &&
  660. checkSightLine(Position(fromPos.x, fromPos.y, fromPos.z - 1), Position(toPos.x, toPos.y, toPos.z - 1)) &&
  661. checkSightLine(Position(toPos.x, toPos.y, toPos.z - 1), toPos))
  662. return true;
  663. }
  664.  
  665. return false;
  666. }
  667.  
  668. return true;
  669. }
  670.  
  671. const Tile* Map::canWalkTo(const Creature* creature, const Position& pos, bool ignoreTile)
  672. {
  673. switch(creature->getWalkCache(pos))
  674. {
  675. case 0:
  676. return NULL;
  677. case 1:
  678. return getTile(pos);
  679. default:
  680. break;
  681. }
  682.  
  683. //used for none-cached tiles
  684. Tile* tile = getTile(pos);
  685. if(!tile)
  686. return NULL;
  687.  
  688. if((ignoreTile || creature->getTile() != tile) && tile->__queryAdd(0, creature, 1,
  689. FLAG_PATHFINDING | FLAG_IGNOREFIELDDAMAGE) != RET_NOERROR)
  690. return NULL;
  691.  
  692. return tile;
  693. }
  694.  
  695. bool Map::getPathMatching(const Creature& creature, std::forward_list<Direction>& dirList, const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) const
  696. {
  697. Position pos = creature.getPosition();
  698. Position endPos;
  699.  
  700. AStarNodes nodes(pos.x, pos.y);
  701.  
  702. int32_t bestMatch = 0;
  703.  
  704. static int_fast32_t dirNeighbors[8][5][2] = {
  705. {{-1, 0}, {0, 1}, {1, 0}, {1, 1}, {-1, 1}},
  706. {{-1, 0}, {0, 1}, {0, -1}, {-1, -1}, {-1, 1}},
  707. {{-1, 0}, {1, 0}, {0, -1}, {-1, -1}, {1, -1}},
  708. {{0, 1}, {1, 0}, {0, -1}, {1, -1}, {1, 1}},
  709. {{1, 0}, {0, -1}, {-1, -1}, {1, -1}, {1, 1}},
  710. {{-1, 0}, {0, -1}, {-1, -1}, {1, -1}, {-1, 1}},
  711. {{0, 1}, {1, 0}, {1, -1}, {1, 1}, {-1, 1}},
  712. {{-1, 0}, {0, 1}, {-1, -1}, {1, 1}, {-1, 1}}
  713. };
  714. static int_fast32_t allNeighbors[8][2] = {
  715. {-1, 0}, {0, 1}, {1, 0}, {0, -1}, {-1, -1}, {1, -1}, {1, 1}, {-1, 1}
  716. };
  717.  
  718. const Position startPos = pos;
  719.  
  720. AStarNode* found = nullptr;
  721. while (fpp.maxSearchDist != 0 || nodes.getClosedNodes() < 100) {
  722. AStarNode* n = nodes.getBestNode();
  723. if (!n) {
  724. if (found) {
  725. break;
  726. }
  727. return false;
  728. }
  729.  
  730. const int_fast32_t x = n->x;
  731. const int_fast32_t y = n->y;
  732. pos.x = x;
  733. pos.y = y;
  734. if (pathCondition(startPos, pos, fpp, bestMatch)) {
  735. found = n;
  736. endPos = pos;
  737. if (bestMatch == 0) {
  738. break;
  739. }
  740. }
  741.  
  742. uint_fast32_t dirCount;
  743. int_fast32_t* neighbors;
  744. if (n->parent) {
  745. const int_fast32_t offset_x = n->parent->x - x;
  746. const int_fast32_t offset_y = n->parent->y - y;
  747. if (offset_y == 0) {
  748. if (offset_x == -1) {
  749. neighbors = *dirNeighbors[DIRECTION_WEST];
  750. } else {
  751. neighbors = *dirNeighbors[DIRECTION_EAST];
  752. }
  753. } else if (!fpp.allowDiagonal || offset_x == 0) {
  754. if (offset_y == -1) {
  755. neighbors = *dirNeighbors[DIRECTION_NORTH];
  756. } else {
  757. neighbors = *dirNeighbors[DIRECTION_SOUTH];
  758. }
  759. } else if (offset_y == -1) {
  760. if (offset_x == -1) {
  761. neighbors = *dirNeighbors[DIRECTION_NORTHWEST];
  762. } else {
  763. neighbors = *dirNeighbors[DIRECTION_NORTHEAST];
  764. }
  765. } else if (offset_x == -1) {
  766. neighbors = *dirNeighbors[DIRECTION_SOUTHWEST];
  767. } else {
  768. neighbors = *dirNeighbors[DIRECTION_SOUTHEAST];
  769. }
  770. dirCount = fpp.allowDiagonal ? 5 : 3;
  771. } else {
  772. dirCount = 8;
  773. neighbors = *allNeighbors;
  774. }
  775.  
  776. const int_fast32_t f = n->f;
  777. for (uint_fast32_t i = 0; i < dirCount; ++i) {
  778. pos.x = x + *neighbors++;
  779. pos.y = y + *neighbors++;
  780.  
  781. if (fpp.maxSearchDist != 0 && (Position::getDistanceX(startPos, pos) > fpp.maxSearchDist || Position::getDistanceY(startPos, pos) > fpp.maxSearchDist)) {
  782. continue;
  783. }
  784.  
  785. if (fpp.keepDistance && !pathCondition.isInRange(startPos, pos, fpp)) {
  786. continue;
  787. }
  788.  
  789. const Tile* tile;
  790. AStarNode* neighborNode = nodes.getNodeByPosition(pos.x, pos.y);
  791. if (neighborNode) {
  792. tile = getTile(pos.x, pos.y, pos.z);
  793. } else {
  794. tile = canWalkTo(creature, pos);
  795. if (!tile) {
  796. continue;
  797. }
  798. }
  799.  
  800. //The cost (g) for this neighbor
  801. const int_fast32_t cost = AStarNodes::getMapWalkCost(n, pos);
  802. const int_fast32_t extraCost = AStarNodes::getTileWalkCost(creature, tile);
  803. const int_fast32_t newf = f + cost + extraCost;
  804.  
  805. if (neighborNode) {
  806. if (neighborNode->f <= newf) {
  807. //The node on the closed/open list is cheaper than this one
  808. continue;
  809. }
  810.  
  811. neighborNode->f = newf;
  812. neighborNode->parent = n;
  813. nodes.openNode(neighborNode);
  814. } else {
  815. //Does not exist in the open/closed list, create a new node
  816. neighborNode = nodes.createOpenNode(n, pos.x, pos.y, newf);
  817. if (!neighborNode) {
  818. if (found) {
  819. break;
  820. }
  821. return false;
  822. }
  823. }
  824. }
  825.  
  826. nodes.closeNode(n);
  827. }
  828.  
  829. if (!found) {
  830. return false;
  831. }
  832.  
  833. int_fast32_t prevx = endPos.x;
  834. int_fast32_t prevy = endPos.y;
  835.  
  836. found = found->parent;
  837. while (found) {
  838. pos.x = found->x;
  839. pos.y = found->y;
  840.  
  841. int_fast32_t dx = pos.getX() - prevx;
  842. int_fast32_t dy = pos.getY() - prevy;
  843.  
  844. prevx = pos.x;
  845. prevy = pos.y;
  846.  
  847. if (dx == 1 && dy == 1) {
  848. dirList.push_front(DIRECTION_NORTHWEST);
  849. } else if (dx == -1 && dy == 1) {
  850. dirList.push_front(DIRECTION_NORTHEAST);
  851. } else if (dx == 1 && dy == -1) {
  852. dirList.push_front(DIRECTION_SOUTHWEST);
  853. } else if (dx == -1 && dy == -1) {
  854. dirList.push_front(DIRECTION_SOUTHEAST);
  855. } else if (dx == 1) {
  856. dirList.push_front(DIRECTION_WEST);
  857. } else if (dx == -1) {
  858. dirList.push_front(DIRECTION_EAST);
  859. } else if (dy == 1) {
  860. dirList.push_front(DIRECTION_NORTH);
  861. } else if (dy == -1) {
  862. dirList.push_front(DIRECTION_SOUTH);
  863. }
  864.  
  865. found = found->parent;
  866. }
  867. return true;
  868. }
  869.  
  870. // AStarNodes
  871.  
  872. AStarNodes::AStarNodes(uint32_t x, uint32_t y)
  873. : nodes(), openNodes()
  874. {
  875. curNode = 1;
  876. closedNodes = 0;
  877. openNodes[0] = true;
  878.  
  879. AStarNode& startNode = nodes[0];
  880. startNode.parent = nullptr;
  881. startNode.x = x;
  882. startNode.y = y;
  883. startNode.f = 0;
  884. nodeTable[(x << 16) | y] = nodes;
  885. }
  886.  
  887. AStarNode* AStarNodes::createOpenNode(AStarNode* parent, uint32_t x, uint32_t y, int_fast32_t f)
  888. {
  889. if (curNode >= MAX_NODES) {
  890. return nullptr;
  891. }
  892.  
  893. size_t retNode = curNode++;
  894. openNodes[retNode] = true;
  895.  
  896. AStarNode* node = nodes + retNode;
  897. nodeTable[(x << 16) | y] = node;
  898. node->parent = parent;
  899. node->x = x;
  900. node->y = y;
  901. node->f = f;
  902. return node;
  903. }
  904.  
  905. AStarNode* AStarNodes::getBestNode()
  906. {
  907. if (curNode == 0) {
  908. return nullptr;
  909. }
  910.  
  911. int32_t best_node_f = std::numeric_limits<int32_t>::max();
  912. int32_t best_node = -1;
  913. for (size_t i = 0; i < curNode; i++) {
  914. if (openNodes[i] && nodes[i].f < best_node_f) {
  915. best_node_f = nodes[i].f;
  916. best_node = i;
  917. }
  918. }
  919.  
  920. if (best_node >= 0) {
  921. return nodes + best_node;
  922. }
  923. return nullptr;
  924. }
  925.  
  926. void AStarNodes::closeNode(AStarNode* node)
  927. {
  928. size_t index = node - nodes;
  929. assert(index < MAX_NODES);
  930. openNodes[index] = false;
  931. ++closedNodes;
  932. }
  933.  
  934. void AStarNodes::openNode(AStarNode* node)
  935. {
  936. size_t index = node - nodes;
  937. assert(index < MAX_NODES);
  938. if (!openNodes[index]) {
  939. openNodes[index] = true;
  940. --closedNodes;
  941. }
  942. }
  943.  
  944. int_fast32_t AStarNodes::getClosedNodes() const
  945. {
  946. return closedNodes;
  947. }
  948.  
  949. AStarNode* AStarNodes::getNodeByPosition(uint32_t x, uint32_t y)
  950. {
  951. auto it = nodeTable.find((x << 16) | y);
  952. if (it == nodeTable.end()) {
  953. return nullptr;
  954. }
  955. return it->second;
  956. }
  957.  
  958. int_fast32_t AStarNodes::getMapWalkCost(AStarNode* node, const Position& neighborPos)
  959. {
  960. if (std::abs(node->x - neighborPos.x) == std::abs(node->y - neighborPos.y)) {
  961. //diagonal movement extra cost
  962. return MAP_DIAGONALWALKCOST;
  963. }
  964. return MAP_NORMALWALKCOST;
  965. }
  966.  
  967. int_fast32_t AStarNodes::getTileWalkCost(const Creature& creature, const Tile* tile)
  968. {
  969. int_fast32_t cost = 0;
  970. if (tile->getTopVisibleCreature(&creature) != nullptr) {
  971. //destroy creature cost
  972. cost += MAP_NORMALWALKCOST * 3;
  973. }
  974.  
  975. if (const MagicField* field = tile->getFieldItem()) {
  976. CombatType_t combatType = field->getCombatType();
  977. if (!creature.isImmune(combatType) && !creature.hasCondition(Combat::DamageToConditionType(combatType))) {
  978. cost += MAP_NORMALWALKCOST * 18;
  979. }
  980. }
  981. return cost;
  982. }
  983.  
  984. // Floor
  985. Floor::~Floor()
  986. {
  987. for (uint32_t i = 0; i < FLOOR_SIZE; ++i) {
  988. for (uint32_t j = 0; j < FLOOR_SIZE; ++j) {
  989. delete tiles[i][j];
  990. }
  991. }
  992. }
  993.  
  994. // QTreeNode
  995. QTreeNode::QTreeNode()
  996. {
  997. leaf = false;
  998. child[0] = nullptr;
  999. child[1] = nullptr;
  1000. child[2] = nullptr;
  1001. child[3] = nullptr;
  1002. }
  1003.  
  1004. QTreeNode::~QTreeNode()
  1005. {
  1006. delete child[0];
  1007. delete child[1];
  1008. delete child[2];
  1009. delete child[3];
  1010. }
  1011.  
  1012. QTreeLeafNode* QTreeNode::getLeaf(uint32_t x, uint32_t y)
  1013. {
  1014. if (leaf) {
  1015. return static_cast<QTreeLeafNode*>(this);
  1016. }
  1017.  
  1018. QTreeNode* node = child[((x & 0x8000) >> 15) | ((y & 0x8000) >> 14)];
  1019. if (!node) {
  1020. return nullptr;
  1021. }
  1022. return node->getLeaf(x << 1, y << 1);
  1023. }
  1024.  
  1025. QTreeLeafNode* QTreeNode::createLeaf(uint32_t x, uint32_t y, uint32_t level)
  1026. {
  1027. if (!isLeaf()) {
  1028. uint32_t index = ((x & 0x8000) >> 15) | ((y & 0x8000) >> 14);
  1029. if (!child[index]) {
  1030. if (level != FLOOR_BITS) {
  1031. child[index] = new QTreeNode();
  1032. } else {
  1033. child[index] = new QTreeLeafNode();
  1034. QTreeLeafNode::newLeaf = true;
  1035. }
  1036. }
  1037. return child[index]->createLeaf(x * 2, y * 2, level - 1);
  1038. }
  1039. return static_cast<QTreeLeafNode*>(this);
  1040. }
  1041.  
  1042. // QTreeLeafNode
  1043. bool QTreeLeafNode::newLeaf = false;
  1044. QTreeLeafNode::QTreeLeafNode()
  1045. {
  1046. for (uint32_t i = 0; i < MAP_MAX_LAYERS; ++i) {
  1047. array[i] = nullptr;
  1048. }
  1049.  
  1050. leaf = true;
  1051. leafS = nullptr;
  1052. leafE = nullptr;
  1053. }
  1054.  
  1055. QTreeLeafNode::~QTreeLeafNode()
  1056. {
  1057. for (uint32_t i = 0; i < MAP_MAX_LAYERS; ++i) {
  1058. delete array[i];
  1059. }
  1060. }
  1061.  
  1062. Floor* QTreeLeafNode::createFloor(uint32_t z)
  1063. {
  1064. if (!array[z]) {
  1065. array[z] = new Floor();
  1066. }
  1067. return array[z];
  1068. }
  1069.  
  1070. void QTreeLeafNode::addCreature(Creature* c)
  1071. {
  1072. creature_list.push_back(c);
  1073.  
  1074. if (c->getPlayer()) {
  1075. player_list.push_back(c);
  1076. }
  1077. }
  1078.  
  1079. void QTreeLeafNode::removeCreature(Creature* c)
  1080. {
  1081. auto iter = std::find(creature_list.begin(), creature_list.end(), c);
  1082. assert(iter != creature_list.end());
  1083. *iter = creature_list.back();
  1084. creature_list.pop_back();
  1085.  
  1086. if (c->getPlayer()) {
  1087. iter = std::find(player_list.begin(), player_list.end(), c);
  1088. assert(iter != player_list.end());
  1089. *iter = player_list.back();
  1090. player_list.pop_back();
  1091. }
  1092. }
  1093.  
  1094. uint32_t Map::clean() const
  1095. {
  1096. uint64_t start = OTSYS_TIME();
  1097. size_t count = 0, tiles = 0;
  1098.  
  1099. if (g_game.getGameState() == GAME_STATE_NORMAL) {
  1100. g_game.setGameState(GAME_STATE_MAINTAIN);
  1101. }
  1102.  
  1103. std::vector<const QTreeNode*> nodes {
  1104. &root
  1105. };
  1106. std::vector<Item*> toRemove;
  1107. do {
  1108. const QTreeNode* node = nodes.back();
  1109. nodes.pop_back();
  1110. if (node->isLeaf()) {
  1111. const QTreeLeafNode* leafNode = static_cast<const QTreeLeafNode*>(node);
  1112. for (uint8_t z = 0; z < MAP_MAX_LAYERS; ++z) {
  1113. Floor* floor = leafNode->getFloor(z);
  1114. if (!floor) {
  1115. continue;
  1116. }
  1117.  
  1118. for (auto& row : floor->tiles) {
  1119. for (auto tile : row) {
  1120. if (!tile || tile->hasFlag(TILESTATE_PROTECTIONZONE)) {
  1121. continue;
  1122. }
  1123.  
  1124. TileItemVector* itemList = tile->getItemList();
  1125. if (!itemList) {
  1126. continue;
  1127. }
  1128.  
  1129. ++tiles;
  1130. for (Item* item : *itemList) {
  1131. if (item->isCleanable()) {
  1132. toRemove.push_back(item);
  1133. }
  1134. }
  1135.  
  1136. for (Item* item : toRemove) {
  1137. g_game.internalRemoveItem(item, -1);
  1138. }
  1139. count += toRemove.size();
  1140. toRemove.clear();
  1141. }
  1142. }
  1143. }
  1144. } else {
  1145. for (auto childNode : node->child) {
  1146. if (childNode) {
  1147. nodes.push_back(childNode);
  1148. }
  1149. }
  1150. }
  1151. } while (!nodes.empty());
  1152.  
  1153. if (g_game.getGameState() == GAME_STATE_MAINTAIN) {
  1154. g_game.setGameState(GAME_STATE_NORMAL);
  1155. }
  1156.  
  1157. std::cout << "> CLEAN: Removed " << count << " item" << (count != 1 ? "s" : "")
  1158. << " from " << tiles << " tile" << (tiles != 1 ? "s" : "") << " in "
  1159. << (OTSYS_TIME() - start) / (1000.) << " seconds." << std::endl;
  1160. return count;
  1161. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement