bool CvPlayerAI::AI_captureUnit(UnitTypes, CvPlot* pPlot) { CvCity* pNearestCity; CvAssert(!isHuman()); // Barbs always capture if (isBarbarian()) return true; // we own it if (pPlot->getTeam() == getTeam()) return true; // no man's land - may as well if (pPlot->getTeam() == NO_TEAM) return true; // friendly, sure (okay, this is pretty much just means open borders) if (pPlot->IsFriendlyTerritory(GetID())) return true; // not friendly, but "near" us pNearestCity = GC.getMap().findCity(pPlot->getX(), pPlot->getY(), NO_PLAYER, getTeam()); if (pNearestCity != NULL) { if (plotDistance(pPlot->getX(), pPlot->getY(), pNearestCity->getX(), pNearestCity->getY()) <= 7) return true; } // very near someone we aren't friends with (and far from our nearest city) pNearestCity = GC.getMap().findCity(pPlot->getX(), pPlot->getY()); if (pNearestCity != NULL) { if (plotDistance(pPlot->getX(), pPlot->getY(), pNearestCity->getX(), pNearestCity->getY()) <= 4) return false; } // I'd rather we grab it and run than destroy it return true; }
bool CvPlayerAI::AI_captureUnit(UnitTypes, CvPlot* pPlot) { CvCity* pNearestCity; CvAssert(!isHuman()); // Barbs always capture if (isBarbarian()) return true; if (pPlot->getTeam() == getTeam()) return true; pNearestCity = GC.getMap().findCity(pPlot->getX(), pPlot->getY(), NO_PLAYER, getTeam()); if (pNearestCity != NULL) { if (plotDistance(pPlot->getX(), pPlot->getY(), pNearestCity->getX(), pNearestCity->getY()) <= 4) return true; } return false; }
/// 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; }
/// 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); } } } } } }
CvPlot* CvPlayerAI::FindBestMusicianTargetPlot(CvUnit* pGreatMusician, bool bOnlySafePaths) { CvAssertMsg(pGreatMusician, "pGreatMusician is null"); if(!pGreatMusician) { return NULL; } int iBestTurnsToReach = MAX_INT; CvPlot* pBestTargetPlot = NULL; CvCity* pBestTargetCity = NULL; int iPathTurns; UnitHandle pMusician = UnitHandle(pGreatMusician); // Find target civ PlayerTypes eTargetPlayer = GetCulture()->GetCivLowestInfluence(true /*bCheckOpenBorders*/); if (eTargetPlayer == NO_PLAYER) { return NULL; } CvPlayer &kTargetPlayer = GET_PLAYER(eTargetPlayer); // Loop through each of that player's cities int iLoop; CvCity *pLoopCity; for(pLoopCity = kTargetPlayer.firstCity(&iLoop); pLoopCity != NULL; pLoopCity = kTargetPlayer.nextCity(&iLoop)) { // Search all the plots adjacent to this city for(int jJ = 0; jJ < NUM_DIRECTION_TYPES; jJ++) { CvPlot* pAdjacentPlot = plotDirection(pLoopCity->getX(), pLoopCity->getY(), ((DirectionTypes)jJ)); if(pAdjacentPlot != NULL) { // Make sure this is still owned by target and is revealed to us bool bRightOwner = (pAdjacentPlot->getOwner() == eTargetPlayer); bool bIsRevealed = pAdjacentPlot->isRevealed(getTeam()); if(bRightOwner && bIsRevealed) { iPathTurns = TurnsToReachTarget(pMusician, pAdjacentPlot, true /*bReusePaths*/, !bOnlySafePaths/*bIgnoreUnits*/); if(iPathTurns < iBestTurnsToReach) { iBestTurnsToReach = iPathTurns; pBestTargetCity = pLoopCity; } } } } } // Found a city now look at ALL the plots owned by that player near that city if (pBestTargetCity) { iBestTurnsToReach = MAX_INT; CvPlot *pLoopPlot; for(int iJ = 0; iJ < NUM_CITY_PLOTS; iJ++) { pLoopPlot = plotCity(pBestTargetCity->getX(), pBestTargetCity->getY(), iJ); if(pLoopPlot != NULL) { // Make sure this is still owned by target and is revealed to us bool bRightOwner = (pLoopPlot->getOwner() == eTargetPlayer); bool bIsRevealed = pLoopPlot->isRevealed(getTeam()); if(bRightOwner && bIsRevealed) { iPathTurns = TurnsToReachTarget(pMusician, pLoopPlot, true /*bReusePaths*/, !bOnlySafePaths/*bIgnoreUnits*/); if(iPathTurns < iBestTurnsToReach) { iBestTurnsToReach = iPathTurns; pBestTargetPlot = pLoopPlot; } } } } } return pBestTargetPlot; }
bool QuietDiplomacy::LeaderDiscussion(CvPlayer* human, CvPlayer* computer, const char* text) { CvAssertMsg(human && computer && text, "Quiet Diplomacy: Assertion error!"); CvAssertMsg(human->isHuman(), "Quiet Diplomacy: Not a human!"); // Send a notification. CvNotifications* notifications = human->GetNotifications(); if(notifications) { // Create localized strings. // Hardcode some translation strings so DLL can be used alone without XML texts. std::string language = Localization::GetCurrentLanguage().GetType(); std::string message; std::string summary; if(DoesTextKeyExist("TXT_KEY_QUIETDIPLOMACY_LEADERDISCUSSION_SUMMARY") && DoesTextKeyExist("TXT_KEY_QUIETDIPLOMACY_LEADERDISCUSSION_MESSAGE")) { // Fetch from the database. Localization::String localeSummary = Localization::Lookup("TXT_KEY_QUIETDIPLOMACY_LEADERDISCUSSION_SUMMARY"); localeSummary << Localization::Lookup(computer->getNameKey()); Localization::String localeMessage = Localization::Lookup("TXT_KEY_QUIETDIPLOMACY_LEADERDISCUSSION_MESSAGE"); localeMessage << Localization::Lookup(computer->getNameKey()); localeMessage << text; summary = localeSummary.toUTF8(); message = localeMessage.toUTF8(); } else { if(language == "pl_PL") { // Polish Localization::String localeLeader = Localization::Lookup(computer->getNameKey()); size_t localeLeaderBytes = 0; const char* localeLeaderString = localeLeader.toUTF8(localeLeaderBytes, 2); summary += "Wiadomo\xc5\x9b\xc4\x87 od "; summary.append(localeLeaderString, localeLeaderBytes); message += Localization::Lookup(computer->getNameKey()).toUTF8(); message += ": "; message += text; } else { // English summary += "Message from "; summary += Localization::Lookup(computer->getNameKey()).toUTF8(); message += Localization::Lookup(computer->getNameKey()).toUTF8(); message += ": "; message += text; } } // Get computer's capital. int x = -1; int y = -1; CvCity* computerCapital = computer->getCapitalCity(); if(computerCapital && computerCapital->isRevealed(human->getTeam(), false)) { x = computerCapital->getX(); y = computerCapital->getY(); } // Add a notification. notifications->Add(NOTIFICATION_PEACE_ACTIVE_PLAYER, message.c_str(), summary.c_str(), x, y, computer->GetID()); } // Inform that we took care of it. return true; }
/// Updates the danger plots values to reflect threats across the map void CvDangerPlots::UpdateDanger(bool bPretendWarWithAllCivs, bool bIgnoreVisibility) { // danger plots have not been initialized yet, so no need to update if(!m_bArrayAllocated) return; // wipe out values int iGridSize = GC.getMap().numPlots(); CvAssertMsg(iGridSize == m_DangerPlots.size(), "iGridSize does not match number of DangerPlots"); for(int i = 0; i < iGridSize; i++) { m_DangerPlots[i].clear(); } //units we know from last turn UnitSet previousKnownUnits = m_knownUnits; m_knownUnits.clear(); CvPlayer& thisPlayer = GET_PLAYER(m_ePlayer); TeamTypes thisTeam = thisPlayer.getTeam(); // for each opposing civ for(int iPlayer = 0; iPlayer < MAX_PLAYERS; iPlayer++) { PlayerTypes ePlayer = (PlayerTypes)iPlayer; CvPlayer& loopPlayer = GET_PLAYER(ePlayer); TeamTypes eTeam = loopPlayer.getTeam(); if(!loopPlayer.isAlive()) continue; if(eTeam == thisTeam) continue; if(ShouldIgnorePlayer(ePlayer) && !bPretendWarWithAllCivs) continue; //for each unit int iLoop; CvUnit* pLoopUnit = NULL; for(pLoopUnit = loopPlayer.firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = loopPlayer.nextUnit(&iLoop)) { UpdateDangerSingleUnit(pLoopUnit, bIgnoreVisibility, true); } // for each city CvCity* pLoopCity; for(pLoopCity = loopPlayer.firstCity(&iLoop); pLoopCity != NULL; pLoopCity = loopPlayer.nextCity(&iLoop)) { if(ShouldIgnoreCity(pLoopCity, bIgnoreVisibility)) continue; #if defined(MOD_EVENTS_CITY_BOMBARD) bool bIndirectFireAllowed = false; int iRange = pLoopCity->getBombardRange(bIndirectFireAllowed); #else int iRange = GC.getCITY_ATTACK_RANGE(); #endif CvPlot* pCityPlot = pLoopCity->plot(); CvPlot* pLoopPlot = NULL; for(int iDX = -(iRange); iDX <= iRange; iDX++) { for(int iDY = -(iRange); iDY <= iRange; iDY++) { pLoopPlot = plotXYWithRangeCheck(pCityPlot->getX(), pCityPlot->getY(), iDX, iDY, iRange); if(!pLoopPlot || pLoopPlot == pCityPlot) continue; #if defined(MOD_EVENTS_CITY_BOMBARD) if (!bIndirectFireAllowed && !pCityPlot->canSeePlot(pLoopPlot, NO_TEAM, iRange, NO_DIRECTION)) continue; #endif AssignCityDangerValue(pLoopCity, pLoopPlot); } } } } // now compare the new known units with the previous known units for (UnitSet::iterator it = previousKnownUnits.begin(); it != previousKnownUnits.end(); ++it) { //might have made peace ... if (ShouldIgnorePlayer(it->first)) continue; if (m_knownUnits.find(*it) == m_knownUnits.end()) { CvUnit* pVanishedUnit = GET_PLAYER(it->first).getUnit(it->second); //it's still there, but moved out of sight - nevertheless count is, a human would do that as well //do not add it to the known units though, so next turn we will have forgotten about it if (pVanishedUnit) UpdateDangerSingleUnit(pVanishedUnit, true, false); } } int iPlotLoop; CvPlot* pPlot, *pAdjacentPlot; for(iPlotLoop = 0; iPlotLoop < GC.getMap().numPlots(); iPlotLoop++) { pPlot = GC.getMap().plotByIndexUnchecked(iPlotLoop); if(pPlot->isRevealed(thisTeam)) { //remember the plot based damage, but it depends on the unit's promotions also, so we won't apply it directly int iPlotDamage = 0; if (pPlot->getFeatureType() != NO_FEATURE) iPlotDamage += (GC.getFeatureInfo(pPlot->getFeatureType())->getTurnDamage()); if (pPlot->getTerrainType() != NO_FEATURE) iPlotDamage += (GC.getTerrainInfo(pPlot->getTerrainType())->getTurnDamage()); m_DangerPlots[iPlotLoop].m_bFlatPlotDamage = (iPlotDamage>0); ImprovementTypes eImprovement = pPlot->getRevealedImprovementType(thisTeam); if(eImprovement != NO_IMPROVEMENT && GC.getImprovementInfo(eImprovement)->GetNearbyEnemyDamage() > 0) { if(!ShouldIgnoreCitadel(pPlot, bIgnoreVisibility)) { for(int iI = 0; iI < NUM_DIRECTION_TYPES; iI++) { pAdjacentPlot = plotDirection(pPlot->getX(), pPlot->getY(), ((DirectionTypes)iI)); if(pAdjacentPlot != NULL) { m_DangerPlots[iPlotLoop].m_pCitadel = pPlot; } } } } } } // testing city danger values CvCity* pLoopCity; int iLoopCity = 0; for(pLoopCity = thisPlayer.firstCity(&iLoopCity); pLoopCity != NULL; pLoopCity = thisPlayer.nextCity(&iLoopCity)) { //adding danger would count each unit multiple times, is biased towards fast units //so we pretend they would all attack the city and tally up the damage //question is, what about our own defensive units in the area. should we count those as well? int iEvalRange = 4; int iThreatValue = 0; for(int iX = -iEvalRange; iX <= iEvalRange; iX++) for(int iY = -iEvalRange; iY <= iEvalRange; iY++) { CvPlot* pEvalPlot = plotXYWithRangeCheck(pLoopCity->getX(), pLoopCity->getY(), iX, iY, iEvalRange); if (pEvalPlot) { const CvUnit* pEnemy = pEvalPlot->getBestDefender(NO_PLAYER, thisPlayer.GetID(), NULL, true); if (pEnemy) { int iAttackerDamage = 0; //to be ignored iThreatValue += TacticalAIHelpers::GetSimulatedDamageFromAttackOnCity(pLoopCity,pEnemy,iAttackerDamage); } } } pLoopCity->SetThreatValue(iThreatValue); } m_bDirty = false; }
/// 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); } } } } } } } } } } } } }
/// Add data for this cell into dominance zone information void CvTacticalAnalysisMap::AddToDominanceZones(int iIndex, CvTacticalAnalysisCell* pCell) { CvPlot* pPlot = GC.getMap().plotByIndex(iIndex); // Compute zone data for this cell m_TempZone.SetAreaID(pPlot->getArea()); m_TempZone.SetOwner(pPlot->getOwner()); m_TempZone.SetWater(pPlot->isWater()); if(!pPlot->isOwned()) { m_TempZone.SetTerritoryType(TACTICAL_TERRITORY_NO_OWNER); } else if(pPlot->getTeam() == m_pPlayer->getTeam()) { m_TempZone.SetTerritoryType(TACTICAL_TERRITORY_FRIENDLY); } else if(GET_TEAM(m_pPlayer->getTeam()).isAtWar(pPlot->getTeam())) { m_TempZone.SetTerritoryType(TACTICAL_TERRITORY_ENEMY); } else { m_TempZone.SetTerritoryType(TACTICAL_TERRITORY_NEUTRAL); } m_TempZone.SetClosestCity(NULL); if(m_TempZone.GetTerritoryType() == TACTICAL_TERRITORY_ENEMY || m_TempZone.GetTerritoryType() == TACTICAL_TERRITORY_NEUTRAL || m_TempZone.GetTerritoryType() == TACTICAL_TERRITORY_FRIENDLY) { int iLoop; int iBestDistance = MAX_INT; CvCity* pBestCity = NULL; for(CvCity* pLoopCity = GET_PLAYER(m_TempZone.GetOwner()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(m_TempZone.GetOwner()).nextCity(&iLoop)) { int iDistance = plotDistance(pLoopCity->getX(), pLoopCity->getY(), pPlot->getX(), pPlot->getY()); if(iDistance < iBestDistance) { iBestDistance = iDistance; pBestCity = pLoopCity; } } if(pBestCity != NULL) { m_TempZone.SetClosestCity(pBestCity); } } // Now see if we already have a matching zone CvTacticalDominanceZone* pZone = FindExistingZone(pPlot); if(!pZone) { // Data populated, now add to vector m_TempZone.SetDominanceZoneID(m_DominanceZones.size()); m_DominanceZones.push_back(m_TempZone); pZone = &m_DominanceZones[m_DominanceZones.size() - 1]; } // If this isn't owned territory, update zone with military strength info if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_NO_OWNER || pZone->GetTerritoryType() == TACTICAL_TERRITORY_TEMP_ZONE) { CvUnit* pFriendlyUnit = pCell->GetFriendlyMilitaryUnit(); if(pFriendlyUnit) { if(pFriendlyUnit->getDomainType() == DOMAIN_AIR || (pFriendlyUnit->getDomainType() == DOMAIN_LAND && !pZone->IsWater()) || (pFriendlyUnit->getDomainType() == DOMAIN_SEA && pZone->IsWater())) { int iStrength = pFriendlyUnit->GetBaseCombatStrengthConsideringDamage(); if(iStrength == 0 && pFriendlyUnit->isEmbarked() && !pZone->IsWater()) { iStrength = pFriendlyUnit->GetBaseCombatStrength(true); } pZone->AddFriendlyStrength(iStrength * m_iUnitStrengthMultiplier); pZone->AddFriendlyRangedStrength(pFriendlyUnit->GetMaxRangedCombatStrength(NULL, /*pCity*/ NULL, true, true)); if(pFriendlyUnit->GetRange() > GetBestFriendlyRange()) { SetBestFriendlyRange(pFriendlyUnit->GetRange()); } if(pFriendlyUnit->IsRangeAttackIgnoreLOS()) { SetIgnoreLOS(true); } pZone->AddFriendlyUnitCount(1); if(pFriendlyUnit->isRanged()) { pZone->AddFriendlyRangedUnitCount(1); } } } CvUnit* pEnemyUnit = pCell->GetEnemyMilitaryUnit(); if(pEnemyUnit) { if(pEnemyUnit->getDomainType() == DOMAIN_AIR || (pEnemyUnit->getDomainType() == DOMAIN_LAND && !pZone->IsWater()) || (pEnemyUnit->getDomainType() == DOMAIN_SEA && pZone->IsWater())) { int iStrength = pEnemyUnit->GetBaseCombatStrengthConsideringDamage(); if(iStrength == 0 && pEnemyUnit->isEmbarked() && !pZone->IsWater()) { iStrength = pEnemyUnit->GetBaseCombatStrength(true); } #if defined(MOD_AI_SMART_V3) int iEnemyRangedStrength = pEnemyUnit->GetMaxRangedCombatStrength(NULL, /*pCity*/ NULL, true, true); if (MOD_AI_SMART_V3) { if (!pCell->IsVisible()) { iStrength /= 2; iEnemyRangedStrength /= 2; } iEnemyRangedStrength = iEnemyRangedStrength * m_iUnitStrengthMultiplier; } #endif pZone->AddEnemyStrength(iStrength * m_iUnitStrengthMultiplier); #if defined(MOD_AI_SMART_V3) pZone->AddEnemyRangedStrength(iEnemyRangedStrength); #else pZone->AddEnemyRangedStrength(pEnemyUnit->GetMaxRangedCombatStrength(NULL, /*pCity*/ NULL, true, true)); #endif pZone->AddEnemyUnitCount(1); if(pEnemyUnit->isRanged()) { pZone->AddEnemyRangedUnitCount(1); } if (pEnemyUnit->getDomainType() == DOMAIN_SEA) { pZone->AddEnemyNavalUnitCount(1); } } } } // Set zone for this cell pCell->SetDominanceZone(pZone->GetDominanceZoneID()); }