/// 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);
}
/// Get center of mass of units in army (account for world wrap!)
CvPlot* CvArmyAI::GetCenterOfMass(float* pfVarX, float* pfVarY)
{
	int iTotalX = 0;
	int iTotalY = 0;
	int iNumUnits = 0;

	UnitHandle pUnit = GetFirstUnit();
	if (!pUnit)
		return NULL;

	int iTotalX2 = 0;
	int iTotalY2 = 0;
	int iWorldWidth = GC.getMap().getGridWidth();
	int iWorldHeight = GC.getMap().getGridHeight();

	//the first unit is our reference ...
	int iRefX = pUnit->getX();
	int iRefY = pUnit->getY();
	iNumUnits++;
	pUnit = GetNextUnit();

	while(pUnit)
	{
		int iDX = pUnit->getX() - iRefX;
		int iDY = pUnit->getY() - iRefY;

		if (GC.getMap().isWrapX())
		{
			if( iDX > +(iWorldWidth / 2))
				iDX -= iWorldWidth;
			if( iDX < -(iWorldWidth / 2))
				iDX += iWorldWidth;
		}
		if (GC.getMap().isWrapY())
		{
			if( iDY > +(iWorldHeight / 2))
				iDY -= iWorldHeight;
			if( iDY < -(iWorldHeight / 2))
				iDY += iWorldHeight;
		}

		iTotalX += iDX;
		iTotalY += iDY;
		iTotalX2 += iDX*iDX;
		iTotalY2 += iDY*iDY;
		iNumUnits++;

		pUnit = GetNextUnit();
	}

	if (iNumUnits==0)
		return NULL;

	//this is for debugging
	float fVarX = (iTotalX2 / (float)iNumUnits) - (iTotalX/(float)iNumUnits)*(iTotalX/(float)iNumUnits);
	float fVarY = (iTotalY2 / (float)iNumUnits) - (iTotalY/(float)iNumUnits)*(iTotalY/(float)iNumUnits);

	//finally, compute average (with rounding)
	int iAvgX = (iTotalX + (iNumUnits / 2)) / iNumUnits + iRefX;
	int iAvgY = (iTotalY + (iNumUnits / 2)) / iNumUnits + iRefY;

	if (fVarX > 64 || fVarY > 64)
	{
		CvString msg = CvString::format("Warning: Army %d with %d units Center of Mass (%d,%d) has a large variance (%.2f,%.2f)\n", GetID(), iNumUnits, iAvgX, iAvgY, fVarX, fVarY);
		OutputDebugString( msg.c_str() );
	}

	//this handles wrapped coordinates
	CvPlot* pCOM = GC.getMap().plot(iAvgX, iAvgY);

	if (!pCOM)
		return NULL;

	if (pfVarX)
		*pfVarX = fVarX;
	if (pfVarY)
		*pfVarY = fVarY;

	//don't return it directly but use the plot of the closest unit
	pUnit = GetFirstUnit();
	std::vector<SPlotWithScore> vPlots;
	while (pUnit)
	{
		if (pUnit->plot()->getDomain()==GetDomainType())
		{
			int iDistToCOM = plotDistance(*pUnit->plot(),*pCOM);
			int iDistToTarget = plotDistance(pUnit->getX(),pUnit->getY(),GetGoalX(),GetGoalY());
			vPlots.push_back( SPlotWithScore(pUnit->plot(),iDistToCOM*100+iDistToTarget) );
		}

		pUnit = GetNextUnit();
	}

	if (vPlots.empty())
		return NULL;

	//this sorts ascending!
	std::sort(vPlots.begin(),vPlots.end());
	return vPlots.front().pPlot;
}
/// Get center of mass of units in army (account for world wrap!)
CvPlot* CvArmyAI::GetCenterOfMass(DomainTypes eDomainRequired)
{
	int iTotalX = 0;
	int iTotalY = 0;
	int iNumUnits = 0;

#if defined(MOD_BALANCE_CORE)
	UnitHandle pUnit = GetFirstUnit();

	if (!pUnit)
		return NULL;

	int iTotalX2 = 0;
	int iTotalY2 = 0;
	int iWorldWidth = GC.getMap().getGridWidth();
	int iWorldHeight = GC.getMap().getGridHeight();

	//the first unit is our reference ...
	int iRefX = pUnit->getX();
	int iRefY = pUnit->getY();
	iNumUnits++;
	pUnit = GetNextUnit();

	while(pUnit)
	{
		int iDX = pUnit->getX() - iRefX;
		int iDY = pUnit->getY() - iRefY;

		if (GC.getMap().isWrapX())
		{
			if( iDX > +(iWorldWidth / 2))
				iDX -= iWorldWidth;
			if( iDX < -(iWorldWidth / 2))
				iDX += iWorldWidth;
		}
		if (GC.getMap().isWrapY())
		{
			if( iDY > +(iWorldHeight / 2))
				iDY -= iWorldHeight;
			if( iDY < -(iWorldHeight / 2))
				iDY += iWorldHeight;
		}

		iTotalX += iDX;
		iTotalY += iDY;
		iTotalX2 += iDX*iDX;
		iTotalY2 += iDY*iDY;
		iNumUnits++;

		pUnit = GetNextUnit();
	}

	if (iNumUnits==0)
		return NULL;

	//this is for debugging
	float fVarX = (iTotalX2 / (float)iNumUnits) - (iTotalX/(float)iNumUnits)*(iTotalX/(float)iNumUnits);
	float fVarY = (iTotalY2 / (float)iNumUnits) - (iTotalY/(float)iNumUnits)*(iTotalY/(float)iNumUnits);

	//finally, compute average (with rounding)
	int iAvgX = (iTotalX + (iNumUnits / 2)) / iNumUnits + iRefX;
	int iAvgY = (iTotalY + (iNumUnits / 2)) / iNumUnits + iRefY;

	if (fVarX > 64 || fVarY > 64)
	{
		CvString msg = CvString::format("Warning: Army %d with %d units Center of Mass (%d,%d) has a large variance (%.2f,%.2f)\n", GetID(), iNumUnits, iAvgX, iAvgY, fVarX, fVarY);
		OutputDebugString( msg.c_str() );
	}

	//this handles wrapped coordinates
	CvPlot* pCOM = GC.getMap().plot(iAvgX, iAvgY);

	if (!pCOM)
		return NULL;

	//don't return it directly but use the plot of the closest unit
	pUnit = GetFirstUnit();
	std::vector<SPlotWithScore> vPlots;
	while (pUnit)
	{
		if (eDomainRequired == NO_DOMAIN || pUnit->plot()->getDomain()==eDomainRequired)
			vPlots.push_back( SPlotWithScore(pUnit->plot(),plotDistance(*pUnit->plot(),*pCOM)) );

		pUnit = GetNextUnit();
	}

	if (vPlots.empty())
		return NULL;

	//this sorts ascending!
	std::sort(vPlots.begin(),vPlots.end());
	return vPlots.front().pPlot;

#else
	CvPlot* pRtnValue = NULL;
	UnitHandle pUnit;
	int iReferenceUnitX = -1;
	int iWorldWidth = GC.getMap().getGridWidth();

	pUnit = GetFirstUnit();
	if(pUnit)
	{
		iReferenceUnitX = pUnit->getX();
	}

	while(pUnit)
	{
		int iUnitX = pUnit->getX();

		bool bWorldWrapAdjust = false;
		int iDiff = iUnitX - iReferenceUnitX;
		if(abs(iDiff) > (iWorldWidth / 2))
		{
			bWorldWrapAdjust = true;
		}

		if(bWorldWrapAdjust)
		{
			iTotalX += iUnitX + iWorldWidth;
		}
		else
		{
			iTotalX += iUnitX;
		}
		iTotalY += pUnit->getY();
		iNumUnits++;
		pUnit = GetNextUnit();
	}

	if(iNumUnits > 0)
	{
		int iAverageX = (iTotalX + (iNumUnits / 2)) / iNumUnits;
		if(iAverageX >= iWorldWidth)
		{
			iAverageX = iAverageX - iWorldWidth;
		}
		int iAverageY = (iTotalY + (iNumUnits / 2)) / iNumUnits;
		pRtnValue = GC.getMap().plot(iAverageX, iAverageY);
	}

	// Domain check
	if (eDomainRequired != NO_DOMAIN && pRtnValue)
	{
		if (pRtnValue->isWater() && eDomainRequired == DOMAIN_LAND || !pRtnValue->isWater() && eDomainRequired == DOMAIN_SEA)
		{
			// Find an adjacent plot that works
			for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
			{
				CvPlot *pLoopPlot = plotDirection(pRtnValue->getX(), pRtnValue->getY(), ((DirectionTypes)iI));
				if (pLoopPlot != NULL)
				{
					if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND)
					{
						return pLoopPlot;
					}
				}
			}

			// Try two plots out if really having problems
			for (int iDX = -2; iDX <= 2; iDX++)
			{
				for (int iDY = -2; iDY <= 2; iDY++)
				{
					CvPlot *pLoopPlot = plotXYWithRangeCheck(pRtnValue->getX(), pRtnValue->getY(), iDX, iDY, 2);
					if (pLoopPlot)
					{
						if (plotDistance(pRtnValue->getX(), pRtnValue->getY(), pLoopPlot->getX(), pLoopPlot->getY()) == 2)
						{
							if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND)
							{
								return pLoopPlot;
							}
						}
					}
				}
			}

			// Give up - just use location of first unit
			pUnit = GetFirstUnit();
			pRtnValue = pUnit->plot();
		}
	}
	return pRtnValue;
#endif
}