//////////////////////////////////////////////////////////////////////// // OpenTibia - an opensource roleplaying game //////////////////////////////////////////////////////////////////////// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . //////////////////////////////////////////////////////////////////////// #ifndef __MAP__ #define __MAP__ #include "tools.h" #include "fileloader.h" #include "position.h" #include "waypoints.h" #include "tile.h" class Creature; class Player; class Game; class Tile; class Map; struct FindPathParams; struct AStarNode { uint16_t x, y; AStarNode* parent; int32_t f, g, h; }; using boost::shared_ptr; #define MAP_MAX_LAYERS 16 #define MAX_NODES 512 #define GET_NODE_INDEX(a) (a - &nodes[0]) #define MAP_NORMALWALKCOST 10 #define MAP_DIAGONALWALKCOST 25 class AStarNodes { public: AStarNodes(); virtual ~AStarNodes() {} void openNode(AStarNode* node); void closeNode(AStarNode* node); uint32_t countOpenNodes(); uint32_t countClosedNodes(); AStarNode* getBestNode(); AStarNode* createOpenNode(); AStarNode* getNodeInList(uint16_t x, uint16_t y); bool isInList(uint16_t x, uint16_t y); int32_t getEstimatedDistance(uint16_t x, uint16_t y, uint16_t xGoal, uint16_t yGoal); int32_t getMapWalkCost(const Creature* creature, AStarNode* node, const Tile* neighbourTile, const Position& neighbourPos); static int32_t getTileWalkCost(const Creature* creature, const Tile* tile); private: AStarNode nodes[MAX_NODES]; std::bitset openNodes; uint32_t curNode; }; template class lessPointer: public std::binary_function { public: bool operator()(T*& t1, T*& t2) {return *t1 < *t2;} }; #define FLOOR_BITS 3 #define FLOOR_SIZE (1 << FLOOR_BITS) #define FLOOR_MASK (FLOOR_SIZE - 1) struct Floor { Floor(); Tile* tiles[FLOOR_SIZE][FLOOR_SIZE]; }; class FrozenPathingConditionCall; class QTreeLeafNode; class QTreeNode { public: QTreeNode(); virtual ~QTreeNode(); bool isLeaf() const {return m_isLeaf;} QTreeLeafNode* getLeaf(uint16_t x, uint16_t y); static QTreeLeafNode* getLeafStatic(QTreeNode* root, uint16_t x, uint16_t y); QTreeLeafNode* createLeaf(uint16_t x, uint16_t y, uint16_t level); protected: bool m_isLeaf; QTreeNode* m_child[4]; friend class Map; }; class QTreeLeafNode : public QTreeNode { public: QTreeLeafNode(); virtual ~QTreeLeafNode(); Floor* createFloor(uint16_t z); Floor* getFloor(uint16_t z){return m_array[z];} QTreeLeafNode* stepSouth(){return m_leafS;} QTreeLeafNode* stepEast(){return m_leafE;} void addCreature(Creature* c); void removeCreature(Creature* c); protected: static bool newLeaf; QTreeLeafNode* m_leafS; QTreeLeafNode* m_leafE; Floor* m_array[MAP_MAX_LAYERS]; CreatureVector creatureList; friend class Map; friend class QTreeNode; }; /** * Map class. * Holds all the actual map-data */ class Map { public: Map(); virtual ~Map() {} static const int32_t maxViewportX = 11; //min value: maxClientViewportX + 1 static const int32_t maxViewportY = 11; //min value: maxClientViewportY + 1 static const int32_t maxClientViewportX = 8; static const int32_t maxClientViewportY = 6; /** * Load a map. * \returns true if the map was loaded successfully */ bool loadMap(const std::string& identifier); /** * Save a map. * \param identifier file/database to save to * \returns true if the map was saved successfully */ bool saveMap(); /** * Get a single tile. * \returns A pointer to that tile. */ Tile* getTile(int32_t x, int32_t y, int32_t z); Tile* getTile(const Position& pos) {return getTile(pos.x, pos.y, pos.z);} /** * Set a single tile. * \param a tile to set for the position */ void setTile(uint16_t _x, uint16_t _y, uint16_t _z, Tile* newTile); void setTile(const Position& pos, Tile* newTile) {setTile(pos.x, pos.y, pos.z, newTile);} /** * Place a creature on the map * \param pos The position to place the creature * \param creature Creature to place on the map * \param extendedPos If true, the creature will in first-hand be placed 2 tiles away * \param forceLogin If true, placing the creature will not fail becase of obstacles (creatures/chests) */ bool placeCreature(const Position& centerPos, Creature* creature, bool extendedPos = false, bool forceLogin = false); /** * Remove a creature from the map. * \param c Creature pointer to the creature to remove */ bool removeCreature(Creature* c); /** * Checks if you can throw an object to that position * \param fromPos from Source point * \param toPos Destination point * \param rangex maximum allowed range horizontially * \param rangey maximum allowed range vertically * \param checkLineOfSight checks if there is any blocking objects in the way * \returns The result if you can throw there or not */ bool canThrowObjectTo(const Position& fromPos, const Position& toPos, bool checkLineOfSight = true, int32_t rangex = Map::maxClientViewportX, int32_t rangey = Map::maxClientViewportY); /** * Checks if path is clear from fromPos to toPos * Notice: This only checks a straight line if the path is clear, for path finding use getPathTo. * \param fromPos from Source point * \param toPos Destination point * \param floorCheck if true then view is not clear if fromPos.z is not the same as toPos.z * \returns The result if there is no obstacles */ bool isSightClear(const Position& fromPos, const Position& toPos, bool floorCheck) const; bool checkSightLine(const Position& fromPos, const Position& toPos) const; /** * Get the path to a specific position on the map. * \param creature The creature that wants a path * \param destPos The position we want a path calculated to * \param listDir contains a list of directions to the destination * \param maxDist Maximum distance from our current position to search, default: -1 (no limit) * \returns returns true if a path was found */ bool getPathTo(const Creature* creature, const Position& destPos, std::list& listDir, int32_t maxDist = -1); bool getPathMatching(const Creature* creature, std::list& dirList, const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp, uint32_t nodesLimit = 100); QTreeLeafNode* getLeaf(uint16_t x, uint16_t y) {return root.getLeaf(x, y);} const Tile* canWalkTo(const Creature* creature, const Position& pos); Waypoints waypoints; protected: QTreeNode root; uint32_t mapWidth, mapHeight; std::string spawnfile, housefile; StringVec descriptions; SpectatorCache spectatorCache; void clearSpectatorCache() {spectatorCache.clear();} // Actually scans the map for spectators void getSpectatorsInternal(SpectatorVec& list, const Position& centerPos, bool checkforduplicate, int32_t minRangeX, int32_t maxRangeX, int32_t minRangeY, int32_t maxRangeY, int32_t minRangeZ, int32_t maxRangeZ); // Use this when a custom spectator vector is needed, this support many // more parameters than the heavily cached version below. void getSpectators(SpectatorVec& list, const Position& centerPos, bool checkforduplicate = false, bool multifloor = false, int32_t minRangeX = 0, int32_t maxRangeX = 0, int32_t minRangeY = 0, int32_t maxRangeY = 0); // The returned SpectatorVec is a temporary and should not be kept around // Take special heed in that the vector will be destroyed if any function // that calls clearSpectatorCache is called. const SpectatorVec& getSpectators(const Position& centerPos); friend class Game; friend class IOMap; }; inline void QTreeLeafNode::addCreature(Creature* c) { creatureList.push_back(c); } inline void QTreeLeafNode::removeCreature(Creature* c) { CreatureVector::iterator it = std::find(creatureList.begin(), creatureList.end(), c); assert(it != creatureList.end()); creatureList.erase(it); } #endif