/// Runs every turn to try and figure out what other known Players' Grand Strategies are void CvGrandStrategyAI::DoGuessOtherPlayersActiveGrandStrategy() { CvWeightedVector<int, 5, true> vGrandStrategyPriorities; FStaticVector< int, 5, true, c_eCiv5GameplayDLL > vGrandStrategyPrioritiesForLogging; GuessConfidenceTypes eGuessConfidence = NO_GUESS_CONFIDENCE_TYPE; int iGrandStrategiesLoop = 0; AIGrandStrategyTypes eGrandStrategy = NO_AIGRANDSTRATEGY; CvAIGrandStrategyXMLEntry* pGrandStrategy = 0; CvString strGrandStrategyName; CvTeam& pTeam = GET_TEAM(GetPlayer()->getTeam()); int iMajorLoop = 0; PlayerTypes eMajor = NO_PLAYER; int iPriority = 0; // Establish world Military strength average int iWorldMilitaryAverage = GC.getGame().GetWorldMilitaryStrengthAverage(GetPlayer()->GetID(), true, true); // Establish world culture and tourism averages int iNumPlayersAlive = 0; int iWorldCultureAverage = 0; int iWorldTourismAverage = 0; for(iMajorLoop = 0; iMajorLoop < MAX_MAJOR_CIVS; iMajorLoop++) { eMajor = (PlayerTypes) iMajorLoop; if(GET_PLAYER(eMajor).isAlive()) { iWorldCultureAverage += GET_PLAYER(eMajor).GetJONSCultureEverGenerated(); iWorldTourismAverage += GET_PLAYER(eMajor).GetCulture()->GetTourism(); iNumPlayersAlive++; } } iWorldCultureAverage /= iNumPlayersAlive; iWorldTourismAverage /= iNumPlayersAlive; // Establish world Tech progress average iNumPlayersAlive = 0; int iWorldNumTechsAverage = 0; TeamTypes eTeam; for(int iTeamLoop = 0; iTeamLoop < MAX_MAJOR_CIVS; iTeamLoop++) // Looping over all MAJOR teams { eTeam = (TeamTypes) iTeamLoop; if(GET_TEAM(eTeam).isAlive()) { iWorldNumTechsAverage += GET_TEAM(eTeam).GetTeamTechs()->GetNumTechsKnown(); iNumPlayersAlive++; } } iWorldNumTechsAverage /= iNumPlayersAlive; // Look at every Major we've met for(iMajorLoop = 0; iMajorLoop < MAX_MAJOR_CIVS; iMajorLoop++) { eMajor = (PlayerTypes) iMajorLoop; if(GET_PLAYER(eMajor).isAlive() && iMajorLoop != GetPlayer()->GetID()) { if(pTeam.isHasMet(GET_PLAYER(eMajor).getTeam())) { for(iGrandStrategiesLoop = 0; iGrandStrategiesLoop < GetAIGrandStrategies()->GetNumAIGrandStrategies(); iGrandStrategiesLoop++) { eGrandStrategy = (AIGrandStrategyTypes) iGrandStrategiesLoop; pGrandStrategy = GetAIGrandStrategies()->GetEntry(iGrandStrategiesLoop); strGrandStrategyName = (CvString) pGrandStrategy->GetType(); if(strGrandStrategyName == "AIGRANDSTRATEGY_CONQUEST") { iPriority = GetGuessOtherPlayerConquestPriority(eMajor, iWorldMilitaryAverage); } else if(strGrandStrategyName == "AIGRANDSTRATEGY_CULTURE") { iPriority = GetGuessOtherPlayerCulturePriority(eMajor, iWorldCultureAverage, iWorldTourismAverage); } else if(strGrandStrategyName == "AIGRANDSTRATEGY_UNITED_NATIONS") { iPriority = GetGuessOtherPlayerUnitedNationsPriority(eMajor); } else if(strGrandStrategyName == "AIGRANDSTRATEGY_SPACESHIP") { iPriority = GetGuessOtherPlayerSpaceshipPriority(eMajor, iWorldNumTechsAverage); } vGrandStrategyPriorities.push_back(iGrandStrategiesLoop, iPriority); vGrandStrategyPrioritiesForLogging.push_back(iPriority); } if(vGrandStrategyPriorities.size() > 0) { // Add "No Grand Strategy" in case we just don't have enough info to go on iPriority = /*40*/ GC.getAI_GRAND_STRATEGY_GUESS_NO_CLUE_WEIGHT(); vGrandStrategyPriorities.push_back(NO_AIGRANDSTRATEGY, iPriority); vGrandStrategyPrioritiesForLogging.push_back(iPriority); vGrandStrategyPriorities.SortItems(); eGrandStrategy = (AIGrandStrategyTypes) vGrandStrategyPriorities.GetElement(0); iPriority = vGrandStrategyPriorities.GetWeight(0); eGuessConfidence = NO_GUESS_CONFIDENCE_TYPE; // How confident are we in our Guess? if(eGrandStrategy != NO_AIGRANDSTRATEGY) { if(iPriority >= /*120*/ GC.getAI_GRAND_STRATEGY_GUESS_POSITIVE_THRESHOLD()) { eGuessConfidence = GUESS_CONFIDENCE_POSITIVE; } else if(iPriority >= /*70*/ GC.getAI_GRAND_STRATEGY_GUESS_LIKELY_THRESHOLD()) { eGuessConfidence = GUESS_CONFIDENCE_LIKELY; } else { eGuessConfidence = GUESS_CONFIDENCE_UNSURE; } } SetGuessOtherPlayerActiveGrandStrategy(eMajor, eGrandStrategy, eGuessConfidence); LogGuessOtherPlayerGrandStrategy(vGrandStrategyPrioritiesForLogging, eMajor); } vGrandStrategyPriorities.clear(); vGrandStrategyPrioritiesForLogging.clear(); } } } }
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; }
/// Runs every turn to determine what the player's Active Grand Strategy is and to change Priority Levels as necessary void CvGrandStrategyAI::DoTurn() { DoGuessOtherPlayersActiveGrandStrategy(); int iGrandStrategiesLoop; AIGrandStrategyTypes eGrandStrategy; CvAIGrandStrategyXMLEntry* pGrandStrategy; CvString strGrandStrategyName; // Loop through all GrandStrategies to set their Priorities for(iGrandStrategiesLoop = 0; iGrandStrategiesLoop < GetAIGrandStrategies()->GetNumAIGrandStrategies(); iGrandStrategiesLoop++) { eGrandStrategy = (AIGrandStrategyTypes) iGrandStrategiesLoop; pGrandStrategy = GetAIGrandStrategies()->GetEntry(iGrandStrategiesLoop); strGrandStrategyName = (CvString) pGrandStrategy->GetType(); // Base Priority looks at Personality Flavors (0 - 10) and multiplies * the Flavors attached to a Grand Strategy (0-10), // so expect a number between 0 and 100 back from this int iPriority = GetBaseGrandStrategyPriority(eGrandStrategy); if(strGrandStrategyName == "AIGRANDSTRATEGY_CONQUEST") { iPriority += GetConquestPriority(); } else if(strGrandStrategyName == "AIGRANDSTRATEGY_CULTURE") { iPriority += GetCulturePriority(); } else if(strGrandStrategyName == "AIGRANDSTRATEGY_UNITED_NATIONS") { iPriority += GetUnitedNationsPriority(); } else if(strGrandStrategyName == "AIGRANDSTRATEGY_SPACESHIP") { iPriority += GetSpaceshipPriority(); } // Random element iPriority += GC.getGame().getJonRandNum(/*50*/ GC.getAI_GS_RAND_ROLL(), "Grand Strategy AI: GS rand roll."); // Give a boost to the current strategy so that small fluctuation doesn't cause a big change if(GetActiveGrandStrategy() == eGrandStrategy && GetActiveGrandStrategy() != NO_AIGRANDSTRATEGY) { iPriority += /*50*/ GC.getAI_GRAND_STRATEGY_CURRENT_STRATEGY_WEIGHT(); } SetGrandStrategyPriority(eGrandStrategy, iPriority); } // Now look at what we think the other players in the game are up to - we might have an opportunity to capitalize somewhere int iNumPlayersAliveAndMet = 0; int iMajorLoop; for(iMajorLoop = 0; iMajorLoop < MAX_MAJOR_CIVS; iMajorLoop++) { if(GET_PLAYER((PlayerTypes) iMajorLoop).isAlive()) { if(GET_TEAM(GetPlayer()->getTeam()).isHasMet(GET_PLAYER((PlayerTypes) iMajorLoop).getTeam())) { iNumPlayersAliveAndMet++; } } } FStaticVector< int, 5, true, c_eCiv5GameplayDLL > viNumGrandStrategiesAdopted; int iNumPlayers; // Init vector for(iGrandStrategiesLoop = 0; iGrandStrategiesLoop < GetAIGrandStrategies()->GetNumAIGrandStrategies(); iGrandStrategiesLoop++) { iNumPlayers = 0; // Tally up how many players we think are pusuing each Grand Strategy for(iMajorLoop = 0; iMajorLoop < MAX_MAJOR_CIVS; iMajorLoop++) { if(GetGuessOtherPlayerActiveGrandStrategy((PlayerTypes) iMajorLoop) == (AIGrandStrategyTypes) iGrandStrategiesLoop) { iNumPlayers++; } } viNumGrandStrategiesAdopted.push_back(iNumPlayers); } FStaticVector< int, 5, true, c_eCiv5GameplayDLL > viGrandStrategyChangeForLogging; int iChange; // Now modify our preferences based on how many people are going for stuff for(iGrandStrategiesLoop = 0; iGrandStrategiesLoop < GetAIGrandStrategies()->GetNumAIGrandStrategies(); iGrandStrategiesLoop++) { eGrandStrategy = (AIGrandStrategyTypes) iGrandStrategiesLoop; // If EVERYONE else we know is also going for this Grand Strategy, reduce our Priority by 50% iChange = GetGrandStrategyPriority(eGrandStrategy) * /*50*/ GC.getAI_GRAND_STRATEGY_OTHER_PLAYERS_GS_MULTIPLIER(); iChange = iChange * viNumGrandStrategiesAdopted[eGrandStrategy] / iNumPlayersAliveAndMet; iChange /= 100; ChangeGrandStrategyPriority(eGrandStrategy, -iChange); viGrandStrategyChangeForLogging.push_back(-iChange); } ChangeNumTurnsSinceActiveSet(1); // Now see which Grand Strategy should be active, based on who has the highest Priority right now // Grand Strategy must be run for at least 10 turns if(GetActiveGrandStrategy() == NO_AIGRANDSTRATEGY || GetNumTurnsSinceActiveSet() >= /*10*/ GC.getAI_GRAND_STRATEGY_NUM_TURNS_STRATEGY_MUST_BE_ACTIVE()) { int iBestPriority = -1; int iPriority; AIGrandStrategyTypes eBestGrandStrategy = NO_AIGRANDSTRATEGY; for(iGrandStrategiesLoop = 0; iGrandStrategiesLoop < GetAIGrandStrategies()->GetNumAIGrandStrategies(); iGrandStrategiesLoop++) { eGrandStrategy = (AIGrandStrategyTypes) iGrandStrategiesLoop; iPriority = GetGrandStrategyPriority(eGrandStrategy); if(iPriority > iBestPriority) { iBestPriority = iPriority; eBestGrandStrategy = eGrandStrategy; } } if(eBestGrandStrategy != GetActiveGrandStrategy()) { SetActiveGrandStrategy(eBestGrandStrategy); m_pPlayer->GetCitySpecializationAI()->SetSpecializationsDirty(SPECIALIZATION_UPDATE_NEW_GRAND_STRATEGY); } } LogGrandStrategies(viGrandStrategyChangeForLogging); }