/// Value of this site for a settler int CvSiteEvaluatorForSettler::PlotFoundValue(CvPlot* pPlot, CvPlayer* pPlayer, YieldTypes eYield, bool bCoastOnly) { CvAssert(pPlot); if(!pPlot) return 0; if(!CanFound(pPlot, pPlayer, true)) { return 0; } // Is there any reason this site doesn't work for a settler? // // First must be on coast if settling a new continent bool bIsCoastal = pPlot->isCoastalLand(GC.getMIN_WATER_SIZE_FOR_OCEAN()); CvArea* pArea = pPlot->area(); CvAssert(pArea); if(!pArea) return 0; int iNumAreaCities = pArea->getCitiesPerPlayer(pPlayer->GetID()); if(bCoastOnly && !bIsCoastal && iNumAreaCities == 0) { return 0; } // Seems okay for a settler, use base class to determine exact value else { return CvCitySiteEvaluator::PlotFoundValue(pPlot, pPlayer, eYield); } }
/// Make some adjustments to flavors based on the map we're on void CvFlavorManager::AdjustWeightsForMap() { int iTotalLandTiles; int iNumPlayers; double iTilesPerPlayer; double fAdjust; int iAdjust; iTotalLandTiles = GC.getMap().getLandPlots(); iNumPlayers = GC.getGame().countMajorCivsAlive(); if(iNumPlayers > 0) { int iNumFlavorTypes = GC.getNumFlavorTypes(); // Find tiles per player iTilesPerPlayer = (double)iTotalLandTiles / (double)iNumPlayers; // Compute +/- addition // // We want this to be logarithmic, since that is the curve between lots of players on a duel map // and a few player on a huge map. "FLAVOR_STANDARD_LOG10_TILES_PER_PLAYER" is the typical log10 of // tiles per player. We go up and down from this point (multiplying by a coefficient) from here fAdjust = log10(iTilesPerPlayer) - GC.getFLAVOR_STANDARD_LOG10_TILES_PER_PLAYER(); fAdjust *= (double)GC.getFLAVOR_EXPANDGROW_COEFFICIENT(); iAdjust = (int)fAdjust; int iFlavorMaxValue = /*20*/ GC.getPERSONALITY_FLAVOR_MAX_VALUE(); int iFlavorMinValue = /*0*/ GC.getPERSONALITY_FLAVOR_MIN_VALUE(); int iExpansionIndex = GC.getInfoTypeForString("FLAVOR_EXPANSION"); int iGrowthIndex = GC.getInfoTypeForString("FLAVOR_GROWTH"); // Boost expansion CvAssert(iExpansionIndex >= 0 && iExpansionIndex < iNumFlavorTypes); if (iExpansionIndex >= 0 && iExpansionIndex < iNumFlavorTypes) { m_piPersonalityFlavor[iExpansionIndex] += iAdjust; if(m_piPersonalityFlavor[iExpansionIndex] > iFlavorMaxValue) { m_piPersonalityFlavor[iExpansionIndex] = iFlavorMaxValue; } } // Reduce growth CvAssert(iGrowthIndex >= 0 && iGrowthIndex < iNumFlavorTypes); if (iGrowthIndex >= 0 && iGrowthIndex < iNumFlavorTypes) { m_piPersonalityFlavor[iGrowthIndex] -= iAdjust; if(m_piPersonalityFlavor[iGrowthIndex] < iFlavorMinValue) { m_piPersonalityFlavor[iGrowthIndex] = iFlavorMinValue; } } // Save these off as our core personality and broadcast updates ResetToBasePersonality(); } }
bool atWar(TeamTypes eTeamA, TeamTypes eTeamB) { if((eTeamA == NO_TEAM) || (eTeamB == NO_TEAM)) { return false; } CvAssert(GET_TEAM(eTeamA).isAtWar(eTeamB) == GET_TEAM(eTeamB).isAtWar(eTeamA)); CvAssert((eTeamA != eTeamB) || !(GET_TEAM(eTeamA).isAtWar(eTeamB))); return GET_TEAM(eTeamA).isAtWar(eTeamB); }
void CvLoggerCSV::DeleteCSV(const char* strLogName) { CvAssert(strLogName != NULL); FILogFile *pLog; pLog = LOGFILEMGR.GetLog(strLogName, FILogFile::kDontTimeStamp); CvAssert(pLog != NULL); LOGFILEMGR.DeleteLog(pLog); }
bool isBeforeUnitCycle(const CvUnit* pFirstUnit, const CvUnit* pSecondUnit) { CvAssert(pFirstUnit != NULL); CvAssert(pSecondUnit != NULL); CvAssert(pFirstUnit != pSecondUnit); if(!pFirstUnit || !pSecondUnit) return false; if(pFirstUnit->getOwner() != pSecondUnit->getOwner()) { return (pFirstUnit->getOwner() < pSecondUnit->getOwner()); } if(pFirstUnit->getDomainType() != pSecondUnit->getDomainType()) { return (pFirstUnit->getDomainType() < pSecondUnit->getDomainType()); } if(pFirstUnit->GetBaseCombatStrength() != pSecondUnit->GetBaseCombatStrength()) { return (pFirstUnit->GetBaseCombatStrength() > pSecondUnit->GetBaseCombatStrength()); } if(pFirstUnit->getUnitType() != pSecondUnit->getUnitType()) { return (pFirstUnit->getUnitType() > pSecondUnit->getUnitType()); } if(pFirstUnit->getLevel() != pSecondUnit->getLevel()) { return (pFirstUnit->getLevel() > pSecondUnit->getLevel()); } #if defined(MOD_UNITS_XP_TIMES_100) if (pFirstUnit->getExperienceTimes100() != pSecondUnit->getExperienceTimes100()) { return (pFirstUnit->getExperienceTimes100() > pSecondUnit->getExperienceTimes100()); } #else if (pFirstUnit->getExperience() != pSecondUnit->getExperience()) { return (pFirstUnit->getExperience() > pSecondUnit->getExperience()); } #endif return (pFirstUnit->GetID() < pSecondUnit->GetID()); }
/// Delete the army void CvArmyAI::Kill() { CvAssert(GetOwner() != NO_PLAYER); CvAssertMsg(GetID() != -1, "GetID() is not expected to be equal with -1"); int iUnitID; iUnitID = GetFirstUnitID(); while(iUnitID != ARMYSLOT_NO_UNIT) { UnitHandle pThisUnit = GET_PLAYER(GetOwner()).getUnit(iUnitID); if(pThisUnit) { pThisUnit->setArmyID(-1); #if defined(MOD_BALANCE_CORE) pThisUnit->AI_setUnitAIType(pThisUnit->getUnitInfo().GetDefaultUnitAIType()); #endif } iUnitID = GetNextUnitID(); } m_FormationEntries.clear(); CvAIOperation* pOperation = GET_PLAYER(GetOwner()).getAIOperation(m_iOperationID); if (pOperation) pOperation->DeleteArmyAI(m_iID); GET_PLAYER(GetOwner()).deleteArmyAI(m_iID); }
/// Value of plot for providing tradeable resources int CvCitySiteEvaluator::ComputeTradeableResourceValue(CvPlot* pPlot, const CvPlayer* pPlayer) { int rtnValue = 0; CvAssert(pPlot); if(!pPlot) return rtnValue; // If we already own this Tile then we already have access to the Strategic Resource if(pPlot->isOwned()) { return rtnValue; } TeamTypes eTeam = NO_TEAM; if(pPlayer != NULL) { eTeam = pPlayer->getTeam(); } ResourceTypes eResource; eResource = pPlot->getResourceType(eTeam); if(eResource != NO_RESOURCE) { ResourceUsageTypes eResourceUsage = GC.getResourceInfo(eResource)->getResourceUsage(); // Multiply number of tradeable resources by flavor value if(eResourceUsage == RESOURCEUSAGE_LUXURY || eResourceUsage == RESOURCEUSAGE_STRATEGIC) { rtnValue += pPlot->getNumResource() * m_iFlavorMultiplier[SITE_EVALUATION_RESOURCES]; if(pPlayer) { // If we don't have this resource yet, increase it's value if(pPlayer->getNumResourceTotal(eResource) == 0) rtnValue *= 3; #if defined(MOD_BALANCE_CORE_RESOURCE_MONOPOLIES) if(MOD_BALANCE_CORE_RESOURCE_MONOPOLIES && (GC.getMap().getNumResources(eResource) > 0)) { //Will this get us closer to a monopoly? if((((pPlot->getNumResource() + pPlayer->getNumResourceTotal(eResource, false) + pPlayer->getResourceExport(eResource)) * 100) / GC.getMap().getNumResources(eResource)) >= 30) { rtnValue *= 2; } else if((((pPlot->getNumResource() + pPlayer->getNumResourceTotal(eResource, false)) * 100) / GC.getMap().getNumResources(eResource)) >= 50) { rtnValue *= 10; } } #endif } } } return rtnValue; }
bool isBeforeUnitCycle(const CvUnit* pFirstUnit, const CvUnit* pSecondUnit) { CvAssert(pFirstUnit != NULL); CvAssert(pSecondUnit != NULL); CvAssert(pFirstUnit != pSecondUnit); if(!pFirstUnit || !pSecondUnit) return false; if(pFirstUnit->getOwner() != pSecondUnit->getOwner()) { return (pFirstUnit->getOwner() < pSecondUnit->getOwner()); } if(pFirstUnit->getDomainType() != pSecondUnit->getDomainType()) { return (pFirstUnit->getDomainType() < pSecondUnit->getDomainType()); } if(pFirstUnit->GetBaseCombatStrength() != pSecondUnit->GetBaseCombatStrength()) { return (pFirstUnit->GetBaseCombatStrength() > pSecondUnit->GetBaseCombatStrength()); } if(pFirstUnit->getUnitType() != pSecondUnit->getUnitType()) { return (pFirstUnit->getUnitType() > pSecondUnit->getUnitType()); } if(pFirstUnit->getLevel() != pSecondUnit->getLevel()) { return (pFirstUnit->getLevel() > pSecondUnit->getLevel()); } if(pFirstUnit->getExperience() != pSecondUnit->getExperience()) { return (pFirstUnit->getExperience() > pSecondUnit->getExperience()); } return (pFirstUnit->GetID() < pSecondUnit->GetID()); }
/// Log all potential builds void CvProjectProductionAI::LogPossibleBuilds() { if(GC.getLogging() && GC.getAILogging()) { CvString strOutBuf; CvString strBaseString; CvString strTemp; CvString playerName; CvString cityName; CvString strDesc; CvString strLogName; CvAssert(m_pCity); if(!m_pCity) return; // Find the name of this civ and city playerName = GET_PLAYER(m_pCity->getOwner()).getCivilizationShortDescription(); cityName = m_pCity->getName(); // Open the log file FILogFile* pLog; pLog = LOGFILEMGR.GetLog(m_pCity->GetCityStrategyAI()->GetLogFileName(playerName, cityName), FILogFile::kDontTimeStamp); CvAssert(pLog); if(!pLog) return; // Get the leading info for this line strBaseString.Format("%03d, ", GC.getGame().getElapsedGameTurns()); strBaseString += playerName + ", " + cityName + ", "; // Dump out the weight of each buildable item for(int iI = 0; iI < m_Buildables.size(); iI++) { CvProjectEntry* pProjectEntry = GC.GetGameProjects()->GetEntry(m_Buildables.GetElement(iI)); strDesc = (pProjectEntry != NULL)? pProjectEntry->GetDescription() : "Unknown"; strTemp.Format("Project, %s, %d", strDesc.GetCString(), m_Buildables.GetWeight(iI)); strOutBuf = strBaseString + strTemp; pLog->Msg(strOutBuf); } } }
void CvLoggerCSV::WriteCSVLog(const char* strLogName, const char* strHeader) { FILogFile *pLog; pLog = LOGFILEMGR.GetLog(strLogName, FILogFile::kDontTimeStamp); CvAssert(pLog != NULL); pLog->Msg(strHeader); }
/// Value of this site for a settler int CvSiteEvaluatorForSettler::PlotFoundValue(CvPlot* pPlot, CvPlayer* pPlayer, YieldTypes eYield, bool bCoastOnly) { CvAssert(pPlot); if(!pPlot) return 0; if(!CanFound(pPlot, pPlayer, true)) { return 0; } // Is there any reason this site doesn't work for a settler? // // First must be on coast if settling a new continent bool bIsCoastal = pPlot->isCoastalLand(GC.getMIN_WATER_SIZE_FOR_OCEAN()); CvArea* pArea = pPlot->area(); CvAssert(pArea); if(!pArea) return 0; int iNumAreaCities = pArea->getCitiesPerPlayer(pPlayer->GetID()); if(bCoastOnly && !bIsCoastal && iNumAreaCities == 0) { return 0; } // Seems okay for a settler, use base class to determine exact value else { // if the civ gets a benefit from settling on a new continent (ie: Indonesia) // double the fertility of that plot int iLuxuryModifier = 0; if (pPlayer->GetPlayerTraits()->WillGetUniqueLuxury(pArea)) { iLuxuryModifier = CvCitySiteEvaluator::PlotFoundValue(pPlot, pPlayer, eYield) * 2; return iLuxuryModifier; } else { return CvCitySiteEvaluator::PlotFoundValue(pPlot, pPlayer, eYield); } } }
void CvPlayerAI::ProcessGreatPeople(void) { SpecialUnitTypes eSpecialUnitGreatPerson = (SpecialUnitTypes) GC.getInfoTypeForString("SPECIALUNIT_PEOPLE"); CvAssert(isAlive()); if(!isAlive()) return; int iLoop; for(CvUnit* pLoopUnit = firstUnit(&iLoop); pLoopUnit; pLoopUnit = nextUnit(&iLoop)) { if(pLoopUnit->getSpecialUnitType() != eSpecialUnitGreatPerson) { continue; } GreatPeopleDirectiveTypes eDirective = NO_GREAT_PEOPLE_DIRECTIVE_TYPE; switch(pLoopUnit->AI_getUnitAIType()) { case UNITAI_WRITER: eDirective = GetDirectiveWriter(pLoopUnit); break; case UNITAI_ARTIST: eDirective = GetDirectiveArtist(pLoopUnit); break; case UNITAI_MUSICIAN: eDirective = GetDirectiveMusician(pLoopUnit); break; case UNITAI_ENGINEER: eDirective = GetDirectiveEngineer(pLoopUnit); break; case UNITAI_MERCHANT: eDirective = GetDirectiveMerchant(pLoopUnit); break; case UNITAI_SCIENTIST: eDirective = GetDirectiveScientist(pLoopUnit); break; case UNITAI_GENERAL: eDirective = GetDirectiveGeneral(pLoopUnit); break; case UNITAI_PROPHET: eDirective = GetDirectiveProphet(pLoopUnit); break; case UNITAI_ADMIRAL: eDirective = GetDirectiveAdmiral(pLoopUnit); break; } pLoopUnit->SetGreatPeopleDirective(eDirective); } }
/// Delete the army void CvArmyAI::Kill() { CvAssert(GetOwner() != NO_PLAYER); CvAssertMsg(GetID() != -1, "GetID() is not expected to be equal with -1"); ReleaseUnits(); CvAIOperation* pOperation = GET_PLAYER(GetOwner()).getAIOperation(m_iOperationID); if (pOperation) pOperation->DeleteArmyAI(m_iID); GET_PLAYER(GetOwner()).deleteArmyAI(m_iID); }
/// Value of plot for providing strategic value int CvCitySiteEvaluator::ComputeStrategicValue(CvPlot* pPlot, const CvPlayer*, int iPlotsFromCity) { int rtnValue = 0; CvAssert(pPlot); if(!pPlot) return rtnValue; #if defined(MOD_BALANCE_CORE_SETTLER) if (MOD_BALANCE_CORE_SETTLER) { //Some features and terrain types are useful strategically. (Or really bad) if(pPlot->getOwner() == NO_PLAYER) { if(iPlotsFromCity <= 3 && (pPlot->getFeatureType() == FEATURE_ICE)) { rtnValue += /*-10*/ GC.getBALANCE_BAD_TILES_STRATEGIC_VALUE(); } if(iPlotsFromCity <= 3 && pPlot->isFreshWater_cached()) { rtnValue += /*2*/ GC.getBALANCE_FRESH_WATER_STRATEGIC_VALUE(); } if(iPlotsFromCity <= 3 && pPlot->isCoastalLand()) { rtnValue += /*2*/ GC.getBALANCE_COAST_STRATEGIC_VALUE(); } } } #endif // Hills in first ring are useful for defense and production if(iPlotsFromCity == 1 && pPlot->isHills()) { rtnValue += /*3*/ GC.getHILL_STRATEGIC_VALUE(); } // Some Features are less attractive to settle in, (e.g. Jungles, since it takes a while before you can clear them and they slow down movement) if(pPlot->getFeatureType() != NO_FEATURE) { int iWeight = GC.getFeatureInfo(pPlot->getFeatureType())->getStartingLocationWeight(); if(iWeight != 0 && iPlotsFromCity == 1) { rtnValue += iWeight; } } rtnValue *= m_iFlavorMultiplier[SITE_EVALUATION_STRATEGIC]; return rtnValue; }
/// Compute unit supply for the turn (returns component info) int CvTreasury::CalculateUnitSupply(int& iPaidUnits, int& iBaseSupplyCost) { int iSupply; iPaidUnits = std::max(0, (m_pPlayer->getNumOutsideUnits() - /*3*/ GC.getINITIAL_FREE_OUTSIDE_UNITS())); // JON: This is set to 0 right now, which pretty much means it's disabled iBaseSupplyCost = iPaidUnits* /*0*/ GC.getINITIAL_OUTSIDE_UNIT_GOLD_PERCENT(); iBaseSupplyCost /= 100; iSupply = iBaseSupplyCost; CvHandicapInfo& playerHandicap = m_pPlayer->getHandicapInfo(); iSupply *= playerHandicap.getUnitCostPercent(); iSupply /= 100; if(!m_pPlayer->isHuman() && !m_pPlayer->IsAITeammateOfHuman() && !m_pPlayer->isBarbarian()) { //iSupply *= gameHandicap->getAIUnitSupplyPercent(); // This is no longer valid //iSupply /= 100; iSupply *= std::max(0, ((GC.getGame().getHandicapInfo().getAIPerEraModifier() * m_pPlayer->GetCurrentEra()) + 100)); iSupply /= 100; } // Game progress factor ranges from 0.0 to 1.0 based on how far into the game we are double fGameProgressFactor = float(GC.getGame().getElapsedGameTurns()) / GC.getGame().getEstimateEndTurn(); // Multiplicative increase - helps scale costs as game goes on - the HIGHER this number the more is paid double fMultiplyFactor = 1.0 + (fGameProgressFactor* /*8*/ GC.getUNIT_MAINTENANCE_GAME_MULTIPLIER()); // Exponential increase - this one really punishes those with a HUGE military - the LOWER this number the more is paid double fExponentialFactor = 1.0 + (fGameProgressFactor / /*7*/ GC.getUNIT_MAINTENANCE_GAME_EXPONENT_DIVISOR()); double fTempCost = fMultiplyFactor * iSupply; int iFinalCost = (int) pow(fTempCost, fExponentialFactor); // A mod at the player level? (Policies, etc.) if(m_pPlayer->GetUnitSupplyMod() != 0) { iFinalCost *= (100 + m_pPlayer->GetUnitSupplyMod()); iFinalCost /= 100; } CvAssert(iFinalCost >= 0); return iFinalCost; }
/// Value of plot for providing strategic value int CvCitySiteEvaluator::ComputeStrategicValue(CvPlot* pPlot, CvPlayer* pPlayer, int iPlotsFromCity) { int rtnValue = 0; CvAssert(pPlot); if(!pPlot) return rtnValue; // Possible chokepoint if impassable terrain and exactly 2 plots from city if(iPlotsFromCity == 2 && (pPlot->isImpassable() || pPlot->isMountain())) { rtnValue += /*5*/ GC.getCHOKEPOINT_STRATEGIC_VALUE(); } // Hills in first ring are useful for defense and production if(iPlotsFromCity == 1 && pPlot->isHills()) { rtnValue += /*3*/ GC.getHILL_STRATEGIC_VALUE(); } // Some Features are less attractive to settle in, (e.g. Jungles, since it takes a while before you can clear them and they slow down movement) if(pPlot->getFeatureType() != NO_FEATURE) { int iWeight = GC.getFeatureInfo(pPlot->getFeatureType())->getStartingLocationWeight(); if(iWeight != 0 && iPlotsFromCity == 1) { rtnValue += iWeight; } } // Nearby City if(pPlayer != NULL && pPlot->isCity()) { // if (pPlot->getOwner() == pPlayer->getID()) { rtnValue += /*-1000*/ GC.getALREADY_OWNED_STRATEGIC_VALUE(); } } // POSSIBLE FUTURE: Is there any way for us to know to grab land between us and another major civ? rtnValue *= m_iFlavorMultiplier[SITE_EVALUATION_STRATEGIC]; return rtnValue; }
/// Value of plot for providing tradeable resources int CvCitySiteEvaluator::ComputeTradeableResourceValue(CvPlot* pPlot, CvPlayer* pPlayer) { int rtnValue = 0; CvAssert(pPlot); if(!pPlot) return rtnValue; // If we already own this Tile then we already have access to the Strategic Resource if(pPlot->isOwned()) { return rtnValue; } TeamTypes eTeam = NO_TEAM; if(pPlayer != NULL) { eTeam = pPlayer->getTeam(); } ResourceTypes eResource; eResource = pPlot->getResourceType(eTeam); if(eResource != NO_RESOURCE) { ResourceUsageTypes eResourceUsage = GC.getResourceInfo(eResource)->getResourceUsage(); // Multiply number of tradeable resources by flavor value if(eResourceUsage == RESOURCEUSAGE_LUXURY || eResourceUsage == RESOURCEUSAGE_STRATEGIC) { rtnValue += pPlot->getNumResource() * m_iFlavorMultiplier[SITE_EVALUATION_RESOURCES]; if(pPlayer) { // If we don't have this resource yet, increase it's value if(pPlayer->getNumResourceTotal(eResource) == 0) rtnValue *= 3; } } } return rtnValue; }
/// Compute inflation for this part of the game int CvTreasury::CalculateInflationRate() { CvGame& kGame = GC.getGame(); CvHandicapInfo& playerHandicap = m_pPlayer->getHandicapInfo(); CvHandicapInfo& gameHandicap = kGame.getHandicapInfo(); CvGameSpeedInfo& gameSpeedInfo = kGame.getGameSpeedInfo(); int iTurns = ((kGame.getGameTurn() + kGame.getElapsedGameTurns()) / 2); iTurns += gameSpeedInfo.getInflationOffset(); if(iTurns <= 0) { return 0; } int iInflationPerTurnTimes10000 = gameSpeedInfo.getInflationPercent(); iInflationPerTurnTimes10000 *= playerHandicap.getInflationPercent(); iInflationPerTurnTimes10000 /= 100; int iModifier = 0; if(!m_pPlayer->isHuman() && !m_pPlayer->isBarbarian()) { int iAIModifier = gameHandicap.getAIInflationPercent(); iAIModifier *= std::max(0, ((gameHandicap.getAIPerEraModifier() * m_pPlayer->GetCurrentEra()) + 100)); iAIModifier /= 100; iModifier += iAIModifier - 100; } iInflationPerTurnTimes10000 *= std::max(0, 100 + iModifier); iInflationPerTurnTimes10000 /= 100; // Keep up to second order terms in binomial series int iRatePercent = (iTurns * iInflationPerTurnTimes10000) / 100; iRatePercent += (iTurns * (iTurns - 1) * iInflationPerTurnTimes10000 * iInflationPerTurnTimes10000) / 2000000; CvAssert(iRatePercent >= 0); return iRatePercent; }
/// Delete the army void CvArmyAI::Kill() { CvAssert(GetOwner() != NO_PLAYER); CvAssertMsg(GetID() != FFreeList::INVALID_INDEX, "GetID() is not expected to be equal with FFreeList::INVALID_INDEX"); int iUnitID; iUnitID = GetFirstUnitID(); while(iUnitID != ARMY_NO_UNIT) { UnitHandle pThisUnit = GET_PLAYER(GetOwner()).getUnit(iUnitID); if(pThisUnit) { pThisUnit->setArmyID(FFreeList::INVALID_INDEX); } iUnitID = GetNextUnitID(); } m_FormationEntries.clear(); }
bool CvPlayerAI::AI_captureUnit(UnitTypes, CvPlot* pPlot) { CvCity* pNearestCity; CvAssert(!isHuman()); // Barbs always capture if (isBarbarian()) return true; // we own it if (pPlot->getTeam() == getTeam()) return true; // no man's land - may as well if (pPlot->getTeam() == NO_TEAM) return true; // friendly, sure (okay, this is pretty much just means open borders) if (pPlot->IsFriendlyTerritory(GetID())) return true; // not friendly, but "near" us pNearestCity = GC.getMap().findCity(pPlot->getX(), pPlot->getY(), NO_PLAYER, getTeam()); if (pNearestCity != NULL) { if (plotDistance(pPlot->getX(), pPlot->getY(), pNearestCity->getX(), pNearestCity->getY()) <= 7) return true; } // very near someone we aren't friends with (and far from our nearest city) pNearestCity = GC.getMap().findCity(pPlot->getX(), pPlot->getY()); if (pNearestCity != NULL) { if (plotDistance(pPlot->getX(), pPlot->getY(), pNearestCity->getX(), pNearestCity->getY()) <= 4) return false; } // I'd rather we grab it and run than destroy it return true; }
/// Recommend highest-weighted Project ProjectTypes CvProjectProductionAI::RecommendProject() { CvAssert(m_pCity); if(!m_pCity) return NO_PROJECT; int iProjectLoop; int iWeight; int iTurnsLeft; // Reset list of all the possible projects m_Buildables.clear(); // Loop through adding the available projects for(iProjectLoop = 0; iProjectLoop < GC.GetGameProjects()->GetNumProjects(); iProjectLoop++) { // Make sure this project can be built now if(m_pCity->canCreate((ProjectTypes)iProjectLoop)) { // Update weight based on turns to construct iTurnsLeft = m_pCity->getProductionTurnsLeft((ProjectTypes) iProjectLoop, 0); iWeight = CityStrategyAIHelpers::ReweightByTurnsLeft(m_ProjectAIWeights.GetWeight((ProjectTypes)iProjectLoop), iTurnsLeft); m_Buildables.push_back(iProjectLoop, iWeight); } } // Sort items and grab the first one if(m_Buildables.size() > 0) { m_Buildables.SortItems(); LogPossibleBuilds(); return (ProjectTypes)m_Buildables.GetElement(0); } // Unless we didn't find any else { return NO_PROJECT; } }
/// Vale of plot for providing faith int CvCitySiteEvaluator::ComputeFaithValue(CvPlot* pPlot, CvPlayer* pPlayer) { int rtnValue = 0; CvAssert(pPlot); if(!pPlot) return rtnValue; // From tile yield if(pPlayer == NULL) { rtnValue += pPlot->calculateNatureYield(YIELD_FAITH, NO_TEAM); } else { rtnValue += pPlot->calculateNatureYield(YIELD_FAITH, pPlayer->getTeam()); } // From resource TeamTypes eTeam = NO_TEAM; if(pPlayer != NULL) { eTeam = pPlayer->getTeam(); } ResourceTypes eResource; eResource = pPlot->getResourceType(eTeam); if(eResource != NO_RESOURCE) { rtnValue += GC.getResourceInfo(eResource)->getYieldChange(YIELD_FAITH); CvImprovementEntry* pImprovement = GC.GetGameImprovements()->GetImprovementForResource(eResource); if(pImprovement) { rtnValue += pImprovement->GetImprovementResourceYield(eResource, YIELD_FAITH); } } return rtnValue * m_iFlavorMultiplier[YIELD_FAITH]; }
/// Vale of plot for providing faith int CvCitySiteEvaluator::ComputeFaithValue(CvPlot* pPlot, const CvPlayer* pPlayer) { int rtnValue = 0; CvAssert(pPlot); if(!pPlot) return rtnValue; // From tile yield if(pPlayer == NULL) { rtnValue += pPlot->calculateNatureYield(YIELD_FAITH, NO_PLAYER); } else { rtnValue += pPlot->calculateNatureYield(YIELD_FAITH, pPlayer->GetID()); } // From resource TeamTypes eTeam = NO_TEAM; if(pPlayer != NULL) { eTeam = pPlayer->getTeam(); } ResourceTypes eResource; eResource = pPlot->getResourceType(eTeam); if(eResource != NO_RESOURCE) { //can we build an improvement on this resource? assume we will do it (natural yield is already considered) CvImprovementEntry* pImprovement = GC.GetGameImprovements()->GetImprovementForResource(eResource); if(pImprovement) { rtnValue += pImprovement->GetImprovementResourceYield(eResource, YIELD_FAITH); } } return rtnValue * m_iFlavorMultiplier[YIELD_FAITH]; }
bool CvPlayerAI::AI_captureUnit(UnitTypes, CvPlot* pPlot) { CvCity* pNearestCity; CvAssert(!isHuman()); // Barbs always capture if (isBarbarian()) return true; if (pPlot->getTeam() == getTeam()) return true; pNearestCity = GC.getMap().findCity(pPlot->getX(), pPlot->getY(), NO_PLAYER, getTeam()); if (pNearestCity != NULL) { if (plotDistance(pPlot->getX(), pPlot->getY(), pNearestCity->getX(), pNearestCity->getY()) <= 4) return true; } return false; }
// --------------------------------------------------------------------------- bool CvUnitMovement::CostsOnlyOne(const CvUnit* pUnit, const CvPlot* pFromPlot, const CvPlot* pToPlot) { if(!pToPlot->isValidDomainForAction(*pUnit)) { // If we are a land unit that can embark, then do further tests. if(pUnit->getDomainType() != DOMAIN_LAND || pUnit->IsHoveringUnit() || pUnit->canMoveAllTerrain() || !pUnit->CanEverEmbark()) return true; } CvAssert(!pUnit->IsImmobile()); if(pUnit->flatMovementCost() || pUnit->getDomainType() == DOMAIN_AIR) { return true; } // Is the unit from a civ that can disembark for just 1 MP? if(!pToPlot->isWater() && pFromPlot->isWater() && pUnit->isEmbarked() && GET_PLAYER(pUnit->getOwner()).GetPlayerTraits()->IsEmbarkedToLandFlatCost()) { return true; } return false; }
int CvProcessProductionAI::CheckProcessBuildSanity(ProcessTypes eProcess, int iTempWeight, int iNumBuildables, int iGPT) { CvProcessInfo* pProcess = GC.getProcessInfo(eProcess); if(!pProcess) { return 0; } if(iTempWeight == 0) return 0; if(iNumBuildables > 0) { if(iTempWeight > 300) { iTempWeight = 300; } } else { if(iTempWeight > 400) { iTempWeight = 400; } } CvPlayerAI& kPlayer = GET_PLAYER(m_pCity->getOwner()); int iModifier = 0; //Bonus % additive. All values below will be added to this and combined with real value at end. int iBonus = 0; ////// //WAR /////// //Fewer processes while at war. int iNumWar = kPlayer.GetMilitaryAI()->GetNumberCivsAtWarWith(false); if(iNumWar > 0) { iBonus -= (iNumWar * 50); if(kPlayer.getNumCities() > 1 && m_pCity->GetThreatCriteria() != -1) { //More cities = more threat. int iThreat = (kPlayer.getNumCities() - m_pCity->GetThreatCriteria()) * 25; if(iThreat > 0) { iBonus -= iThreat; } } if(m_pCity->IsBastion()) { iBonus -= 100; } if(m_pCity->IsBlockaded(true)) { iBonus -= 100; } if(m_pCity->IsBlockadedWaterAndLand()) { iBonus -= 100; } } //Tiny army? Eek! if(kPlayer.getNumMilitaryUnits() <= (kPlayer.getNumCities() * 2)) { iBonus -= 100; } MilitaryAIStrategyTypes eBuildCriticalDefenses = (MilitaryAIStrategyTypes) GC.getInfoTypeForString("MILITARYAISTRATEGY_LOSING_WARS"); // scale based on flavor and world size if(eBuildCriticalDefenses != NO_MILITARYAISTRATEGY && kPlayer.GetMilitaryAI()->IsUsingStrategy(eBuildCriticalDefenses)) { iModifier -= 50; } EconomicAIStrategyTypes eStrategyLosingMoney = (EconomicAIStrategyTypes) GC.getInfoTypeForString("ECONOMICAISTRATEGY_LOSING_MONEY"); EconomicAIStrategyTypes eStrategyCultureGS = (EconomicAIStrategyTypes) GC.getInfoTypeForString("ECONOMICAISTRATEGY_GS_CULTURE"); AICityStrategyTypes eNeedFood = (AICityStrategyTypes) GC.getInfoTypeForString("AICITYSTRATEGY_NEED_IMPROVEMENT_FOOD"); AICityStrategyTypes eNeedFoodNaval = (AICityStrategyTypes) GC.getInfoTypeForString("AICITYSTRATEGY_NEED_NAVAL_GROWTH"); EconomicAIStrategyTypes eGrowCrazy = (EconomicAIStrategyTypes) GC.getInfoTypeForString("ECONOMICAISTRATEGY_GROW_LIKE_CRAZY"); AICityStrategyTypes eScienceCap = (AICityStrategyTypes) GC.getInfoTypeForString("AICITYSTRATEGY_KEY_SCIENCE_CITY"); //Yield value. //Base value of production. iModifier += (m_pCity->getYieldRate(YIELD_PRODUCTION, false) / 5); for(int iYield = 0; iYield < NUM_YIELD_TYPES; iYield++) { YieldTypes eYield = (YieldTypes)iYield; if(eYield == NO_YIELD) continue; if(m_pCity->GetCityStrategyAI()->GetMostDeficientYield() == eYield) { iModifier += 50; } if(pProcess->getProductionToYieldModifier(eYield) > 0) { switch(eYield) { case YIELD_GOLD: { if(MOD_BALANCE_CORE_HAPPINESS) { if(m_pCity->getUnhappinessFromGold() > 0) { iModifier += (m_pCity->getUnhappinessFromGold() * 2); } } if(eStrategyLosingMoney != NO_ECONOMICAISTRATEGY && kPlayer.GetEconomicAI()->IsUsingStrategy(eStrategyLosingMoney)) { iModifier += 25; } } break; case YIELD_CULTURE: { if(MOD_BALANCE_CORE_HAPPINESS) { if(m_pCity->getUnhappinessFromCulture() > 0) { iModifier += (m_pCity->getUnhappinessFromCulture() * 2); } } if(eStrategyCultureGS != NO_ECONOMICAISTRATEGY && kPlayer.GetEconomicAI()->IsUsingStrategy(eStrategyCultureGS)) { iModifier += 25; } } break; case YIELD_SCIENCE: { if(MOD_BALANCE_CORE_HAPPINESS) { if(m_pCity->getUnhappinessFromScience() > 0) { iModifier += (m_pCity->getUnhappinessFromScience() * 2); } } if(eScienceCap != NO_AICITYSTRATEGY && m_pCity->GetCityStrategyAI()->IsUsingCityStrategy(eScienceCap)) { iModifier += 25; } } break; case YIELD_FOOD: { if(m_pCity->GetCityCitizens()->IsForcedAvoidGrowth()) return 0; int iExcessFoodTimes100 = m_pCity->getYieldRateTimes100(YIELD_FOOD, false) - (m_pCity->foodConsumption() * 100); if (iExcessFoodTimes100 < 0) { iModifier += 25; } if(MOD_BALANCE_CORE_HAPPINESS) { if(m_pCity->getUnhappinessFromStarving() > 0) { iModifier += (m_pCity->getUnhappinessFromStarving() * 5); } } if(eGrowCrazy != NO_ECONOMICAISTRATEGY && kPlayer.GetEconomicAI()->IsUsingStrategy(eGrowCrazy)) { iModifier += 15; } if(eNeedFood != NO_AICITYSTRATEGY && m_pCity->GetCityStrategyAI()->IsUsingCityStrategy(eNeedFood)) { iModifier += 15; } if(eNeedFoodNaval != NO_AICITYSTRATEGY && m_pCity->GetCityStrategyAI()->IsUsingCityStrategy(eNeedFoodNaval)) { iModifier += 10; } } break; } } } for(int iI = 0; iI < GC.getNumLeagueProjectInfos(); iI++) { LeagueProjectTypes eLeagueProject = (LeagueProjectTypes) iI; CvLeagueProjectEntry* pInfo = GC.getLeagueProjectInfo(eLeagueProject); if (pInfo && pInfo->GetProcess() == eProcess) { if (GC.getGame().GetGameLeagues()->CanContributeToLeagueProject(m_pCity->getOwner(), eLeagueProject)) { FStaticVector<LeagueProjectRewardTypes, 4, true, c_eCiv5GameplayDLL> veRewards; veRewards.push_back(pInfo->GetRewardTier3()); veRewards.push_back(pInfo->GetRewardTier2()); veRewards.push_back(pInfo->GetRewardTier1()); for (uint i = 0; i < veRewards.size(); i++) { CvLeagueProjectRewardEntry* pRewardInfo = GC.getLeagueProjectRewardInfo(veRewards[i]); CvAssert(pRewardInfo); if (!pRewardInfo) continue; // Free Building in Capital if (pRewardInfo->GetBuilding() != NO_BUILDING) { CvBuildingEntry* pBuildingInfo = GC.getBuildingInfo(pRewardInfo->GetBuilding()); if(pBuildingInfo) { int iValue = 1000; if(kPlayer.getCapitalCity() != NULL) { iValue = kPlayer.getCapitalCity()->GetCityStrategyAI()->GetBuildingProductionAI()->CheckBuildingBuildSanity(pRewardInfo->GetBuilding(), iValue, 5, 5, 1); iModifier += iValue; } else { iModifier += m_pCity->GetCityStrategyAI()->GetBuildingProductionAI()->GetWeight(pRewardInfo->GetBuilding()); } } } // Happiness if (pRewardInfo->GetHappiness() != 0) { iModifier += pRewardInfo->GetHappiness() * (50 - kPlayer.GetHappiness()); } // Free Social Policy if (pRewardInfo->GetFreeSocialPolicies() > 0) { iModifier += (kPlayer.GetPlayerPolicies()->GetNumPoliciesOwned() * 20); } EconomicAIStrategyTypes eStrategyCultureGS = (EconomicAIStrategyTypes) GC.getInfoTypeForString("ECONOMICAISTRATEGY_GS_CULTURE"); // Temporary Culture Modifier if (pRewardInfo->GetCultureBonusTurns() > 0) { if(eStrategyCultureGS != NO_ECONOMICAISTRATEGY && kPlayer.GetEconomicAI()->IsUsingStrategy(eStrategyCultureGS)) { iModifier += 250; } } // Temporary Tourism Modifier if (pRewardInfo->GetTourismBonusTurns() > 0) { if(eStrategyCultureGS != NO_ECONOMICAISTRATEGY && kPlayer.GetEconomicAI()->IsUsingStrategy(eStrategyCultureGS)) { iModifier += 250; } } // Golden Age Points if (pRewardInfo->GetGoldenAgePoints() > 0) { if(kPlayer.GetPlayerTraits()->GetGoldenAgeDurationModifier() > 0) { iModifier += (pRewardInfo->GetGoldenAgePoints() + kPlayer.GetPlayerTraits()->GetGoldenAgeDurationModifier()) * 5; } else { iModifier += (pRewardInfo->GetGoldenAgePoints() + kPlayer.getGoldenAgeModifier()) * 5; } } // City-State Influence Boost //antonjs: todo: ordering, to prevent ally / no longer ally notif spam EconomicAIStrategyTypes eStrategyUNGS = (EconomicAIStrategyTypes) GC.getInfoTypeForString("ECONOMICAISTRATEGY_GS_DIPLOMACY"); if (pRewardInfo->GetCityStateInfluenceBoost() > 0) { if(eStrategyUNGS != NO_ECONOMICAISTRATEGY && kPlayer.GetEconomicAI()->IsUsingStrategy(eStrategyUNGS)) { iModifier += 250; } } EconomicAIStrategyTypes eStrategySpaceShip = (EconomicAIStrategyTypes) GC.getInfoTypeForString("ECONOMICAISTRATEGY_GS_SPACESHIP"); // Beaker boost based on previous turns if (pRewardInfo->GetBaseBeakersTurnsToCount() > 0) { if(eStrategySpaceShip != NO_ECONOMICAISTRATEGY && kPlayer.GetEconomicAI()->IsUsingStrategy(eStrategySpaceShip)) { iModifier += 250; } } // Free unit class if (pRewardInfo->GetFreeUnitClass() != NO_UNITCLASS) { UnitTypes eUnit = (UnitTypes) kPlayer.getCivilizationInfo().getCivilizationUnits(pRewardInfo->GetFreeUnitClass()); if (eUnit != NO_UNIT) { CvUnitEntry* pkUnitInfo = GC.getUnitInfo(eUnit); if(pkUnitInfo) { int iValue = 500; if(kPlayer.getCapitalCity() != NULL) { iValue = kPlayer.getCapitalCity()->GetCityStrategyAI()->GetUnitProductionAI()->CheckUnitBuildSanity(eUnit, false, NULL, iValue, 1); } iModifier += iValue; } } } EconomicAIStrategyTypes eStrategyConquest = (EconomicAIStrategyTypes) GC.getInfoTypeForString("ECONOMICAISTRATEGY_GS_CONQUEST"); #if defined(MOD_DIPLOMACY_CITYSTATES_RESOLUTIONS) if (MOD_DIPLOMACY_CITYSTATES_RESOLUTIONS) { //CSD Project Rewards if (pRewardInfo->GetAttackBonusTurns() > 0) { if(eStrategyConquest != NO_ECONOMICAISTRATEGY && kPlayer.GetEconomicAI()->IsUsingStrategy(eStrategyConquest)) { iModifier += 150; } } if (pRewardInfo->GetBaseFreeUnits() > 0) { if(eStrategyConquest != NO_ECONOMICAISTRATEGY && kPlayer.GetEconomicAI()->IsUsingStrategy(eStrategyConquest)) { iModifier += 150; } } // Temporary Culture Modifier if (pRewardInfo->GetNumFreeGreatPeople() > 0) { iModifier += 250; } } #endif } } } } if(iGPT <= 0) { iModifier += (iGPT *= -2); } if(m_pCity->IsPuppet()) { iTempWeight *= (60 + iModifier); iTempWeight /= 100; } else { iTempWeight *= (100 + iModifier); iTempWeight /= 100; } return iTempWeight; }
/// Is it valid for this player to found a city here? bool CvCitySiteEvaluator::CanFound(CvPlot* pPlot, const CvPlayer* pPlayer, bool bTestVisible) const { CvAssert(pPlot); if(!pPlot) return false; CvPlot* pLoopPlot(NULL); bool bValid(false); int iRange(0), iDX(0), iDY(0); // Used to have a Python hook: CANNOT_FOUND_CITY_CALLBACK if(GC.getGame().isFinalInitialized()) { if(GC.getGame().isOption(GAMEOPTION_ONE_CITY_CHALLENGE) && pPlayer && pPlayer->isHuman()) { if(pPlayer->getNumCities() > 0) { return false; } } } if(pPlot->isImpassable() || pPlot->isMountain()) { return false; } if(pPlot->getFeatureType() != NO_FEATURE) { if(GC.getFeatureInfo(pPlot->getFeatureType())->isNoCity()) { return false; } } if(pPlayer) { if(pPlot->isOwned() && (pPlot->getOwner() != pPlayer->GetID())) { return false; } } CvTerrainInfo* pTerrainInfo = GC.getTerrainInfo(pPlot->getTerrainType()); if(!bValid) { if(pTerrainInfo->isFound()) { bValid = true; } } if(!bValid) { if(pTerrainInfo->isFoundCoast()) { if(pPlot->isCoastalLand()) { bValid = true; } } } if(!bValid) { if(pTerrainInfo->isFoundFreshWater()) { if(pPlot->isFreshWater()) { bValid = true; } } } // Used to have a Python hook: CAN_FOUND_CITIES_ON_WATER_CALLBACK if(pPlot->isWater()) { return false; } if(!bValid) { return false; } if(!bTestVisible) { // look at same land mass iRange = GC.getMIN_CITY_RANGE(); for(iDX = -(iRange); iDX <= iRange; iDX++) { for(iDY = -(iRange); iDY <= iRange; iDY++) { pLoopPlot = plotXYWithRangeCheck(pPlot->getX(), pPlot->getY(), iDX, iDY, iRange); if(pLoopPlot != NULL) { if(pLoopPlot->isCity()) { if(pLoopPlot->getLandmass() == pPlot->getLandmass()) { return false; } else if(hexDistance(iDX, iDY) < iRange) // one less for off shore { return false; } } } } } } return true; }
/// 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; }
/// Value of this site for a civ starting location int CvSiteEvaluatorForStart::PlotFoundValue(CvPlot* pPlot, CvPlayer* pPlayer, YieldTypes, bool) { int rtnValue = 0; int iI; CvPlot* pLoopPlot(NULL); int iCelticForestCount = 0; CvAssert(pPlot); if(!pPlot) return rtnValue; if(!CanFound(pPlot, pPlayer, false)) { return rtnValue; } // Is there any reason this site doesn't work for a start location? // // Not on top of a goody hut if(pPlot->isGoody()) { return 0; } // We have our own special method of scoring, so don't call the base class for that (like settler version does) #if defined(MOD_GLOBAL_CITY_WORKING) int iLimit = (pPlayer != NULL) ? pPlayer->GetNumWorkablePlots() : AVG_CITY_PLOTS; for(iI = 0; iI < iLimit; iI++) #else for(iI = 0; iI < NUM_CITY_PLOTS; iI++) #endif { pLoopPlot = plotCity(pPlot->getX(), pPlot->getY(), iI); // Too close to map edge? if(pLoopPlot == NULL) { return 0; } else { int iDistance = plotDistance(pPlot->getX(), pPlot->getY(), pLoopPlot->getX(), pLoopPlot->getY()); #if defined(MOD_GLOBAL_CITY_WORKING) if (pPlayer != NULL) { CvAssert(iDistance <= pPlayer->getWorkPlotDistance()); if(iDistance > pPlayer->getWorkPlotDistance()) continue; } else { CvAssert(iDistance <= AVG_CITY_RADIUS); if(iDistance > AVG_CITY_RADIUS) continue; } #else CvAssert(iDistance <= NUM_CITY_RINGS); if(iDistance > NUM_CITY_RINGS) continue; #endif int iRingModifier = m_iRingModifier[iDistance]; // Skip the city plot itself for now if(iDistance != 0) { rtnValue += iRingModifier * ComputeFoodValue(pLoopPlot, pPlayer) * /*6*/ GC.getSTART_AREA_FOOD_MULTIPLIER(); rtnValue += iRingModifier * ComputeHappinessValue(pLoopPlot, pPlayer) * /*12*/ GC.getSTART_AREA_HAPPINESS_MULTIPLIER(); rtnValue += iRingModifier * ComputeProductionValue(pLoopPlot, pPlayer) * /*8*/ GC.getSTART_AREA_PRODUCTION_MULTIPLIER(); rtnValue += iRingModifier * ComputeGoldValue(pLoopPlot, pPlayer) * /*2*/ GC.getSTART_AREA_GOLD_MULTIPLIER(); rtnValue += iRingModifier * ComputeScienceValue(pLoopPlot, pPlayer) * /*1*/ GC.getSTART_AREA_SCIENCE_MULTIPLIER(); rtnValue += iRingModifier * ComputeFaithValue(pLoopPlot, pPlayer) * /*1*/ GC.getSTART_AREA_FAITH_MULTIPLIER(); rtnValue += iRingModifier * ComputeTradeableResourceValue(pLoopPlot, pPlayer) * /*1*/ GC.getSTART_AREA_RESOURCE_MULTIPLIER(); rtnValue += iRingModifier * ComputeStrategicValue(pLoopPlot, pPlayer, iDistance) * /*1*/ GC.getSTART_AREA_STRATEGIC_MULTIPLIER(); } if (pPlayer) { if (iDistance == 1 && pLoopPlot->getFeatureType() == FEATURE_FOREST) { if (pLoopPlot->getImprovementType() == NO_IMPROVEMENT && pPlayer->GetPlayerTraits()->IsFaithFromUnimprovedForest()) { iCelticForestCount += 1; } } } } } if (iCelticForestCount >= 3) { rtnValue += 2 * 1000 * m_iFlavorMultiplier[YIELD_FAITH]; } else if (iCelticForestCount >= 1) { rtnValue += 1 * 1000 * m_iFlavorMultiplier[YIELD_FAITH]; } if(rtnValue < 0) rtnValue = 0; // Finally, look at the city plot itself and use it as an overall multiplier if(pPlot->getResourceType() != NO_RESOURCE) { rtnValue += rtnValue * GC.getBUILD_ON_RESOURCE_PERCENT() / 100; } if(pPlot->isRiver()) { rtnValue += rtnValue * GC.getBUILD_ON_RIVER_PERCENT() / 100; } if(pPlot->isCoastalLand()) { rtnValue += rtnValue * GC.getSTART_AREA_BUILD_ON_COAST_PERCENT() / 100; } return rtnValue; }
/// Value of plot for providing strategic value int CvCitySiteEvaluator::ComputeStrategicValue(CvPlot* pPlot, CvPlayer* pPlayer, int iPlotsFromCity) { int rtnValue = 0; CvAssert(pPlot); if(!pPlot) return rtnValue; // Possible chokepoint if impassable terrain and exactly 2 plots from city if(iPlotsFromCity == 2 && (pPlot->isImpassable() || pPlot->isMountain())) { rtnValue += /*5*/ GC.getCHOKEPOINT_STRATEGIC_VALUE(); } #if defined(MOD_BALANCE_CORE_SETTLER) if (MOD_BALANCE_CORE_SETTLER) { //Some features and terrain types are useful strategically. (Or really bad) if((pPlot->getOwner() == NO_PLAYER) || (pPlot->getOwner() != pPlayer->GetID())) { if(iPlotsFromCity <= 3 && (pPlot->getFeatureType() == FEATURE_ICE) || (pPlot->getTerrainType() == TERRAIN_SNOW)) { rtnValue += /*-10*/ GC.getBALANCE_BAD_TILES_STRATEGIC_VALUE(); } if(iPlotsFromCity <= 3 && pPlot->isFreshWater()) { rtnValue += /*2*/ GC.getBALANCE_FRESH_WATER_STRATEGIC_VALUE(); } if(iPlotsFromCity <= 3 && pPlot->isCoastalLand()) { rtnValue += /*2*/ GC.getBALANCE_COAST_STRATEGIC_VALUE(); } } } #endif // Hills in first ring are useful for defense and production if(iPlotsFromCity == 1 && pPlot->isHills()) { rtnValue += /*3*/ GC.getHILL_STRATEGIC_VALUE(); } // Some Features are less attractive to settle in, (e.g. Jungles, since it takes a while before you can clear them and they slow down movement) if(pPlot->getFeatureType() != NO_FEATURE) { int iWeight = GC.getFeatureInfo(pPlot->getFeatureType())->getStartingLocationWeight(); if(iWeight != 0 && iPlotsFromCity == 1) { rtnValue += iWeight; } } // Nearby City if(pPlayer != NULL && pPlot->isCity()) { // if (pPlot->getOwner() == pPlayer->getID()) { rtnValue += /*-1000*/ GC.getALREADY_OWNED_STRATEGIC_VALUE(); } } // POSSIBLE FUTURE: Is there any way for us to know to grab land between us and another major civ? rtnValue *= m_iFlavorMultiplier[SITE_EVALUATION_STRATEGIC]; return rtnValue; }