瀏覽代碼

CGameState: move two pathfinding-related functions to CPathfinderHelper

Both getMovementCost and getNeighbours have nothing to do with gamestate.
ArseniyShestakov 10 年之前
父節點
當前提交
b2e1ee5363
共有 8 個文件被更改,包括 111 次插入113 次删除
  1. 2 2
      AI/VCAI/Fuzzy.cpp
  2. 0 5
      CCallback.cpp
  3. 0 1
      CCallback.h
  4. 0 97
      lib/CGameState.cpp
  5. 0 2
      lib/CGameState.h
  6. 97 3
      lib/CPathfinder.cpp
  7. 9 0
      lib/CPathfinder.h
  8. 3 3
      server/CGameHandler.cpp

+ 2 - 2
AI/VCAI/Fuzzy.cpp

@@ -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
-}
+}

+ 0 - 5
CCallback.cpp

@@ -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);

+ 0 - 1
CCallback.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);
 

+ 0 - 97
lib/CGameState.cpp

@@ -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);

+ 0 - 2
lib/CGameState.h

@@ -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 -----

+ 97 - 3
lib/CPathfinder.cpp

@@ -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)
 {

+ 9 - 0
lib/CPathfinder.h

@@ -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);
+};

+ 3 - 3
server/CGameHandler.cpp

@@ -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)