mirror of
https://github.com/vcmi/vcmi.git
synced 2025-04-15 11:46:56 +02:00
CGameState: move two pathfinding-related functions to CPathfinderHelper
Both getMovementCost and getNeighbours have nothing to do with gamestate.
This commit is contained in:
parent
d3c8ca7c1c
commit
b2e1ee5363
@ -421,7 +421,7 @@ float FuzzyHelper::evaluate (Goals::VisitTile & g)
|
|||||||
|
|
||||||
//assert(cb->isInTheMap(g.tile));
|
//assert(cb->isInTheMap(g.tile));
|
||||||
float turns = 0;
|
float turns = 0;
|
||||||
float distance = cb->getMovementCost(g.hero.h, g.tile);
|
float distance = CPathfinderHelper::getCost(g.hero.h, g.tile);
|
||||||
if (!distance) //we stand on that tile
|
if (!distance) //we stand on that tile
|
||||||
turns = 0;
|
turns = 0;
|
||||||
else
|
else
|
||||||
@ -530,4 +530,4 @@ float FuzzyHelper::evaluate (Goals::AbstractGoal & g)
|
|||||||
void FuzzyHelper::setPriority (Goals::TSubgoal & g)
|
void FuzzyHelper::setPriority (Goals::TSubgoal & g)
|
||||||
{
|
{
|
||||||
g->setpriority(g->accept(this)); //this enforces returned value is set
|
g->setpriority(g->accept(this)); //this enforces returned value is set
|
||||||
}
|
}
|
||||||
|
@ -290,11 +290,6 @@ bool CCallback::canMoveBetween(const int3 &a, const int3 &b)
|
|||||||
return gs->checkForVisitableDir(a, b) && gs->checkForVisitableDir(b, a);
|
return gs->checkForVisitableDir(a, b) && gs->checkForVisitableDir(b, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CCallback::getMovementCost(const CGHeroInstance * hero, int3 dest)
|
|
||||||
{
|
|
||||||
return gs->getMovementCost(hero, hero->visitablePos(), dest, hero->movement);
|
|
||||||
}
|
|
||||||
|
|
||||||
const CPathsInfo * CCallback::getPathsInfo(const CGHeroInstance *h)
|
const CPathsInfo * CCallback::getPathsInfo(const CGHeroInstance *h)
|
||||||
{
|
{
|
||||||
return cl->getPathsInfo(h);
|
return cl->getPathsInfo(h);
|
||||||
|
@ -104,7 +104,6 @@ public:
|
|||||||
|
|
||||||
//client-specific functionalities (pathfinding)
|
//client-specific functionalities (pathfinding)
|
||||||
virtual bool canMoveBetween(const int3 &a, const int3 &b);
|
virtual bool canMoveBetween(const int3 &a, const int3 &b);
|
||||||
virtual int getMovementCost(const CGHeroInstance * hero, int3 dest);
|
|
||||||
virtual int3 getGuardingCreaturePosition(int3 tile);
|
virtual int3 getGuardingCreaturePosition(int3 tile);
|
||||||
virtual const CPathsInfo * getPathsInfo(const CGHeroInstance *h);
|
virtual const CPathsInfo * getPathsInfo(const CGHeroInstance *h);
|
||||||
|
|
||||||
|
@ -2061,103 +2061,6 @@ PlayerRelations::PlayerRelations CGameState::getPlayerRelations( PlayerColor col
|
|||||||
return PlayerRelations::ENEMIES;
|
return PlayerRelations::ENEMIES;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameState::getNeighbours(const TerrainTile &srct, int3 tile, std::vector<int3> &vec, const boost::logic::tribool &onLand, bool limitCoastSailing)
|
|
||||||
{
|
|
||||||
static const int3 dirs[] = { int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0),
|
|
||||||
int3(1,1,0),int3(-1,1,0),int3(1,-1,0),int3(-1,-1,0) };
|
|
||||||
|
|
||||||
//vec.reserve(8); //optimization
|
|
||||||
for (auto & dir : dirs)
|
|
||||||
{
|
|
||||||
const int3 hlp = tile + dir;
|
|
||||||
if(!map->isInTheMap(hlp))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const TerrainTile &hlpt = map->getTile(hlp);
|
|
||||||
|
|
||||||
// //we cannot visit things from blocked tiles
|
|
||||||
// if(srct.blocked && !srct.visitable && hlpt.visitable && srct.blockingObjects.front()->ID != HEROI_TYPE)
|
|
||||||
// {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
if(srct.terType == ETerrainType::WATER && limitCoastSailing && hlpt.terType == ETerrainType::WATER && dir.x && dir.y) //diagonal move through water
|
|
||||||
{
|
|
||||||
int3 hlp1 = tile,
|
|
||||||
hlp2 = tile;
|
|
||||||
hlp1.x += dir.x;
|
|
||||||
hlp2.y += dir.y;
|
|
||||||
|
|
||||||
if(map->getTile(hlp1).terType != ETerrainType::WATER || map->getTile(hlp2).terType != ETerrainType::WATER)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((indeterminate(onLand) || onLand == (hlpt.terType!=ETerrainType::WATER) )
|
|
||||||
&& hlpt.terType != ETerrainType::ROCK)
|
|
||||||
{
|
|
||||||
vec.push_back(hlp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int CGameState::getMovementCost(const CGHeroInstance *h, const int3 &src, const int3 &dest, int remainingMovePoints, const int &turn, bool checkLast)
|
|
||||||
{
|
|
||||||
if(src == dest) //same tile
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
TerrainTile &s = map->getTile(src),
|
|
||||||
&d = map->getTile(dest);
|
|
||||||
|
|
||||||
//get basic cost
|
|
||||||
int ret = h->getTileCost(d, s, turn);
|
|
||||||
|
|
||||||
auto flyBonus = h->getBonusAtTurn(Bonus::FLYING_MOVEMENT, turn);
|
|
||||||
auto waterWalkingBonus = h->getBonusAtTurn(Bonus::WATER_WALKING, turn);
|
|
||||||
if(d.blocked && flyBonus)
|
|
||||||
{
|
|
||||||
ret *= (100.0 + flyBonus->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)
|
|
||||||
{
|
|
||||||
ret *= (100.0 + waterWalkingBonus->val) / 100.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(src.x != dest.x && src.y != dest.y) //it's diagonal move
|
|
||||||
{
|
|
||||||
int old = ret;
|
|
||||||
ret *= 1.414213;
|
|
||||||
//diagonal move costs too much but normal move is possible - allow diagonal move for remaining move points
|
|
||||||
if(ret > remainingMovePoints && remainingMovePoints >= old)
|
|
||||||
{
|
|
||||||
return remainingMovePoints;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int left = remainingMovePoints-ret;
|
|
||||||
if(checkLast && left > 0 && remainingMovePoints-ret < 250) //it might be the last tile - if no further move possible we take all move points
|
|
||||||
{
|
|
||||||
std::vector<int3> vec;
|
|
||||||
vec.reserve(8); //optimization
|
|
||||||
getNeighbours(d, dest, vec, s.terType != ETerrainType::WATER, true);
|
|
||||||
for(auto & elem : vec)
|
|
||||||
{
|
|
||||||
int fcost = getMovementCost(h, dest, elem, left, turn, false);
|
|
||||||
if(fcost <= left)
|
|
||||||
{
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret = remainingMovePoints;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CGameState::apply(CPack *pack)
|
void CGameState::apply(CPack *pack)
|
||||||
{
|
{
|
||||||
ui16 typ = typeList.getTypeID(pack);
|
ui16 typ = typeList.getTypeID(pack);
|
||||||
|
@ -339,8 +339,6 @@ public:
|
|||||||
bool isVisible(int3 pos, PlayerColor player);
|
bool isVisible(int3 pos, PlayerColor player);
|
||||||
bool isVisible(const CGObjectInstance *obj, boost::optional<PlayerColor> player);
|
bool isVisible(const CGObjectInstance *obj, boost::optional<PlayerColor> player);
|
||||||
|
|
||||||
void getNeighbours(const TerrainTile &srct, int3 tile, std::vector<int3> &vec, const boost::logic::tribool &onLand, bool limitCoastSailing);
|
|
||||||
int getMovementCost(const CGHeroInstance * h, const int3 &src, const int3 &dest, int remainingMovePoints =- 1, const int &turn = 0, bool checkLast = true);
|
|
||||||
int getDate(Date::EDateType mode=Date::DAY) const; //mode=0 - total days in game, mode=1 - day of week, mode=2 - current week, mode=3 - current month
|
int getDate(Date::EDateType mode=Date::DAY) const; //mode=0 - total days in game, mode=1 - day of week, mode=2 - current week, mode=3 - current month
|
||||||
|
|
||||||
// ----- getters, setters -----
|
// ----- getters, setters -----
|
||||||
|
@ -143,7 +143,7 @@ void CPathfinder::calculatePaths()
|
|||||||
if(!isMovementToDestPossible())
|
if(!isMovementToDestPossible())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int cost = gs->getMovementCost(hero, cp->coord, dp->coord, movement);
|
int cost = CPathfinderHelper::getCost(hero, cp->coord, dp->coord, movement);
|
||||||
int remains = movement - cost;
|
int remains = movement - cost;
|
||||||
if(destAction == CGPathNode::EMBARK || destAction == CGPathNode::DISEMBARK)
|
if(destAction == CGPathNode::EMBARK || destAction == CGPathNode::DISEMBARK)
|
||||||
{
|
{
|
||||||
@ -156,7 +156,7 @@ void CPathfinder::calculatePaths()
|
|||||||
//occurs rarely, when hero with low movepoints tries to leave the road
|
//occurs rarely, when hero with low movepoints tries to leave the road
|
||||||
turnAtNextTile++;
|
turnAtNextTile++;
|
||||||
int moveAtNextTile = maxMovePoints(cp);
|
int moveAtNextTile = maxMovePoints(cp);
|
||||||
cost = gs->getMovementCost(hero, cp->coord, dp->coord, moveAtNextTile); //cost must be updated, movement points changed :(
|
cost = CPathfinderHelper::getCost(hero, cp->coord, dp->coord, moveAtNextTile); //cost must be updated, movement points changed :(
|
||||||
remains = moveAtNextTile - cost;
|
remains = moveAtNextTile - cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +204,7 @@ void CPathfinder::addNeighbours(const int3 &coord)
|
|||||||
ct = &gs->map->getTile(coord);
|
ct = &gs->map->getTile(coord);
|
||||||
|
|
||||||
std::vector<int3> tiles;
|
std::vector<int3> tiles;
|
||||||
gs->getNeighbours(*ct, coord, tiles, boost::logic::indeterminate, cp->layer == ELayer::SAIL); // TODO: find out if we still need "limitCoastSailing" option
|
CPathfinderHelper::getNeighbours(gs, *ct, coord, tiles, boost::logic::indeterminate, cp->layer == ELayer::SAIL); // TODO: find out if we still need "limitCoastSailing" option
|
||||||
sTileObj = ct->topVisitableObj(coord == out.hpos);
|
sTileObj = ct->topVisitableObj(coord == out.hpos);
|
||||||
if(canVisitObject())
|
if(canVisitObject())
|
||||||
{
|
{
|
||||||
@ -625,6 +625,100 @@ bool CPathfinder::canVisitObject() const
|
|||||||
return cp->layer == ELayer::LAND || cp->layer == ELayer::SAIL;
|
return cp->layer == ELayer::LAND || cp->layer == ELayer::SAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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),
|
||||||
|
int3(1,1,0),int3(-1,1,0),int3(1,-1,0),int3(-1,-1,0) };
|
||||||
|
|
||||||
|
//vec.reserve(8); //optimization
|
||||||
|
for (auto & dir : dirs)
|
||||||
|
{
|
||||||
|
const int3 hlp = tile + dir;
|
||||||
|
if(!gs->isInTheMap(hlp))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const TerrainTile &hlpt = gs->map->getTile(hlp);
|
||||||
|
|
||||||
|
// //we cannot visit things from blocked tiles
|
||||||
|
// if(srct.blocked && !srct.visitable && hlpt.visitable && srct.blockingObjects.front()->ID != HEROI_TYPE)
|
||||||
|
// {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if(srct.terType == ETerrainType::WATER && limitCoastSailing && hlpt.terType == ETerrainType::WATER && dir.x && dir.y) //diagonal move through water
|
||||||
|
{
|
||||||
|
int3 hlp1 = tile,
|
||||||
|
hlp2 = tile;
|
||||||
|
hlp1.x += dir.x;
|
||||||
|
hlp2.y += dir.y;
|
||||||
|
|
||||||
|
if(gs->map->getTile(hlp1).terType != ETerrainType::WATER || gs->map->getTile(hlp2).terType != ETerrainType::WATER)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((indeterminate(onLand) || onLand == (hlpt.terType!=ETerrainType::WATER) )
|
||||||
|
&& hlpt.terType != ETerrainType::ROCK)
|
||||||
|
{
|
||||||
|
vec.push_back(hlp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int CPathfinderHelper::getCost(const CGHeroInstance * h, const int3 &src, const int3 &dst, const int &remainingMovePoints, const int &turn, 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);
|
||||||
|
|
||||||
|
auto flyBonus = h->getBonusAtTurn(Bonus::FLYING_MOVEMENT, turn);
|
||||||
|
auto waterWalkingBonus = h->getBonusAtTurn(Bonus::WATER_WALKING, turn);
|
||||||
|
if(d->blocked && flyBonus)
|
||||||
|
{
|
||||||
|
ret *= (100.0 + flyBonus->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)
|
||||||
|
{
|
||||||
|
ret *= (100.0 + waterWalkingBonus->val) / 100.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(src.x != dst.x && src.y != dst.y) //it's diagonal move
|
||||||
|
{
|
||||||
|
int old = ret;
|
||||||
|
ret *= 1.414213;
|
||||||
|
//diagonal move costs too much but normal move is possible - allow diagonal move for remaining move points
|
||||||
|
if(ret > remainingMovePoints && remainingMovePoints >= old)
|
||||||
|
return remainingMovePoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
int left = remainingMovePoints-ret;
|
||||||
|
if(checkLast && left > 0 && remainingMovePoints-ret < 250) //it might be the last tile - if no further move possible we take all move points
|
||||||
|
{
|
||||||
|
std::vector<int3> vec;
|
||||||
|
vec.reserve(8); //optimization
|
||||||
|
getNeighbours(h->cb->gameState(), *d, dst, vec, s->terType != ETerrainType::WATER, true);
|
||||||
|
for(auto & elem : vec)
|
||||||
|
{
|
||||||
|
int fcost = getCost(h, dst, elem, left, turn, false);
|
||||||
|
if(fcost <= left)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = remainingMovePoints;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CPathfinderHelper::getCost(const CGHeroInstance * h, const int3 &dst)
|
||||||
|
{
|
||||||
|
return getCost(h, h->visitablePos(), dst, h->movement);
|
||||||
|
}
|
||||||
|
|
||||||
CGPathNode::CGPathNode(int3 Coord, ELayer Layer)
|
CGPathNode::CGPathNode(int3 Coord, ELayer Layer)
|
||||||
: coord(Coord), layer(Layer)
|
: coord(Coord), layer(Layer)
|
||||||
{
|
{
|
||||||
|
@ -178,3 +178,12 @@ private:
|
|||||||
bool canVisitObject() const;
|
bool canVisitObject() const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DLL_LINKAGE CPathfinderHelper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
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 getCost(const CGHeroInstance * h, const int3 &src, const int3 &dst, const int &remainingMovePoints =- 1, const int &turn = 0, const bool &checkLast = true);
|
||||||
|
static int getCost(const CGHeroInstance * h, const int3 &dst);
|
||||||
|
};
|
||||||
|
@ -1764,7 +1764,6 @@ bool CGameHandler::moveHero( ObjectInstanceID hid, int3 dst, ui8 teleporting, bo
|
|||||||
}
|
}
|
||||||
|
|
||||||
const TerrainTile t = *gs->getTile(hmpos);
|
const TerrainTile t = *gs->getTile(hmpos);
|
||||||
const int cost = gs->getMovementCost(h, h->getPosition(), hmpos, h->movement);
|
|
||||||
const int3 guardPos = gs->guardingCreaturePosition(hmpos);
|
const int3 guardPos = gs->guardingCreaturePosition(hmpos);
|
||||||
|
|
||||||
const bool embarking = !h->boat && !t.visitableObjects.empty() && t.visitableObjects.back()->ID == Obj::BOAT;
|
const bool embarking = !h->boat && !t.visitableObjects.empty() && t.visitableObjects.back()->ID == Obj::BOAT;
|
||||||
@ -1779,8 +1778,9 @@ bool CGameHandler::moveHero( ObjectInstanceID hid, int3 dst, ui8 teleporting, bo
|
|||||||
tmh.movePoints = h->movement;
|
tmh.movePoints = h->movement;
|
||||||
|
|
||||||
//check if destination tile is available
|
//check if destination tile is available
|
||||||
bool canFly = h->getBonusAtTurn(Bonus::FLYING_MOVEMENT);
|
const bool canFly = h->getBonusAtTurn(Bonus::FLYING_MOVEMENT);
|
||||||
bool canWalkOnSea = h->getBonusAtTurn(Bonus::WATER_WALKING);
|
const bool canWalkOnSea = h->getBonusAtTurn(Bonus::WATER_WALKING);
|
||||||
|
const int cost = CPathfinderHelper::getCost(h, h->getPosition(), hmpos, h->movement);
|
||||||
|
|
||||||
//it's a rock or blocked and not visitable tile
|
//it's a rock or blocked and not visitable tile
|
||||||
//OR hero is on land and dest is water and (there is not present only one object - boat)
|
//OR hero is on land and dest is water and (there is not present only one object - boat)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user