//"Check plots for wetlands or seaWater. Returns true if found" bool CvMap::findWater(CvPlot* pPlot, int iRange, bool bFreshWater) { PROFILE_FUNC(); for (int iDX = -(iRange); iDX <= iRange; iDX++) { for (int iDY = -(iRange); iDY <= iRange; iDY++) { CvPlot* pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY); if (pLoopPlot != NULL) { if (bFreshWater) { if (pLoopPlot->isRiver()) { return true; } } else { if (pLoopPlot->isWater()) { return true; } } } } } return false; }
void round1_noCher(){ TFile *fIn1 = new TFile("/home/jmbenlloch/next/petalo/work/histo/LXe_VUV3mm_xy2.4cm_z5cm_n1.7_noCher_QE_1_SPTR_0_ASIC_0_DT300_histos.root", "read"); TFile *fIn2 = new TFile("/home/jmbenlloch/next/petalo/work/histo/LXe_TPB3mm_xy2.4cm_z5cm_n1.7_noCher_QE_1_SPTR_0_ASIC_0_DT300_histos.root", "read"); TFile *fIn3 = new TFile("/home/jmbenlloch/next/petalo/work/histo/LYSO_VUV3mm_xy2.4cm_z5cm_n1.8_noCher_QE_1_SPTR_0_ASIC_0_DT300_histos.root", "read"); plotX(fIn1,fIn2,fIn3); plotY(fIn1,fIn2,fIn3); plotZ(fIn1,fIn2,fIn3); plotT(fIn1,fIn2,fIn3); plotNPhotons(fIn1,fIn2,fIn3); plotCRT(fIn1,fIn2,fIn3); plotFirstPE(fIn1,fIn2,fIn3); plotXY(fIn1,fIn2,fIn3); fIn1->Close(); fIn2->Close(); fIn3->Close(); TFile *fIn1 = new TFile("/home/jmbenlloch/next/petalo/work/histo/LXe_VUV3mm_xy2.4cm_z5cm_n1.7_noCher_QE_1_SPTR_0_ASIC_0_DT300_histos.root", "read"); TFile *fIn2 = new TFile("/home/jmbenlloch/next/petalo/work/histo/LXe_TPB3mm_xy2.4cm_z5cm_n1.7_noCher_QE_1_SPTR_0_ASIC_0_DT300_histos.root", "read"); TFile *fIn3 = new TFile("/home/jmbenlloch/next/petalo/work/histo/LYSO_VUV3mm_xy2.4cm_z5cm_n1.8_noCher_QE_1_SPTR_0_ASIC_0_DT300_histos.root", "read"); plotCRTCombined(fIn1,fIn2,fIn3); fIn1->Close(); fIn2->Close(); fIn3->Close(); }
// Mark cells we can use to bomb a specific target void CvTacticalAnalysisMap::SetTargetBombardCells(CvPlot* pTarget, int iRange, bool bIgnoreLOS) { int iDX, iDY; CvPlot* pLoopPlot; int iPlotIndex; int iPlotDistance; for(iDX = -(iRange); iDX <= iRange; iDX++) { for(iDY = -(iRange); iDY <= iRange; iDY++) { pLoopPlot = plotXY(pTarget->getX(), pTarget->getY(), iDX, iDY); if(pLoopPlot != NULL) { iPlotDistance = plotDistance(pLoopPlot->getX(), pLoopPlot->getY(), pTarget->getX(), pTarget->getY()); if(iPlotDistance > 0 && iPlotDistance <= iRange) { iPlotIndex = GC.getMap().plotNum(pLoopPlot->getX(), pLoopPlot->getY()); if(m_pPlots[iPlotIndex].IsRevealed() && !m_pPlots[iPlotIndex].IsImpassableTerrain() && !m_pPlots[iPlotIndex].IsImpassableTerritory()) { if(!m_pPlots[iPlotIndex].IsEnemyCity() && !m_pPlots[iPlotIndex].IsNeutralCity()) { if(bIgnoreLOS || pLoopPlot->canSeePlot(pTarget, m_pPlayer->getTeam(), iRange, NO_DIRECTION)) { m_pPlots[iPlotIndex].SetWithinRangeOfTarget(true); } } } } } } } }
CvPlot* plotXYWithRangeCheck(int iX, int iY, int iDX, int iDY, int iRange) { int hexRange; // I'm assuming iDX and iDY are in hex-space if((iDX >= 0) == (iDY >= 0)) // the signs match { int iAbsDX = iDX >= 0 ? iDX : -iDX; int iAbsDY = iDY >= 0 ? iDY : -iDY; hexRange = iAbsDX + iAbsDY; } else { int iAbsDX = iDX >= 0 ? iDX : -iDX; int iAbsDY = iDY >= 0 ? iDY : -iDY; hexRange = iAbsDX >= iAbsDY ? iAbsDX : iAbsDY; } if(hexRange > iRange) { return NULL; } return plotXY(iX, iY, iDX, iDY); }
void CvMapGenerator::addNonUniqueBonusType(BonusTypes eBonusType) { int iBonusCount = calculateNumBonusesToAdd(eBonusType); if (iBonusCount == 0) { return; } std::vector<int> aiShuffle(GC.getMapINLINE().numPlotsINLINE()); GC.getGameINLINE().getMapRand().shuffleSequence(aiShuffle, "addNonUniqueBonusType shuffle"); CvBonusInfo& pBonusInfo = GC.getBonusInfo(eBonusType); bool bIgnoreLatitude = false; gDLL->getPythonIFace()->pythonIsBonusIgnoreLatitudes(&bIgnoreLatitude); CvPlot* pPlot = NULL; for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++) { pPlot = GC.getMapINLINE().plotByIndexINLINE(aiShuffle[iI]); if (canPlaceBonusAt(eBonusType, pPlot->getX_INLINE(), pPlot->getY_INLINE(), bIgnoreLatitude)) { pPlot->setBonusType(eBonusType); iBonusCount--; for (int iDX = -(pBonusInfo.getGroupRange()); iDX <= pBonusInfo.getGroupRange(); iDX++) { for (int iDY = -(pBonusInfo.getGroupRange()); iDY <= pBonusInfo.getGroupRange(); iDY++) { if (iBonusCount > 0) { CvPlot* pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY); if (pLoopPlot != NULL) { if (canPlaceBonusAt(eBonusType, pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), bIgnoreLatitude)) { if (GC.getGameINLINE().getMapRandNum(100, "addNonUniqueBonusType") < pBonusInfo.getGroupRand()) { pLoopPlot->setBonusType(eBonusType); iBonusCount--; } } } } } } FAssertMsg(iBonusCount >= 0, "iBonusCount must be >= 0"); if (iBonusCount == 0) { break; } } } }
void CvMapGenerator::addUniqueBonusType(BonusTypes eBonusType) { int* piAreaTried = new int[GC.getMapINLINE().getNumAreas()]; for (int iI = 0; iI < GC.getMapINLINE().getNumAreas(); iI++) { piAreaTried[iI] = FFreeList::INVALID_INDEX; } CvBonusInfo& pBonusInfo = GC.getBonusInfo(eBonusType); int iBonusCount = calculateNumBonusesToAdd(eBonusType); bool bIgnoreLatitude = false; gDLL->getPythonIFace()->pythonIsBonusIgnoreLatitudes(&bIgnoreLatitude); FAssertMsg(pBonusInfo.isOneArea(), "addUniqueBonusType called with non-unique bonus type"); while (true) { int iBestValue = 0; int iLoop = 0; CvArea *pBestArea = NULL; CvArea *pLoopArea = NULL; for(pLoopArea = GC.getMapINLINE().firstArea(&iLoop); pLoopArea != NULL; pLoopArea = GC.getMapINLINE().nextArea(&iLoop)) { bool bTried = false; for (int iI = 0; iI < GC.getMapINLINE().getNumAreas(); iI++) { if (pLoopArea->getID() == piAreaTried[iI]) { bTried = true; break; } } if (!bTried) { int iNumUniqueBonusesOnArea = pLoopArea->countNumUniqueBonusTypes() + 1; // number of unique bonuses starting on the area, plus this one int iNumTiles = pLoopArea->getNumTiles(); int iValue = iNumTiles / iNumUniqueBonusesOnArea; if (iValue > iBestValue) { iBestValue = iValue; pBestArea = pLoopArea; } } } if (pBestArea == NULL) { break; // can't place bonus on any area } for (int iI = 0; iI < GC.getMapINLINE().getNumAreas(); iI++) { if (piAreaTried[iI] == FFreeList::INVALID_INDEX) { piAreaTried[iI] = pBestArea->getID(); break; } } // Place the bonuses: std::vector<int> aiShuffle(GC.getMapINLINE().numPlotsINLINE()); GC.getGameINLINE().getMapRand().shuffleSequence(aiShuffle, "addUniqueBonusType shuffle"); for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++) { CvPlot* pPlot = GC.getMapINLINE().plotByIndexINLINE(aiShuffle[iI]); FAssertMsg(pPlot != NULL, "addUniqueBonusType(): pPlot is null"); if (GC.getMapINLINE().getNumBonuses(eBonusType) >= iBonusCount) { break; // We already have enough } if (pBestArea == pPlot->area()) { if (canPlaceBonusAt(eBonusType, pPlot->getX_INLINE(), pPlot->getY_INLINE(), bIgnoreLatitude)) { pPlot->setBonusType(eBonusType); for (int iDX = -(pBonusInfo.getGroupRange()); iDX <= pBonusInfo.getGroupRange(); iDX++) { for (int iDY = -(pBonusInfo.getGroupRange()); iDY <= pBonusInfo.getGroupRange(); iDY++) { if (GC.getMapINLINE().getNumBonuses(eBonusType) < iBonusCount) { CvPlot* pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY); if (pLoopPlot != NULL && (pLoopPlot->area() == pBestArea)) { if (canPlaceBonusAt(eBonusType, pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), bIgnoreLatitude)) { if (GC.getGameINLINE().getMapRandNum(100, "addUniqueBonusType") < pBonusInfo.getGroupRand()) { pLoopPlot->setBonusType(eBonusType); } } } } } } } } } } SAFE_DELETE_ARRAY(piAreaTried); }
bool CvMapGenerator::canPlaceBonusAt(BonusTypes eBonus, int iX, int iY, bool bIgnoreLatitude) { PROFILE_FUNC(); CvArea* pArea; CvPlot* pPlot; CvPlot* pLoopPlot; int iRange; int iDX, iDY; int iI; pPlot = GC.getMapINLINE().plotINLINE(iX, iY); pArea = pPlot->area(); if (!(pPlot->canHaveBonus(eBonus, bIgnoreLatitude))) { return false; } long result = 0; if (gDLL->getPythonIFace()->pythonCanPlaceBonusAt(pPlot, &result) && !gDLL->getPythonIFace()->pythonUsingDefaultImpl()) // Python override { if (result >= 0) { return result; } else { FAssertMsg(false, "canPlaceBonusAt() must return >= 0"); } } for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++) { pLoopPlot = plotDirection(iX, iY, ((DirectionTypes)iI)); if (pLoopPlot != NULL) { if ((pLoopPlot->getBonusType() != NO_BONUS) && (pLoopPlot->getBonusType() != eBonus)) { return false; } } } CvBonusInfo& pInfo = GC.getBonusInfo(eBonus); if (pPlot->isWater()) { if (((GC.getMapINLINE().getNumBonusesOnLand(eBonus) * 100) / (GC.getMapINLINE().getNumBonuses(eBonus) + 1)) < pInfo.getMinLandPercent()) { return false; } } // Make sure there are none of the same bonus nearby: iRange = pInfo.getUniqueRange(); for (iDX = -(iRange); iDX <= iRange; iDX++) { for (iDY = -(iRange); iDY <= iRange; iDY++) { pLoopPlot = plotXY(iX, iY, iDX, iDY); if (pLoopPlot != NULL) { if (pLoopPlot->area() == pArea) { if (plotDistance(iX, iY, pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()) <= iRange) { if (pLoopPlot->getBonusType() == eBonus) { return false; } } } } } } return true; }
bool CvMapGenerator::canPlaceGoodyAt(ImprovementTypes eImprovement, int iX, int iY) { PROFILE_FUNC(); CvPlot* pPlot; FAssertMsg(eImprovement != NO_IMPROVEMENT, "Improvement is not assigned a valid value"); FAssertMsg(GC.getImprovementInfo(eImprovement).isGoody(), "ImprovementType eImprovement is expected to be a goody"); if (GC.getGameINLINE().isOption(GAMEOPTION_NO_GOODY_HUTS)) { return false; } pPlot = GC.getMapINLINE().plotINLINE(iX, iY); if (!(pPlot->canHaveImprovement(eImprovement, NO_TEAM))) { return false; } long result = 0; if (gDLL->getPythonIFace()->pythonCanPlaceGoodyAt(pPlot, &result) && !gDLL->getPythonIFace()->pythonUsingDefaultImpl()) // Python override { if (result >= 0) { return result; } else { FAssertMsg(false, "pythonGetRiverAltitude() must return >= 0"); } } if (pPlot->getImprovementType() != NO_IMPROVEMENT) { return false; } if (pPlot->getBonusType() != NO_BONUS) { return false; } if (pPlot->isImpassable()) { return false; } int iUniqueRange = GC.getImprovementInfo(eImprovement).getGoodyUniqueRange(); for (int iDX = -iUniqueRange; iDX <= iUniqueRange; iDX++) { for (int iDY = -iUniqueRange; iDY <= iUniqueRange; iDY++) { CvPlot *pLoopPlot = plotXY(iX, iY, iDX, iDY); if (pLoopPlot != NULL && pLoopPlot->getImprovementType() == eImprovement) { return false; } } } return true; }
///Tks Med CvPlot* CvMap::syncRandPlot(int iFlags, int iArea, int iMinUnitDistance, int iTimeout, bool bIgnoreNativeTeams) { ///TKe CvPlot* pPlot = NULL; int iCount = 0; while (iCount < iTimeout) { CvPlot* pTestPlot = plotSorenINLINE(GC.getGameINLINE().getSorenRandNum(getGridWidthINLINE(), "Rand Plot Width"), GC.getGameINLINE().getSorenRandNum(getGridHeightINLINE(), "Rand Plot Height")); FAssertMsg(pTestPlot != NULL, "TestPlot is not assigned a valid value"); if ((iArea == -1) || (pTestPlot->getArea() == iArea)) { bool bValid = true; if (bValid) { if (iMinUnitDistance != -1) { for (int iDX = -(iMinUnitDistance); iDX <= iMinUnitDistance; iDX++) { for (int iDY = -(iMinUnitDistance); iDY <= iMinUnitDistance; iDY++) { CvPlot* pLoopPlot = plotXY(pTestPlot->getX_INLINE(), pTestPlot->getY_INLINE(), iDX, iDY); if (pLoopPlot != NULL) { if (pLoopPlot->isUnit()) { bValid = false; } } } } } } if (bValid) { if (iFlags & RANDPLOT_LAND) { if (pTestPlot->isWater()) { bValid = false; } } } if (bValid) { if (iFlags & RANDPLOT_UNOWNED) { if (pTestPlot->isOwned()) { ///Tks Med if (bIgnoreNativeTeams) { if (!GET_PLAYER(pTestPlot->getOwnerINLINE()).isNative()) { bValid = false; } } else { bValid = false; } ///TKe } } } if (bValid) { if (iFlags & RANDPLOT_ADJACENT_UNOWNED) { if (pTestPlot->isAdjacentOwned()) { bValid = false; } } } if (bValid) { if (iFlags & RANDPLOT_ADJACENT_LAND) { if (!(pTestPlot->isAdjacentToLand())) { bValid = false; } } } if (bValid) { if (iFlags & RANDPLOT_PASSIBLE) { if (pTestPlot->isImpassable()) { bValid = false; } } } if (bValid) { if (iFlags & RANDPLOT_NOT_VISIBLE_TO_CIV) { ///TKs Med if (pTestPlot->isVisibleToCivTeam(bIgnoreNativeTeams)) { bValid = false; } ///TKe } } ///TKs Med if (bValid) { if (bIgnoreNativeTeams) { if (pTestPlot->isVisibleToWatchingHuman()) { bValid = false; } } } ///TKe if (bValid) { if (iFlags & RANDPLOT_NOT_CITY) { if (pTestPlot->isCity()) { bValid = false; } } } if (bValid) { pPlot = pTestPlot; break; } } iCount++; } return pPlot; }
bool CvMapGenerator::canPlaceBonusAt(BonusTypes eBonus, int iX, int iY, bool bIgnoreLatitude) { PROFILE_FUNC(); CvArea* pArea; CvPlot* pPlot; CvPlot* pLoopPlot; int iRange; int iDX, iDY; int iI; pPlot = GC.getMapINLINE().plotINLINE(iX, iY); pArea = pPlot->area(); if (!(pPlot->canHaveBonus(eBonus, bIgnoreLatitude))) { return false; } long result = 0; CyPlot kPlot = CyPlot(pPlot); CyArgsList argsList; argsList.add(gDLL->getPythonIFace()->makePythonObject(&kPlot)); if (gDLL->getPythonIFace()->callFunction(gDLL->getPythonIFace()->getMapScriptModule(), "canPlaceBonusAt", argsList.makeFunctionArgs(), &result)) { if (!gDLL->getPythonIFace()->pythonUsingDefaultImpl()) { if (result >= 0) { return result; } else { FAssertMsg(false, "canPlaceBonusAt() must return >= 0"); } } } for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++) { pLoopPlot = plotDirection(iX, iY, ((DirectionTypes)iI)); if (pLoopPlot != NULL) { if ((pLoopPlot->getBonusType() != NO_BONUS) && (pLoopPlot->getBonusType() != eBonus)) { return false; } } } CvBonusInfo& pInfo = GC.getBonusInfo(eBonus); CvBonusClassInfo& pClassInfo = GC.getBonusClassInfo((BonusClassTypes) pInfo.getBonusClassType()); if (pPlot->isWater()) { if (((GC.getMapINLINE().getNumBonusesOnLand(eBonus) * 100) / (GC.getMapINLINE().getNumBonuses(eBonus) + 1)) < pInfo.getMinLandPercent()) { return false; } } // Make sure there are no bonuses of the same class (but a different type) nearby: iRange = pClassInfo.getUniqueRange(); for (iDX = -(iRange); iDX <= iRange; iDX++) { for (iDY = -(iRange); iDY <= iRange; iDY++) { pLoopPlot = plotXY(iX, iY, iDX, iDY); if (pLoopPlot != NULL) { if (pLoopPlot->area() == pArea) { if (plotDistance(iX, iY, pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()) <= iRange) { BonusTypes eOtherBonus = pLoopPlot->getBonusType(); if (eOtherBonus != NO_BONUS) { if (GC.getBonusInfo(eOtherBonus).getBonusClassType() == pInfo.getBonusClassType()) { return false; } } } } } } } // Make sure there are none of the same bonus nearby: iRange = pInfo.getUniqueRange(); for (iDX = -(iRange); iDX <= iRange; iDX++) { for (iDY = -(iRange); iDY <= iRange; iDY++) { pLoopPlot = plotXY(iX, iY, iDX, iDY); if (pLoopPlot != NULL) { if (pLoopPlot->area() == pArea) { if (plotDistance(iX, iY, pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()) <= iRange) { if (pLoopPlot->getBonusType() == eBonus) { return false; } } } } } } return true; }
CyPlot* cysPlotXY(int iX, int iY, int iDX, int iDY) { static CyPlot plot; plot.setPlot(plotXY(iX, iY, iDX, iDY)); return &plot; }
CyPlot* cyPlotXY(int iX, int iY, int iDX, int iDY) { return new CyPlot(plotXY(iX, iY, iDX, iDY)); }
/// 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(DomainTypes eDomainRequired) { CvPlot* pRtnValue = NULL; int iTotalX = 0; int iTotalY = 0; int iNumUnits = 0; 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 #ifdef AUI_HEXSPACE_DX_LOOPS int iMaxDX, iDX; CvPlot* pLoopPlot; for (int iDY = -2; iDY <= 2; iDY++) { iMaxDX = 2 - MAX(0, iDY); for (iDX = -2 - MIN(0, iDY); iDX <= iMaxDX; iDX++) // MIN() and MAX() stuff is to reduce loops (hexspace!) { // No need for range check because loops are set up properly pLoopPlot = plotXY(pRtnValue->getX(), pRtnValue->getY(), iDX, iDY); if (pLoopPlot) { if (hexDistance(iDX, iDY) == 2) #else 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) { #ifdef AUI_FIX_HEX_DISTANCE_INSTEAD_OF_PLOT_DISTANCE if (hexDistance(iDX, iDY) == 2) #else if (plotDistance(pRtnValue->getX(), pRtnValue->getY(), pLoopPlot->getX(), pLoopPlot->getY()) == 2) #endif #endif { 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; } /// Return distance from this plot of unit in army farthest away int CvArmyAI::GetFurthestUnitDistance(CvPlot* pPlot) { int iLargestDistance = 0; UnitHandle pUnit; int iNewDistance; pUnit = GetFirstUnit(); while(pUnit) { iNewDistance = plotDistance(pUnit->getX(), pUnit->getY(), pPlot->getX(), pPlot->getY()); if(iNewDistance > iLargestDistance) { iLargestDistance = iNewDistance; } pUnit = GetNextUnit(); } return iLargestDistance; } // FORMATION ACCESSORS /// Retrieve index of the formation used by this army int CvArmyAI::GetFormationIndex() const { return m_iFormationIndex; } /// Set index of the formation used by this army void CvArmyAI::SetFormationIndex(int iFormationIndex) { CvArmyFormationSlot slot; if(m_iFormationIndex != iFormationIndex) { m_iFormationIndex = iFormationIndex; CvMultiUnitFormationInfo* thisFormation = GC.getMultiUnitFormationInfo(m_iFormationIndex); if(thisFormation) { int iNumSlots = thisFormation->getNumFormationSlotEntries(); // Build all the formation entries m_FormationEntries.clear(); for(int iI = 0; iI < iNumSlots; iI++) { slot.SetUnitID(ARMY_NO_UNIT); slot.SetTurnAtCheckpoint(ARMYSLOT_UNKNOWN_TURN_AT_CHECKPOINT); m_FormationEntries.push_back(slot); } } } } /// How many slots are there in this formation if filled int CvArmyAI::GetNumFormationEntries() const { return m_FormationEntries.size(); } /// How many slots do we currently have filled? int CvArmyAI::GetNumSlotsFilled() const { int iRtnValue = 0; for(unsigned int iI = 0; iI < m_FormationEntries.size(); iI++) { if(m_FormationEntries[iI].m_iUnitID != ARMY_NO_UNIT) { iRtnValue++; } } return iRtnValue; }
/// 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; }
/// 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; }
// Mark cells we can use to bomb a specific target void CvTacticalAnalysisMap::SetTargetBombardCells(CvPlot* pTarget, int iRange, bool bIgnoreLOS) { int iDX, iDY; CvPlot* pLoopPlot; int iPlotIndex; #ifdef AUI_HEXSPACE_DX_LOOPS int iMaxDX; for (iDY = -iRange; iDY <= iRange; iDY++) { iMaxDX = iRange - MAX(0, iDY); for (iDX = -iRange - MIN(0, iDY); iDX <= iMaxDX; iDX++) // MIN() and MAX() stuff is to reduce loops (hexspace!) #else int iPlotDistance; for(iDX = -(iRange); iDX <= iRange; iDX++) { for(iDY = -(iRange); iDY <= iRange; iDY++) #endif { #ifdef AUI_HEXSPACE_DX_LOOPS if (iDX == 0 && iDY == 0) continue; #endif pLoopPlot = plotXY(pTarget->getX(), pTarget->getY(), iDX, iDY); if(pLoopPlot != NULL) { #ifndef AUI_HEXSPACE_DX_LOOPS #ifdef AUI_FIX_HEX_DISTANCE_INSTEAD_OF_PLOT_DISTANCE iPlotDistance = hexDistance(iDX, iDY); #else iPlotDistance = plotDistance(pLoopPlot->getX(), pLoopPlot->getY(), pTarget->getX(), pTarget->getY()); #endif if(iPlotDistance > 0 && iPlotDistance <= iRange) #endif { iPlotIndex = GC.getMap().plotNum(pLoopPlot->getX(), pLoopPlot->getY()); if(m_pPlots[iPlotIndex].IsRevealed() && !m_pPlots[iPlotIndex].IsImpassableTerrain() && !m_pPlots[iPlotIndex].IsImpassableTerritory()) { if(!m_pPlots[iPlotIndex].IsEnemyCity() && !m_pPlots[iPlotIndex].IsNeutralCity()) { if(bIgnoreLOS || pLoopPlot->canSeePlot(pTarget, m_pPlayer->getTeam(), iRange, NO_DIRECTION)) { m_pPlots[iPlotIndex].SetWithinRangeOfTarget(true); } } } } } } } } // Mark cells we can use to bomb a specific target void CvTacticalAnalysisMap::SetTargetFlankBonusCells(CvPlot* pTarget) { CvPlot* pLoopPlot; int iPlotIndex; // No flank attacks on units at sea (where all combat is bombards) if(pTarget->isWater()) { return; } for(int iI = 0; iI < NUM_DIRECTION_TYPES; iI++) { pLoopPlot = plotDirection(pTarget->getX(), pTarget->getY(), ((DirectionTypes)iI)); if(pLoopPlot != NULL) { iPlotIndex = GC.getMap().plotNum(pLoopPlot->getX(), pLoopPlot->getY()); if(m_pPlots[iPlotIndex].IsRevealed() && !m_pPlots[iPlotIndex].IsImpassableTerrain() && !m_pPlots[iPlotIndex].IsImpassableTerritory()) { if(!m_pPlots[iPlotIndex].IsFriendlyCity() && !m_pPlots[iPlotIndex].IsEnemyCity() && !m_pPlots[iPlotIndex].IsNeutralCity()) { if(!m_pPlots[iPlotIndex].IsFriendlyTurnEndTile() && m_pPlots[iPlotIndex].GetEnemyMilitaryUnit() == NULL) { m_pPlots[iPlotIndex].SetHelpsProvidesFlankBonus(true); } } } } } }