mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
CPathfinderHelper: implement TurnInfo to avoid bonus re-checking
TurnInfo contain information about what movement-related bonuses and MP hero going to have on certain turn. This way we can collect this information once for each turn so it's huge performance boost.
This commit is contained in:
parent
2ef9d7c3ec
commit
9a63735c24
@ -48,9 +48,10 @@ CPathfinder::CPathfinder(CPathsInfo &_out, CGameState *_gs, const CGHeroInstance
|
||||
throw std::runtime_error("Wrong checksum");
|
||||
}
|
||||
|
||||
if(hero->getBonusAtTurn(Bonus::FLYING_MOVEMENT))
|
||||
hlp = new CPathfinderHelper(hero);
|
||||
if(hlp->ti->bonusFlying)
|
||||
options.useFlying = true;
|
||||
if(hero->getBonusAtTurn(Bonus::WATER_WALKING))
|
||||
if(hlp->ti->bonusWaterWalking)
|
||||
options.useWaterWalking = true;
|
||||
if(CGWhirlpool::isProtected(hero))
|
||||
options.useTeleportWhirlpool = true;
|
||||
@ -61,14 +62,6 @@ CPathfinder::CPathfinder(CPathsInfo &_out, CGameState *_gs, const CGHeroInstance
|
||||
|
||||
void CPathfinder::calculatePaths()
|
||||
{
|
||||
int maxMovePointsLand = hero->maxMovePoints(true);
|
||||
int maxMovePointsWater = hero->maxMovePoints(false);
|
||||
|
||||
auto maxMovePoints = [&](CGPathNode *cp) -> int
|
||||
{
|
||||
return cp->layer == ELayer::SAIL ? maxMovePointsWater : maxMovePointsLand;
|
||||
};
|
||||
|
||||
auto passOneTurnLimitCheck = [&](bool shouldCheck) -> bool
|
||||
{
|
||||
if(options.oneTurnSpecialLayersLimit && shouldCheck)
|
||||
@ -109,10 +102,11 @@ void CPathfinder::calculatePaths()
|
||||
cp->locked = true;
|
||||
|
||||
int movement = cp->moveRemains, turn = cp->turns;
|
||||
hlp->updateTurnInfo(turn);
|
||||
if(!movement)
|
||||
{
|
||||
movement = maxMovePoints(cp);
|
||||
turn++;
|
||||
hlp->updateTurnInfo(++turn);
|
||||
movement = hlp->getMaxMovePoints(cp->layer);
|
||||
}
|
||||
|
||||
//add accessible neighbouring nodes to the queue
|
||||
@ -143,7 +137,7 @@ void CPathfinder::calculatePaths()
|
||||
if(!isMovementToDestPossible())
|
||||
continue;
|
||||
|
||||
int cost = CPathfinderHelper::getMovementCost(hero, cp->coord, dp->coord, movement);
|
||||
int cost = CPathfinderHelper::getMovementCost(hero, cp->coord, dp->coord, movement, hlp->ti);
|
||||
int remains = movement - cost;
|
||||
if(destAction == CGPathNode::EMBARK || destAction == CGPathNode::DISEMBARK)
|
||||
{
|
||||
@ -154,9 +148,9 @@ void CPathfinder::calculatePaths()
|
||||
if(remains < 0)
|
||||
{
|
||||
//occurs rarely, when hero with low movepoints tries to leave the road
|
||||
turnAtNextTile++;
|
||||
int moveAtNextTile = maxMovePoints(cp);
|
||||
cost = CPathfinderHelper::getMovementCost(hero, cp->coord, dp->coord, moveAtNextTile); //cost must be updated, movement points changed :(
|
||||
hlp->updateTurnInfo(++turnAtNextTile);
|
||||
int moveAtNextTile = hlp->getMaxMovePoints(i);
|
||||
cost = CPathfinderHelper::getMovementCost(hero, cp->coord, dp->coord, moveAtNextTile, hlp->ti); //cost must be updated, movement points changed :(
|
||||
remains = moveAtNextTile - cost;
|
||||
}
|
||||
|
||||
@ -282,13 +276,13 @@ bool CPathfinder::isLayerAvailable(const ELayer &layer, const int &turn) const
|
||||
switch(layer)
|
||||
{
|
||||
case ELayer::AIR:
|
||||
if(!hero->getBonusAtTurn(Bonus::FLYING_MOVEMENT, turn))
|
||||
if(!hlp->ti->bonusFlying)
|
||||
return false;
|
||||
|
||||
break;
|
||||
|
||||
case ELayer::WATER:
|
||||
if(!hero->getBonusAtTurn(Bonus::WATER_WALKING, turn))
|
||||
if(!hlp->ti->bonusWaterWalking)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
@ -625,6 +619,43 @@ bool CPathfinder::canVisitObject() const
|
||||
return cp->layer == ELayer::LAND || cp->layer == ELayer::SAIL;
|
||||
}
|
||||
|
||||
CPathfinderHelper::CPathfinderHelper(const CGHeroInstance * Hero)
|
||||
: ti(nullptr), hero(Hero)
|
||||
{
|
||||
turnsInfo.reserve(16);
|
||||
updateTurnInfo();
|
||||
}
|
||||
|
||||
void CPathfinderHelper::updateTurnInfo(const int &turn)
|
||||
{
|
||||
if(!ti || ti->turn != turn)
|
||||
{
|
||||
if(turn < turnsInfo.size())
|
||||
ti = turnsInfo[turn];
|
||||
else
|
||||
{
|
||||
ti = getTurnInfo(hero, turn);
|
||||
turnsInfo.push_back(ti);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CPathfinderHelper::getMaxMovePoints(const EPathfindingLayer &layer) const
|
||||
{
|
||||
return layer == EPathfindingLayer::SAIL ? ti->maxMovePointsWater : ti->maxMovePointsLand;
|
||||
}
|
||||
|
||||
TurnInfo * CPathfinderHelper::getTurnInfo(const CGHeroInstance * h, const int &turn)
|
||||
{
|
||||
auto turnInfo = new TurnInfo;
|
||||
turnInfo->turn = turn;
|
||||
turnInfo->maxMovePointsLand = h->maxMovePoints(true);
|
||||
turnInfo->maxMovePointsWater = h->maxMovePoints(false);
|
||||
turnInfo->bonusFlying = h->getBonusAtTurn(Bonus::FLYING_MOVEMENT, turn);
|
||||
turnInfo->bonusWaterWalking = h->getBonusAtTurn(Bonus::WATER_WALKING, turn);
|
||||
return turnInfo;
|
||||
}
|
||||
|
||||
void CPathfinderHelper::getNeighbours(CGameState * gs, const TerrainTile &srct, const int3 &tile, std::vector<int3> &vec, const boost::logic::tribool &onLand, const bool &limitCoastSailing)
|
||||
{
|
||||
static const int3 dirs[] = { int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0),
|
||||
@ -664,27 +695,28 @@ void CPathfinderHelper::getNeighbours(CGameState * gs, const TerrainTile &srct,
|
||||
}
|
||||
}
|
||||
|
||||
int CPathfinderHelper::getMovementCost(const CGHeroInstance * h, const int3 &src, const int3 &dst, const int &remainingMovePoints, const int &turn, const bool &checkLast)
|
||||
int CPathfinderHelper::getMovementCost(const CGHeroInstance * h, const int3 &src, const int3 &dst, const int &remainingMovePoints, const TurnInfo * ti, const bool &checkLast)
|
||||
{
|
||||
if(src == dst) //same tile
|
||||
return 0;
|
||||
|
||||
auto s = h->cb->getTile(src), d = h->cb->getTile(dst);
|
||||
int ret = h->getTileCost(*d, *s, turn);
|
||||
if(!ti)
|
||||
ti = getTurnInfo(h);
|
||||
|
||||
auto flyBonus = h->getBonusAtTurn(Bonus::FLYING_MOVEMENT, turn);
|
||||
auto waterWalkingBonus = h->getBonusAtTurn(Bonus::WATER_WALKING, turn);
|
||||
if(d->blocked && flyBonus)
|
||||
auto s = h->cb->getTile(src), d = h->cb->getTile(dst);
|
||||
int ret = h->getTileCost(*d, *s, ti);
|
||||
|
||||
if(d->blocked && ti->bonusFlying)
|
||||
{
|
||||
ret *= (100.0 + flyBonus->val) / 100.0;
|
||||
ret *= (100.0 + ti->bonusFlying->val) / 100.0;
|
||||
}
|
||||
else if(d->terType == ETerrainType::WATER)
|
||||
{
|
||||
if(h->boat && s->hasFavourableWinds() && d->hasFavourableWinds()) //Favourable Winds
|
||||
ret *= 0.666;
|
||||
else if(!h->boat && waterWalkingBonus)
|
||||
else if(!h->boat && ti->bonusWaterWalking)
|
||||
{
|
||||
ret *= (100.0 + waterWalkingBonus->val) / 100.0;
|
||||
ret *= (100.0 + ti->bonusWaterWalking->val) / 100.0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -705,7 +737,7 @@ int CPathfinderHelper::getMovementCost(const CGHeroInstance * h, const int3 &src
|
||||
getNeighbours(h->cb->gameState(), *d, dst, vec, s->terType != ETerrainType::WATER, true);
|
||||
for(auto & elem : vec)
|
||||
{
|
||||
int fcost = getMovementCost(h, dst, elem, left, turn, false);
|
||||
int fcost = getMovementCost(h, dst, elem, left, ti, false);
|
||||
if(fcost <= left)
|
||||
return ret;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
class CGHeroInstance;
|
||||
class CGObjectInstance;
|
||||
struct TerrainTile;
|
||||
class CPathfinderHelper;
|
||||
|
||||
struct DLL_LINKAGE CGPathNode
|
||||
{
|
||||
@ -128,6 +129,7 @@ private:
|
||||
|
||||
CPathsInfo &out;
|
||||
const CGHeroInstance *hero;
|
||||
CPathfinderHelper * hlp;
|
||||
|
||||
struct NodeComparer
|
||||
{
|
||||
@ -179,11 +181,31 @@ private:
|
||||
|
||||
};
|
||||
|
||||
struct TurnInfo
|
||||
{
|
||||
int turn;
|
||||
int maxMovePointsLand;
|
||||
int maxMovePointsWater;
|
||||
const Bonus * bonusFlying;
|
||||
const Bonus * bonusWaterWalking;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CPathfinderHelper
|
||||
{
|
||||
public:
|
||||
TurnInfo * ti;
|
||||
const CGHeroInstance * hero;
|
||||
|
||||
CPathfinderHelper(const CGHeroInstance * Hero);
|
||||
void updateTurnInfo(const int &turn = 0);
|
||||
int getMaxMovePoints(const EPathfindingLayer &layer) const;
|
||||
static TurnInfo * getTurnInfo(const CGHeroInstance * h, const int &turn = 0);
|
||||
|
||||
static void getNeighbours(CGameState * gs, const TerrainTile &srct, const int3 &tile, std::vector<int3> &vec, const boost::logic::tribool &onLand, const bool &limitCoastSailing);
|
||||
|
||||
static int getMovementCost(const CGHeroInstance * h, const int3 &src, const int3 &dst, const int &remainingMovePoints =- 1, const int &turn = 0, const bool &checkLast = true);
|
||||
static int getMovementCost(const CGHeroInstance * h, const int3 &src, const int3 &dst, const int &remainingMovePoints =- 1, const TurnInfo * ti = nullptr, const bool &checkLast = true);
|
||||
static int getMovementCost(const CGHeroInstance * h, const int3 &dst);
|
||||
|
||||
private:
|
||||
std::vector<TurnInfo *> turnsInfo;
|
||||
};
|
||||
|
@ -56,7 +56,7 @@ static int lowestSpeed(const CGHeroInstance * chi)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ui32 CGHeroInstance::getTileCost(const TerrainTile &dest, const TerrainTile &from, const int &turn) const
|
||||
ui32 CGHeroInstance::getTileCost(const TerrainTile &dest, const TerrainTile &from, const TurnInfo * ti) const
|
||||
{
|
||||
unsigned ret = GameConstants::BASE_MOVEMENT_COST;
|
||||
|
||||
@ -80,7 +80,7 @@ ui32 CGHeroInstance::getTileCost(const TerrainTile &dest, const TerrainTile &fro
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(!getBonusAtTurn(Bonus::NO_TERRAIN_PENALTY, turn, from.terType))
|
||||
else if(!getBonusAtTurn(Bonus::NO_TERRAIN_PENALTY, ti->turn, from.terType))
|
||||
{
|
||||
// NOTE: in H3 neutral stacks will ignore terrain penalty only if placed as topmost stack(s) in hero army.
|
||||
// This is clearly bug in H3 however intended behaviour is not clear.
|
||||
|
@ -21,6 +21,7 @@ class CHero;
|
||||
class CGBoat;
|
||||
class CGTownInstance;
|
||||
struct TerrainTile;
|
||||
struct TurnInfo;
|
||||
|
||||
class CGHeroPlaceholder : public CGObjectInstance
|
||||
{
|
||||
@ -129,7 +130,7 @@ public:
|
||||
EAlignment::EAlignment getAlignment() const;
|
||||
const std::string &getBiography() const;
|
||||
bool needsLastStack()const override;
|
||||
ui32 getTileCost(const TerrainTile &dest, const TerrainTile &from, const int &turn) const; //move cost - applying pathfinding skill, road and terrain modifiers. NOT includes diagonal move penalty, last move levelling
|
||||
ui32 getTileCost(const TerrainTile &dest, const TerrainTile &from, const TurnInfo * ti) const; //move cost - applying pathfinding skill, road and terrain modifiers. NOT includes diagonal move penalty, last move levelling
|
||||
ui32 getLowestCreatureSpeed() const;
|
||||
int3 getPosition(bool h3m = false) const; //h3m=true - returns position of hero object; h3m=false - returns position of hero 'manifestation'
|
||||
si32 manaRegain() const; //how many points of mana can hero regain "naturally" in one day
|
||||
|
Loading…
Reference in New Issue
Block a user