mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +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));
|
||||
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
|
||||
turns = 0;
|
||||
else
|
||||
@ -530,4 +530,4 @@ float FuzzyHelper::evaluate (Goals::AbstractGoal & g)
|
||||
void FuzzyHelper::setPriority (Goals::TSubgoal & g)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
int CCallback::getMovementCost(const CGHeroInstance * hero, int3 dest)
|
||||
{
|
||||
return gs->getMovementCost(hero, hero->visitablePos(), dest, hero->movement);
|
||||
}
|
||||
|
||||
const CPathsInfo * CCallback::getPathsInfo(const CGHeroInstance *h)
|
||||
{
|
||||
return cl->getPathsInfo(h);
|
||||
|
@ -104,7 +104,6 @@ public:
|
||||
|
||||
//client-specific functionalities (pathfinding)
|
||||
virtual bool canMoveBetween(const int3 &a, const int3 &b);
|
||||
virtual int getMovementCost(const CGHeroInstance * hero, int3 dest);
|
||||
virtual int3 getGuardingCreaturePosition(int3 tile);
|
||||
virtual const CPathsInfo * getPathsInfo(const CGHeroInstance *h);
|
||||
|
||||
|
@ -2061,103 +2061,6 @@ PlayerRelations::PlayerRelations CGameState::getPlayerRelations( PlayerColor col
|
||||
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)
|
||||
{
|
||||
ui16 typ = typeList.getTypeID(pack);
|
||||
|
@ -339,8 +339,6 @@ public:
|
||||
bool isVisible(int3 pos, 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
|
||||
|
||||
// ----- getters, setters -----
|
||||
|
@ -143,7 +143,7 @@ void CPathfinder::calculatePaths()
|
||||
if(!isMovementToDestPossible())
|
||||
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;
|
||||
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
|
||||
turnAtNextTile++;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -204,7 +204,7 @@ void CPathfinder::addNeighbours(const int3 &coord)
|
||||
ct = &gs->map->getTile(coord);
|
||||
|
||||
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);
|
||||
if(canVisitObject())
|
||||
{
|
||||
@ -625,6 +625,100 @@ bool CPathfinder::canVisitObject() const
|
||||
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)
|
||||
: coord(Coord), layer(Layer)
|
||||
{
|
||||
|
@ -178,3 +178,12 @@ private:
|
||||
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 int cost = gs->getMovementCost(h, h->getPosition(), hmpos, h->movement);
|
||||
const int3 guardPos = gs->guardingCreaturePosition(hmpos);
|
||||
|
||||
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;
|
||||
|
||||
//check if destination tile is available
|
||||
bool canFly = h->getBonusAtTurn(Bonus::FLYING_MOVEMENT);
|
||||
bool canWalkOnSea = h->getBonusAtTurn(Bonus::WATER_WALKING);
|
||||
const bool canFly = h->getBonusAtTurn(Bonus::FLYING_MOVEMENT);
|
||||
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
|
||||
//OR hero is on land and dest is water and (there is not present only one object - boat)
|
||||
|
Loading…
Reference in New Issue
Block a user