CvPlot* CvArmyAI::DetectNearbyEnemy(PlayerTypes eEnemy, bool bNaval) { UnitHandle pUnit = GetFirstUnit(); while(pUnit) { for(int iDirectionLoop = 0; iDirectionLoop < NUM_DIRECTION_TYPES; ++iDirectionLoop) { CvPlot* pAdjacentPlot = plotDirection(pUnit->getX(), pUnit->getY(), ((DirectionTypes)iDirectionLoop)); if(pAdjacentPlot != NULL && pAdjacentPlot->isWater()==bNaval && pAdjacentPlot->getOwner() == eEnemy) { UnitHandle pOtherUnit = pAdjacentPlot->getBestDefender(eEnemy); if(pOtherUnit) { if(GC.getLogging() && GC.getAILogging()) { CvString strMsg; strMsg.Format("Ran into enemy unit during attack (x=%d y=%d). Need to declare war to continue!", pAdjacentPlot->getX(), pAdjacentPlot->getY()); GET_PLAYER(m_eOwner).getAIOperation(m_iOperationID)->LogOperationSpecialMessage(strMsg); } return pAdjacentPlot; } } } pUnit = GetNextUnit(); } return NULL; }
// --------------------------------------------------------------------------- /// Called every turn void CvBarbarians::BeginTurn() { CvGame &kGame = GC.getGame(); const ImprovementTypes eCamp = kGame.GetBarbarianCampImprovementType(); CvMap& kMap = GC.getMap(); int iWorldNumPlots = kMap.numPlots(); for (int iPlotLoop = 0; iPlotLoop < iWorldNumPlots; iPlotLoop++) { if (m_aiPlotBarbCampSpawnCounter[iPlotLoop] > 0) { // No Camp here any more CvPlot* pPlot = kMap.plotByIndex(iPlotLoop); if (pPlot->getImprovementType() != eCamp) { m_aiPlotBarbCampSpawnCounter[iPlotLoop] = -1; m_aiPlotBarbCampNumUnitsSpawned[iPlotLoop] = -1; } else { m_aiPlotBarbCampSpawnCounter[iPlotLoop]--; } } // Counter is negative, meaning a camp was cleared here recently and isn't allowed to respawn in the area for a while else if (m_aiPlotBarbCampSpawnCounter[iPlotLoop] < -1) { m_aiPlotBarbCampSpawnCounter[iPlotLoop]++; } #if defined(MOD_DIPLOMACY_CITYSTATES) if (MOD_DIPLOMACY_CITYSTATES) { if (m_aiPlotBarbCitySpawnCounter[iPlotLoop] > 0) { // No City here any more CvPlot* pPlot = kMap.plotByIndex(iPlotLoop); if (pPlot->isCity() && pPlot->getOwner() != BARBARIAN_PLAYER) { m_aiPlotBarbCitySpawnCounter[iPlotLoop] = -1; m_aiPlotBarbCityNumUnitsSpawned[iPlotLoop] = -1; } else { m_aiPlotBarbCitySpawnCounter[iPlotLoop]--; } } // Counter is negative, meaning a camp was cleared here recently and isn't allowed to respawn in the area for a while else if (m_aiPlotBarbCitySpawnCounter[iPlotLoop] < -1) { m_aiPlotBarbCitySpawnCounter[iPlotLoop]++; } } #endif } }
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; }
/// 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; }
/// 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); }
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; }
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; }
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; }
/// Retrieve the relative value of this plot (including plots that would be in city radius) int CvCitySiteEvaluator::PlotFoundValue(CvPlot* pPlot, const CvPlayer* pPlayer, YieldTypes eYield, bool /*bCoastOnly*/, CvString* pDebug) { CvAssert(pPlot); if(!pPlot) return -1; // Make sure this player can even build a city here if(!CanFound(pPlot, pPlayer, false)) { if(pDebug) *pDebug = "cannot found"; return -1; } //for debugging std::vector<std::string> vQualifiersPositive; std::vector<std::string> vQualifiersNegative; //total int iTotalPlotValue = 0; int iValueModifier = 0; //general modifiers int iCivModifier = 0; //civ-specific modifiers int iStratModifier = 0; //strategic modifiers int iCelticForestCount = 0; int iIroquoisForestCount = 0; int iBrazilJungleCount = 0; int iNaturalWonderCount = 0; int iDesertCount = 0; int iWetlandsCount = 0; int iLakeCount = 0; int iLuxuryCount = 0; //currently just for debugging int iTotalFoodValue = 0; int iTotalHappinessValue = 0; int iTotalProductionValue = 0; int iTotalGoldValue = 0; int iTotalScienceValue = 0; int iTotalFaithValue = 0; int iTotalResourceValue = 0; int iTotalStrategicValue = 0; //use a slightly negative base value to discourage settling in bad lands int iDefaultPlotValue = -100; int iBorderlandRange = 6; int iCapitalArea = NULL; bool bIsAlmostCoast = false; bool bIsInca = false; int iAdjacentMountains = 0; std::vector<SPlotWithScore> workablePlots; workablePlots.reserve(49); TeamTypes eTeam = pPlayer ? pPlayer->getTeam() : NO_TEAM; PlayerTypes ePlayer = pPlayer ? pPlayer->GetID() : NO_PLAYER; if (pPlayer) { 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; } } } } int iRange = pPlayer ? pPlayer->getWorkPlotDistance() : 3; for (int iDX = -iRange; iDX <= iRange; iDX++) { for (int iDY = -iRange; iDY <= iRange; 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 <= iRange) { int iRingModifier = m_iRingModifier[iDistance]; //not only our cities, also other player's cities! int iExistingCityDistance = GC.getGame().GetClosestCityDistance(pLoopPlot); //count the tile only if the city will be able to work it if ( !pLoopPlot->isValidMovePlot(pPlayer->GetID()) || pLoopPlot->getWorkingCity()!=NULL || iExistingCityDistance<=2 ) iRingModifier = 0; if (iExistingCityDistance==3) //this plot will likely be contested between the two cities, reduce its value iRingModifier /= 2; int iPlotValue = iDefaultPlotValue; if (iRingModifier>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; if (eYield == NO_YIELD || eYield == YIELD_FOOD) iFoodValue = ComputeFoodValue(pLoopPlot, pPlayer) * /*15*/ GC.getSETTLER_FOOD_MULTIPLIER(); if (eYield == NO_YIELD || eYield == YIELD_PRODUCTION) iProductionValue = ComputeProductionValue(pLoopPlot, pPlayer) * /*3*/ GC.getSETTLER_PRODUCTION_MULTIPLIER(); if (eYield == NO_YIELD || eYield == YIELD_GOLD) iGoldValue = ComputeGoldValue(pLoopPlot, pPlayer) * /*2*/ GC.getSETTLER_GOLD_MULTIPLIER(); if (eYield == NO_YIELD || eYield == YIELD_SCIENCE) iScienceValue = ComputeScienceValue(pLoopPlot, pPlayer) * /*1*/ GC.getSETTLER_SCIENCE_MULTIPLIER(); if (eYield == NO_YIELD || eYield == YIELD_FAITH) iFaithValue = ComputeFaithValue(pLoopPlot, pPlayer) * /*1*/ GC.getSETTLER_FAITH_MULTIPLIER(); if (pLoopPlot->getOwner() == NO_PLAYER) // there is no benefit if we already own these tiles { iHappinessValue = ComputeHappinessValue(pLoopPlot, pPlayer) * /*6*/ GC.getSETTLER_HAPPINESS_MULTIPLIER(); iResourceValue = 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; iPlotValue += iRingModifier * ( iFoodValue + iHappinessValue + iProductionValue + iGoldValue + iScienceValue + iFaithValue + iResourceValue ) + iStrategicValue; } // for the central plot if (iDistance==0) vQualifiersPositive.push_back( CvString::format("raw plot value %d", iPlotValue).c_str() ); if (iDistance==1 && !pPlot->isCoastalLand(GC.getMIN_WATER_SIZE_FOR_OCEAN()) && pLoopPlot->isCoastalLand(GC.getMIN_WATER_SIZE_FOR_OCEAN())) bIsAlmostCoast = true; // 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 (pLoopPlot->IsNaturalWonder() && iPlotValue>0) iPlotValue *= 15; // lower value a lot if we already own this tile if (iPlotValue > 0 && pLoopPlot->getOwner() == ePlayer && ePlayer != NO_PLAYER) iPlotValue /= 2; // add this plot into the total workablePlots.push_back( SPlotWithScore(pLoopPlot,iPlotValue) ); // some civ-specific checks 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 (iDistance <= iRange) ++iBrazilJungleCount; } else if (ePlotFeature == FEATURE_MARSH || ePlotFeature == FEATURE_FLOOD_PLAINS) { if (iDistance <= iRange) ++iWetlandsCount; } if (pLoopPlot->IsNaturalWonder()) { if (iDistance <= iRange) ++iNaturalWonderCount; } if (pLoopPlot->isLake()) { if (iDistance <= iRange) ++iLakeCount; } if (pLoopPlot->getResourceType(NO_TEAM) != NO_RESOURCE) { ResourceTypes eResource = pLoopPlot->getResourceType(eTeam); if(eResource != NO_RESOURCE && GC.getResourceInfo(eResource)->getResourceUsage() == RESOURCEUSAGE_LUXURY) { if (iDistance <= iRange) { ++iLuxuryCount; } } } if (pLoopPlot->getTerrainType() == TERRAIN_DESERT) { if (iDistance <= iRange) { if (ePlotResource == NO_RESOURCE) { ++iDesertCount; } } } if (bIsInca) { if (pLoopPlot->isHills() && iDistance <= iRange) { iAdjacentMountains = pLoopPlot->GetNumAdjacentMountains(); if (iAdjacentMountains > 0 && iAdjacentMountains < 6) { //give the bonus if it's hills, with additional if bordered by mountains iCivModifier += (iAdjacentMountains+1) * m_iIncaMultiplier; vQualifiersPositive.push_back("(C) incan hills"); } } } } } } } //take into account only the best 70% of the plots - in the near term the city will not work all plots anyways std::stable_sort( workablePlots.begin(), workablePlots.end() ); size_t iIrrelevantPlots = workablePlots.size()*30/100; for (size_t idx=iIrrelevantPlots; idx<workablePlots.size(); idx++) { SPlotWithScore& ref = workablePlots[idx]; iTotalPlotValue += ref.score; } if (iTotalPlotValue<0) return 0; //civ-specific bonuses if (pPlayer) { if (pPlayer->GetPlayerTraits()->IsFaithFromUnimprovedForest()) { if (iCelticForestCount >= 3) { iCivModifier += 2 * 1000 * m_iFlavorMultiplier[YIELD_FAITH]; vQualifiersPositive.push_back("(C) much forest"); } else if (iCelticForestCount >= 1) { iCivModifier += 1 * 1000 * m_iFlavorMultiplier[YIELD_FAITH]; vQualifiersPositive.push_back("(C) some forest"); } } else if (pPlayer->GetPlayerTraits()->IsMoveFriendlyWoodsAsRoad()) { iCivModifier += iIroquoisForestCount * 10; vQualifiersPositive.push_back("(C) forested"); } else if (pPlayer->GetPlayerTraits()->GetNaturalWonderYieldModifier() > 0) //ie: Spain { iCivModifier += iNaturalWonderCount * m_iSpainMultiplier; vQualifiersPositive.push_back("(C) natural wonders"); } // 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()) { iCivModifier += iBrazilJungleCount * m_iBrazilMultiplier; vQualifiersPositive.push_back("(C) jungle"); } } } // 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() && !pkEntry->IsAdjacentCity()) { CivilizationTypes eCiv = pkEntry->GetRequiredCivilization(); if(eCiv == pPlayer->getCivilizationType()) { iCivModifier += iDesertCount * m_iMorrocoMultiplier; vQualifiersPositive.push_back("(C) desert"); } } } // Custom code for France ImprovementTypes eFranceImprovement = (ImprovementTypes)GC.getInfoTypeForString("IMPROVEMENT_CHATEAU", true); if(eFranceImprovement != NO_IMPROVEMENT) { CvImprovementEntry* pkEntry = GC.getImprovementInfo(eFranceImprovement); if(pkEntry != NULL && pkEntry->IsSpecificCivRequired() && pkEntry->IsAdjacentLuxury()) { CivilizationTypes eCiv = pkEntry->GetRequiredCivilization(); if(eCiv == pPlayer->getCivilizationType()) { iCivModifier += iLuxuryCount * m_iFranceMultiplier; vQualifiersPositive.push_back("(C) luxury"); } } } //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()) { iCivModifier += iWetlandsCount * m_iNetherlandsMultiplier; if(pkEntry->IsAdjacentLake()) { iCivModifier += (iLakeCount * m_iNetherlandsMultiplier); } vQualifiersPositive.push_back("(C) wetlands"); } } } } // Finally, look at the city plot itself if (pPlot->getResourceType(eTeam) != NO_RESOURCE) { iValueModifier += (int)iTotalPlotValue * /*-50*/ GC.getBUILD_ON_RESOURCE_PERCENT() / 100; vQualifiersNegative.push_back("(V) city on resource"); } if (pPlot->IsNaturalWonder()) { iValueModifier += (int)iTotalPlotValue * /*-50*/ GC.getBUILD_ON_RESOURCE_PERCENT() / 100; vQualifiersNegative.push_back("(V) city on natural wonder"); } if ( iTotalFoodValue>5*iTotalProductionValue || iTotalProductionValue > 2*iTotalFoodValue ) { iValueModifier -= (int)iTotalPlotValue * 10 / 100; vQualifiersNegative.push_back("(V) unbalanced yields"); } if (pPlot->isRiver()) { iValueModifier += (int)iTotalPlotValue * /*15*/ GC.getBUILD_ON_RIVER_PERCENT() / 100; if(pPlayer && pPlayer->GetPlayerTraits()->IsRiverTradeRoad()) iValueModifier += (int)iTotalPlotValue * /*15*/ GC.getBUILD_ON_RIVER_PERCENT() / 100 * 2; vQualifiersPositive.push_back("(V) river"); } if (bIsAlmostCoast) { iValueModifier -= (iTotalPlotValue * 25) / 100; vQualifiersNegative.push_back("(V) almost coast"); } CvArea* pArea = pPlot->area(); int iGoodTiles = 1; if(pArea != NULL) { iGoodTiles = max(1,(pArea->getNumUnownedTiles() - pArea->GetNumBadPlots())); } //Island maps need a little more loose restriction here. if(GC.getMap().GetAIMapHint() & ciMapHint_NavalOffshore) { if (pPlot->isCoastalLand(GC.getMIN_WATER_SIZE_FOR_OCEAN())) { if(pArea != NULL && iGoodTiles > 0) { iValueModifier += (iTotalPlotValue * /*40*/ GC.getSETTLER_BUILD_ON_COAST_PERCENT()) / 100; vQualifiersPositive.push_back("(V) coast"); if (pPlayer) { int iNavalFlavor = pPlayer->GetGrandStrategyAI()->GetPersonalityAndGrandStrategy((FlavorTypes)m_iNavalIndex); if (iNavalFlavor > 7) { iValueModifier += (iTotalPlotValue * /*40*/ GC.getSETTLER_BUILD_ON_COAST_PERCENT()) / 100; } if (pPlayer->getCivilizationInfo().isCoastalCiv()) // we really like the coast (England, Norway, Polynesia, Carthage, etc.) { iValueModifier += iTotalPlotValue; } } } } else { if(iGoodTiles <= 3) { iValueModifier -= (iTotalPlotValue * 40) / 100; vQualifiersNegative.push_back("(V) not enough good plots"); } else if(iGoodTiles <= 6) { iValueModifier -= (iTotalPlotValue * 20) / 100; vQualifiersNegative.push_back("(V) few good plots"); } } } else { if (pPlot->isCoastalLand(GC.getMIN_WATER_SIZE_FOR_OCEAN())) { if(pArea != NULL && iGoodTiles > 3) { iValueModifier += (iTotalPlotValue * /*40*/ GC.getSETTLER_BUILD_ON_COAST_PERCENT()) / 100; vQualifiersPositive.push_back("(V) coast"); if (pPlayer) { int iNavalFlavor = pPlayer->GetGrandStrategyAI()->GetPersonalityAndGrandStrategy((FlavorTypes)m_iNavalIndex); if (iNavalFlavor > 7) { iValueModifier += (iTotalPlotValue * /*40*/ GC.getSETTLER_BUILD_ON_COAST_PERCENT()) / 100; } if (pPlayer->getCivilizationInfo().isCoastalCiv()) // we really like the coast (England, Norway, Polynesia, Carthage, etc.) { iValueModifier += iTotalPlotValue; } } } else if(pArea != NULL && iGoodTiles == 1) { iValueModifier -= (iTotalPlotValue * 40) / 100; vQualifiersNegative.push_back("(V) coast on 1-tile island is not great"); } else { iValueModifier -= (iTotalPlotValue * 25) / 100; vQualifiersNegative.push_back("(V) coast on small island"); } } else { if(iGoodTiles <= 5) { iValueModifier -= (iTotalPlotValue * 40) / 100; vQualifiersNegative.push_back("(V) not enough good plots"); } else if(iGoodTiles <= 10) { iValueModifier -= (iTotalPlotValue * 20) / 100; vQualifiersNegative.push_back("(V) few good plots"); } } } //Is this a chokepoint? if(pPlot->IsChokePoint()) { iStratModifier += (iTotalPlotValue * /*100*/ GC.getBALANCE_CHOKEPOINT_STRATEGIC_VALUE()) / 100; vQualifiersPositive.push_back("(S) chokepoint"); //each landbride is a chokepoint, but not every chokepoint is a landbridge if(pPlot->IsLandbridge(12,54)) { iStratModifier += (iTotalPlotValue * /*100*/ GC.getBALANCE_CHOKEPOINT_STRATEGIC_VALUE()) / 100; vQualifiersPositive.push_back("(S) landbridge"); } } //Check for strategic landgrab int iOwnCityDistance = pPlayer ? pPlayer->GetCityDistance(pPlot) : INT_MAX; int iOtherCityDistance = INT_MAX; //check if the closest city is our or somebody else's CvCity* pClosestCity = GC.getGame().GetClosestCity(pPlot); if( pClosestCity && (!pPlayer || pClosestCity->getOwner()!=pPlayer->GetID()) ) { iOtherCityDistance = GC.getGame().GetClosestCityDistance(pPlot); PlayerTypes eOtherPlayer = (PlayerTypes) pClosestCity->getOwner(); PlayerProximityTypes eProximity = GET_PLAYER(eOtherPlayer).GetProximityToPlayer(pPlayer->GetID()); if(eProximity >= PLAYER_PROXIMITY_CLOSE && iOtherCityDistance<=iBorderlandRange) { //Neighbor must not be too strong if ( pPlayer->GetMilitaryMight() > GET_PLAYER(eOtherPlayer).GetMilitaryMight()*1.4f ) { iStratModifier += (iTotalPlotValue * /*50*/ GC.getBALANCE_EMPIRE_BORDERLAND_STRATEGIC_VALUE()) / 100; vQualifiersPositive.push_back("(S) landgrab"); } else if ( pPlayer->GetMilitaryMight() < GET_PLAYER(eOtherPlayer).GetMilitaryMight()*0.8f ) { iStratModifier -= (iTotalPlotValue * /*50*/ GC.getBALANCE_EMPIRE_BORDERLAND_STRATEGIC_VALUE()) / 100; vQualifiersNegative.push_back("(S) too dangerous"); } } } // where is our personal sweet spot? int iMinDistance = /*3*/ GC.getMIN_CITY_RANGE(); if(pPlayer && pPlayer->isMinorCiv()) { if(GC.getMap().getWorldInfo().getMinDistanceCityStates() > 0) { iMinDistance = GC.getMap().getWorldInfo().getMinDistanceCityStates(); } } else if(GC.getMap().getWorldInfo().getMinDistanceCities() > 0) { iMinDistance = GC.getMap().getWorldInfo().getMinDistanceCities(); } if (iOwnCityDistance <= iMinDistance) { //this case should be handled by the distance check in CanFound() also iValueModifier -= iTotalPlotValue / 2; vQualifiersNegative.push_back("(V) too close to existing friendly city"); } // AI only if (pPlayer && !pPlayer->isHuman()) { int iSweetMin = GC.getSETTLER_DISTANCE_DROPOFF_MODIFIER(); int iSweetMax = GC.getSETTLER_DISTANCE_DROPOFF_MODIFIER()+1; //check our preferred balance between tall and wide int iGrowthFlavor = pPlayer->GetGrandStrategyAI()->GetPersonalityAndGrandStrategy((FlavorTypes)m_iGrowthIndex); if (iGrowthFlavor > 5) { iSweetMax++; iSweetMin++; } else if (iGrowthFlavor < 5) { iSweetMax--; iSweetMin--; } int iExpansionFlavor = pPlayer->GetGrandStrategyAI()->GetPersonalityAndGrandStrategy((FlavorTypes)m_iExpansionIndex); if (iExpansionFlavor > 5) { iSweetMax++; iSweetMin++; } else if (iExpansionFlavor < 5) { iSweetMax--; iSweetMin--; } if(iSweetMin < iMinDistance) iSweetMin = iMinDistance; //this affects both friendly and other cities if (min(iOwnCityDistance,iOtherCityDistance) >= iSweetMin && max(iOwnCityDistance,iOtherCityDistance) <= iSweetMax) { iValueModifier += (iTotalPlotValue*20)/100; //make this a small bonus, there is a separate distance check anyway vQualifiersPositive.push_back("(V) optimal distance to existing cities"); } //boldness comes into play when there are enemy cities around int iBoldness = pPlayer->GetDiplomacyAI()->GetBoldness(); if (iBoldness > 5) iSweetMin--; if (iBoldness < 5) iSweetMin++; if (iOtherCityDistance<=iSweetMin) { iStratModifier -= iTotalPlotValue / 2; vQualifiersNegative.push_back("(S) too close to existing enemy city"); } } #if defined(MOD_EVENTS_CITY_FOUNDING) if (MOD_EVENTS_CITY_FOUNDING) { if (GAMEEVENTINVOKE_TESTALL(GAMEEVENT_PlayerCanFoundCity, pPlayer->GetID(), pPlot->getX(), pPlot->getY()) == GAMEEVENTRETURN_FALSE) { return false; } } #endif //logging logging logging if (pDebug) { pDebug->Format("%d,%d,%d,%d", iTotalPlotValue, iValueModifier, iStratModifier, iCivModifier); for (size_t i=0; i<vQualifiersPositive.size();i++) { pDebug->append(",positive: "); pDebug->append(vQualifiersPositive[i].c_str()); } for (size_t i=0; i<vQualifiersNegative.size();i++) { pDebug->append(",negative: "); pDebug->append(vQualifiersNegative[i].c_str()); } } return max(0,iTotalPlotValue + iValueModifier + iStratModifier + iCivModifier); }
/// 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 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; if ( pPlayer->getCapitalCity() ) iCapitalArea = pPlayer->getCapitalCity()->getArea(); 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 (iDistance > 0 && iDistance <= NUM_CITY_RINGS) { 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 (pLoopPlot->IsNaturalWonder() && iDistance > 0 && iDistance <= NUM_CITY_RINGS) { iPlotValue += iPlotValue * 2 + 10; } // lower value a lot if we already own this tile if (iPlotValue > 0 && pLoopPlot->getOwner() == pPlayer->GetID()) { iPlotValue /= 4; } // add this plot into the total rtnValue += iPlotValue; if (pLoopPlot->getFeatureType() == FEATURE_FOREST) { if (iDistance <= 5) { ++iIroquoisForestCount; if (iDistance == 1) { if (pLoopPlot->getImprovementType() == NO_IMPROVEMENT) { ++iCelticForestCount; } } } } } } 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 (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; } 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())) { rtnValue += (int)rtnValue * /*25*/ GC.getSETTLER_BUILD_ON_COAST_PERCENT() / 100; int iNavalFlavor = pPlayer->GetGrandStrategyAI()->GetPersonalityAndGrandStrategy((FlavorTypes)m_iNavalIndex); if (iNavalFlavor > 7) { rtnValue += (int)rtnValue * /*25*/ GC.getSETTLER_BUILD_ON_COAST_PERCENT() / 100; } if (pPlayer->getCivilizationInfo().isCoastalCiv()) // we really like the coast (England, Norway, Polynesia, Carthage, etc.) { rtnValue *= 2; } } // 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; } } } rtnValue = (rtnValue > 0) ? rtnValue : 0; return rtnValue; }
/// 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()); }
// Indicate the plots we might want to move to that the enemy can attack void CvTacticalAnalysisMap::MarkCellsNearEnemy() { int iDistance; // Look at every cell on the map for(int iI = 0; iI < GC.getMap().numPlots(); iI++) { bool bMarkedIt = false; // Set true once we've found one that enemy can move past (worst case) CvPlot* pPlot = GC.getMap().plotByIndexUnchecked(iI); if(m_pPlots[iI].IsRevealed() && !m_pPlots[iI].IsImpassableTerrain() && !m_pPlots[iI].IsImpassableTerritory()) { // Friendly cities always safe if(!m_pPlots[iI].IsFriendlyCity()) { if(!pPlot->isVisibleToEnemyTeam(m_pPlayer->getTeam())) { m_pPlots[iI].SetNotVisibleToEnemy(true); } else { for(unsigned int iUnitIndex = 0; iUnitIndex < m_EnemyUnits.size() && !bMarkedIt; iUnitIndex++) { CvUnit* pUnit = m_EnemyUnits[iUnitIndex]; if(pUnit->getArea() == pPlot->getArea()) { // Distance check before hitting pathfinder iDistance = plotDistance(pUnit->getX(), pUnit->getY(), pPlot->getX(), pPlot->getY()); if(iDistance == 0) { m_pPlots[iI].SetSubjectToAttack(true); m_pPlots[iI].SetEnemyCanMovePast(true); bMarkedIt = true; } // TEMPORARY OPTIMIZATION: Assumes can't use roads or RR else if(iDistance <= pUnit->baseMoves()) { int iTurnsToReach; iTurnsToReach = TurnsToReachTarget(pUnit, pPlot, true /*bReusePaths*/, true /*bIgnoreUnits*/); // Its ok to reuse paths because when ignoring units, we don't use the tactical analysis map (which we are building) if(iTurnsToReach <= 1) { m_pPlots[iI].SetSubjectToAttack(true); } if(iTurnsToReach == 0) { m_pPlots[iI].SetEnemyCanMovePast(true); bMarkedIt = true; } } } } // Check adjacent plots for enemy citadels if(!m_pPlots[iI].IsSubjectToAttack()) { CvPlot* pAdjacentPlot; for(int jJ = 0; jJ < NUM_DIRECTION_TYPES; jJ++) { pAdjacentPlot = plotDirection(pPlot->getX(), pPlot->getY(), ((DirectionTypes)jJ)); if(pAdjacentPlot != NULL && pAdjacentPlot->getOwner() != NO_PLAYER) { if(atWar(m_pPlayer->getTeam(), GET_PLAYER(pAdjacentPlot->getOwner()).getTeam())) { ImprovementTypes eImprovement = pAdjacentPlot->getImprovementType(); if(eImprovement != NO_IMPROVEMENT && GC.getImprovementInfo(eImprovement)->GetNearbyEnemyDamage() > 0) { m_pPlots[iI].SetSubjectToAttack(true); break; } } } } } } } } } }