2023-06-21 12:46:09 +02:00
|
|
|
/*
|
|
|
|
* CGPathNode.h, part of VCMI engine
|
|
|
|
*
|
|
|
|
* Authors: listed in file AUTHORS in main folder
|
|
|
|
*
|
|
|
|
* License: GNU General Public License v2.0 or later
|
|
|
|
* Full text of license available in license.txt file, in main folder
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "../GameConstants.h"
|
|
|
|
#include "../int3.h"
|
|
|
|
|
|
|
|
#include <boost/heap/fibonacci_heap.hpp>
|
|
|
|
|
|
|
|
VCMI_LIB_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
class CGHeroInstance;
|
|
|
|
class CGObjectInstance;
|
|
|
|
class CGameState;
|
|
|
|
class CPathfinderHelper;
|
|
|
|
struct TerrainTile;
|
|
|
|
|
|
|
|
template<typename N>
|
|
|
|
struct DLL_LINKAGE NodeComparer
|
|
|
|
{
|
|
|
|
STRONG_INLINE
|
|
|
|
bool operator()(const N * lhs, const N * rhs) const
|
|
|
|
{
|
|
|
|
return lhs->getCost() > rhs->getCost();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-06-21 14:38:57 +02:00
|
|
|
enum class EPathAccessibility : ui8
|
|
|
|
{
|
|
|
|
NOT_SET,
|
|
|
|
ACCESSIBLE, //tile can be entered and passed
|
|
|
|
VISITABLE, //tile can be entered as the last tile in path
|
2024-05-28 15:37:42 +02:00
|
|
|
GUARDED, //tile can be entered, but is in zone of control of nearby monster (may also contain visitable object, if any)
|
2023-06-21 14:38:57 +02:00
|
|
|
BLOCKVIS, //visitable from neighboring tile but not passable
|
|
|
|
FLYABLE, //can only be accessed in air layer
|
|
|
|
BLOCKED //tile can be neither entered nor visited
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class EPathNodeAction : ui8
|
|
|
|
{
|
|
|
|
UNKNOWN,
|
|
|
|
EMBARK,
|
|
|
|
DISEMBARK,
|
|
|
|
NORMAL,
|
|
|
|
BATTLE,
|
|
|
|
VISIT,
|
|
|
|
BLOCKING_VISIT,
|
|
|
|
TELEPORT_NORMAL,
|
|
|
|
TELEPORT_BLOCKING_VISIT,
|
|
|
|
TELEPORT_BATTLE
|
|
|
|
};
|
|
|
|
|
2023-06-21 12:46:09 +02:00
|
|
|
struct DLL_LINKAGE CGPathNode
|
|
|
|
{
|
2024-07-15 09:49:04 +02:00
|
|
|
using TFibHeap = boost::heap::fibonacci_heap<CGPathNode *, boost::heap::compare<NodeComparer<CGPathNode>>>;
|
2023-06-21 12:46:09 +02:00
|
|
|
using ELayer = EPathfindingLayer;
|
|
|
|
|
2024-07-15 09:49:04 +02:00
|
|
|
TFibHeap::handle_type pqHandle;
|
|
|
|
TFibHeap * pq;
|
2023-06-21 12:46:09 +02:00
|
|
|
CGPathNode * theNodeBefore;
|
2024-07-15 09:49:04 +02:00
|
|
|
|
2023-06-21 12:46:09 +02:00
|
|
|
int3 coord; //coordinates
|
|
|
|
ELayer layer;
|
2024-07-15 09:49:04 +02:00
|
|
|
|
|
|
|
float cost; //total cost of the path to this tile measured in turns with fractions
|
2023-06-22 13:42:24 +02:00
|
|
|
int moveRemains; //remaining movement points after hero reaches the tile
|
2023-06-21 12:46:09 +02:00
|
|
|
ui8 turns; //how many turns we have to wait before reaching the tile - 0 means current turn
|
2023-06-21 14:38:57 +02:00
|
|
|
EPathAccessibility accessible;
|
|
|
|
EPathNodeAction action;
|
2023-06-21 12:46:09 +02:00
|
|
|
bool locked;
|
|
|
|
|
|
|
|
CGPathNode()
|
|
|
|
: coord(-1),
|
|
|
|
layer(ELayer::WRONG),
|
|
|
|
pqHandle(nullptr)
|
|
|
|
{
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
STRONG_INLINE
|
|
|
|
void reset()
|
|
|
|
{
|
|
|
|
locked = false;
|
2023-06-21 14:38:57 +02:00
|
|
|
accessible = EPathAccessibility::NOT_SET;
|
2023-06-21 12:46:09 +02:00
|
|
|
moveRemains = 0;
|
|
|
|
cost = std::numeric_limits<float>::max();
|
|
|
|
turns = 255;
|
|
|
|
theNodeBefore = nullptr;
|
|
|
|
pq = nullptr;
|
2024-07-15 09:49:04 +02:00
|
|
|
action = EPathNodeAction::UNKNOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
STRONG_INLINE
|
|
|
|
bool inPQ() const
|
|
|
|
{
|
|
|
|
return pq != nullptr;
|
2023-06-21 12:46:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
STRONG_INLINE
|
|
|
|
float getCost() const
|
|
|
|
{
|
|
|
|
return cost;
|
|
|
|
}
|
|
|
|
|
|
|
|
STRONG_INLINE
|
|
|
|
void setCost(float value)
|
|
|
|
{
|
2024-02-15 00:30:29 +02:00
|
|
|
if(vstd::isAlmostEqual(value, cost))
|
2023-06-21 12:46:09 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
bool getUpNode = value < cost;
|
|
|
|
cost = value;
|
|
|
|
// If the node is in the heap, update the heap.
|
2024-07-15 09:49:04 +02:00
|
|
|
if(inPQ())
|
2023-06-21 12:46:09 +02:00
|
|
|
{
|
|
|
|
if(getUpNode)
|
|
|
|
{
|
|
|
|
pq->increase(this->pqHandle);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pq->decrease(this->pqHandle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
STRONG_INLINE
|
2023-06-21 14:38:57 +02:00
|
|
|
void update(const int3 & Coord, const ELayer Layer, const EPathAccessibility Accessible)
|
2023-06-21 12:46:09 +02:00
|
|
|
{
|
|
|
|
if(layer == ELayer::WRONG)
|
|
|
|
{
|
|
|
|
coord = Coord;
|
|
|
|
layer = Layer;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
accessible = Accessible;
|
|
|
|
}
|
|
|
|
|
|
|
|
STRONG_INLINE
|
|
|
|
bool reachable() const
|
|
|
|
{
|
|
|
|
return turns < 255;
|
|
|
|
}
|
|
|
|
|
2023-09-15 21:18:36 +02:00
|
|
|
bool isTeleportAction() const
|
|
|
|
{
|
|
|
|
if (action != EPathNodeAction::TELEPORT_NORMAL &&
|
|
|
|
action != EPathNodeAction::TELEPORT_BLOCKING_VISIT &&
|
|
|
|
action != EPathNodeAction::TELEPORT_BATTLE)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2023-06-21 12:46:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
struct DLL_LINKAGE CGPath
|
|
|
|
{
|
|
|
|
std::vector<CGPathNode> nodes; //just get node by node
|
|
|
|
|
2023-09-15 21:18:36 +02:00
|
|
|
/// Starting position of path, matches location of hero
|
|
|
|
const CGPathNode & currNode() const;
|
|
|
|
/// First node in path, this is where hero will move next
|
|
|
|
const CGPathNode & nextNode() const;
|
|
|
|
/// Last node in path, this is what hero wants to reach in the end
|
|
|
|
const CGPathNode & lastNode() const;
|
|
|
|
|
2023-06-21 12:46:09 +02:00
|
|
|
int3 startPos() const; // start point
|
|
|
|
int3 endPos() const; //destination point
|
|
|
|
};
|
|
|
|
|
|
|
|
struct DLL_LINKAGE CPathsInfo
|
|
|
|
{
|
|
|
|
using ELayer = EPathfindingLayer;
|
|
|
|
|
|
|
|
const CGHeroInstance * hero;
|
|
|
|
int3 hpos;
|
|
|
|
int3 sizes;
|
|
|
|
boost::multi_array<CGPathNode, 4> nodes; //[layer][level][w][h]
|
|
|
|
|
|
|
|
CPathsInfo(const int3 & Sizes, const CGHeroInstance * hero_);
|
|
|
|
~CPathsInfo();
|
|
|
|
const CGPathNode * getPathInfo(const int3 & tile) const;
|
|
|
|
bool getPath(CGPath & out, const int3 & dst) const;
|
|
|
|
const CGPathNode * getNode(const int3 & coord) const;
|
|
|
|
|
|
|
|
STRONG_INLINE
|
|
|
|
CGPathNode * getNode(const int3 & coord, const ELayer layer)
|
|
|
|
{
|
2023-11-02 16:56:02 +02:00
|
|
|
return &nodes[layer.getNum()][coord.z][coord.x][coord.y];
|
2023-06-21 12:46:09 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct DLL_LINKAGE PathNodeInfo
|
|
|
|
{
|
|
|
|
CGPathNode * node;
|
|
|
|
const CGObjectInstance * nodeObject;
|
|
|
|
const CGHeroInstance * nodeHero;
|
|
|
|
const TerrainTile * tile;
|
|
|
|
int3 coord;
|
|
|
|
bool guarded;
|
2023-08-19 20:43:50 +02:00
|
|
|
PlayerRelations objectRelations;
|
|
|
|
PlayerRelations heroRelations;
|
2023-06-21 12:46:09 +02:00
|
|
|
bool isInitialPosition;
|
|
|
|
|
|
|
|
PathNodeInfo();
|
|
|
|
|
|
|
|
virtual void setNode(CGameState * gs, CGPathNode * n);
|
|
|
|
|
|
|
|
void updateInfo(CPathfinderHelper * hlp, CGameState * gs);
|
|
|
|
|
|
|
|
bool isNodeObjectVisitable() const;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct DLL_LINKAGE CDestinationNodeInfo : public PathNodeInfo
|
|
|
|
{
|
2023-06-21 14:38:57 +02:00
|
|
|
EPathNodeAction action;
|
2023-06-21 12:46:09 +02:00
|
|
|
int turn;
|
|
|
|
int movementLeft;
|
|
|
|
float cost; //same as CGPathNode::cost
|
|
|
|
bool blocked;
|
|
|
|
bool isGuardianTile;
|
|
|
|
|
|
|
|
CDestinationNodeInfo();
|
|
|
|
|
2024-02-10 21:22:08 +02:00
|
|
|
void setNode(CGameState * gs, CGPathNode * n) override;
|
2023-06-21 12:46:09 +02:00
|
|
|
|
|
|
|
virtual bool isBetterWay() const;
|
|
|
|
};
|
|
|
|
|
|
|
|
VCMI_LIB_NAMESPACE_END
|