mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +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:
		| @@ -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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user