// Mark cells we can use to bomb a specific target
void CvTacticalAnalysisMap::SetTargetFlankBonusCells(CvPlot* pTarget)
{
	CvPlot* pLoopPlot;
	int iPlotIndex;

	// No flank attacks on units at sea (where all combat is bombards)
	if(pTarget->isWater())
	{
		return;
	}

	for(int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
	{
		pLoopPlot = plotDirection(pTarget->getX(), pTarget->getY(), ((DirectionTypes)iI));
		if(pLoopPlot != NULL)
		{
			iPlotIndex = GC.getMap().plotNum(pLoopPlot->getX(), pLoopPlot->getY());
			if(m_pPlots[iPlotIndex].IsRevealed() && !m_pPlots[iPlotIndex].IsImpassableTerrain() && !m_pPlots[iPlotIndex].IsImpassableTerritory())
			{
				if(!m_pPlots[iPlotIndex].IsFriendlyCity() && !m_pPlots[iPlotIndex].IsEnemyCity() && !m_pPlots[iPlotIndex].IsNeutralCity())
				{
					if(!m_pPlots[iPlotIndex].IsFriendlyTurnEndTile() && m_pPlots[iPlotIndex].GetEnemyMilitaryUnit() == NULL)
					{
						m_pPlots[iPlotIndex].SetHelpsProvidesFlankBonus(true);
					}
				}
			}
		}
	}
}
Пример #2
0
CvPlot* CvArmyAI::DetectNearbyEnemy(PlayerTypes eEnemy, bool bNaval)
{
	UnitHandle pUnit = GetFirstUnit();
	while(pUnit)
	{
		for(int iDirectionLoop = 0; iDirectionLoop < NUM_DIRECTION_TYPES; ++iDirectionLoop)
		{
			CvPlot* pAdjacentPlot = plotDirection(pUnit->getX(), pUnit->getY(), ((DirectionTypes)iDirectionLoop));
			if(pAdjacentPlot != NULL && pAdjacentPlot->isWater()==bNaval && pAdjacentPlot->getOwner() == eEnemy)
			{
				UnitHandle pOtherUnit = pAdjacentPlot->getBestDefender(eEnemy);
				if(pOtherUnit)
				{
					if(GC.getLogging() && GC.getAILogging())
					{
						CvString strMsg;
						strMsg.Format("Ran into enemy unit during attack (x=%d y=%d). Need to declare war to continue!", pAdjacentPlot->getX(), pAdjacentPlot->getY());
						GET_PLAYER(m_eOwner).getAIOperation(m_iOperationID)->LogOperationSpecialMessage(strMsg);
					}

					return pAdjacentPlot;
				}
			}
		}
		pUnit = GetNextUnit();
	}

	return NULL;
}
Пример #3
0
CvPlot* CvPlayerAI::FindBestMerchantTargetPlot(CvUnit* pGreatMerchant, bool bOnlySafePaths)
{
	CvAssertMsg(pGreatMerchant, "pGreatMerchant is null");
	if(!pGreatMerchant)
	{
		return NULL;
	}

	int iBestTurnsToReach = MAX_INT;
	CvPlot* pBestTargetPlot = NULL;
	int iPathTurns;
	UnitHandle pMerchant = UnitHandle(pGreatMerchant);
	CvTeam& kTeam = GET_TEAM(getTeam());

	// Loop through each city state
	for(int iI = 0; iI < MAX_PLAYERS; iI++)
	{
		CvPlayer& kPlayer = GET_PLAYER((PlayerTypes)iI);
		if(kPlayer.isMinorCiv())
		{
			CvPlot* pCSPlot = kPlayer.getStartingPlot();
			if(pCSPlot)
			{
				if(pCSPlot->isRevealed(getTeam()))
				{
					// Is this a minor we are friendly with?
					if(GetDiplomacyAI()->GetMinorCivApproach(kPlayer.GetID()) != MINOR_CIV_APPROACH_CONQUEST &&
					        !kTeam.isAtWar(kPlayer.getTeam()) && GetDiplomacyAI()->GetWarGoal(kPlayer.GetID()) == NO_WAR_GOAL_TYPE)
					{
						// Search all the plots adjacent to this city (since can't enter the minor city plot itself)
						for(int jJ = 0; jJ < NUM_DIRECTION_TYPES; jJ++)
						{
							CvPlot* pAdjacentPlot = plotDirection(pCSPlot->getX(), pCSPlot->getY(), ((DirectionTypes)jJ));
							if(pAdjacentPlot != NULL)
							{
								// Make sure this is still owned by the city state and is revealed to us and isn't a water tile
								if(pAdjacentPlot->getOwner() == (PlayerTypes)iI && pAdjacentPlot->isRevealed(getTeam())
								        && !pAdjacentPlot->isWater())
								{
									iPathTurns = TurnsToReachTarget(pMerchant, pAdjacentPlot, true /*bReusePaths*/, !bOnlySafePaths/*bIgnoreUnits*/);
									if(iPathTurns < iBestTurnsToReach)
									{
										iBestTurnsToReach = iPathTurns;
										pBestTargetPlot = pAdjacentPlot;
									}
								}
							}
						}
					}
				}
			}
		}
	}

	return pBestTargetPlot;
}
int CvMapGenerator::getRiverValueAtPlot(CvPlot* pPlot)
{
	CvPlot* pAdjacentPlot;
	CvRandom riverRand;
	int iSum;
	int iI;

	FAssert(pPlot != NULL);

	long result = 0;
	CyPlot kPlot = CyPlot(pPlot);
	CyArgsList argsList;
	argsList.add(gDLL->getPythonIFace()->makePythonObject(&kPlot));
	if (gDLL->getPythonIFace()->callFunction(gDLL->getPythonIFace()->getMapScriptModule(), "getRiverAltitude", argsList.makeFunctionArgs(), &result))
	{
		if (!gDLL->getPythonIFace()->pythonUsingDefaultImpl()) // Python override
		{
			if (result >= 0)
			{
				return result;
			}
			else
			{
				FAssertMsg(false, "python getRiverAltitude() must return >= 0");
			}
		}
	}

	iSum = result;

	iSum += ((NUM_PLOT_TYPES - pPlot->getPlotType()) * 20);

	for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
	{
		pAdjacentPlot = plotDirection(pPlot->getX_INLINE(), pPlot->getY_INLINE(), ((DirectionTypes)iI));

		if (pAdjacentPlot != NULL)
		{
			iSum += (NUM_PLOT_TYPES - pAdjacentPlot->getPlotType());
		}
		else
		{
			iSum += (NUM_PLOT_TYPES * 10);
		}
	}

	riverRand.init((pPlot->getX_INLINE() * 43251267) + (pPlot->getY_INLINE() * 8273903));

	iSum += (riverRand.get(10, "River Rand"));

	return iSum;
}
bool OnSameBodyOfWater(CvCity* pCity1, CvCity* pCity2)
{
	for(int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
	{
		CvPlot* pAdjacentPlot1 = plotDirection(pCity1->getX(), pCity1->getY(), ((DirectionTypes)iI));

		if(pAdjacentPlot1 != NULL && pAdjacentPlot1->isWater())
		{
			for(int jJ = 0; jJ < NUM_DIRECTION_TYPES; jJ++)
			{
				CvPlot* pAdjacentPlot2 = plotDirection(pCity2->getX(), pCity2->getY(), ((DirectionTypes)jJ));
				if(pAdjacentPlot2 != NULL && pAdjacentPlot2->isWater())
				{
					if(pAdjacentPlot2->getArea() == pAdjacentPlot1->getArea())
					{
						return true;
					}
				}
			}
		}
	}
	return false;
}
Пример #6
0
CvPlot* CvPlayerAI::FindBestMusicianTargetPlot(CvUnit* pGreatMusician, bool bOnlySafePaths)
{
	CvAssertMsg(pGreatMusician, "pGreatMusician is null");
	if(!pGreatMusician)
	{
		return NULL;
	}

	int iBestTurnsToReach = MAX_INT;
	CvPlot* pBestTargetPlot = NULL;
	CvCity* pBestTargetCity = NULL;
	int iPathTurns;
	UnitHandle pMusician = UnitHandle(pGreatMusician);

	// Find target civ
	PlayerTypes eTargetPlayer = GetCulture()->GetCivLowestInfluence(true /*bCheckOpenBorders*/);
	if (eTargetPlayer == NO_PLAYER)
	{
		return NULL;
	}

	CvPlayer &kTargetPlayer = GET_PLAYER(eTargetPlayer);

	// Loop through each of that player's cities
	int iLoop;
	CvCity *pLoopCity;
	for(pLoopCity = kTargetPlayer.firstCity(&iLoop); pLoopCity != NULL; pLoopCity = kTargetPlayer.nextCity(&iLoop))
	{
		// Search all the plots adjacent to this city
		for(int jJ = 0; jJ < NUM_DIRECTION_TYPES; jJ++)
		{
			CvPlot* pAdjacentPlot = plotDirection(pLoopCity->getX(), pLoopCity->getY(), ((DirectionTypes)jJ));
			if(pAdjacentPlot != NULL)
			{
				// Make sure this is still owned by target and is revealed to us
				bool bRightOwner = (pAdjacentPlot->getOwner() == eTargetPlayer);
				bool bIsRevealed = pAdjacentPlot->isRevealed(getTeam());
				if(bRightOwner && bIsRevealed)
				{
					iPathTurns = TurnsToReachTarget(pMusician, pAdjacentPlot, true /*bReusePaths*/, !bOnlySafePaths/*bIgnoreUnits*/);
					if(iPathTurns < iBestTurnsToReach)
					{
						iBestTurnsToReach = iPathTurns;
						pBestTargetCity = pLoopCity;
					}
				}
			}
		}
	}

	// Found a city now look at ALL the plots owned by that player near that city
	if (pBestTargetCity)
	{
		iBestTurnsToReach = MAX_INT;
		CvPlot *pLoopPlot;
		for(int iJ = 0; iJ < NUM_CITY_PLOTS; iJ++)
		{
			pLoopPlot = plotCity(pBestTargetCity->getX(), pBestTargetCity->getY(), iJ);
			if(pLoopPlot != NULL)
			{
				// Make sure this is still owned by target and is revealed to us
				bool bRightOwner = (pLoopPlot->getOwner() == eTargetPlayer);
				bool bIsRevealed = pLoopPlot->isRevealed(getTeam());
				if(bRightOwner && bIsRevealed)
				{
					iPathTurns = TurnsToReachTarget(pMusician, pLoopPlot, true /*bReusePaths*/, !bOnlySafePaths/*bIgnoreUnits*/);
					if(iPathTurns < iBestTurnsToReach)
					{
						iBestTurnsToReach = iPathTurns;
						pBestTargetPlot = pLoopPlot;
					}
				}
			}	
		}
	}

	return pBestTargetPlot;
}
Пример #7
0
CvPlot* CvPlayerAI::FindBestMerchantTargetPlot(CvUnit* pGreatMerchant, bool bOnlySafePaths)
{
	CvAssertMsg(pGreatMerchant, "pGreatMerchant is null");
	if(!pGreatMerchant)
	{
		return NULL;
	}

	int iBestTurnsToReach = MAX_INT;
	CvPlot* pBestTargetPlot = NULL;
	int iPathTurns;
	UnitHandle pMerchant = UnitHandle(pGreatMerchant);
	CvTeam& kTeam = GET_TEAM(getTeam());

	//bool bIsVenice = GetPlayerTraits()->IsNoAnnexing();
	//bool bWantsCash = GreatMerchantWantsCash();

	// Loop through each city state
	for(int iI = 0; iI < MAX_PLAYERS; iI++)
	{
		CvPlayer& kPlayer = GET_PLAYER((PlayerTypes)iI);
		if (!kPlayer.isMinorCiv())
		{
			continue;
		}

		// if I'm Venice, I don't want to send a Merchant of Venice to a buy a city that I have trade routes 
		// with because it's probably more valuable as a trade partner than as an owned entity
		//if (!bWantsCash)
		//{
		//	if (bIsVenice)
		//	{
		//		if (GetTrade()->IsConnectedToPlayer(kPlayer.GetID()))
		//		{
		//			continue;
		//		}
		//	}
		//}

		CvPlot* pCSPlot = kPlayer.getStartingPlot();
		if (!pCSPlot)
		{
			continue;
		}

		if (!pCSPlot->isRevealed(getTeam()))
		{
			continue;
		}

		// Is this a minor we are friendly with?
		bool bMinorCivApproachIsCorrect = (GetDiplomacyAI()->GetMinorCivApproach(kPlayer.GetID()) != MINOR_CIV_APPROACH_CONQUEST);
		bool bNotAtWar = !kTeam.isAtWar(kPlayer.getTeam());
		bool bNotPlanningAWar = GetDiplomacyAI()->GetWarGoal(kPlayer.GetID()) == NO_WAR_GOAL_TYPE;

		if(bMinorCivApproachIsCorrect && bNotAtWar && bNotPlanningAWar)
		{
			// Search all the plots adjacent to this city (since can't enter the minor city plot itself)
			for(int jJ = 0; jJ < NUM_DIRECTION_TYPES; jJ++)
			{
				CvPlot* pAdjacentPlot = plotDirection(pCSPlot->getX(), pCSPlot->getY(), ((DirectionTypes)jJ));
				if(pAdjacentPlot != NULL)
				{
					// Make sure this is still owned by the city state and is revealed to us and isn't a water tile
					//if(pAdjacentPlot->getOwner() == (PlayerTypes)iI && pAdjacentPlot->isRevealed(getTeam()) && !pAdjacentPlot->isWater())
					bool bRightOwner = (pAdjacentPlot->getOwner() == (PlayerTypes)iI);
					bool bIsRevealed = pAdjacentPlot->isRevealed(getTeam());
					if(bRightOwner && bIsRevealed)
					{
						iPathTurns = TurnsToReachTarget(pMerchant, pAdjacentPlot, true /*bReusePaths*/, !bOnlySafePaths/*bIgnoreUnits*/);
						if(iPathTurns < iBestTurnsToReach)
						{
							iBestTurnsToReach = iPathTurns;
							pBestTargetPlot = pAdjacentPlot;
						}
					}
				}
			}
		}
	}

	return pBestTargetPlot;
}
/// Get center of mass of units in army (account for world wrap!)
CvPlot* CvArmyAI::GetCenterOfMass(DomainTypes eDomainRequired)
{
	CvPlot* pRtnValue = NULL;
	int iTotalX = 0;
	int iTotalY = 0;
	int iNumUnits = 0;
	UnitHandle pUnit;
	int iReferenceUnitX = -1;
	int iWorldWidth = GC.getMap().getGridWidth();

	pUnit = GetFirstUnit();
	if(pUnit)
	{
		iReferenceUnitX = pUnit->getX();
	}

	while(pUnit)
	{
		int iUnitX = pUnit->getX();

		bool bWorldWrapAdjust = false;
		int iDiff = iUnitX - iReferenceUnitX;
		if(abs(iDiff) > (iWorldWidth / 2))
		{
			bWorldWrapAdjust = true;
		}

		if(bWorldWrapAdjust)
		{
			iTotalX += iUnitX + iWorldWidth;
		}
		else
		{
			iTotalX += iUnitX;
		}
		iTotalY += pUnit->getY();
		iNumUnits++;
		pUnit = GetNextUnit();
	}

	if(iNumUnits > 0)
	{
		int iAverageX = (iTotalX + (iNumUnits / 2)) / iNumUnits;
		if(iAverageX >= iWorldWidth)
		{
			iAverageX = iAverageX - iWorldWidth;
		}
		int iAverageY = (iTotalY + (iNumUnits / 2)) / iNumUnits;
		pRtnValue = GC.getMap().plot(iAverageX, iAverageY);
	}

	// Domain check
	if (eDomainRequired != NO_DOMAIN && pRtnValue)
	{
		if (pRtnValue->isWater() && eDomainRequired == DOMAIN_LAND || !pRtnValue->isWater() && eDomainRequired == DOMAIN_SEA)
		{
			// Find an adjacent plot that works
			for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
			{
				CvPlot *pLoopPlot = plotDirection(pRtnValue->getX(), pRtnValue->getY(), ((DirectionTypes)iI));
				if (pLoopPlot != NULL)
				{
					if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND)
					{
						return pLoopPlot;
					}
				}
			}

			// Try two plots out if really having problems
			for (int iDX = -2; iDX <= 2; iDX++)
			{
				for (int iDY = -2; iDY <= 2; iDY++)
				{
					CvPlot *pLoopPlot = plotXYWithRangeCheck(pRtnValue->getX(), pRtnValue->getY(), iDX, iDY, 2);
					if (pLoopPlot)
					{
						if (plotDistance(pRtnValue->getX(), pRtnValue->getY(), pLoopPlot->getX(), pLoopPlot->getY()) == 2)
						{
							if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND)
							{
								return pLoopPlot;
							}
						}
					}
				}
			}

			// Give up - just use location of first unit
			pUnit = GetFirstUnit();
			pRtnValue = pUnit->plot();
		}
	}

	return pRtnValue;
}
Пример #9
0
//Note from Blake:
//Iustus wrote this function, it ensures that a new river actually
//creates fresh water on the passed plot. Quite useful really
//Altouh I veto'd it's use since I like that you don't always
//get fresh water starts.
// pFreshWaterPlot = the plot we want to give a fresh water river
//
bool CvMapGenerator::addRiver(CvPlot* pFreshWaterPlot)
{
	FAssertMsg(pFreshWaterPlot != NULL, "NULL plot parameter");

	// cannot have a river flow next to water
	if (pFreshWaterPlot->isWater())
	{
		return false;
	}

	// if it already has a fresh water river, then success! we done
	if (pFreshWaterPlot->isRiver())
	{
		return true;
	}

	bool bSuccess = false;

	// randomize the order of directions
	std::vector<int> aiShuffle(NUM_CARDINALDIRECTION_TYPES);
	GC.getGameINLINE().getMapRand().shuffleSequence(aiShuffle, NULL);

	// make two passes, once for each flow direction of the river
	int iNWFlowPass = GC.getGameINLINE().getMapRandNum(2, "addRiver");
	for (int iPass = 0; !bSuccess && iPass <= 1; iPass++)
	{
		// try placing a river edge in each direction, in random order
		for (int iI = 0; !bSuccess && iI < NUM_CARDINALDIRECTION_TYPES; iI++)
		{
			CardinalDirectionTypes eRiverDirection = NO_CARDINALDIRECTION;
			CvPlot *pRiverPlot = NULL;

			switch (aiShuffle[iI])
			{
			case CARDINALDIRECTION_NORTH:
				if (iPass == iNWFlowPass)
				{
					pRiverPlot = plotDirection(pFreshWaterPlot->getX_INLINE(), pFreshWaterPlot->getY_INLINE(), DIRECTION_NORTH);
					eRiverDirection = CARDINALDIRECTION_WEST;
				}
				else
				{
					pRiverPlot = plotDirection(pFreshWaterPlot->getX_INLINE(), pFreshWaterPlot->getY_INLINE(), DIRECTION_NORTHWEST);
					eRiverDirection = CARDINALDIRECTION_EAST;
				}
				break;

			case CARDINALDIRECTION_EAST:
				if (iPass == iNWFlowPass)
				{
					pRiverPlot = pFreshWaterPlot;
					eRiverDirection = CARDINALDIRECTION_NORTH;
				}
				else
				{
					pRiverPlot = plotDirection(pFreshWaterPlot->getX_INLINE(), pFreshWaterPlot->getY_INLINE(), DIRECTION_NORTH);
					eRiverDirection = CARDINALDIRECTION_SOUTH;
				}
				break;

			case CARDINALDIRECTION_SOUTH:
				if (iPass == iNWFlowPass)
				{
					pRiverPlot = pFreshWaterPlot;
					eRiverDirection = CARDINALDIRECTION_WEST;
				}
				else
				{
					pRiverPlot = plotDirection(pFreshWaterPlot->getX_INLINE(), pFreshWaterPlot->getY_INLINE(), DIRECTION_WEST);
					eRiverDirection = CARDINALDIRECTION_EAST;
				}
				break;

			case CARDINALDIRECTION_WEST:
				if (iPass == iNWFlowPass)
				{
					pRiverPlot = plotDirection(pFreshWaterPlot->getX_INLINE(), pFreshWaterPlot->getY_INLINE(), DIRECTION_WEST);
					eRiverDirection = CARDINALDIRECTION_NORTH;
				}
				else
				{
					pRiverPlot = plotDirection(pFreshWaterPlot->getX_INLINE(), pFreshWaterPlot->getY_INLINE(), DIRECTION_NORTHWEST);
					eRiverDirection = CARDINALDIRECTION_SOUTH;
				}
				break;

			default:
				FAssertMsg(false, "invalid cardinal direction");
			}

			if (pRiverPlot != NULL && !pRiverPlot->hasCoastAtSECorner())
			{
				// try to make the river
				doRiver(pRiverPlot, eRiverDirection, eRiverDirection, -1);

				// if it succeeded, then we will be a river now!
				if (pFreshWaterPlot->isRiver())
				{
					bSuccess = true;
				}
			}
		}
	}

	return bSuccess;
}
Пример #10
0
//	--------------------------------------------------------------------------------
bool CvUnitMovement::IsSlowedByZOC(const CvUnit* pUnit, const CvPlot* pFromPlot, const CvPlot* pToPlot)
{
	if (pUnit->IsIgnoreZOC() || CostsOnlyOne(pUnit, pFromPlot, pToPlot))
	{
		return false;
	}

	// Zone of Control
	if(GC.getZONE_OF_CONTROL_ENABLED() > 0)
	{
		IDInfo* pAdjUnitNode;
		CvUnit* pLoopUnit;

		int iFromPlotX = pFromPlot->getX();
		int iFromPlotY = pFromPlot->getY();
		int iToPlotX = pToPlot->getX();
		int iToPlotY = pToPlot->getY();
		TeamTypes unit_team_type     = pUnit->getTeam();
		DomainTypes unit_domain_type = pUnit->getDomainType();
		bool bIsVisibleEnemyUnit     = pToPlot->isVisibleEnemyUnit(pUnit);
		CvTeam& kUnitTeam = GET_TEAM(unit_team_type);

		for(int iDirection0 = 0; iDirection0 < NUM_DIRECTION_TYPES; iDirection0++)
		{
			CvPlot* pAdjPlot = plotDirection(iFromPlotX, iFromPlotY, ((DirectionTypes)iDirection0));
			if(NULL != pAdjPlot)
			{
				// check city zone of control
				if(pAdjPlot->isEnemyCity(*pUnit))
				{
					// Loop through plots adjacent to the enemy city and see if it's the same as our unit's Destination Plot
					for(int iDirection = 0; iDirection < NUM_DIRECTION_TYPES; iDirection++)
					{
						CvPlot* pEnemyAdjPlot = plotDirection(pAdjPlot->getX(), pAdjPlot->getY(), ((DirectionTypes)iDirection));
						if(NULL != pEnemyAdjPlot)
						{
							// Destination adjacent to enemy city?
							if(pEnemyAdjPlot->getX() == iToPlotX && pEnemyAdjPlot->getY() == iToPlotY)
							{
								return true;
							}
						}
					}
				}

				pAdjUnitNode = pAdjPlot->headUnitNode();
				// Loop through all units to see if there's an enemy unit here
				while(pAdjUnitNode != NULL)
				{
					if((pAdjUnitNode->eOwner >= 0) && pAdjUnitNode->eOwner < MAX_PLAYERS)
					{
						pLoopUnit = (GET_PLAYER(pAdjUnitNode->eOwner).getUnit(pAdjUnitNode->iID));
					}
					else
					{
						pLoopUnit = NULL;
					}

					pAdjUnitNode = pAdjPlot->nextUnitNode(pAdjUnitNode);

					if(!pLoopUnit) continue;

					TeamTypes unit_loop_team_type = pLoopUnit->getTeam();

					if(pLoopUnit->isInvisible(unit_team_type,false)) continue;

					// Combat unit?
					if(!pLoopUnit->IsCombatUnit())
					{
						continue;
					}

					// At war with this unit's team?
					if(unit_loop_team_type == BARBARIAN_TEAM || kUnitTeam.isAtWar(unit_loop_team_type))
					{

						// Same Domain?

						DomainTypes loop_unit_domain_type = pLoopUnit->getDomainType();
						if(loop_unit_domain_type != unit_domain_type)
						{
							// this is valid
							if(loop_unit_domain_type == DOMAIN_SEA && unit_domain_type)
							{
								// continue on
							}
							else
							{
								continue;
							}
						}

						// Embarked?
						if(unit_domain_type == DOMAIN_LAND && pLoopUnit->isEmbarked())
						{
							continue;
						}

						// Loop through plots adjacent to the enemy unit and see if it's the same as our unit's Destination Plot
						for(int iDirection2 = 0; iDirection2 < NUM_DIRECTION_TYPES; iDirection2++)
						{
							CvPlot* pEnemyAdjPlot = plotDirection(pAdjPlot->getX(), pAdjPlot->getY(), ((DirectionTypes)iDirection2));
							if(!pEnemyAdjPlot)
							{
								continue;
							}

							// Don't check Enemy Unit's plot
							if(!bIsVisibleEnemyUnit)
							{
								// Destination adjacent to enemy unit?
								if(pEnemyAdjPlot->getX() == iToPlotX && pEnemyAdjPlot->getY() == iToPlotY)
								{
									return true;
								}
							}
						}
					}
				}
			}
		}
	}
	return false;
}
Пример #11
0
/// Get center of mass of units in army (account for world wrap!)
CvPlot* CvArmyAI::GetCenterOfMass(DomainTypes eDomainRequired)
{
	int iTotalX = 0;
	int iTotalY = 0;
	int iNumUnits = 0;

#if defined(MOD_BALANCE_CORE)
	UnitHandle pUnit = GetFirstUnit();

	if (!pUnit)
		return NULL;

	int iTotalX2 = 0;
	int iTotalY2 = 0;
	int iWorldWidth = GC.getMap().getGridWidth();
	int iWorldHeight = GC.getMap().getGridHeight();

	//the first unit is our reference ...
	int iRefX = pUnit->getX();
	int iRefY = pUnit->getY();
	iNumUnits++;
	pUnit = GetNextUnit();

	while(pUnit)
	{
		int iDX = pUnit->getX() - iRefX;
		int iDY = pUnit->getY() - iRefY;

		if (GC.getMap().isWrapX())
		{
			if( iDX > +(iWorldWidth / 2))
				iDX -= iWorldWidth;
			if( iDX < -(iWorldWidth / 2))
				iDX += iWorldWidth;
		}
		if (GC.getMap().isWrapY())
		{
			if( iDY > +(iWorldHeight / 2))
				iDY -= iWorldHeight;
			if( iDY < -(iWorldHeight / 2))
				iDY += iWorldHeight;
		}

		iTotalX += iDX;
		iTotalY += iDY;
		iTotalX2 += iDX*iDX;
		iTotalY2 += iDY*iDY;
		iNumUnits++;

		pUnit = GetNextUnit();
	}

	if (iNumUnits==0)
		return NULL;

	//this is for debugging
	float fVarX = (iTotalX2 / (float)iNumUnits) - (iTotalX/(float)iNumUnits)*(iTotalX/(float)iNumUnits);
	float fVarY = (iTotalY2 / (float)iNumUnits) - (iTotalY/(float)iNumUnits)*(iTotalY/(float)iNumUnits);

	//finally, compute average (with rounding)
	int iAvgX = (iTotalX + (iNumUnits / 2)) / iNumUnits + iRefX;
	int iAvgY = (iTotalY + (iNumUnits / 2)) / iNumUnits + iRefY;

	if (fVarX > 64 || fVarY > 64)
	{
		CvString msg = CvString::format("Warning: Army %d with %d units Center of Mass (%d,%d) has a large variance (%.2f,%.2f)\n", GetID(), iNumUnits, iAvgX, iAvgY, fVarX, fVarY);
		OutputDebugString( msg.c_str() );
	}

	//this handles wrapped coordinates
	CvPlot* pCOM = GC.getMap().plot(iAvgX, iAvgY);

	if (!pCOM)
		return NULL;

	//don't return it directly but use the plot of the closest unit
	pUnit = GetFirstUnit();
	std::vector<SPlotWithScore> vPlots;
	while (pUnit)
	{
		if (eDomainRequired == NO_DOMAIN || pUnit->plot()->getDomain()==eDomainRequired)
			vPlots.push_back( SPlotWithScore(pUnit->plot(),plotDistance(*pUnit->plot(),*pCOM)) );

		pUnit = GetNextUnit();
	}

	if (vPlots.empty())
		return NULL;

	//this sorts ascending!
	std::sort(vPlots.begin(),vPlots.end());
	return vPlots.front().pPlot;

#else
	CvPlot* pRtnValue = NULL;
	UnitHandle pUnit;
	int iReferenceUnitX = -1;
	int iWorldWidth = GC.getMap().getGridWidth();

	pUnit = GetFirstUnit();
	if(pUnit)
	{
		iReferenceUnitX = pUnit->getX();
	}

	while(pUnit)
	{
		int iUnitX = pUnit->getX();

		bool bWorldWrapAdjust = false;
		int iDiff = iUnitX - iReferenceUnitX;
		if(abs(iDiff) > (iWorldWidth / 2))
		{
			bWorldWrapAdjust = true;
		}

		if(bWorldWrapAdjust)
		{
			iTotalX += iUnitX + iWorldWidth;
		}
		else
		{
			iTotalX += iUnitX;
		}
		iTotalY += pUnit->getY();
		iNumUnits++;
		pUnit = GetNextUnit();
	}

	if(iNumUnits > 0)
	{
		int iAverageX = (iTotalX + (iNumUnits / 2)) / iNumUnits;
		if(iAverageX >= iWorldWidth)
		{
			iAverageX = iAverageX - iWorldWidth;
		}
		int iAverageY = (iTotalY + (iNumUnits / 2)) / iNumUnits;
		pRtnValue = GC.getMap().plot(iAverageX, iAverageY);
	}

	// Domain check
	if (eDomainRequired != NO_DOMAIN && pRtnValue)
	{
		if (pRtnValue->isWater() && eDomainRequired == DOMAIN_LAND || !pRtnValue->isWater() && eDomainRequired == DOMAIN_SEA)
		{
			// Find an adjacent plot that works
			for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
			{
				CvPlot *pLoopPlot = plotDirection(pRtnValue->getX(), pRtnValue->getY(), ((DirectionTypes)iI));
				if (pLoopPlot != NULL)
				{
					if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND)
					{
						return pLoopPlot;
					}
				}
			}

			// Try two plots out if really having problems
			for (int iDX = -2; iDX <= 2; iDX++)
			{
				for (int iDY = -2; iDY <= 2; iDY++)
				{
					CvPlot *pLoopPlot = plotXYWithRangeCheck(pRtnValue->getX(), pRtnValue->getY(), iDX, iDY, 2);
					if (pLoopPlot)
					{
						if (plotDistance(pRtnValue->getX(), pRtnValue->getY(), pLoopPlot->getX(), pLoopPlot->getY()) == 2)
						{
							if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND)
							{
								return pLoopPlot;
							}
						}
					}
				}
			}

			// Give up - just use location of first unit
			pUnit = GetFirstUnit();
			pRtnValue = pUnit->plot();
		}
	}
	return pRtnValue;
#endif
}
// Indicate the plots we might want to move to that the enemy can attack
void CvTacticalAnalysisMap::MarkCellsNearEnemy()
{
	int iDistance;

	// Look at every cell on the map
	for(int iI = 0; iI < GC.getMap().numPlots(); iI++)
	{
		bool bMarkedIt = false;   // Set true once we've found one that enemy can move past (worst case)

		CvPlot* pPlot = GC.getMap().plotByIndexUnchecked(iI);
		if(m_pPlots[iI].IsRevealed() && !m_pPlots[iI].IsImpassableTerrain() && !m_pPlots[iI].IsImpassableTerritory())
		{
			// Friendly cities always safe
			if(!m_pPlots[iI].IsFriendlyCity())
			{
				if(!pPlot->isVisibleToEnemyTeam(m_pPlayer->getTeam()))
				{
					m_pPlots[iI].SetNotVisibleToEnemy(true);
				}
				else
				{
					for(unsigned int iUnitIndex = 0;  iUnitIndex < m_EnemyUnits.size() && !bMarkedIt; iUnitIndex++)
					{
						CvUnit* pUnit = m_EnemyUnits[iUnitIndex];
						if(pUnit->getArea() == pPlot->getArea())
						{
							// Distance check before hitting pathfinder
							iDistance = plotDistance(pUnit->getX(), pUnit->getY(), pPlot->getX(), pPlot->getY());
							if(iDistance == 0)
							{
								m_pPlots[iI].SetSubjectToAttack(true);
								m_pPlots[iI].SetEnemyCanMovePast(true);
								bMarkedIt = true;
							}

							// TEMPORARY OPTIMIZATION: Assumes can't use roads or RR
							else if(iDistance <= pUnit->baseMoves())
							{
								int iTurnsToReach;
								iTurnsToReach = TurnsToReachTarget(pUnit, pPlot, true /*bReusePaths*/, true /*bIgnoreUnits*/);	// Its ok to reuse paths because when ignoring units, we don't use the tactical analysis map (which we are building)
								if(iTurnsToReach <= 1)
								{
									m_pPlots[iI].SetSubjectToAttack(true);
								}
								if(iTurnsToReach == 0)
								{
									m_pPlots[iI].SetEnemyCanMovePast(true);
									bMarkedIt = true;
								}
							}
						}
					}

					// Check adjacent plots for enemy citadels
					if(!m_pPlots[iI].IsSubjectToAttack())
					{
						CvPlot* pAdjacentPlot;
						for(int jJ = 0; jJ < NUM_DIRECTION_TYPES; jJ++)
						{
							pAdjacentPlot = plotDirection(pPlot->getX(), pPlot->getY(), ((DirectionTypes)jJ));
							if(pAdjacentPlot != NULL && pAdjacentPlot->getOwner() != NO_PLAYER)
							{
								if(atWar(m_pPlayer->getTeam(), GET_PLAYER(pAdjacentPlot->getOwner()).getTeam()))
								{
									ImprovementTypes eImprovement = pAdjacentPlot->getImprovementType();
									if(eImprovement != NO_IMPROVEMENT && GC.getImprovementInfo(eImprovement)->GetNearbyEnemyDamage() > 0)
									{
										m_pPlots[iI].SetSubjectToAttack(true);
										break;
									}
								}
							}
						}
					}
				}
			}
		}
	}
}
bool CvMapGenerator::canPlaceBonusAt(BonusTypes eBonus, int iX, int iY, bool bIgnoreLatitude)
{
	PROFILE_FUNC();

	CvArea* pArea;
	CvPlot* pPlot;
	CvPlot* pLoopPlot;
	int iRange;
	int iDX, iDY;
	int iI;

	pPlot = GC.getMapINLINE().plotINLINE(iX, iY);
	pArea = pPlot->area();

	if (!(pPlot->canHaveBonus(eBonus, bIgnoreLatitude)))
	{
		return false;
	}

	long result = 0;
	CyPlot kPlot = CyPlot(pPlot);
	CyArgsList argsList;
	argsList.add(gDLL->getPythonIFace()->makePythonObject(&kPlot));
	if (gDLL->getPythonIFace()->callFunction(gDLL->getPythonIFace()->getMapScriptModule(), "canPlaceBonusAt", argsList.makeFunctionArgs(), &result))
	{
		if (!gDLL->getPythonIFace()->pythonUsingDefaultImpl())
		{
			if (result >= 0)
			{
				return result;
			}
			else
			{
				FAssertMsg(false, "canPlaceBonusAt() must return >= 0");
			}
		}
	}

	for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
	{
		pLoopPlot = plotDirection(iX, iY, ((DirectionTypes)iI));

		if (pLoopPlot != NULL)
		{
			if ((pLoopPlot->getBonusType() != NO_BONUS) && (pLoopPlot->getBonusType() != eBonus))
			{
				return false;
			}
		}
	}

	CvBonusInfo& pInfo = GC.getBonusInfo(eBonus);
	CvBonusClassInfo& pClassInfo = GC.getBonusClassInfo((BonusClassTypes) pInfo.getBonusClassType());

	if (pPlot->isWater())
	{
		if (((GC.getMapINLINE().getNumBonusesOnLand(eBonus) * 100) / (GC.getMapINLINE().getNumBonuses(eBonus) + 1)) < pInfo.getMinLandPercent())
		{
			return false;
		}
	}

	// Make sure there are no bonuses of the same class (but a different type) nearby:

	iRange = pClassInfo.getUniqueRange();

	for (iDX = -(iRange); iDX <= iRange; iDX++)
	{
		for (iDY = -(iRange); iDY <= iRange; iDY++)
		{
			pLoopPlot	= plotXY(iX, iY, iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (pLoopPlot->area() == pArea)
				{
					if (plotDistance(iX, iY, pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()) <= iRange)
					{
						BonusTypes eOtherBonus = pLoopPlot->getBonusType();
						if (eOtherBonus != NO_BONUS)
						{
							if (GC.getBonusInfo(eOtherBonus).getBonusClassType() == pInfo.getBonusClassType())
							{
								return false;
							}
						}
					}
				}
			}
		}
	}

	// Make sure there are none of the same bonus nearby:

	iRange = pInfo.getUniqueRange();

	for (iDX = -(iRange); iDX <= iRange; iDX++)
	{
		for (iDY = -(iRange); iDY <= iRange; iDY++)
		{
			pLoopPlot	= plotXY(iX, iY, iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (pLoopPlot->area() == pArea)
				{
					if (plotDistance(iX, iY, pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()) <= iRange)
					{
						if (pLoopPlot->getBonusType() == eBonus)
						{
							return false;
						}
					}
				}
			}
		}
	}

	return true;
}
Пример #14
0
CvPlot* CvPlayerAI::FindBestArtistTargetPlot(CvUnit* pGreatArtist, int& iResultScore)
{
	CvAssertMsg(pGreatArtist, "pGreatArtist is null");
	if(!pGreatArtist)
	{
		return NULL;
	}

	iResultScore = 0;

	CvPlotsVector& m_aiPlots = GetPlots();

	CvPlot* pBestPlot = NULL;
	int iBestScore = 0;

	// loop through plots and wipe out ones that are invalid
	const uint nPlots = m_aiPlots.size();
	for(uint ui = 0; ui < nPlots; ui++)
	{
		if(m_aiPlots[ui] == -1)
		{
			continue;
		}

		CvPlot* pPlot = GC.getMap().plotByIndex(m_aiPlots[ui]);

		if(pPlot->isWater())
		{
			continue;
		}

		if(!pPlot->IsAdjacentOwnedByOtherTeam(getTeam()))
		{
			continue;
		}

		// don't build over luxury resources
		ResourceTypes eResource = pPlot->getResourceType();
		if(eResource != NO_RESOURCE)
		{
			CvResourceInfo* pkResource = GC.getResourceInfo(eResource);
			if(pkResource != NULL)
			{
				if (pkResource->getResourceUsage() == RESOURCEUSAGE_LUXURY)
				{
					continue;
				}
			}
		}

		// if no improvement can be built on this plot, then don't consider it
		FeatureTypes eFeature = pPlot->getFeatureType();
		if (eFeature != NO_FEATURE && GC.getFeatureInfo(eFeature)->isNoImprovement())
		{
			continue;
		}

		// Improvement already here?
		ImprovementTypes eImprovement = (ImprovementTypes)pPlot->getImprovementType();
		if (eImprovement != NO_IMPROVEMENT)
		{
			CvImprovementEntry* pkImprovementInfo = GC.getImprovementInfo(eImprovement);
			if(pkImprovementInfo)
			{
				if (pkImprovementInfo->GetCultureBombRadius() > 0)
				{
					continue;
				}
			}
		}

		int iScore = 0;

		for(int iI = 0; iI < NUM_DIRECTION_TYPES; ++iI)
		{
			CvPlot* pAdjacentPlot = plotDirection(pPlot->getX(), pPlot->getY(), ((DirectionTypes)iI));
			// if there's no plot, bail
			if(pAdjacentPlot == NULL)
			{
				continue;
			}

			// if the plot is ours or no one's, bail
			if(pAdjacentPlot->getTeam() == NO_TEAM || pAdjacentPlot->getTeam() == getTeam())
			{
				continue;
			}

			// don't evaluate city plots since we don't get ownership of them with the bomb
			if(pAdjacentPlot->getPlotCity())
			{
				continue;
			}

			const PlayerTypes eOtherPlayer = pAdjacentPlot->getOwner();
			if(GET_PLAYER(eOtherPlayer).isMinorCiv())
			{
				MinorCivApproachTypes eMinorApproach = GetDiplomacyAI()->GetMinorCivApproach(eOtherPlayer);
				// if we're friendly or protective, don't be a jerk. Bail out.
				if(eMinorApproach != MINOR_CIV_APPROACH_CONQUEST && eMinorApproach != MINOR_CIV_APPROACH_IGNORE)
				{
					iScore = 0;
					break;
				}
			}
			else
			{
				MajorCivApproachTypes eMajorApproach = GetDiplomacyAI()->GetMajorCivApproach(eOtherPlayer, true);
				DisputeLevelTypes eLandDisputeLevel = GetDiplomacyAI()->GetLandDisputeLevel(eOtherPlayer);

				bool bTicked = eMajorApproach == MAJOR_CIV_APPROACH_HOSTILE;
				bool bTickedAboutLand = eMajorApproach == MAJOR_CIV_APPROACH_NEUTRAL && (eLandDisputeLevel == DISPUTE_LEVEL_STRONG || eLandDisputeLevel == DISPUTE_LEVEL_FIERCE);

				// only bomb if we're hostile
				if(!bTicked && !bTickedAboutLand)
				{
					iScore = 0;
					break;
				}
			}

			eResource = pAdjacentPlot->getResourceType();
			if(eResource != NO_RESOURCE)
			{
				iScore += GetBuilderTaskingAI()->GetResourceWeight(eResource, NO_IMPROVEMENT, pAdjacentPlot->getNumResource()) * 10;
			}
			else
			{
				for(int iYield = 0; iYield < NUM_YIELD_TYPES; iYield++)
				{
					iScore += pAdjacentPlot->getYield((YieldTypes)iYield);
				}
			}
		}

		if(iScore > iBestScore)
		{
			iBestScore = iScore;
			pBestPlot = pPlot;
		}
	}

	iResultScore = iBestScore;
	return pBestPlot;
}
Пример #15
0
/// Updates the danger plots values to reflect threats across the map
void CvDangerPlots::UpdateDanger(bool bPretendWarWithAllCivs, bool bIgnoreVisibility)
{
	// danger plots have not been initialized yet, so no need to update
	if(!m_bArrayAllocated)
		return;

	// wipe out values
	int iGridSize = GC.getMap().numPlots();
	CvAssertMsg(iGridSize == m_DangerPlots.size(), "iGridSize does not match number of DangerPlots");
	for(int i = 0; i < iGridSize; i++)
	{
		m_DangerPlots[i].clear();
	}

	//units we know from last turn
	UnitSet previousKnownUnits = m_knownUnits;
	m_knownUnits.clear();

	CvPlayer& thisPlayer = GET_PLAYER(m_ePlayer);
	TeamTypes thisTeam = thisPlayer.getTeam();

	// for each opposing civ
	for(int iPlayer = 0; iPlayer < MAX_PLAYERS; iPlayer++)
	{
		PlayerTypes ePlayer = (PlayerTypes)iPlayer;
		CvPlayer& loopPlayer = GET_PLAYER(ePlayer);
		TeamTypes eTeam = loopPlayer.getTeam();

		if(!loopPlayer.isAlive())
			continue;

		if(eTeam == thisTeam)
			continue;

		if(ShouldIgnorePlayer(ePlayer) && !bPretendWarWithAllCivs)
			continue;

		//for each unit
		int iLoop;
		CvUnit* pLoopUnit = NULL;
		for(pLoopUnit = loopPlayer.firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = loopPlayer.nextUnit(&iLoop))
		{
			UpdateDangerSingleUnit(pLoopUnit, bIgnoreVisibility, true);
		}

		// for each city
		CvCity* pLoopCity;
		for(pLoopCity = loopPlayer.firstCity(&iLoop); pLoopCity != NULL; pLoopCity = loopPlayer.nextCity(&iLoop))
		{
			if(ShouldIgnoreCity(pLoopCity, bIgnoreVisibility))
				continue;

#if defined(MOD_EVENTS_CITY_BOMBARD)
			bool bIndirectFireAllowed = false;
			int iRange = pLoopCity->getBombardRange(bIndirectFireAllowed);
#else
			int iRange = GC.getCITY_ATTACK_RANGE();
#endif
			CvPlot* pCityPlot = pLoopCity->plot();
			CvPlot* pLoopPlot = NULL;
			for(int iDX = -(iRange); iDX <= iRange; iDX++)
			{
				for(int iDY = -(iRange); iDY <= iRange; iDY++)
				{
					pLoopPlot = plotXYWithRangeCheck(pCityPlot->getX(), pCityPlot->getY(), iDX, iDY, iRange);
					if(!pLoopPlot || pLoopPlot == pCityPlot)
						continue;

#if defined(MOD_EVENTS_CITY_BOMBARD)
					if (!bIndirectFireAllowed && !pCityPlot->canSeePlot(pLoopPlot, NO_TEAM, iRange, NO_DIRECTION))
						continue;
#endif
					AssignCityDangerValue(pLoopCity, pLoopPlot);
				}
			}
		}
	}

	// now compare the new known units with the previous known units
	for (UnitSet::iterator it = previousKnownUnits.begin(); it != previousKnownUnits.end(); ++it)
	{
		//might have made peace ...
		if (ShouldIgnorePlayer(it->first))
			continue;

		if (m_knownUnits.find(*it) == m_knownUnits.end())
		{
			CvUnit* pVanishedUnit = GET_PLAYER(it->first).getUnit(it->second);

			//it's still there, but moved out of sight - nevertheless count is, a human would do that as well
			//do not add it to the known units though, so next turn we will have forgotten about it
			if (pVanishedUnit)
				UpdateDangerSingleUnit(pVanishedUnit, true, false);
		}
	}

	int iPlotLoop;
	CvPlot* pPlot, *pAdjacentPlot;
	for(iPlotLoop = 0; iPlotLoop < GC.getMap().numPlots(); iPlotLoop++)
	{
		pPlot = GC.getMap().plotByIndexUnchecked(iPlotLoop);

		if(pPlot->isRevealed(thisTeam))
		{
			//remember the plot based damage, but it depends on the unit's promotions also, so we won't apply it directly
			int iPlotDamage = 0;
			if (pPlot->getFeatureType() != NO_FEATURE)
				iPlotDamage += (GC.getFeatureInfo(pPlot->getFeatureType())->getTurnDamage());
			if (pPlot->getTerrainType() != NO_FEATURE)
				iPlotDamage += (GC.getTerrainInfo(pPlot->getTerrainType())->getTurnDamage());

			m_DangerPlots[iPlotLoop].m_bFlatPlotDamage = (iPlotDamage>0);

			ImprovementTypes eImprovement = pPlot->getRevealedImprovementType(thisTeam);
			if(eImprovement != NO_IMPROVEMENT && GC.getImprovementInfo(eImprovement)->GetNearbyEnemyDamage() > 0)
			{
				if(!ShouldIgnoreCitadel(pPlot, bIgnoreVisibility))
				{
					for(int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
					{
						pAdjacentPlot = plotDirection(pPlot->getX(), pPlot->getY(), ((DirectionTypes)iI));

						if(pAdjacentPlot != NULL)
						{
							m_DangerPlots[iPlotLoop].m_pCitadel = pPlot;
						}
					}
				}
			}
		}
	}

	// testing city danger values
	CvCity* pLoopCity;
	int iLoopCity = 0;
	for(pLoopCity = thisPlayer.firstCity(&iLoopCity); pLoopCity != NULL; pLoopCity = thisPlayer.nextCity(&iLoopCity))
	{
		//adding danger would count each unit multiple times, is biased towards fast units
		//so we pretend they would all attack the city and tally up the damage
		//question is, what about our own defensive units in the area. should we count those as well?
		int iEvalRange = 4;
		int iThreatValue = 0;
		for(int iX = -iEvalRange; iX <= iEvalRange; iX++)
			for(int iY = -iEvalRange; iY <= iEvalRange; iY++)
			{
				CvPlot* pEvalPlot = plotXYWithRangeCheck(pLoopCity->getX(), pLoopCity->getY(), iX, iY, iEvalRange);
				if (pEvalPlot)
				{
					const CvUnit* pEnemy = pEvalPlot->getBestDefender(NO_PLAYER, thisPlayer.GetID(), NULL, true);
					if (pEnemy)
					{
						int iAttackerDamage = 0; //to be ignored
						iThreatValue += TacticalAIHelpers::GetSimulatedDamageFromAttackOnCity(pLoopCity,pEnemy,iAttackerDamage);
					}
				}
			}

		pLoopCity->SetThreatValue(iThreatValue);
	}

	m_bDirty = false;
}
Пример #16
0
bool CvMapGenerator::canPlaceBonusAt(BonusTypes eBonus, int iX, int iY, bool bIgnoreLatitude)
{
	PROFILE_FUNC();

	CvArea* pArea;
	CvPlot* pPlot;
	CvPlot* pLoopPlot;
	int iRange;
	int iDX, iDY;
	int iI;

	pPlot = GC.getMapINLINE().plotINLINE(iX, iY);
	pArea = pPlot->area();

	if (!(pPlot->canHaveBonus(eBonus, bIgnoreLatitude)))
	{
		return false;
	}

	long result = 0;
	if (gDLL->getPythonIFace()->pythonCanPlaceBonusAt(pPlot, &result) && !gDLL->getPythonIFace()->pythonUsingDefaultImpl()) // Python override
	{
		if (result >= 0)
		{
			return result;
		}
		else
		{
			FAssertMsg(false, "canPlaceBonusAt() must return >= 0");
		}
	}

	for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
	{
		pLoopPlot = plotDirection(iX, iY, ((DirectionTypes)iI));

		if (pLoopPlot != NULL)
		{
			if ((pLoopPlot->getBonusType() != NO_BONUS) && (pLoopPlot->getBonusType() != eBonus))
			{
				return false;
			}
		}
	}

	CvBonusInfo& pInfo = GC.getBonusInfo(eBonus);

	if (pPlot->isWater())
	{
		if (((GC.getMapINLINE().getNumBonusesOnLand(eBonus) * 100) / (GC.getMapINLINE().getNumBonuses(eBonus) + 1)) < pInfo.getMinLandPercent())
		{
			return false;
		}
	}

	// Make sure there are none of the same bonus nearby:

	iRange = pInfo.getUniqueRange();

	for (iDX = -(iRange); iDX <= iRange; iDX++)
	{
		for (iDY = -(iRange); iDY <= iRange; iDY++)
		{
			pLoopPlot	= plotXY(iX, iY, iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (pLoopPlot->area() == pArea)
				{
					if (plotDistance(iX, iY, pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()) <= iRange)
					{
						if (pLoopPlot->getBonusType() == eBonus)
						{
							return false;
						}
					}
				}
			}
		}
	}

	return true;
}
Пример #17
0
/// Get center of mass of units in army (account for world wrap!)
CvPlot* CvArmyAI::GetCenterOfMass(DomainTypes eDomainRequired)
{
	CvPlot* pRtnValue = NULL;
	int iTotalX = 0;
	int iTotalY = 0;
	int iNumUnits = 0;
	UnitHandle pUnit;
	int iReferenceUnitX = -1;
	int iWorldWidth = GC.getMap().getGridWidth();

	pUnit = GetFirstUnit();
	if(pUnit)
	{
		iReferenceUnitX = pUnit->getX();
	}

	while(pUnit)
	{
		int iUnitX = pUnit->getX();

		bool bWorldWrapAdjust = false;
		int iDiff = iUnitX - iReferenceUnitX;
		if(abs(iDiff) > (iWorldWidth / 2))
		{
			bWorldWrapAdjust = true;
		}

		if(bWorldWrapAdjust)
		{
			iTotalX += iUnitX + iWorldWidth;
		}
		else
		{
			iTotalX += iUnitX;
		}
		iTotalY += pUnit->getY();
		iNumUnits++;
		pUnit = GetNextUnit();
	}

	if(iNumUnits > 0)
	{
		int iAverageX = (iTotalX + (iNumUnits / 2)) / iNumUnits;
		if(iAverageX >= iWorldWidth)
		{
			iAverageX = iAverageX - iWorldWidth;
		}
		int iAverageY = (iTotalY + (iNumUnits / 2)) / iNumUnits;
		pRtnValue = GC.getMap().plot(iAverageX, iAverageY);
	}

	// Domain check
	if (eDomainRequired != NO_DOMAIN && pRtnValue)
	{
		if (pRtnValue->isWater() && eDomainRequired == DOMAIN_LAND || !pRtnValue->isWater() && eDomainRequired == DOMAIN_SEA)
		{
			// Find an adjacent plot that works
			for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
			{
				CvPlot *pLoopPlot = plotDirection(pRtnValue->getX(), pRtnValue->getY(), ((DirectionTypes)iI));
				if (pLoopPlot != NULL)
				{
					if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND)
					{
						return pLoopPlot;
					}
				}
			}

			// Try two plots out if really having problems
#ifdef AUI_HEXSPACE_DX_LOOPS
			int iMaxDX, iDX;
			CvPlot* pLoopPlot;
			for (int iDY = -2; iDY <= 2; iDY++)
			{
				iMaxDX = 2 - MAX(0, iDY);
				for (iDX = -2 - MIN(0, iDY); iDX <= iMaxDX; iDX++) // MIN() and MAX() stuff is to reduce loops (hexspace!)
				{
					// No need for range check because loops are set up properly
					pLoopPlot = plotXY(pRtnValue->getX(), pRtnValue->getY(), iDX, iDY);
					if (pLoopPlot)
					{
						if (hexDistance(iDX, iDY) == 2)
#else
			for (int iDX = -2; iDX <= 2; iDX++)
			{
				for (int iDY = -2; iDY <= 2; iDY++)
				{
					CvPlot *pLoopPlot = plotXYWithRangeCheck(pRtnValue->getX(), pRtnValue->getY(), iDX, iDY, 2);
					if (pLoopPlot)
					{
#ifdef AUI_FIX_HEX_DISTANCE_INSTEAD_OF_PLOT_DISTANCE
						if (hexDistance(iDX, iDY) == 2)
#else
						if (plotDistance(pRtnValue->getX(), pRtnValue->getY(), pLoopPlot->getX(), pLoopPlot->getY()) == 2)
#endif
#endif
						{
							if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND)
							{
								return pLoopPlot;
							}
						}
					}
				}
			}

			// Give up - just use location of first unit
			pUnit = GetFirstUnit();
			pRtnValue = pUnit->plot();
		}
	}

	return pRtnValue;
}

/// Return distance from this plot of unit in army farthest away
int CvArmyAI::GetFurthestUnitDistance(CvPlot* pPlot)
{
	int iLargestDistance = 0;
	UnitHandle pUnit;
	int iNewDistance;

	pUnit = GetFirstUnit();
	while(pUnit)
	{
		iNewDistance = plotDistance(pUnit->getX(), pUnit->getY(), pPlot->getX(), pPlot->getY());
		if(iNewDistance > iLargestDistance)
		{
			iLargestDistance = iNewDistance;
		}
		pUnit = GetNextUnit();
	}
	return iLargestDistance;
}

// FORMATION ACCESSORS

/// Retrieve index of the formation used by this army
int CvArmyAI::GetFormationIndex() const
{
	return m_iFormationIndex;
}

/// Set index of the formation used by this army
void CvArmyAI::SetFormationIndex(int iFormationIndex)
{
	CvArmyFormationSlot slot;

	if(m_iFormationIndex != iFormationIndex)
	{
		m_iFormationIndex = iFormationIndex;

		CvMultiUnitFormationInfo* thisFormation = GC.getMultiUnitFormationInfo(m_iFormationIndex);
		if(thisFormation)
		{
			int iNumSlots = thisFormation->getNumFormationSlotEntries();

			// Build all the formation entries
			m_FormationEntries.clear();
			for(int iI = 0; iI < iNumSlots; iI++)
			{
				slot.SetUnitID(ARMY_NO_UNIT);
				slot.SetTurnAtCheckpoint(ARMYSLOT_UNKNOWN_TURN_AT_CHECKPOINT);
				m_FormationEntries.push_back(slot);
			}
		}
	}
}

/// How many slots are there in this formation if filled
int CvArmyAI::GetNumFormationEntries() const
{
	return m_FormationEntries.size();
}

/// How many slots do we currently have filled?
int CvArmyAI::GetNumSlotsFilled() const
{
	int iRtnValue = 0;

	for(unsigned int iI = 0; iI < m_FormationEntries.size(); iI++)
	{
		if(m_FormationEntries[iI].m_iUnitID != ARMY_NO_UNIT)
		{
			iRtnValue++;
		}
	}
	return iRtnValue;
}
Пример #18
0
/// Updates the danger plots values to reflect threats across the map
void CvDangerPlots::UpdateDanger (bool bPretendWarWithAllCivs, bool bIgnoreVisibility)
{
	// danger plots have not been initialized yet, so no need to update
	if (!m_bArrayAllocated)
	{
		return;
	}

	// wipe out values
	int iGridSize = GC.getMap().numPlots();
	CvAssertMsg(iGridSize == m_DangerPlots.size(), "iGridSize does not match number of DangerPlots");
	for (int i = 0; i < iGridSize; i++)
	{
		m_DangerPlots[i] = 0;
	}

	CvPlayer& thisPlayer = GET_PLAYER(m_ePlayer);
	TeamTypes thisTeam = thisPlayer.getTeam();

	// for each opposing civ
	for (int iPlayer = 0; iPlayer < MAX_PLAYERS; iPlayer++)
	{
		PlayerTypes ePlayer = (PlayerTypes)iPlayer;
		CvPlayer& loopPlayer = GET_PLAYER(ePlayer);
		TeamTypes eTeam = loopPlayer.getTeam();

		if (!loopPlayer.isAlive())
		{
			continue;
		}

		if (eTeam == thisTeam)
		{
			continue;
		}

		if (ShouldIgnorePlayer(ePlayer) && !bPretendWarWithAllCivs)
		{
			continue;
		}

		//for each unit
		int iLoop;
		CvUnit* pLoopUnit = NULL;
		for (pLoopUnit = loopPlayer.firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = loopPlayer.nextUnit(&iLoop))
		{
			if (ShouldIgnoreUnit(pLoopUnit, bIgnoreVisibility))
			{
				continue;
			}

			int iRange = pLoopUnit->baseMoves();
			if (pLoopUnit->canRangeStrike())
			{
				iRange += pLoopUnit->GetRange();
			}

			CvPlot* pUnitPlot = pLoopUnit->plot();
			AssignUnitDangerValue(pLoopUnit, pUnitPlot);
			CvPlot* pLoopPlot = NULL;

			for (int iDX = -(iRange); iDX <= iRange; iDX++)
			{
				for (int iDY = -(iRange); iDY <= iRange; iDY++)
				{
					pLoopPlot = plotXYWithRangeCheck(pUnitPlot->getX(), pUnitPlot->getY(), iDX, iDY, iRange);
					if (!pLoopPlot || pLoopPlot == pUnitPlot)
					{
						continue;
					}

					if (!pLoopUnit->canMoveOrAttackInto(*pLoopPlot) && !pLoopUnit->canRangeStrikeAt(pLoopPlot->getX(),pLoopPlot->getY()))
					{
						continue;
					}

					AssignUnitDangerValue(pLoopUnit, pLoopPlot);
				}
			}
		}

		// for each city
		CvCity* pLoopCity;
		for (pLoopCity = loopPlayer.firstCity(&iLoop); pLoopCity != NULL; pLoopCity = loopPlayer.nextCity(&iLoop))
		{
			if (ShouldIgnoreCity(pLoopCity, bIgnoreVisibility))
			{
				continue;
			}

			int iRange = GC.getCITY_ATTACK_RANGE();
			CvPlot* pCityPlot = pLoopCity->plot();
			AssignCityDangerValue(pLoopCity, pCityPlot);
			CvPlot* pLoopPlot = NULL;

			for (int iDX = -(iRange); iDX <= iRange; iDX++)
			{
				for (int iDY = -(iRange); iDY <= iRange; iDY++)
				{
					pLoopPlot = plotXYWithRangeCheck(pCityPlot->getX(), pCityPlot->getY(), iDX, iDY, iRange);
					if (!pLoopPlot)
					{
						continue;
					}

					AssignCityDangerValue(pLoopCity, pLoopPlot);
				}
			}
		}
	}

	// Citadels
	int iCitadelValue = GetDangerValueOfCitadel();
	int iPlotLoop;
	CvPlot *pPlot, *pAdjacentPlot;
	for (iPlotLoop = 0; iPlotLoop < GC.getMap().numPlots(); iPlotLoop++)
	{
		pPlot = GC.getMap().plotByIndexUnchecked(iPlotLoop);

		if (pPlot->isRevealed(thisTeam))
		{
			ImprovementTypes eImprovement = pPlot->getRevealedImprovementType(thisTeam);
			if (eImprovement != NO_IMPROVEMENT && GC.getImprovementInfo(eImprovement)->GetNearbyEnemyDamage() > 0)
			{
				if (!ShouldIgnoreCitadel(pPlot, bIgnoreVisibility))
				{
					for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
					{
						pAdjacentPlot = plotDirection(pPlot->getX(), pPlot->getY(), ((DirectionTypes)iI));

						if (pAdjacentPlot != NULL)
						{
							AddDanger(pAdjacentPlot->getX(), pAdjacentPlot->getY(), iCitadelValue);
						}
					}
				}
			}
		}
	}

	// testing city danger values
	CvCity* pLoopCity;
	int iLoopCity = 0;
	for (pLoopCity = thisPlayer.firstCity(&iLoopCity); pLoopCity != NULL; pLoopCity = thisPlayer.nextCity(&iLoopCity))
	{
		int iThreatValue = GetCityDanger(pLoopCity);
		pLoopCity->SetThreatValue(iThreatValue);
	}

	m_bDirty = false;
}
CyPlot* cyPlotDirection(int iX, int iY, DirectionTypes eDirection)
{
	return new CyPlot(plotDirection(iX, iY, eDirection));
}
//	--------------------------------------------------------------------------------
bool CvUnitMovement::IsSlowedByZOC(const CvUnit* pUnit, const CvPlot* pFromPlot, const CvPlot* pToPlot)
{
	if (pUnit->IsIgnoreZOC())
		return false;

	// Zone of Control
	if(GC.getZONE_OF_CONTROL_ENABLED() <= 0)
		return false;

	TeamTypes eUnitTeam = pUnit->getTeam();
	DomainTypes eUnitDomain = pUnit->getDomainType();
	CvTeam& kUnitTeam = GET_TEAM(eUnitTeam);

	//there are only two plots we need to check
	DirectionTypes moveDir = directionXY(pFromPlot,pToPlot);
	int eRight = (int(moveDir) + 1) % 6;
	int eLeft = (int(moveDir) + 5) % 6; 
	CvPlot* aPlotsToCheck[2];
	aPlotsToCheck[0] = plotDirection(pFromPlot->getX(),pFromPlot->getY(),(DirectionTypes)eRight);
	aPlotsToCheck[1] = plotDirection(pFromPlot->getX(),pFromPlot->getY(),(DirectionTypes)eLeft);
	for (int iCount=0; iCount<2; iCount++)
	{
		CvPlot* pAdjPlot = aPlotsToCheck[iCount];

		if(!pAdjPlot)
			continue;

		// check city zone of control
		if(pAdjPlot->isEnemyCity(*pUnit))
			return true;

		// Loop through all units to see if there's an enemy unit here
		IDInfo* pAdjUnitNode = pAdjPlot->headUnitNode();
		while(pAdjUnitNode != NULL)
		{
			CvUnit* pLoopUnit = NULL;
			if((pAdjUnitNode->eOwner >= 0) && pAdjUnitNode->eOwner < MAX_PLAYERS)
				pLoopUnit = (GET_PLAYER(pAdjUnitNode->eOwner).getUnit(pAdjUnitNode->iID));

			pAdjUnitNode = pAdjPlot->nextUnitNode(pAdjUnitNode);

			if(!pLoopUnit) 
				continue;

			if(pLoopUnit->isInvisible(eUnitTeam,false))
				continue;

			// Combat unit?
			if(!pLoopUnit->IsCombatUnit())
				continue;

			// Embarked units don't have ZOC
			if(pLoopUnit->isEmbarked())
				continue;

			// At war with this unit's team?
			TeamTypes eLoopUnitTeam = pLoopUnit->getTeam();
			if(eLoopUnitTeam == BARBARIAN_TEAM || kUnitTeam.isAtWar(eLoopUnitTeam) || pLoopUnit->isAlwaysHostile(*pAdjPlot) )
			{
				// Same Domain?
				DomainTypes eLoopUnitDomain = pLoopUnit->getDomainType();
				if(eLoopUnitDomain != eUnitDomain)
				{
					// hovering units always exert a ZOC
					if (pLoopUnit->IsHoveringUnit() || eLoopUnitDomain==DOMAIN_HOVER)
					{
						// continue on
					}
					// water unit can ZoC embarked land unit
					else if(eLoopUnitDomain == DOMAIN_SEA && (pToPlot->needsEmbarkation(pUnit) || pFromPlot->needsEmbarkation(pUnit)) )
					{
						// continue on
					}
					else
					{
						// ignore this unit
						continue;
					}
				}
				else
				{
					//land units don't ZoC embarked units (if they stay embarked)
					if(eLoopUnitDomain == DOMAIN_LAND && pToPlot->needsEmbarkation(pUnit) && pFromPlot->needsEmbarkation(pUnit))
					{
						continue;
					}
				}

				//ok, all conditions fulfilled
				return true;
			}
		}
	}

	return false;
}
// Mark cells we can use to bomb a specific target
void CvTacticalAnalysisMap::SetTargetBombardCells(CvPlot* pTarget, int iRange, bool bIgnoreLOS)
{
	int iDX, iDY;
	CvPlot* pLoopPlot;
	int iPlotIndex;
#ifdef AUI_HEXSPACE_DX_LOOPS
	int iMaxDX;
	for (iDY = -iRange; iDY <= iRange; iDY++)
	{
		iMaxDX = iRange - MAX(0, iDY);
		for (iDX = -iRange - MIN(0, iDY); iDX <= iMaxDX; iDX++) // MIN() and MAX() stuff is to reduce loops (hexspace!)
#else
	int iPlotDistance;

	for(iDX = -(iRange); iDX <= iRange; iDX++)
	{
		for(iDY = -(iRange); iDY <= iRange; iDY++)
#endif
		{
#ifdef AUI_HEXSPACE_DX_LOOPS
			if (iDX == 0 && iDY == 0)
				continue;
#endif
			pLoopPlot = plotXY(pTarget->getX(), pTarget->getY(), iDX, iDY);
			if(pLoopPlot != NULL)
			{
#ifndef AUI_HEXSPACE_DX_LOOPS
#ifdef AUI_FIX_HEX_DISTANCE_INSTEAD_OF_PLOT_DISTANCE
				iPlotDistance = hexDistance(iDX, iDY);
#else
				iPlotDistance = plotDistance(pLoopPlot->getX(), pLoopPlot->getY(), pTarget->getX(), pTarget->getY());
#endif
				if(iPlotDistance > 0 && iPlotDistance <= iRange)
#endif
				{
					iPlotIndex = GC.getMap().plotNum(pLoopPlot->getX(), pLoopPlot->getY());
					if(m_pPlots[iPlotIndex].IsRevealed() && !m_pPlots[iPlotIndex].IsImpassableTerrain() && !m_pPlots[iPlotIndex].IsImpassableTerritory())
					{
						if(!m_pPlots[iPlotIndex].IsEnemyCity() && !m_pPlots[iPlotIndex].IsNeutralCity())
						{
							if(bIgnoreLOS || pLoopPlot->canSeePlot(pTarget, m_pPlayer->getTeam(), iRange, NO_DIRECTION))
							{
								m_pPlots[iPlotIndex].SetWithinRangeOfTarget(true);
							}
						}
					}
				}
			}
		}
	}
}

// Mark cells we can use to bomb a specific target
void CvTacticalAnalysisMap::SetTargetFlankBonusCells(CvPlot* pTarget)
{
	CvPlot* pLoopPlot;
	int iPlotIndex;

	// No flank attacks on units at sea (where all combat is bombards)
	if(pTarget->isWater())
	{
		return;
	}

	for(int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
	{
		pLoopPlot = plotDirection(pTarget->getX(), pTarget->getY(), ((DirectionTypes)iI));
		if(pLoopPlot != NULL)
		{
			iPlotIndex = GC.getMap().plotNum(pLoopPlot->getX(), pLoopPlot->getY());
			if(m_pPlots[iPlotIndex].IsRevealed() && !m_pPlots[iPlotIndex].IsImpassableTerrain() && !m_pPlots[iPlotIndex].IsImpassableTerritory())
			{
				if(!m_pPlots[iPlotIndex].IsFriendlyCity() && !m_pPlots[iPlotIndex].IsEnemyCity() && !m_pPlots[iPlotIndex].IsNeutralCity())
				{
					if(!m_pPlots[iPlotIndex].IsFriendlyTurnEndTile() && m_pPlots[iPlotIndex].GetEnemyMilitaryUnit() == NULL)
					{
						m_pPlots[iPlotIndex].SetHelpsProvidesFlankBonus(true);
					}
				}
			}
		}
	}
}