// Can this tile be attacked by an enemy unit or city next turn?
bool CvDangerPlotContents::IsUnderImmediateThreat(const CvUnit* pUnit)
{
	if (!m_pPlot || !pUnit)
		return false;

	// Air units operate off of intercepts instead of units/cities that can attack them
	if (pUnit->getDomainType() == DOMAIN_AIR)
	{
		if (pUnit->GetBestInterceptor(*m_pPlot))
		{
			return true;
		}
	}
	else
	{
		// Cities in range
		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())
			{
				return true;
			}
		}

		// Units in range
		for (DangerUnitVector::iterator it = m_apUnits.begin(); it < m_apUnits.end(); ++it)
		{
			CvUnit* pUnit = GET_PLAYER(it->first).getUnit(it->second);
			if (pUnit && !pUnit->isDelayedDeath() && !pUnit->IsDead())
			{
				return true;
			}
		}

		// Citadel etc in range
		if (GetDamageFromFeatures(pUnit->getOwner()) > 0)
		{
			return true;
		}
	}

	// Terrain damage is greater than heal rate
	int iMinimumDamage = m_bFlatPlotDamage ? m_pPlot->getTurnDamage(pUnit->ignoreTerrainDamage(), pUnit->ignoreFeatureDamage(), pUnit->extraTerrainDamage(), pUnit->extraFeatureDamage()) : 0;

	if (pUnit->canHeal(m_pPlot))
	{
		iMinimumDamage -= pUnit->healRate(m_pPlot);
	}

	return (iMinimumDamage > 0);
}
// Can this tile be attacked by an enemy unit or city next turn?
bool CvDangerPlotContents::IsUnderImmediateThreat(PlayerTypes ePlayer)
{
	if (!m_pPlot)
		return false;

	// Terrain damage
	if (m_bFlatPlotDamage)
		return true;

	// Cities in range
	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() != GET_PLAYER(ePlayer).getTeam())
		{
			return true;
		}
	}

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

		if (pUnit && !pUnit->isDelayedDeath() && !pUnit->IsDead())
		{
			return true;
		}
	}

	// Citadel etc in range
	if (GetDamageFromFeatures(ePlayer) > 0)
	{
		return true;
	}

	return false;
}
/// Add data for this cell into dominance zone information
void CvTacticalAnalysisMap::AddToDominanceZones(int iIndex, CvTacticalAnalysisCell* pCell)
{
	TeamTypes ourTeam = GET_PLAYER(m_ePlayer).getTeam();
	CvPlot* pPlot = GC.getMap().plotByIndex(iIndex);

	// Compute zone data for this cell
	CvTacticalDominanceZone newZone;
	newZone.SetAreaID(pPlot->getArea());
	newZone.SetWater(pPlot->isWater());

	int iCityDistance = GC.getGame().GetClosestCityDistanceInTurns(pPlot);
	CvCity* pCity = GC.getGame().GetClosestCityByEstimatedTurns(pPlot);
	PlayerTypes eOwnerPlayer = NO_PLAYER;
	TeamTypes eOwnerTeam = NO_TEAM;

	//for plots far away from a city, check the owner
	if (iCityDistance>2)
	{
		eOwnerTeam = pPlot->getTeam();
		eOwnerPlayer = pPlot->getOwner();

		//there is almost always a closest city, but we're not always interested
		if (pCity && eOwnerPlayer!=pCity->getOwner())
			pCity = NULL;
	}
	else if (pCity) //look at the city
	{
		eOwnerTeam = pCity->getTeam();
		eOwnerPlayer = pCity->getOwner();
	}

	newZone.SetOwner(eOwnerPlayer);
	newZone.SetZoneCity(pCity);
	newZone.Extend(pPlot);

	if(eOwnerTeam==NO_TEAM)
	{
		newZone.SetTerritoryType(TACTICAL_TERRITORY_NO_OWNER);
	}
	else if(eOwnerTeam == ourTeam)
	{
		newZone.SetTerritoryType(TACTICAL_TERRITORY_FRIENDLY);
	}
	else if(GET_TEAM(ourTeam).isAtWar(eOwnerTeam))
	{
		newZone.SetTerritoryType(TACTICAL_TERRITORY_ENEMY);
	}
	else
	{
		newZone.SetTerritoryType(TACTICAL_TERRITORY_NEUTRAL);
	}

	// Now see if we already have a matching zone
	CvTacticalDominanceZone* pZone = MergeWithExistingZone(&newZone);
	if(!pZone)
	{
		// Data populated, now add to vector
		newZone.SetDominanceZoneID(m_DominanceZones.size());
		m_DominanceZones.push_back(newZone);
		pZone = &m_DominanceZones[m_DominanceZones.size() - 1];
	}

	// Set zone for this cell
	pCell->SetDominanceZone(pZone->GetDominanceZoneID());
	pZone->Extend(pPlot);
}
Пример #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;
}
Пример #5
0
// Get the maximum damage unit could receive at this plot in the next turn
int CvDangerPlotContents::GetDanger(PlayerTypes ePlayer)
{
	if (!m_pPlot)
		return 0;

	// Damage from terrain - since we don't know the unit, just assume 20
	int iPlotDamage = m_bFlatPlotDamage ? 20 : 0;

	// Damage from units
	CvPlot* pAttackerPlot = NULL;

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

		if ( !pUnit || pUnit->isDelayedDeath() || pUnit->IsDead())
		{
			continue;
		}

		pAttackerPlot = NULL;
		if (pUnit->IsCanAttackRanged())
		{
			if (pUnit->getDomainType() == DOMAIN_AIR)
			{
				iPlotDamage += pUnit->GetAirCombatDamage(NULL, NULL, false, 0, m_pPlot);
			}
			else
			{
				iPlotDamage += pUnit->GetRangeCombatDamage(NULL, NULL, false, 0, m_pPlot);
			}
		}
		else
		{
			if (plotDistance(m_iX, m_iY, pUnit->getX(), pUnit->getY()) == 1)
			{
				pAttackerPlot = pUnit->plot();
			}
			//we don't know the defender strength, so assume it's equal to attacker strength!
			iPlotDamage += pUnit->getCombatDamage(
				pUnit->GetMaxAttackStrength(pAttackerPlot, m_pPlot, NULL),
				pUnit->GetBaseCombatStrength()*100, 
				pUnit->getDamage(), false, false, false);

			if (pUnit->isRangedSupportFire())
			{
				iPlotDamage += pUnit->GetRangeCombatDamage(NULL, 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() != GET_PLAYER(ePlayer).getTeam())
			iPlotDamage += pCity->rangeCombatDamage(NULL, NULL, false, m_pPlot);
	}

	// Damage from features
	iPlotDamage += GetDamageFromFeatures(ePlayer);

	return iPlotDamage;
}
Пример #6
0
// Get the maximum damage city could receive this turn if it were in this plot
int CvDangerPlotContents::GetDanger(CvCity* pCity, const CvUnit* pPretendGarrison)
{
	if (!m_pPlot || !pCity)
		return 0;

	int iPlotDamage = 0;
	CvPlot* pCityPlot = pCity->plot();
	const int iCityX = pCityPlot->getX();
	const int iCityY = pCityPlot->getY();

	CvCityGarrisonOverride guard(pCity,pPretendGarrison);

	CvPlot* pAttackerPlot = NULL;
	CvUnit* pInterceptor = NULL;

	// Damage from ranged units and melees that cannot capture 
	for (DangerUnitVector::iterator it = m_apUnits.begin(); it < m_apUnits.end(); ++it)
	{
		CvUnit* pUnit = GET_PLAYER(it->first).getUnit(it->second);
		if (!pUnit || pUnit->isDelayedDeath() || pUnit->IsDead())
		{
			continue;
		}

		pAttackerPlot = NULL;
		
		if (pUnit->IsCanAttackRanged())
		{
			if (pUnit->getDomainType() == DOMAIN_AIR)
			{
				pInterceptor = pUnit->GetBestInterceptor(*m_pPlot);
				int iInterceptDamage = 0;
				if (pInterceptor)
				{
					// Always assume interception is successful
					iInterceptDamage = pInterceptor->GetInterceptionDamage(pUnit, false);
				}
				iPlotDamage += pUnit->GetAirCombatDamage(NULL, pCity, false, iInterceptDamage, m_pPlot);
			}
			else
			{
				iPlotDamage += pUnit->GetRangeCombatDamage(NULL, pCity, false, 0, m_pPlot);
			}
		}
		else if (pUnit->isNoCapture())
		{
			if (plotDistance(iCityX, iCityY, pUnit->getX(), pUnit->getY()) == 1)
			{
				pAttackerPlot = pUnit->plot();
			}
			iPlotDamage += pUnit->getCombatDamage(pUnit->GetMaxAttackStrength(pAttackerPlot, pCityPlot, NULL),
				pCity->getStrengthValue(), pUnit->getDamage(), false, false, true);
			
			if (pUnit->isRangedSupportFire())
			{
				iPlotDamage += pUnit->GetRangeCombatDamage(NULL, pCity, false, 0, pCityPlot);
			}
		}
	}

	// 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() == pCity->getTeam())
		{
			continue;
		}

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

	// Damage from melee units
	for (DangerUnitVector::iterator it = m_apUnits.begin(); it < m_apUnits.end(); ++it)
	{
		CvUnit* pUnit = GET_PLAYER(it->first).getUnit(it->second);
		if (!pUnit || pUnit->isDelayedDeath() || pUnit->IsDead())
		{
			continue;
		}

		pAttackerPlot = NULL;

		if (!pUnit->IsCanAttackRanged() && !pUnit->isNoCapture())
		{
			if (plotDistance(iCityX, iCityY, pUnit->getX(), pUnit->getY()) == 1)
			{
				pAttackerPlot = pUnit->plot();
			}

			iPlotDamage += pUnit->getCombatDamage(pUnit->GetMaxAttackStrength(pAttackerPlot, pCityPlot, NULL),
				pCity->getStrengthValue(), pUnit->getDamage(), false, false, true);

			if (pUnit->isRangedSupportFire())
			{
				iPlotDamage += pUnit->GetRangeCombatDamage(NULL, pCity, false, 0, pCityPlot);
			}
		}
	}

	//if we have a garrison, split the damage
	CvUnit* pGarrison = pCity->GetGarrisonedUnit();
	if (pGarrison)
	{
		int iUnitShare = (iPlotDamage*2*pGarrison->GetMaxHitPoints())/(pCity->GetMaxHitPoints()+2*pGarrison->GetMaxHitPoints());
		iPlotDamage -= iUnitShare;
	}

	return iPlotDamage;
}