// 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;
	int iPlotDistance;

	for(iDX = -(iRange); iDX <= iRange; iDX++)
	{
		for(iDY = -(iRange); iDY <= iRange; iDY++)
		{
			pLoopPlot = plotXY(pTarget->getX(), pTarget->getY(), iDX, iDY);
			if(pLoopPlot != NULL)
			{
				iPlotDistance = plotDistance(pLoopPlot->getX(), pLoopPlot->getY(), pTarget->getX(), pTarget->getY());
				if(iPlotDistance > 0 && iPlotDistance <= iRange)
				{
					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);
							}
						}
					}
				}
			}
		}
	}
}
//------------------------------------------------------------------------------
void CvDllNetMessageHandler::ResponseCityBuyPlot(PlayerTypes ePlayer, int iCityID, int iX, int iY)
{
	CvPlayerAI& kPlayer = GET_PLAYER(ePlayer);
	CvCity* pkCity = kPlayer.getCity(iCityID);
	if(pkCity != NULL)
	{
		CvPlot* pkPlot = NULL;

		// (-1,-1) means pick a random plot to buy
		if(iX == -1 && iY == -1)
		{
#if defined(MOD_BALANCE_CORE)
			pkPlot = pkCity->GetNextBuyablePlot(false);
#else
			pkPlot = pkCity->GetNextBuyablePlot();
#endif
		}
		else
		{
			pkPlot = GC.getMap().plot(iX, iY);
		}

		if(pkPlot != NULL)
		{
			if(pkCity->CanBuyPlot(pkPlot->getX(), pkPlot->getY()))
			{
				pkCity->BuyPlot(pkPlot->getX(), pkPlot->getY());
				if(ePlayer == GC.getGame().getActivePlayer() && GC.GetEngineUserInterface()->isCityScreenUp())
				{
					GC.GetEngineUserInterface()->setDirty(CityScreen_DIRTY_BIT, true);
				}
			}
		}
	}
}
/// Updates the danger plots values to reflect threats across the map
void CvDistanceMap::Update()
{
	const CvMap& map = GC.getMap();
	int nPlots = map.numPlots();

	m_vDistance = std::vector<int>(nPlots,INT_MAX);
	m_vClosestFeature = std::vector<int>(nPlots,0);
	m_bArrayAllocated = true;
		
	// since we know there are very few cities compared to the number of plots,
	// we don't need to do the full distance transform

	for (int i = 0; i < MAX_PLAYERS; i++)
	{
		if (m_ePlayer!=NO_PLAYER && m_ePlayer!=i)
			continue;

		// for each city
		CvPlayer& thisPlayer = GET_PLAYER((PlayerTypes)i);
		int iCityIndex = 0;
		for(CvCity* pLoopCity = thisPlayer.firstCity(&iCityIndex); pLoopCity != NULL; pLoopCity = thisPlayer.nextCity(&iCityIndex))
		{
			CvPlot* pCityPlot = pLoopCity->plot();

			for (int iPlotIndex=0; iPlotIndex<nPlots; iPlotIndex++)
			{
				CvPlot* pPlot = map.plotByIndexUnchecked(iPlotIndex);
				if (pPlot)
				{
					int iDistance = plotDistance( pCityPlot->getX(),pCityPlot->getY(),pPlot->getX(),pPlot->getY() );

					bool bUpdate = (iDistance < m_vDistance[iPlotIndex]);
					
					//in case of equal distance, take care not to prefer the player with the lower ID
					if (iDistance == m_vDistance[iPlotIndex]) 
					{
						PlayerTypes currentOwner = (PlayerTypes) UNPACK_OWNER(m_vClosestFeature[iPlotIndex]);
						CvCity* pCurrentCity = GET_PLAYER(currentOwner).getCity( UNPACK_ID(m_vClosestFeature[iPlotIndex]) );
						bUpdate = (pCurrentCity->getGameTurnFounded() > pLoopCity->getGameTurnFounded());
					}

					if (bUpdate)
					{
						m_vDistance[iPlotIndex] = iDistance;
						m_vClosestFeature[iPlotIndex] = PACK(pLoopCity->getOwner(), pLoopCity->GetID());
					}
				}
			}
		}
	}

	m_bDirty = false;
}
Esempio n. 4
0
int CvPlayerAI::AI_plotTargetMissionAIs(CvPlot* pPlot, MissionAITypes eMissionAI, int iRange)
{
	int iCount = 0;

	int iLoop;
	for(CvUnit* pLoopUnit = firstUnit(&iLoop); pLoopUnit; pLoopUnit = nextUnit(&iLoop))
	{
		CvPlot* pMissionPlot = pLoopUnit->GetMissionAIPlot();
		if(!pMissionPlot)
		{
			continue;
		}

		MissionAITypes eGroupMissionAI = pLoopUnit->GetMissionAIType();
		if(eGroupMissionAI != eMissionAI)
		{
			continue;
		}

		int iDistance = plotDistance(pPlot->getX(), pPlot->getY(), pMissionPlot->getX(), pMissionPlot->getY());
		if(iDistance == iRange)
		{
			iCount++;
		}
	}

	return iCount;
}
//------------------------------------------------------------------------------
void CvDllNetMessageHandler::ResponseSwapUnits(PlayerTypes ePlayer, int iUnitID, MissionTypes eMission, int iData1, int iData2, int iFlags, bool bShift)
{
	CvUnit::dispatchingNetMessage(true);

	CvPlayerAI& kPlayer = GET_PLAYER(ePlayer);
	CvUnit* pkUnit = kPlayer.getUnit(iUnitID);

	if(pkUnit != NULL)
	{
		// Get target plot
		CvMap& kMap = GC.getMap();
		CvPlot* pkTargetPlot = kMap.plot(iData1, iData2);

		if(pkTargetPlot != NULL)
		{
			CvPlot* pkOriginationPlot = pkUnit->plot();

			// Find unit to move out
			for(int iI = 0; iI < pkTargetPlot->getNumUnits(); iI++)
			{
				CvUnit* pkUnit2 = pkTargetPlot->getUnitByIndex(iI);

				if(pkUnit2 && pkUnit2->AreUnitsOfSameType(*pkUnit))
				{
					// Start the swap
					pkUnit->PushMission(CvTypes::getMISSION_MOVE_TO(), iData1, iData2, CvUnit::MOVEFLAG_IGNORE_STACKING, bShift, true);

					// Move the other unit back out, again splitting if necessary
					pkUnit2->PushMission(CvTypes::getMISSION_MOVE_TO(), pkOriginationPlot->getX(), pkOriginationPlot->getY());
				}
			}
		}
	}
	CvUnit::dispatchingNetMessage(false);
}
Esempio n. 6
0
/// Sums the danger values of the plots around the city to determine the danger value of the city
int CvDangerPlots::GetCityDanger (CvCity* pCity)
{
	CvAssertMsg(pCity, "pCity is null");
	if(!pCity) return 0;

	CvAssertMsg(pCity->getOwner() == m_ePlayer, "City does not belong to us");

	CvPlot* pPlot = pCity->plot();
	int iEvalRange = GC.getAI_DIPLO_PLOT_RANGE_FROM_CITY_HOME_FRONT();

	int iDangerValue = 0;

	for (int iX = -iEvalRange; iX <= iEvalRange; iX++)
	{
		for (int iY = -iEvalRange; iY <= iEvalRange; iY++)
		{
			CvPlot* pEvalPlot = plotXYWithRangeCheck(pPlot->getX(), pPlot->getY(), iX, iY, iEvalRange);
			if (!pEvalPlot)
			{
				continue;
			}

			iDangerValue += GetDanger(*pEvalPlot);
		}
	}

	return iDangerValue;
}
// 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);
					}
				}
			}
		}
	}
}
/// Return the maximum amount of damage that could be dealt to a non-specific unit at this plot
int CvDangerPlots::GetDanger(const CvPlot& pPlot, PlayerTypes ePlayer)
{
	if(!m_bArrayAllocated)
		return 0;

	const int idx = pPlot.getX() + pPlot.getY() * GC.getMap().getGridWidth();
	return m_DangerPlots[idx].GetDanger(ePlayer);
}
/// Returns if the tile is in danger
bool CvDangerPlots::IsUnderImmediateThreat(const CvPlot& pPlot, PlayerTypes ePlayer)
{
	if(!m_bArrayAllocated)
		return 0;

	const int idx = pPlot.getX() + pPlot.getY() * GC.getMap().getGridWidth();
	return m_DangerPlots[idx].IsUnderImmediateThreat(ePlayer);
}
Esempio n. 10
0
std::vector<CvUnit*> CvDangerPlots::GetPossibleAttackers(const CvPlot& Plot) const
{
	if(!m_bArrayAllocated)
		return std::vector<CvUnit*>();

	const int idx = Plot.getX() + Plot.getY() * GC.getMap().getGridWidth();

	return m_DangerPlots[idx].GetPossibleAttackers();
}
Esempio n. 11
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 CvDistanceMap::GetClosestFeatureDistance(const CvPlot& plot)
{
	if (m_bDirty)
		Update();

	if (m_bArrayAllocated)
		return m_vDistance[ GC.getMap().plotNum( plot.getX(), plot.getY() ) ]; 

	return INT_MAX;
}
Esempio n. 13
0
void CvDistanceMap::Dump(const char* filename)
{
	ofstream out(filename);
	if (out)
	{
		out << "#x,y,hx,hz,water,distance,id,owner\n"; 
		for (int i=0; i<GC.getMap().numPlots(); i++)
		{
			CvPlot* pPlot =  GC.getMap().plotByIndexUnchecked(i);
			int xHex = xToHexspaceX(pPlot->getX(),pPlot->getY());
			int zHex = -xHex-pPlot->getY();

			out << pPlot->getX() << "," << pPlot->getY() << "," << xHex << "," << zHex << "," << (pPlot->isWater() ? 1 : 0) << "," 
				<< GetClosestFeatureDistance(*pPlot) << "," << GetClosestFeatureID(*pPlot) << "," << GetClosestFeatureOwner(*pPlot) << "\n";
		}
	}
	out.close();

}
//	-----------------------------------------------------------------------------------------------
int CvDistanceMap::GetClosestFeatureOwner(const CvPlot& plot)
{
	if (m_bDirty)
		Update();

	if (m_bArrayAllocated)
		return UNPACK_OWNER( m_vClosestFeature[ GC.getMap().plotNum( plot.getX(), plot.getY() ) ] );

	return -1;
}
/// Returns if the unit is in immediate danger
bool CvDangerPlots::IsUnderImmediateThreat(const CvPlot& pPlot, const CvUnit* pUnit)
{
	if(!m_bArrayAllocated)
		return 0;

	const int idx = pPlot.getX() + pPlot.getY() * GC.getMap().getGridWidth();
	if (pUnit)
	{
		return m_DangerPlots[idx].GetDanger(pUnit) > 0;
	}
	return m_DangerPlots[idx].GetDanger(NO_PLAYER);
}
Esempio n. 16
0
/// Return the maximum amount of damage a city could take at this plot
int CvDangerPlots::GetDanger(const CvPlot& pPlot, CvCity* pCity, const CvUnit* pPretendGarrison)
{
	if(!m_bArrayAllocated)
		return 0;

	const int idx = pPlot.getX() + pPlot.getY() * GC.getMap().getGridWidth();
	if (pCity != NULL)
	{
		return m_DangerPlots[idx].GetDanger(pCity, pPretendGarrison);
	}
	return m_DangerPlots[idx].GetDanger(NO_PLAYER);
}
Esempio n. 17
0
/// Return the maximum amount of damage a unit could take at this plot
int CvDangerPlots::GetDanger(const CvPlot& pPlot, const CvUnit* pUnit, AirActionType iAirAction)
{
	if(!m_bArrayAllocated)
		return 0;

	const int idx = pPlot.getX() + pPlot.getY() * GC.getMap().getGridWidth();
	if (pUnit)
	{
		return m_DangerPlots[idx].GetDanger(pUnit, iAirAction);
	}
	return m_DangerPlots[idx].GetDanger(NO_PLAYER);
}
bool CvDllPythonEvents::reportKbdEvent(int evt, int key, int iCursorX, int iCursorY)
{
	if (preEvent())
	{
		NiPoint3 pt3Location;
		CvPlot* pPlot = gDLL->getEngineIFace()->pickPlot(iCursorX, iCursorY, pt3Location);
		CyArgsList eventData;
		eventData.add("kbdEvent");
		eventData.add(evt);
		eventData.add(key);
		eventData.add(iCursorX);
		eventData.add(iCursorY);
		eventData.add(pPlot ? pPlot->getX() : -1);
		eventData.add(pPlot ? pPlot->getY() : -1);

		return postEvent(eventData);
	}
	return false;
}
Esempio n. 19
0
void CvPlayerAI::AI_updateFoundValues(bool bStartingLoc)
{
	int iLoop;
	const int iNumPlots = GC.getMap().numPlots();
	for(CvArea *pLoopArea = GC.getMap().firstArea(&iLoop); pLoopArea != NULL; pLoopArea = GC.getMap().nextArea(&iLoop))
	{
		pLoopArea->setTotalFoundValue(0);
	}

	const PlayerTypes eID = GetID();
	if (bStartingLoc)
	{
		for (int iI = 0; iI < iNumPlots; iI++)
		{
			GC.getMap().plotByIndexUnchecked(iI)->setFoundValue(eID, -1);
		}
	}
	else
	{
		const TeamTypes eTeam = getTeam();
		for (int iI = 0; iI < iNumPlots; iI++)
		{
			CvPlot* pLoopPlot = GC.getMap().plotByIndexUnchecked(iI);

			if (pLoopPlot->isRevealed(eTeam))
			{
				const int iValue = AI_foundValue(pLoopPlot->getX(), pLoopPlot->getY());
				pLoopPlot->setFoundValue(eID, iValue);
				CvArea *pLoopArea = GC.getMap().getArea(pLoopPlot->getArea());
				if (pLoopArea && !pLoopArea->isWater())
				{
					pLoopArea->setTotalFoundValue(pLoopArea->getTotalFoundValue() + iValue);
				}
			}
			else
			{
				pLoopPlot->setFoundValue(eID, -1);
			}
		}
	}
}
bool CvDllPythonEvents::reportMouseEvent(int evt, int iCursorX, int iCursorY, bool bInterfaceConsumed)
{
	if (preEvent())
	{
		NiPoint3 pt3Location;
		CvPlot* pPlot = gDLL->getEngineIFace()->pickPlot(iCursorX, iCursorY, pt3Location);
		CyArgsList eventData;
		eventData.add("mouseEvent");				// add key to lookup python handler fxn
		eventData.add(evt);
		eventData.add(iCursorX);
		eventData.add(iCursorY);
		eventData.add(pPlot ? pPlot->getX() : -1);
		eventData.add(pPlot ? pPlot->getY() : -1);
		eventData.add(bInterfaceConsumed);

		// add list of active screens
		std::vector<int> screens;
		gDLL->getInterfaceIFace()->getInterfaceScreenIdsForInput(screens);
		eventData.add(screens.size() ? &screens[0] : NULL, screens.size());

		return postEvent(eventData);
	}
	return false;
}
// Indicate the plots we might want to move to that the enemy can attack
void CvTacticalAnalysisMap::MarkCellsNearEnemy()
{
	for(unsigned int iUnitIndex = 0;  iUnitIndex < m_EnemyUnits.size(); iUnitIndex++)
	{
		CvUnit* pUnit = getUnit(m_EnemyUnits[iUnitIndex]);
		
		//for ranged every plot we can enter with movement left is a base for attack
		int iMinMovesLeft = pUnit->IsCanAttackRanged() ? 1 : 0;

		//be a bit conservative here, use ZOC - if one of our units is killed, this is not correct anymore
		//therefore we later do a dilation filter on the cells
		ReachablePlots tiles = pUnit->GetAllPlotsInReachThisTurn(false,true,false,iMinMovesLeft);

		for (ReachablePlots::iterator moveTile=tiles.begin(); moveTile!=tiles.end(); ++moveTile)
		{
			CvPlot* pMoveTile = GC.getMap().plotByIndexUnchecked(moveTile->iPlotIndex);
			int iPlotIndex = GC.getMap().plotNum(pMoveTile->getX(),pMoveTile->getY());

			if (pUnit->IsCanAttackRanged())
			{
				std::set<int> rangedPlots;
				//this generates some overlap, but preventing that is about as bad as ignoring it
				TacticalAIHelpers::GetPlotsUnderRangedAttackFrom(pUnit,pMoveTile,rangedPlots,false,false);
				for (std::set<int>::iterator attackTile=rangedPlots.begin(); attackTile!=rangedPlots.end(); ++attackTile)
				{
					m_pCells[*attackTile].SetSubjectToAttack(true);
				}
			}
			else
			{
				//for melee every tile he can move into can be attacked
				m_pCells[iPlotIndex].SetSubjectToAttack(true);
			}
		}
	}

	//do the dilation
	std::vector<int> vCellsToMark;
	for (int iPlotLoop = 0; iPlotLoop < GC.getMap().numPlots(); iPlotLoop++)
	{
		//nothing to do
		if (m_pCells[iPlotLoop].IsSubjectToAttack())
			continue;

		CvPlot* pPlot = GC.getMap().plotByIndexUnchecked(iPlotLoop);

		//danger plots are calculated without ZOC
		if (GET_PLAYER(m_ePlayer).GetPossibleAttackers(*pPlot).size()>0)
		{
			//check whether neighbors are subject to attack with ZOC
			CvPlot** aPlotsToCheck = GC.getMap().getNeighborsUnchecked(pPlot);
			for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
			{
				CvPlot* pAdjacentPlot = aPlotsToCheck[iI];
				if (pAdjacentPlot)
				{
					if (m_pCells[pAdjacentPlot->GetPlotIndex()].IsSubjectToAttack())
					{
						vCellsToMark.push_back(iPlotLoop);
						break;
					}
				}
			}
		}
	}
	//this should give a nice compromise
	for (size_t iI = 0; iI < vCellsToMark.size(); iI++)
		m_pCells[vCellsToMark[iI]].SetSubjectToAttack(true);

	// Look at every cell on the map
	for(int iI = 0; iI < GC.getMap().numPlots(); iI++)
	{
		CvPlot* pPlot = GC.getMap().plotByIndexUnchecked(iI);
		if(m_pCells[iI].IsRevealed() && !m_pCells[iI].IsImpassableTerrain() && !m_pCells[iI].IsImpassableTerritory())
		{
			// Friendly cities always safe
			if(!m_pCells[iI].IsFriendlyCity())
			{
				if(!pPlot->isVisibleToEnemy(m_ePlayer))
				{
					m_pCells[iI].SetNotVisibleToEnemy(true);
				}
				else
				{
					// Check adjacent plots for enemy citadels
					if(!m_pCells[iI].IsSubjectToAttack())
					{
						if ( pPlot->IsNearEnemyCitadel( m_ePlayer ) )
								m_pCells[iI].SetSubjectToAttack(true);

						for(unsigned int iCityIndex = 0;  iCityIndex < m_EnemyCities.size(); iCityIndex++)
						{
							CvCity* pCity = getCity( m_EnemyCities[iCityIndex] );
							if (pCity->canRangeStrikeAt( pPlot->getX(), pPlot->getY() ))
								m_pCells[iI].SetSubjectToAttack(true);
						}
					}
				}
			}
		}
	}
}
Esempio n. 22
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;
}
Esempio n. 23
0
/// Return the danger value of a given plot
int CvDangerPlots::GetDanger (const CvPlot & pPlot) const
{
	const int idx = pPlot.getX() + pPlot.getY() * GC.getMap().getGridWidth();
	return m_DangerPlots[idx];
}
int plotDistance(const CvPlot& plotA, const CvPlot& plotB)
{
	return plotDistance(plotA.getX(),plotA.getY(),plotB.getX(),plotB.getY());
}
Esempio n. 25
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;
}
Esempio n. 26
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;
}
Esempio n. 27
0
/// Recalculate when each unit will arrive at the current army position, whatever that is
void CvArmyAI::UpdateCheckpointTurnsAndRemoveBadUnits()
{
	CvAIOperation* pOperation = GET_PLAYER(GetOwner()).getAIOperation(GetOperationID());
	//should be updated before calling this ...
	CvPlot* pCurrentArmyPlot = GC.getMap().plot(GetX(), GetY());

	//kick out damaged units, but if we're defending or escorting, no point in running away
	if (pOperation->IsOffensive())
	{
		for (unsigned int iI = 0; iI < m_FormationEntries.size(); iI++)
		{
			if (!m_FormationEntries[iI].IsUsed())
				continue;

			CvUnit* pUnit = GET_PLAYER(m_eOwner).getUnit(m_FormationEntries[iI].m_iUnitID);
			if (pUnit == NULL)
				continue;

			//failsafe - make sure the army ID is set
			if (pUnit->getArmyID() != GetID())
				pUnit->setArmyID(GetID());

			//let tactical AI handle those
			if (pUnit->GetCurrHitPoints() < pUnit->GetMaxHitPoints() / 3)
				RemoveUnit(m_FormationEntries[iI].GetUnitID());
		}
	}

	//update for all units in this army. ignore the ones still being built
	int iGatherTolerance = pOperation->GetGatherTolerance(this, pCurrentArmyPlot);
	for(unsigned int iI = 0; iI < m_FormationEntries.size(); iI++)
	{
		if (!m_FormationEntries[iI].IsUsed())
			continue;

		CvUnit* pUnit = GET_PLAYER(m_eOwner).getUnit(m_FormationEntries[iI].GetUnitID());
		if(pUnit && pCurrentArmyPlot)
		{
			if(plotDistance(*pUnit->plot(),*pCurrentArmyPlot)<iGatherTolerance)
			{
				m_FormationEntries[iI].SetTurnsToCheckpoint(0);
			}
			else
			{
				//be generous with the flags here, for some ops the muster point may be far away and intermittendly occupied by foreign units ...
				int iFlags = CvUnit::MOVEFLAG_APPROX_TARGET_RING2 | CvUnit::MOVEFLAG_IGNORE_STACKING | CvUnit::MOVEFLAG_IGNORE_ZOC;
				int iTurnsToReachCheckpoint = pUnit->TurnsToReachTarget(pCurrentArmyPlot, iFlags, pOperation->GetMaximumRecruitTurns());

				//if we're already moving to target, the current army plot is moving, so we cannot check progress against ...
				if ( iTurnsToReachCheckpoint==INT_MAX ||
					 (GetArmyAIState()==ARMYAISTATE_WAITING_FOR_UNITS_TO_CATCH_UP && !m_FormationEntries[iI].IsMakingProgressTowardsCheckpoint(iTurnsToReachCheckpoint)) )
				{
					CvString strMsg;
					strMsg.Format("Removing %s %d from army %d because no progress to checkpoint (%d:%d). ETA %d, previously %d.", 
						pUnit->getName().c_str(), m_FormationEntries[iI].GetUnitID(), GetID(), pCurrentArmyPlot->getX(), pCurrentArmyPlot->getY(),
						iTurnsToReachCheckpoint, m_FormationEntries[iI].m_iPrevEstimatedTurnsToCheckpoint);
					pOperation->LogOperationSpecialMessage(strMsg);
					RemoveUnit(m_FormationEntries[iI].GetUnitID());
				}
				else
					m_FormationEntries[iI].SetTurnsToCheckpoint(iTurnsToReachCheckpoint);
			}
		}
	}
}
/// 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;
}
/// Retrieve the relative value of this plot (including plots that would be in city radius)
int CvCitySiteEvaluator::PlotFoundValue(CvPlot* pPlot, CvPlayer* pPlayer, YieldTypes eYield, bool)
{
	CvAssert(pPlot);
	if(!pPlot)
		return 0;

	// Make sure this player can even build a city here
	if(!CanFound(pPlot, pPlayer, false))
	{
		return 0;
	}

	int rtnValue = 0;

	int iFoodValue = 0;
	int iHappinessValue = 0;
	int iProductionValue = 0;
	int iGoldValue = 0;
	int iScienceValue = 0;
	int iFaithValue = 0;
	int iResourceValue = 0;
	int iStrategicValue = 0;

	int iCelticForestCount = 0;
	int iIroquoisForestCount = 0;
	int iBrazilJungleCount = 0;
	int iNaturalWonderCount = 0;
	int iDesertCount = 0;
	int iWetlandsCount = 0;
#if defined(MOD_BALANCE_CORE_SETTLER)
	int iWaterPlot = 0;
	int iBadPlot = 0;
	int iLoopPlots = 0;
#endif

	int iTotalFoodValue = 0;
	int iTotalHappinessValue = 0;
	int iTotalProductionValue = 0;
	int iTotalGoldValue = 0;
	int iTotalScienceValue = 0;
	int iTotalFaithValue = 0;
	int iTotalResourceValue = 0;
	int iTotalStrategicValue = 0;

	int iClosestCityOfMine = 999;
	int iClosestEnemyCity = 999;

	int iCapitalArea = NULL;

	bool bIsInca = false;
	int iAdjacentMountains = 0;

	if ( pPlayer->getCapitalCity() )
		iCapitalArea = pPlayer->getCapitalCity()->getArea();

	// Custom code for Inca ideal terrace farm locations
	ImprovementTypes eIncaImprovement = (ImprovementTypes)GC.getInfoTypeForString("IMPROVEMENT_TERRACE_FARM", true);  
	if(eIncaImprovement != NO_IMPROVEMENT)
	{
		CvImprovementEntry* pkEntry = GC.getImprovementInfo(eIncaImprovement);
		if(pkEntry != NULL && pkEntry->IsSpecificCivRequired())
		{
			CivilizationTypes eCiv = pkEntry->GetRequiredCivilization();
			if(eCiv == pPlayer->getCivilizationType())
			{
				bIsInca = true;
			}
		}
	}

	for (int iDX = -7; iDX <= 7; iDX++)
	{
		for (int iDY = -7; iDY <= 7; iDY++)
		{
			CvPlot* pLoopPlot = plotXY(pPlot->getX(), pPlot->getY(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				int iDistance = plotDistance(pPlot->getX(), pPlot->getY(), pLoopPlot->getX(), pLoopPlot->getY());
				if (iDistance <= 7)
				{
					if ((pLoopPlot->getOwner() == NO_PLAYER) || (pLoopPlot->getOwner() == pPlayer->GetID()))
					{
						// See if there are other cities nearby
						if (iClosestCityOfMine > iDistance)
						{
							if (pLoopPlot->isCity())
							{
								iClosestCityOfMine = iDistance;
							}
						}

						// Skip the city plot itself for now
						if (iDistance <= 5)
						{
							int iRingModifier = m_iRingModifier[iDistance];

							iFoodValue = 0;
							iProductionValue = 0;
							iGoldValue = 0;
							iScienceValue = 0;
							iHappinessValue = 0;
							iResourceValue = 0;
							iStrategicValue = 0;

#if defined(MOD_GLOBAL_CITY_WORKING)
							if (iDistance > 0 && iDistance <= pPlayer->getWorkPlotDistance())
#else	
							if (iDistance > 0 && iDistance <= NUM_CITY_RINGS)
#endif
							{
								if (eYield == NO_YIELD || eYield == YIELD_FOOD)
								{
									iFoodValue = iRingModifier * ComputeFoodValue(pLoopPlot, pPlayer) * /*15*/ GC.getSETTLER_FOOD_MULTIPLIER();
								}
								if (eYield == NO_YIELD || eYield == YIELD_PRODUCTION)
								{
									iProductionValue = iRingModifier * ComputeProductionValue(pLoopPlot, pPlayer) * /*3*/ GC.getSETTLER_PRODUCTION_MULTIPLIER();
								}
								if (eYield == NO_YIELD || eYield == YIELD_GOLD)
								{
									iGoldValue = iRingModifier * ComputeGoldValue(pLoopPlot, pPlayer) * /*2*/ GC.getSETTLER_GOLD_MULTIPLIER();
								}
								if (eYield == NO_YIELD || eYield == YIELD_SCIENCE)
								{
									iScienceValue = iRingModifier * ComputeScienceValue(pLoopPlot, pPlayer) * /*1*/ GC.getSETTLER_SCIENCE_MULTIPLIER();
								}
								if (eYield == NO_YIELD || eYield == YIELD_FAITH)
								{
									iFaithValue = iRingModifier * ComputeFaithValue(pLoopPlot, pPlayer) * /*1*/ GC.getSETTLER_FAITH_MULTIPLIER();
								}
							}

							// whether or not we are working these we get the benefit as long as culture can grow to take them
							if (iDistance <= 5 && pLoopPlot->getOwner() == NO_PLAYER) // there is no benefit if we already own these tiles
							{
								iHappinessValue = iRingModifier * ComputeHappinessValue(pLoopPlot, pPlayer) * /*6*/ GC.getSETTLER_HAPPINESS_MULTIPLIER();
								iResourceValue = iRingModifier * ComputeTradeableResourceValue(pLoopPlot, pPlayer) * /*1*/ GC.getSETTLER_RESOURCE_MULTIPLIER();
								if (iDistance)
									iStrategicValue = ComputeStrategicValue(pLoopPlot, pPlayer, iDistance) * /*1*/ GC.getSETTLER_STRATEGIC_MULTIPLIER();  // the ring is included in the computation
							}

							iTotalFoodValue += iFoodValue;
							iTotalHappinessValue += iHappinessValue;
							iTotalProductionValue += iProductionValue;
							iTotalGoldValue += iGoldValue;
							iTotalScienceValue += iScienceValue;
							iTotalFaithValue += iFaithValue;
							iTotalResourceValue += iResourceValue;
							iTotalStrategicValue += iStrategicValue;

							int iPlotValue = iFoodValue + iHappinessValue + iProductionValue + iGoldValue + iScienceValue + iFaithValue + iResourceValue;
							
							if (iPlotValue == 0)
							{
								// this tile is so bad it gets negatives
								iPlotValue -= iRingModifier * GC.getSETTLER_FOOD_MULTIPLIER() * 2;
							}
							iPlotValue += iStrategicValue;

							// if this tile is a NW boost the value just so that we force the AI to claim them (if we can work it)
#if defined(MOD_GLOBAL_CITY_WORKING)
							if (pLoopPlot->IsNaturalWonder() && iDistance > 0 && iDistance <= pPlayer->getWorkPlotDistance())
#else	
							if (pLoopPlot->IsNaturalWonder() && iDistance > 0 && iDistance <= NUM_CITY_RINGS)
#endif
							{
								//iPlotValue += iPlotValue * 2 + 10;
								iPlotValue += iPlotValue * 2 + 500;
							}

							// lower value a lot if we already own this tile
							if (iPlotValue > 0 && pLoopPlot->getOwner() == pPlayer->GetID())
							{
#if defined(MOD_BALANCE_CORE_SETTLER)
								if (MOD_BALANCE_CORE_SETTLER) 
								{
									iPlotValue *= 2;
									iPlotValue /= 3;
								}
#else
								iPlotValue /= 4;
#endif
							}

							// add this plot into the total
							rtnValue += iPlotValue;

							FeatureTypes ePlotFeature = pLoopPlot->getFeatureType();
							ImprovementTypes ePlotImprovement = pLoopPlot->getImprovementType();
							ResourceTypes ePlotResource = pLoopPlot->getResourceType();

							if (ePlotFeature == FEATURE_FOREST)
							{
								if (iDistance <= 5)
								{
									++iIroquoisForestCount;
									if (iDistance == 1)
									{
										if (ePlotImprovement == NO_IMPROVEMENT)
										{
											++iCelticForestCount;
										}
									}
								}
							}
							else if (ePlotFeature == FEATURE_JUNGLE)
							{
#if defined(MOD_GLOBAL_CITY_WORKING)
								if (iDistance <= pPlayer->getWorkPlotDistance())
#else	
								if (iDistance <= NUM_CITY_RINGS)
#endif
								{
									++iBrazilJungleCount;
								}
							}
							else if (ePlotFeature == FEATURE_MARSH || ePlotFeature == FEATURE_FLOOD_PLAINS)
							{
#if defined(MOD_GLOBAL_CITY_WORKING)
								if (iDistance <= pPlayer->getWorkPlotDistance())
#else	
								if (iDistance <= NUM_CITY_RINGS)
#endif
								{
									++iWetlandsCount;
								}
							}

							if (pLoopPlot->IsNaturalWonder())
							{
								if (iDistance <= 1)
								{
									++iNaturalWonderCount;
								}
							}

							if (pLoopPlot->getTerrainType() == TERRAIN_DESERT)
							{
#if defined(MOD_GLOBAL_CITY_WORKING)
								if (iDistance <= pPlayer->getWorkPlotDistance())
#else	
								if (iDistance <= NUM_CITY_RINGS)
#endif
								{
									if (ePlotResource == NO_RESOURCE)
									{
										++iDesertCount;
									}
								}
							}

							if (bIsInca)
							{
								if (pLoopPlot->isHills())
								{
#if defined(MOD_GLOBAL_CITY_WORKING)
								if (iDistance <= pPlayer->getWorkPlotDistance())
#else	
								if (iDistance <= NUM_CITY_RINGS)
#endif
									{
										iAdjacentMountains = pLoopPlot->GetNumAdjacentMountains();
										if (iAdjacentMountains > 0 && iAdjacentMountains < 6)
										{
											//give the bonus if it's hills, with additional if bordered by mountains
											rtnValue += m_iIncaMultiplier + (iAdjacentMountains * m_iIncaMultiplier);
										}
									}
									
								}
							}
#if defined(MOD_BALANCE_CORE_SETTLER)
							if (MOD_BALANCE_CORE_SETTLER) 
							{
								if(pLoopPlot->isWater() && pLoopPlot->HasResource(NO_RESOURCE))
								{
									iWaterPlot++;
								}
								if(pLoopPlot == NULL || pLoopPlot->isImpassable() || pLoopPlot->getTerrainType() == TERRAIN_SNOW || pLoopPlot->getFeatureType() == FEATURE_ICE)
								{
									iBadPlot++;
								}
							}
#endif	
						}
					}
					else // this tile is owned by someone else
					{
						// See if there are other cities nearby (only count major civs)
						if (iClosestEnemyCity > iDistance)
						{
							if (pLoopPlot->isCity() && (pLoopPlot->getOwner() < MAX_MAJOR_CIVS))
							{
								iClosestEnemyCity = iDistance;
							}
						}
					}
				}
			}
#if defined(MOD_BALANCE_CORE_SETTLER)
			if (MOD_BALANCE_CORE_SETTLER) 
			{
				iLoopPlots++;
			}
#endif
		}
	}

	if (pPlayer->GetPlayerTraits()->IsFaithFromUnimprovedForest())
	{
		if (iCelticForestCount >= 3)
		{
			rtnValue += 2 * 1000 * m_iFlavorMultiplier[YIELD_FAITH];
		}
		else if (iCelticForestCount >= 1)
		{
			rtnValue += 1 * 1000 * m_iFlavorMultiplier[YIELD_FAITH];
		}
	}
	else if (pPlayer->GetPlayerTraits()->IsMoveFriendlyWoodsAsRoad())
	{
		rtnValue += iIroquoisForestCount * 10;	
	}
	else if (pPlayer->GetPlayerTraits()->GetNaturalWonderYieldModifier() > 0)	//ie: Spain
	{
		rtnValue += iNaturalWonderCount * m_iSpainMultiplier;	
	}

	// Custom code for Brazil
	ImprovementTypes eBrazilImprovement = (ImprovementTypes)GC.getInfoTypeForString("IMPROVEMENT_BRAZILWOOD_CAMP", true);  
	if(eBrazilImprovement != NO_IMPROVEMENT)
	{
		CvImprovementEntry* pkEntry = GC.getImprovementInfo(eBrazilImprovement);
		if(pkEntry != NULL && pkEntry->IsSpecificCivRequired())
		{
			CivilizationTypes eCiv = pkEntry->GetRequiredCivilization();
			if(eCiv == pPlayer->getCivilizationType())
			{
				rtnValue += iBrazilJungleCount * m_iBrazilMultiplier;
			}
		}
	}

	// Custom code for Morocco
	ImprovementTypes eMoroccoImprovement = (ImprovementTypes)GC.getInfoTypeForString("IMPROVEMENT_KASBAH", true);  
	if(eMoroccoImprovement != NO_IMPROVEMENT)
	{
		CvImprovementEntry* pkEntry = GC.getImprovementInfo(eMoroccoImprovement);
		if(pkEntry != NULL && pkEntry->IsSpecificCivRequired())
		{
			CivilizationTypes eCiv = pkEntry->GetRequiredCivilization();
			if(eCiv == pPlayer->getCivilizationType())
			{
				rtnValue += iDesertCount * m_iMorrocoMultiplier;
			}
		}
	}

	//Custom code for Netherlands
	ImprovementTypes ePolderImprovement = (ImprovementTypes)GC.getInfoTypeForString("IMPROVEMENT_POLDER", true);  
	if(ePolderImprovement != NO_IMPROVEMENT)
	{
		CvImprovementEntry* pkEntry = GC.getImprovementInfo(ePolderImprovement);
		if(pkEntry != NULL && pkEntry->IsSpecificCivRequired())
		{
			CivilizationTypes eCiv = pkEntry->GetRequiredCivilization();
			if(eCiv == pPlayer->getCivilizationType())
			{
				rtnValue += iWetlandsCount * m_iNetherlandsMultiplier;
			}
		}
	}

	if (rtnValue < 0) rtnValue = 0;

	// Finally, look at the city plot itself and use it as an overall multiplier
	if (pPlot->getResourceType(pPlayer->getTeam()) != NO_RESOURCE)
	{
		rtnValue += (int)rtnValue * /*-50*/ GC.getBUILD_ON_RESOURCE_PERCENT() / 100;
	}

	if (pPlot->isRiver())
	{
		rtnValue += (int)rtnValue * /*15*/ GC.getBUILD_ON_RIVER_PERCENT() / 100;
	}

	if (pPlot->isCoastalLand(GC.getMIN_WATER_SIZE_FOR_OCEAN()))
	{
		// okay, coast used to have lots of gold so players settled there "naturally", it doesn't any more, so I am going to give it a nudge in that direction
		// slewis - removed Brian(?)'s rtnValue adjustment and raised the BUILD_ON_COAST_PERCENT to 40 from 25
		//rtnValue += rtnValue > 0 ? 10 : 0;
		rtnValue += (int)rtnValue * /*40*/ GC.getSETTLER_BUILD_ON_COAST_PERCENT() / 100;
		int iNavalFlavor = pPlayer->GetGrandStrategyAI()->GetPersonalityAndGrandStrategy((FlavorTypes)m_iNavalIndex);
		if (iNavalFlavor > 7)
		{
			rtnValue += (int)rtnValue * /*40*/ GC.getSETTLER_BUILD_ON_COAST_PERCENT() / 100;
		}
		if (pPlayer->getCivilizationInfo().isCoastalCiv()) // we really like the coast (England, Norway, Polynesia, Carthage, etc.)
		{
			rtnValue += rtnValue > 0 ? 25 : 0;
			rtnValue *= 2;
		}
	}
#if defined(MOD_BALANCE_CORE_SETTLER)
	if (MOD_BALANCE_CORE_SETTLER) 
	{
		//Is this a water chokepoint? (More than four would make this a peninsula, which is not what we are looking for.)
		if(pPlot->IsChokePoint(true, false, 0))
		{
			rtnValue += (int)rtnValue * /*100*/ GC.getBALANCE_CHOKEPOINT_STRATEGIC_VALUE() / 100;
		}
		//Looking for mountains for chokepoints.
		//If the adjacent plot is not touching another mountain, and there is more than one mountain around pPlot, we've found a potential chokepoint.
		else if(pPlot->IsChokePoint(false, true, 1))
		{
			//Awesome, we found a mountain chokepoint within 1. Emphasize!
			rtnValue += (int)rtnValue * /*100*/ GC.getBALANCE_CHOKEPOINT_STRATEGIC_VALUE() / 75;
		}
		else if(pPlot->IsChokePoint(false, true, 2))
		{
			//Awesome, we found a mountain chokepoint within 2. Emphasize!
			rtnValue += (int)rtnValue * /*100*/ GC.getBALANCE_CHOKEPOINT_STRATEGIC_VALUE() / 100;
		}
		else if(pPlot->IsChokePoint(false, true, 3))
		{
			//Awesome, we found a mountain chokepoint within 3. Emphasize!
			rtnValue += (int)rtnValue * /*100*/ GC.getBALANCE_CHOKEPOINT_STRATEGIC_VALUE() / 125;
		}
		//Too many bad plots?
		if(iBadPlot > (iLoopPlots / 4))
		{
			rtnValue /= 5;
		}
		//Too much empty water?
		if(iWaterPlot > (iLoopPlots / 2))
		{
			rtnValue *= 2;
			rtnValue /= 3;
		}
	}
	//Let's see what we can do. (Strategic site locator pulled from below - less loop cycles used this way, as all we care about is the city plot itself, not every plot in the city's loop.
	if(pPlayer != NULL)
	{
		for(int iMajorLoop = 0; iMajorLoop < MAX_MAJOR_CIVS; iMajorLoop++)
		{
			PlayerTypes eOtherPlayer = (PlayerTypes) iMajorLoop;
			PlayerProximityTypes eProximity = GET_PLAYER(eOtherPlayer).GetProximityToPlayer(pPlayer->GetID());
			if(eOtherPlayer != pPlayer->GetID() && eOtherPlayer != NO_PLAYER && GET_PLAYER(eOtherPlayer).isAlive() && !GET_PLAYER(eOtherPlayer).isMinorCiv() && !GET_PLAYER(eOtherPlayer).isBarbarian())
			{
				if(eProximity >= PLAYER_PROXIMITY_CLOSE)
				{
					CvCity* pLoopTheirCity;
					int iClosestDistance = 6;
					int iDistance = 0;
					int iLoop;
					for(pLoopTheirCity = GET_PLAYER(eOtherPlayer).firstCity(&iLoop); pLoopTheirCity != NULL; pLoopTheirCity = GET_PLAYER(eOtherPlayer).nextCity(&iLoop))
					{
						if(pLoopTheirCity != NULL)
						{
							if(pPlot->getArea() == pLoopTheirCity->getArea())
							{
								iDistance = plotDistance(pPlot->getX(), pPlot->getY(), pLoopTheirCity->getX(), pLoopTheirCity->getY());
								
								if(iDistance <= iClosestDistance)
								{
									//There's at least 6 hexes between these plots, which means we can theoretically settle here.
									int iNumPlots = 0;
									int iNumBadPlots = 0;

									for(int iDX = -iClosestDistance; iDX <= iClosestDistance; iDX++)
									{
										for(int iDY = -iClosestDistance; iDY <= iClosestDistance; iDY++)
										{
											CvPlot* pLoopPlot = plotXYWithRangeCheck(pPlot->getX(), pPlot->getY(), iDX, iDY, iClosestDistance);
											if(pLoopPlot)
											{
												//Let's look for good, empty land.
												if(pLoopPlot->isImpassable() || pLoopPlot->isWater() || pLoopPlot->getOwner() != NO_PLAYER) 
												{
													iNumBadPlots++;
												}
													iNumPlots++;
											}
										}
									}
									if(iNumBadPlots > 0)
									{
										iNumBadPlots = (iNumBadPlots * 130) / 100;
									}
									//Good space must be greater than bad plots by at least 30%
									if(iNumPlots > iNumBadPlots)
									{
										//If there is significant empty land, and it is within the theoretical hex separation of the nearest two cities of two different players, there's a good chance it is border land. GET IT!
										rtnValue += (int)rtnValue * /*50*/ GC.getBALANCE_EMPIRE_BORDERLAND_STRATEGIC_VALUE() / 100;
										break;
									}
								}
							}
						}
					}
				}
			}
		}
	}
#endif

	// Nearby Cities?

	// Human
	if (pPlayer != NULL && pPlayer->isHuman())
	{
		if (iClosestCityOfMine == 3)
		{
			rtnValue /= 2;
		}
	}
	// AI
	else
	{
		int iGrowthFlavor = pPlayer->GetGrandStrategyAI()->GetPersonalityAndGrandStrategy((FlavorTypes)m_iGrowthIndex);
		int iExpansionFlavor = pPlayer->GetGrandStrategyAI()->GetPersonalityAndGrandStrategy((FlavorTypes)m_iExpansionIndex);

		int iSweetSpot = 5;
		iSweetSpot += (iGrowthFlavor > 7) ?  1 : 0;
		iSweetSpot += (iExpansionFlavor > 7) ?  -1 : 0;
		iSweetSpot += (iGrowthFlavor < 4) ?  -1 : 0;
		iSweetSpot += (iExpansionFlavor < 4) ?  1 : 0;
		iSweetSpot = max(4,iSweetSpot);
		iSweetSpot = min(6,iSweetSpot);

		if (iClosestCityOfMine == iSweetSpot) 
		{
			// 1.5 was not enough 2.0 was too much, so lets split the difference
			rtnValue *= 175;
			rtnValue /= 100;
		}
		else if (iClosestCityOfMine < iSweetSpot)
		{
			rtnValue /= 2;
		}
		else if (iClosestCityOfMine > 7)
		{
			rtnValue *= 2;
			rtnValue /= 3;
		}

		// use boldness to decide if we want to push close to enemies
		int iBoldness = pPlayer->GetDiplomacyAI()->GetBoldness();
		if (iBoldness < 4)
		{
			if (iClosestEnemyCity <= 4)
			{
				rtnValue /= 4;
			}
			else if (iClosestEnemyCity == 5)
			{
				rtnValue /= 2;
			}
		}
		else if (iBoldness > 7)
		{
			if (iClosestEnemyCity <= 5 && iClosestCityOfMine < 8)
			{
				rtnValue *= 3;
				rtnValue /= 2;
			}
		}
		else
		{
			if (iClosestEnemyCity < 5)
			{
				rtnValue *= 2;
				rtnValue /= 3;
			}
		}

		// if we are offshore, pull cities in tighter
		if (iCapitalArea != pPlot->getArea())
		{
			if (iClosestCityOfMine < 7)
			{
				rtnValue *= 3;
				rtnValue /= 2;
			}
		}
#if defined(MOD_BALANCE_CORE_SETTLER)
	if (MOD_BALANCE_CORE_SETTLER) 
		{
			//Let's judge just how well we can defend this city if we push out. If our neighbors are stronger than us, let's turtle a bit.
			for(int iMajorLoop = 0; iMajorLoop < MAX_MAJOR_CIVS; iMajorLoop++)
			{
				PlayerTypes eOtherPlayer = (PlayerTypes) iMajorLoop;
				if(eOtherPlayer != NO_PLAYER && GET_PLAYER(eOtherPlayer).isAlive() && !GET_PLAYER(eOtherPlayer).isMinorCiv() && !GET_PLAYER(eOtherPlayer).isBarbarian())
				{
					PlayerProximityTypes eProximity = GET_PLAYER(eOtherPlayer).GetProximityToPlayer(pPlayer->GetID());
					if(eProximity == PLAYER_PROXIMITY_NEIGHBORS && (pPlayer->GetMilitaryMight() < GET_PLAYER(eOtherPlayer).GetMilitaryMight()))
					{
						//Is the plot we're looking at in the same area as our strong neighbor?
						if (iClosestEnemyCity <= 6)
						{
							rtnValue /= 2;
						}
					}
				}
			}
		}
#endif
	}

	rtnValue = (rtnValue > 0) ? rtnValue : 0;

	return rtnValue;
}
Esempio n. 30
0
/// Add a unit to our army (and we know which slot)
void CvArmyAI::AddUnit(int iUnitID, int iSlotNum)
{
	CvPlayer& thisPlayer = GET_PLAYER(m_eOwner);
	CvUnit* pThisUnit = thisPlayer.getUnit(iUnitID);
	if (!pThisUnit)
		return;

	// remove this unit from an army if it is already in one
	thisPlayer.removeFromArmy(pThisUnit->getArmyID(), GetID());
	m_FormationEntries[iSlotNum] = CvArmyFormationSlot(); //reset
	m_FormationEntries[iSlotNum].SetUnitID(iUnitID);
	pThisUnit->setArmyID(GetID());

#if defined(MOD_BALANCE_CORE)
	//just for avoiding confusion
	pThisUnit->setTacticalMove(NO_TACTICAL_MOVE);
#endif

	// Finally, compute when we think this unit will arrive at the next checkpoint
	CvPlot* pMusterPlot = GC.getMap().plot(GetX(), GetY());
	if(pMusterPlot)
	{
		int iFlags = CvUnit::MOVEFLAG_APPROX_TARGET_RING2 | CvUnit::MOVEFLAG_IGNORE_STACKING | CvUnit::MOVEFLAG_IGNORE_ZOC;
		int iTurnsToReachCheckpoint = pThisUnit->TurnsToReachTarget(pMusterPlot, iFlags, GC.getAI_OPERATIONAL_MAX_RECRUIT_TURNS_ENEMY_TERRITORY());
		if(iTurnsToReachCheckpoint < MAX_INT)
		{
			m_FormationEntries[iSlotNum].SetTurnsToCheckpoint(iTurnsToReachCheckpoint);
		}

		if (GC.getLogging() && GC.getAILogging())
		{
			CvAIOperation* pOperation = GET_PLAYER(GetOwner()).getAIOperation(GetOperationID());
			CvString strMsg;
			strMsg.Format("Added %s %d to slot %d in army %d. ETA at (%d:%d) is %d ", pThisUnit->getName().c_str(),
				m_FormationEntries[iSlotNum].GetUnitID(), iSlotNum, GetID(), pMusterPlot->getX(), pMusterPlot->getY(), iTurnsToReachCheckpoint);
			pOperation->LogOperationSpecialMessage(strMsg);
		}
	}
}