void CvMapGenerator::addLakes() { PROFILE_FUNC(); if (gDLL->getPythonIFace()->pythonAddLakes() && !gDLL->getPythonIFace()->pythonUsingDefaultImpl()) { return; // Python override } gDLL->NiTextOut("Adding Lakes..."); CvPlot* pLoopPlot; int iI; for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++) { gDLL->callUpdater(); pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI); FAssertMsg(pLoopPlot != NULL, "LoopPlot is not assigned a valid value"); if (!(pLoopPlot->isWater())) { if (!(pLoopPlot->isCoastalLand())) { if (!(pLoopPlot->isRiver())) { if (GC.getGameINLINE().getMapRandNum(GC.getXMLval(XML_LAKE_PLOT_RAND), "addLakes") == 0) { pLoopPlot->setPlotType(PLOT_OCEAN); } } } } } }
int CvArea::countCoastalLand() const { if (isWater()) { return 0; } int iCount = 0; for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++) { CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI); if (pLoopPlot->getArea() == getID()) { if (pLoopPlot->isCoastalLand()) { iCount++; } } } return iCount; }
void CvMapGenerator::addRivers() { PROFILE_FUNC(); if (gDLL->getPythonIFace()->pythonAddRivers() && !gDLL->getPythonIFace()->pythonUsingDefaultImpl()) { return; // Python override } gDLL->NiTextOut("Adding Rivers..."); CvPlot* pLoopPlot; CvPlot* pStartPlot; int iPass; int iRiverSourceRange; int iSeaWaterRange; int iI; for (iPass = 0; iPass < 4; iPass++) { if (iPass <= 1) { iRiverSourceRange = GC.getXMLval(XML_RIVER_SOURCE_MIN_RIVER_RANGE); } else { iRiverSourceRange = (GC.getXMLval(XML_RIVER_SOURCE_MIN_RIVER_RANGE) / 2); } if (iPass <= 1) { iSeaWaterRange = GC.getXMLval(XML_RIVER_SOURCE_MIN_SEAWATER_RANGE); } else { iSeaWaterRange = (GC.getXMLval(XML_RIVER_SOURCE_MIN_SEAWATER_RANGE) / 2); } for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++) { gDLL->callUpdater(); pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI); FAssertMsg(pLoopPlot != NULL, "LoopPlot is not assigned a valid value"); if (!(pLoopPlot->isWater())) { if (((iPass == 0) && (pLoopPlot->isHills() || pLoopPlot->isPeak())) || ((iPass == 1) && !(pLoopPlot->isCoastalLand()) && (GC.getGameINLINE().getMapRandNum(8, "addRivers") == 0)) || ((iPass == 2) && (pLoopPlot->isHills() || pLoopPlot->isPeak()) && (pLoopPlot->area()->getNumRiverEdges() < ((pLoopPlot->area()->getNumTiles() / GC.getXMLval(XML_PLOTS_PER_RIVER_EDGE)) + 1))) || ((iPass == 3) && (pLoopPlot->area()->getNumRiverEdges() < ((pLoopPlot->area()->getNumTiles() / GC.getXMLval(XML_PLOTS_PER_RIVER_EDGE)) + 1)))) { if (!(GC.getMapINLINE().findWater(pLoopPlot, iRiverSourceRange, true))) { if (!(GC.getMapINLINE().findWater(pLoopPlot, iSeaWaterRange, false))) { pStartPlot = pLoopPlot->getInlandCorner(); if (pStartPlot != NULL) { doRiver(pStartPlot); } } } } } } } }
/// 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); }