/// Establish order of zone processing for the turn
void CvTacticalAnalysisMap::PrioritizeZones()
{
	// Loop through the dominance zones
	for(unsigned int iI = 0; iI < m_DominanceZones.size(); iI++)
	{
		// Find the zone and compute dominance here
		CvTacticalDominanceZone* pZone = &m_DominanceZones[iI];
		eTacticalDominanceFlags eDominance = ComputeDominance(pZone);

		// Establish a base value for the region
		int iBaseValue = 1;
		int iMultiplier = 1;

		// Temporary zone?
		if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_TEMP_ZONE)
		{
			iMultiplier = 1000;
		}
		else
		{
			CvCity* pClosestCity = pZone->GetZoneCity();
			if(pClosestCity && pClosestCity->isAdjacentToArea(pZone->GetAreaID()))
			{
				iBaseValue += (1 + (int)sqrt((float)pClosestCity->getPopulation()));

				if(GET_PLAYER(m_ePlayer).GetTacticalAI()->IsTemporaryZoneCity(pClosestCity))
				{
					iBaseValue *= 2;
				}

				else if (pClosestCity->isVisible( GET_PLAYER(m_ePlayer).getTeam(), false))
				{
					iBaseValue *= 4;

					// How damaged is this visible city?
					int iMaxDamageMultiplier = 10;
					int iDamage = pClosestCity->getDamage();
					if (iDamage > (pClosestCity->GetMaxHitPoints() / iMaxDamageMultiplier))
					{
						iBaseValue *= (int)((iDamage + 1) * 10 / pClosestCity->GetMaxHitPoints());
					}
				}

#if defined(MOD_BALANCE_CORE)
				if (GET_PLAYER(m_ePlayer).IsCityAlreadyTargeted(pClosestCity) || GET_PLAYER(m_ePlayer).GetMilitaryAI()->IsCurrentAttackTarget(pClosestCity) )
				{
					iBaseValue *= 2;
				}

				if (pClosestCity->GetPlayer()->isMinorCiv())
				{
					//At war with ally of this minor? Greatly reduce priority.
					PlayerTypes eAlly = pClosestCity->GetPlayer()->GetMinorCivAI()->GetAlly();
					if (eAlly != NO_PLAYER && GET_TEAM(GET_PLAYER(m_ePlayer).getTeam()).isAtWar(GET_PLAYER(eAlly).getTeam()))
					{
						iBaseValue = 1;
					}
				}
#endif
			}

			if(!pZone->IsWater())
			{
				iBaseValue *= 3;
			}

			// Now compute a multiplier based on current conditions here
			if(eDominance == TACTICAL_DOMINANCE_ENEMY)
			{
				if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_ENEMY)
				{
					iMultiplier = 1;
				}
				else if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_FRIENDLY)
				{
					iMultiplier = 8;
				}
			}
			else if(eDominance == TACTICAL_DOMINANCE_EVEN)
			{
				if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_ENEMY)
				{
					iMultiplier = 4;
				}
				else if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_FRIENDLY)
				{
					iMultiplier = 4;
				}
			}
			else if(eDominance == TACTICAL_DOMINANCE_FRIENDLY)
			{
				if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_ENEMY)
				{
					iMultiplier = 8;
				}
				else if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_FRIENDLY)
				{
					iMultiplier = 1;
				}
			}
			if(!GET_PLAYER(m_ePlayer).isMinorCiv())
			{
				if(GET_PLAYER(m_ePlayer).GetDiplomacyAI()->GetStateAllWars() == STATE_ALL_WARS_WINNING)
				{
					if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_ENEMY)
					{
#if defined(MOD_BALANCE_CORE_MILITARY)
						iMultiplier *= 4;
#else
						iMultiplier *= 2;
#endif
					}
				}
				else if(GET_PLAYER(m_ePlayer).GetDiplomacyAI()->GetStateAllWars() == STATE_ALL_WARS_LOSING)
				{
					if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_FRIENDLY)
					{
						iMultiplier *= 4;
					}
				}
			}
		}

		// Save off the value for this zone
		pZone->SetDominanceZoneValue( iBaseValue * iMultiplier);
	}

	std::stable_sort(m_DominanceZones.begin(), m_DominanceZones.end());
}
/// Calculate military presences in each owned dominance zone
void CvTacticalAnalysisMap::CalculateMilitaryStrengths()
{
	TeamTypes eTeam = GET_PLAYER(m_ePlayer).getTeam();

	// Loop through the dominance zones
	for(unsigned int iI = 0; iI < m_DominanceZones.size(); iI++)
	{
		CvTacticalDominanceZone* pZone = &m_DominanceZones[iI];
		CvCity *pClosestCity = pZone->GetZoneCity();
		if(pClosestCity)
		{
			// Start with strength of the city itself
			int iCityHitPoints = pClosestCity->GetMaxHitPoints() - pClosestCity->getDamage();
			int iStrength = pClosestCity->getStrengthValue() * iCityHitPoints / GC.getMAX_CITY_HIT_POINTS();

			if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_FRIENDLY)
			{
				pZone->AddFriendlyMeleeStrength(iStrength);
				pZone->AddFriendlyRangedStrength(pClosestCity->getStrengthValue(true));
			}
			else if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_ENEMY)
			{
				pZone->AddEnemyMeleeStrength(iStrength);
				pZone->AddEnemyRangedStrength(pClosestCity->getStrengthValue(true));
			}
			else
			{ 
				pZone->AddNeutralStrength(iStrength);
			}
		}

		// check all units in the world
		for(int iPlayerLoop = 0; iPlayerLoop < MAX_PLAYERS; iPlayerLoop++)
		{
			CvPlayer& kPlayer = GET_PLAYER((PlayerTypes) iPlayerLoop);
			bool bEnemy = GET_TEAM(eTeam).isAtWar(kPlayer.getTeam());
			bool bFriendly = (eTeam==kPlayer.getTeam());

			int iLoop;
			for(CvUnit* pLoopUnit = kPlayer.firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = kPlayer.nextUnit(&iLoop))
			{
				if(!pLoopUnit->IsCombatUnit())
					continue;

				bool bUnitMayBeRelevant = (pLoopUnit->getDomainType() == DOMAIN_AIR ||
						pLoopUnit->isRanged() || //ranged power is cross-domain!
						(pLoopUnit->getDomainType() == DOMAIN_LAND && !pZone->IsWater()) ||
						((pLoopUnit->getDomainType() == DOMAIN_SEA || (pLoopUnit->isEmbarked() && pClosestCity) && pZone->IsWater())));
						//embarked melee still count in water zone if there's a city to attack/defend

				if (!bUnitMayBeRelevant)
					continue;

				CvPlot* pPlot = pLoopUnit->plot();
				if(!pPlot)
					continue;

				//a little cheating for AI - invisible units still count with reduced strength
				bool bVisible = pPlot->isVisible(eTeam) || pPlot->isAdjacentVisible(eTeam, false);
				bool bZoneTypeMismatch = (pLoopUnit->getDomainType() == DOMAIN_LAND && pZone->IsWater()) || (pLoopUnit->getDomainType() == DOMAIN_SEA && !pZone->IsWater());

				//embarked units and crossdomain count only partially
				bool bReducedStrength = pLoopUnit->isEmbarked() || bZoneTypeMismatch;

				//if there is a city, units in adjacent zones can also count
				int iDistance = 0;
				if (pClosestCity)
				{
					iDistance = plotDistance(pLoopUnit->getX(), pLoopUnit->getY(), pClosestCity->getX(), pClosestCity->getY());
					if (iDistance > m_iTacticalRange)
						continue;
					else if (iDistance > (m_iTacticalRange / 2))
					{
						if (bZoneTypeMismatch)
							continue;
						else
							bReducedStrength = true;
					}
					else
					{
						//if on another continent, they can't easily take part in the fight
						if (!pClosestCity->isMatchingArea(pLoopUnit->plot()))
							bReducedStrength = true;
					}
				}
				else
				{
					//if there is no city, the unit must be in the zone itself
					if ( GetCell(pLoopUnit->plot()->GetPlotIndex())->GetDominanceZone() != pZone->GetDominanceZoneID() )
						continue;
				}

				int iMultiplier = m_iTacticalRange + MIN(3 - iDistance, 0);  // 3 because action may still be spread out over the zone
				if(iMultiplier > 0)
				{
					int iUnitStrength = pLoopUnit->GetBaseCombatStrengthConsideringDamage();

					//unit might disembark ... so don't count it for water zone, but for adjacent land
					if(iUnitStrength == 0 && pLoopUnit->isEmbarked() && !pZone->IsWater())
						iUnitStrength = pLoopUnit->GetBaseCombatStrength();

					int iRangedStrength = pLoopUnit->GetMaxRangedCombatStrength(NULL, /*pCity*/ NULL, true, true) / 100;

					if(!bVisible || bReducedStrength)
					{
						iUnitStrength /= 2;
						iRangedStrength /= 2;
					}

					if (bEnemy)
					{
#if defined(MOD_BALANCE_CORE_MILITARY_LOGGING)
						//CvString msg;
						//msg.Format("Zone %d, Enemy %s %d with %d hp at %d,%d - distance %d, strength %d, ranged strength %d (total %d)",
						//	pZone->GetDominanceZoneID(), pLoopUnit->getName().c_str(), pLoopUnit->GetID(), pLoopUnit->GetCurrHitPoints(),
						//	pLoopUnit->getX(), pLoopUnit->getY(),	iDistance, iUnitStrength, iRangedStrength, pZone->GetOverallEnemyStrength());
						//GET_PLAYER(m_ePlayer).GetTacticalAI()->LogTacticalMessage(msg, true /*bSkipLogDominanceZone*/);
#endif

						if (pLoopUnit->getDomainType() == DOMAIN_SEA)
						{
							pZone->AddEnemyNavalStrength(iUnitStrength*iMultiplier*m_iUnitStrengthMultiplier);
							pZone->AddEnemyNavalRangedStrength(iRangedStrength*iMultiplier*m_iUnitStrengthMultiplier);
							pZone->AddEnemyNavalUnitCount(1);
						}
						else
						{
							pZone->AddEnemyMeleeStrength(iUnitStrength*iMultiplier*m_iUnitStrengthMultiplier);
							pZone->AddEnemyRangedStrength(iRangedStrength*iMultiplier*m_iUnitStrengthMultiplier);
							pZone->AddEnemyUnitCount(1);
						}

						//again only for enemies
						if(pZone->GetRangeClosestEnemyUnit()<0 || iDistance<pZone->GetRangeClosestEnemyUnit())
							pZone->SetRangeClosestEnemyUnit(iDistance);
					}
					else if (bFriendly)
					{

#if defined(MOD_BALANCE_CORE_MILITARY_LOGGING)
						//CvString msg;
						//msg.Format("Zone %d, Friendly %s %d with %d hp at %d,%d - distance %d, strength %d, ranged strength %d (total %d)",
						//	pZone->GetDominanceZoneID(), pLoopUnit->getName().c_str(), pLoopUnit->GetID(), pLoopUnit->GetCurrHitPoints(),
						//	pLoopUnit->getX(), pLoopUnit->getY(), iDistance, iUnitStrength, iRangedStrength, pZone->GetOverallFriendlyStrength());
						//GET_PLAYER(m_ePlayer).GetTacticalAI()->LogTacticalMessage(msg, true /*bSkipLogDominanceZone*/);
#endif

						if (pLoopUnit->getDomainType() == DOMAIN_SEA)
						{
							pZone->AddFriendlyNavalStrength(iUnitStrength*iMultiplier*m_iUnitStrengthMultiplier);
							pZone->AddFriendlyNavalRangedStrength(iRangedStrength*iMultiplier*m_iUnitStrengthMultiplier);
							pZone->AddFriendlyNavalUnitCount(1);
						}
						else
						{
							pZone->AddFriendlyMeleeStrength(iUnitStrength*iMultiplier*m_iUnitStrengthMultiplier);
							pZone->AddFriendlyRangedStrength(iRangedStrength*iMultiplier*m_iUnitStrengthMultiplier);
							pZone->AddFriendlyUnitCount(1);
						}
					}
					else
					{
						//neutral has only very few stats
						pZone->AddNeutralStrength(iUnitStrength*iMultiplier*m_iUnitStrengthMultiplier);
						pZone->AddNeutralUnitCount(1);
					}
				}
			}
		}
	}
}
/// Calculate military presences in each owned dominance zone
void CvTacticalAnalysisMap::CalculateMilitaryStrengths()
{
	// Loop through the dominance zones
	CvTacticalDominanceZone* pZone;
	CvCity* pClosestCity = NULL;
	int iDistance;
	int iMultiplier;
	int iLoop;
	CvUnit* pLoopUnit;
	TeamTypes eTeam;

	eTeam = m_pPlayer->getTeam();

	for(unsigned int iI = 0; iI < m_DominanceZones.size(); iI++)
	{
		pZone = &m_DominanceZones[iI];

		if(pZone->GetTerritoryType() != TACTICAL_TERRITORY_NO_OWNER)
		{
			pClosestCity = pZone->GetClosestCity();
			if(pClosestCity)
			{
				// Start with strength of the city itself
				int iCityHitPoints = pClosestCity->GetMaxHitPoints() - pClosestCity->getDamage();
				int iStrength = m_iTacticalRange * pClosestCity->getStrengthValue() * iCityHitPoints / GC.getMAX_CITY_HIT_POINTS();
				if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_FRIENDLY)
				{
					pZone->AddFriendlyStrength(iStrength);
#if defined(MOD_AI_SMART_V3)
					pZone->AddFriendlyRangedStrength(pClosestCity->getStrengthValue(MOD_AI_SMART_V3));
#else
					pZone->AddFriendlyRangedStrength(pClosestCity->getStrengthValue());
#endif
				}
#if defined(MOD_AI_SMART_V3)
				else if(!MOD_AI_SMART_V3 || pZone->GetTerritoryType() == TACTICAL_TERRITORY_ENEMY)
#else
				else
#endif
				{
					pZone->AddEnemyStrength(iStrength);
#if defined(MOD_AI_SMART_V3)
					pZone->AddEnemyRangedStrength(pClosestCity->getStrengthValue(MOD_AI_SMART_V3));
#else
					pZone->AddEnemyRangedStrength(pClosestCity->getStrengthValue());
#endif
				}

				// Loop through all of OUR units first
				for(pLoopUnit = m_pPlayer->firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = m_pPlayer->nextUnit(&iLoop))
				{
					if(pLoopUnit->IsCombatUnit())
					{
						if(pLoopUnit->getDomainType() == DOMAIN_AIR ||
#if defined(MOD_AI_SMART_V3)
								//ranged power is cross-domain!
								(MOD_AI_SMART_V3 && pLoopUnit->isRanged()) ||
#endif
						        (pLoopUnit->getDomainType() == DOMAIN_LAND && !pZone->IsWater()) ||
						        (pLoopUnit->getDomainType() == DOMAIN_SEA && pZone->IsWater()))
						{
							iDistance = plotDistance(pLoopUnit->getX(), pLoopUnit->getY(), pClosestCity->getX(), pClosestCity->getY());
							if (iDistance <= m_iTacticalRange)
							{
#if defined(MOD_AI_SMART_V3)
								int iRange = MOD_AI_SMART_V3 ? MIN(4 - iDistance, 0) : 4 - iDistance;
								iMultiplier = m_iTacticalRange + iRange;
#else
								iMultiplier = (m_iTacticalRange + 4 - iDistance);  // "4" so unit strength isn't totally dominated by proximity to city
#endif
								if(iMultiplier > 0)
								{
									int iUnitStrength = pLoopUnit->GetBaseCombatStrengthConsideringDamage();
									if(iUnitStrength == 0 && pLoopUnit->isEmbarked() && !pZone->IsWater())
									{
										iUnitStrength = pLoopUnit->GetBaseCombatStrength(true);
									}
									pZone->AddFriendlyStrength(iUnitStrength * iMultiplier * m_iUnitStrengthMultiplier);
									pZone->AddFriendlyRangedStrength(pLoopUnit->GetMaxRangedCombatStrength(NULL, /*pCity*/ NULL, true, true));
									if(pLoopUnit->GetRange() > GetBestFriendlyRange())
									{
										SetBestFriendlyRange(pLoopUnit->GetRange());
									}
									if(pLoopUnit->IsRangeAttackIgnoreLOS())
									{
										SetIgnoreLOS(true);
									}
									pZone->AddFriendlyUnitCount(1);
									if(pLoopUnit->isRanged())
									{
										pZone->AddFriendlyRangedUnitCount(1);
									}
								}
							}
						}
					}
				}

				// Repeat for all visible enemy units (or adjacent to visible)
				for(int iPlayerLoop = 0; iPlayerLoop < MAX_CIV_PLAYERS; iPlayerLoop++)
				{
					CvPlayer& kPlayer = GET_PLAYER((PlayerTypes) iPlayerLoop);
					if(GET_TEAM(eTeam).isAtWar(kPlayer.getTeam()))
					{
						for(pLoopUnit = kPlayer.firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = kPlayer.nextUnit(&iLoop))
						{
							if(pLoopUnit->IsCombatUnit())
							{
								if(pLoopUnit->getDomainType() == DOMAIN_AIR ||
#if defined(MOD_AI_SMART_V3)
										//ranged power is cross-domain!
										(MOD_AI_SMART_V3 && pLoopUnit->isRanged()) ||
#endif
								        (pLoopUnit->getDomainType() == DOMAIN_LAND && !pZone->IsWater()) ||
								        (pLoopUnit->getDomainType() == DOMAIN_SEA && pZone->IsWater()))
								{
									CvPlot* pPlot;
									pPlot = pLoopUnit->plot();
									if(pPlot)
									{
										bool bVisible = true;
										iDistance = plotDistance(pLoopUnit->getX(), pLoopUnit->getY(), pClosestCity->getX(), pClosestCity->getY());
										if (iDistance <= m_iTacticalRange)
										{
#if defined(MOD_AI_SMART_V3)
											int iRange = MOD_AI_SMART_V3 ? MIN(4 - iDistance, 0) : 4 - iDistance;
											iMultiplier = m_iTacticalRange + iRange;  // 4 because action may still be spread out over the zone
#else
											iMultiplier = (m_iTacticalRange + 4 - iDistance);  // "4" so unit strength isn't totally dominated by proximity to city
#endif
											if(!pPlot->isVisible(eTeam) && !pPlot->isAdjacentVisible(eTeam, false))
											{
												bVisible = false;
											}
											if(iMultiplier > 0)
											{
												int iUnitStrength = pLoopUnit->GetBaseCombatStrengthConsideringDamage();
												if(iUnitStrength == 0 && pLoopUnit->isEmbarked() && !pZone->IsWater())
												{
													iUnitStrength = pLoopUnit->GetBaseCombatStrength(true);
												}

												if(!bVisible)
												{
													iUnitStrength /= 2;
												}

												pZone->AddEnemyStrength(iUnitStrength * iMultiplier * m_iUnitStrengthMultiplier);

												int iRangedStrength = pLoopUnit->GetMaxRangedCombatStrength(NULL, /*pCity*/ NULL, true, true);
												if(!bVisible)
												{
													iRangedStrength /= 2;
												}

												pZone->AddEnemyRangedStrength(iRangedStrength);

												if(bVisible)
												{
													pZone->AddEnemyUnitCount(1);
													if(iDistance < pZone->GetRangeClosestEnemyUnit())
													{
														pZone->SetRangeClosestEnemyUnit(iDistance);
													}
													if(pLoopUnit->isRanged())
													{
														pZone->AddEnemyRangedUnitCount(1);
													}
													if(pLoopUnit->getDomainType() == DOMAIN_SEA)
													{
														pZone->AddEnemyNavalUnitCount(1);
													}
												}
											}
										}
									}
								}
							}
						}

					}
				}
			}
		}
	}
Ejemplo n.º 4
0
// Get the maximum damage unit could receive at this plot in the next turn (update this with CvUnitCombat changes!)
int CvDangerPlotContents::GetDanger(const CvUnit* pUnit, AirActionType iAirAction)
{
	if (!m_pPlot || !pUnit)
		return 0;

	// Air units only take damage from interceptions
	if (pUnit->getDomainType() == DOMAIN_AIR)
		return GetAirUnitDamage(pUnit, iAirAction);

	//simple caching for speedup
	SUnitStats unitStats(pUnit);
	if (unitStats==m_lastUnit)
		return m_lastResult;

	//otherwise calculate from scratch
	int iPlotDamage = 0;

	CvCity* pFriendlyCity = NULL;
	if ( m_pPlot->isFriendlyCity(*pUnit,true) )
		pFriendlyCity = m_pPlot->getPlotCity();

	// Civilians can be captured - unless they would need to be embarked on this plot
	if (!pUnit->IsCombatUnit() && pUnit->isNativeDomain(m_pPlot))
	{
		// If plot contains an enemy unit, mark it as max danger
		if (m_pPlot->getBestDefender(NO_PLAYER, pUnit->getOwner(), NULL, true))
		{
			return MAX_INT;
		}

		for (DangerUnitVector::iterator it = m_apUnits.begin(); it < m_apUnits.end(); ++it)
		{
			CvUnit* pAttacker = GET_PLAYER(it->first).getUnit(it->second);

			if ( pAttacker && !pAttacker->isDelayedDeath() && !pAttacker->IsDead())
			{
				// If in a city and the city can be captured, we are in highest danger
				if (pFriendlyCity)
				{
					if (GetDanger(pFriendlyCity) + pFriendlyCity->getDamage() > pFriendlyCity->GetMaxHitPoints())
					{
						return MAX_INT;
					}
				}
				// Look for a possible plot defender
				else 
				{
					IDInfo* pUnitNode = m_pPlot->headUnitNode();
					CvUnit* pBestDefender = NULL;
					while (pUnitNode != NULL)
					{
						pBestDefender = ::getUnit(*pUnitNode);
						pUnitNode = m_pPlot->nextUnitNode(pUnitNode);

						if (pBestDefender && pBestDefender->getOwner() == pUnit->getOwner())
						{
							//fix endless recursion with stacked embarked civilians: defender must also be able to attack
							if (pBestDefender->IsCanDefend() && pBestDefender->IsCanAttack())
							{
								if (pBestDefender != pUnit)
								{
									if (pBestDefender->isWaiting() || !(pBestDefender->canMove()))
									{
										break;
									}
								}
							}
						}
						pBestDefender = NULL;
					}
					// If there is a defender and it might be killed, high danger
					if (pBestDefender && (pBestDefender->isWaiting() || !pBestDefender->canMove()))
					{
						if (GetDanger(pBestDefender) > pBestDefender->GetCurrHitPoints())
						{
							return INT_MAX;
						}
					}
					else if (pBestDefender==NULL)
					{
						//Civilian could be captured on this tile
						return MAX_INT;
					}
				}
			}
		}

		// Damage from features (citadel)
		iPlotDamage += GetDamageFromFeatures(pUnit->getOwner());
		iPlotDamage += m_bFlatPlotDamage ? m_pPlot->getTurnDamage(pUnit->ignoreTerrainDamage(), pUnit->ignoreFeatureDamage(), pUnit->extraTerrainDamage(), pUnit->extraFeatureDamage()) : 0;

		// Damage from cities
		for (DangerCityVector::iterator it = m_apCities.begin(); it < m_apCities.end(); ++it)
		{
			CvCity* pCity = GET_PLAYER(it->first).getCity(it->second);
			if (!pCity || pCity->getTeam() == pUnit->getTeam())
				continue;

			iPlotDamage += pCity->rangeCombatDamage(pUnit, NULL, false, m_pPlot);
		}

		//update cache
		m_lastUnit = unitStats;
		m_lastResult = iPlotDamage;
		return iPlotDamage;
	}

	// Capturing a city with a garrisoned unit destroys the garrisoned unit
	if (pFriendlyCity)
	{
		int iCityDanger = GetDanger(pFriendlyCity, (pUnit->getDomainType() == DOMAIN_LAND ? pUnit : NULL));
		if (iCityDanger + pFriendlyCity->getDamage() < pFriendlyCity->GetMaxHitPoints())
		{
			if (pUnit->CanGarrison())
			{
				// Reconstruct the amount of damage the garrison would absorb for the city
				int iUnitShare = (iCityDanger*2*pUnit->GetMaxHitPoints()) / pFriendlyCity->GetMaxHitPoints();

				// Damage from features
				return iUnitShare + GetDamageFromFeatures(pUnit->getOwner());
			}
			else
				return 0;
		}
		else
		{
			return MAX_INT;
		}
	}

	CvPlot* pAttackerPlot = NULL;
	CvUnit* pInterceptor = NULL;
	// Damage from units
	// EXTREMELY IMPORTANT THAT NO RNG IS USED FOR PREDICTION!
	// Otherwise a tooltip or similar can change the game state
	for (DangerUnitVector::iterator it = m_apUnits.begin(); it < m_apUnits.end(); ++it)
	{
		CvUnit* pAttacker = GET_PLAYER(it->first).getUnit(it->second);
		if (!pAttacker || pAttacker->isDelayedDeath() || pAttacker->IsDead())
			continue;

		pAttackerPlot = NULL;
		if (pAttacker->plot() != m_pPlot)
		{				
			if (pAttacker->IsCanAttackRanged())
			{
				if (pAttacker->getDomainType() == DOMAIN_AIR)
				{
					pInterceptor = pAttacker->GetBestInterceptor(*m_pPlot, pUnit);
					int iInterceptDamage = 0;
					if (pInterceptor)
					{
						// Always assume interception is successful
						iInterceptDamage = pInterceptor->GetInterceptionDamage(pUnit, false);
					}
					iPlotDamage += pAttacker->GetAirCombatDamage(pUnit, NULL, false, iInterceptDamage, m_pPlot);
				}
				else
				{
					iPlotDamage += pAttacker->GetRangeCombatDamage(pUnit, NULL, false, 0, m_pPlot);
				}
			}
			else
			{
				if (plotDistance(m_iX, m_iY, pUnit->getX(), pUnit->getY()) == 1)
				{
					pAttackerPlot = pAttacker->plot();
				}
				iPlotDamage += pAttacker->getCombatDamage(
					pAttacker->GetMaxAttackStrength(pAttackerPlot, m_pPlot, pUnit),
					pUnit->GetMaxDefenseStrength(m_pPlot, pAttacker), pAttacker->getDamage(), false, false, false);
				if (pAttacker->isRangedSupportFire())
				{
					iPlotDamage += pAttacker->GetRangeCombatDamage(pUnit, NULL, false, 0, m_pPlot, pAttackerPlot);
				}
			}
		}
	}

	// Damage from cities
	for (DangerCityVector::iterator it = m_apCities.begin(); it < m_apCities.end(); ++it)
	{
		CvCity* pCity = GET_PLAYER(it->first).getCity(it->second);
		if (!pCity || pCity->getTeam() == pUnit->getTeam())
			continue;

		iPlotDamage += pCity->rangeCombatDamage(pUnit, NULL, false, m_pPlot);
	}

	// Damage from surrounding features (citadel) and the plot itself
	iPlotDamage += GetDamageFromFeatures(pUnit->getOwner());
	iPlotDamage += m_bFlatPlotDamage ? m_pPlot->getTurnDamage(pUnit->ignoreTerrainDamage(), pUnit->ignoreFeatureDamage(), pUnit->extraTerrainDamage(), pUnit->extraFeatureDamage()) : 0;

	//update cache
	m_lastUnit = unitStats;
	m_lastResult = iPlotDamage;

	//done
	return iPlotDamage;
}
/// Establish order of zone processing for the turn
void CvTacticalAnalysisMap::PrioritizeZones()
{
	// Loop through the dominance zones
	CvTacticalDominanceZone* pZone;
	int iBaseValue;
	int iMultiplier;
	CvCity* pClosestCity = NULL;

	for(unsigned int iI = 0; iI < m_DominanceZones.size(); iI++)
	{
		// Find the zone and compute dominance here
		pZone = &m_DominanceZones[iI];
		eTacticalDominanceFlags eDominance = ComputeDominance(pZone);

		// Establish a base value for the region
		iBaseValue = 1;

		// Temporary zone?
		if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_TEMP_ZONE)
		{
			iMultiplier = 1000;
		}
		else
		{
			pClosestCity = pZone->GetClosestCity();

			if(pClosestCity)
			{
				iBaseValue += (1 + (int)sqrt((float)pZone->GetClosestCity()->getPopulation()));

				if(pClosestCity->isCapital() && !pClosestCity->GetPlayer()->isMinorCiv())
				{
					iBaseValue *= 2;
				}

				if(m_pPlayer->GetTacticalAI()->IsTemporaryZoneCity(pClosestCity))
				{
					iBaseValue *= 20;
				}

				else if (pZone->GetClosestCity()->isVisible(m_pPlayer->getTeam(), false))
				{
					iBaseValue *= 4;

					// How damaged is this visible city?
					int iMaxDamageMultiplier = 10;
					int iDamage = pClosestCity->getDamage();
					if (iDamage > (pClosestCity->GetMaxHitPoints() / iMaxDamageMultiplier))
					{
						iBaseValue *= (int)((iDamage + 1) * 10 / pClosestCity->GetMaxHitPoints());
					}
				}
			}

			if(!pZone->IsWater())
			{
				iBaseValue *= 3;
			}

			// Now compute a multiplier based on current conditions here
			iMultiplier = 1;
			if(eDominance == TACTICAL_DOMINANCE_ENEMY)
			{
				if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_ENEMY)
				{
					iMultiplier = 2;
				}
				else if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_FRIENDLY)
				{
					iMultiplier = 6;
				}
			}
			else if(eDominance == TACTICAL_DOMINANCE_EVEN)
			{
				if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_ENEMY)
				{
					iMultiplier = 4;
				}
				else if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_FRIENDLY)
				{
					iMultiplier = 4;
				}
			}
			else if(eDominance == TACTICAL_DOMINANCE_FRIENDLY)
			{
				if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_ENEMY)
				{
					iMultiplier = 8;
				}
				else if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_FRIENDLY)
				{
					iMultiplier = 1;
				}
			}
			if(!m_pPlayer->isMinorCiv())
			{
				if(m_pPlayer->GetDiplomacyAI()->GetStateAllWars() == STATE_ALL_WARS_WINNING)
				{
					if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_ENEMY)
					{
						iMultiplier *= 2;
					}
				}
				else if(m_pPlayer->GetDiplomacyAI()->GetStateAllWars() == STATE_ALL_WARS_LOSING)
				{
					if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_FRIENDLY)
					{
						iMultiplier *= 4;
					}
				}
			}
		}

		// Save off the value for this zone
		if((iBaseValue * iMultiplier) <= 0)
		{
			FAssertMsg((iBaseValue * iMultiplier) > 0, "Invalid Dominance Zone Value");
		}
		pZone->SetDominanceZoneValue(iBaseValue * iMultiplier);
	}

	std::stable_sort(m_DominanceZones.begin(), m_DominanceZones.end());
}