Hooks
static bool BeforeCvWonderProductionAI_ChooseWonder(CvWonderProductionAI* self, bool bUseAsyncRandom, bool bAdjustForOtherPlayers, int& iWonderWeight, BuildingTypes& result);static void AfterCvWonderProductionAI_ChooseWonder(CvWonderProductionAI* self, bool bUseAsyncRandom, bool bAdjustForOtherPlayers, int& iWonderWeight, BuildingTypes& result);static BuildingTypes ReplaceCvWonderProductionAI_ChooseWonder(BuildingTypes (*original)(CvWonderProductionAI*, bool, bool, int&), CvWonderProductionAI* self, bool bUseAsyncRandom, bool bAdjustForOtherPlayers, int& iWonderWeight);CivRegisterBefore<CivHooks::CvWonderProductionAI_ChooseWonder>(host, &BeforeCvWonderProductionAI_ChooseWonder);CivRegisterAfter<CivHooks::CvWonderProductionAI_ChooseWonder>(host, &AfterCvWonderProductionAI_ChooseWonder);CivRegisterReplace<CivHooks::CvWonderProductionAI_ChooseWonder>(host, &ReplaceCvWonderProductionAI_ChooseWonder);
Code
199/// Recommend highest-weighted wonder, also return total weight of all buildable wonders200BuildingTypes CvWonderProductionAI::ChooseWonder(bool bUseAsyncRandom, bool bAdjustForOtherPlayers, int& iWonderWeight)201{202 int iBldgLoop;203 int iWeight;204 int iTurnsRequired;205 int iEstimatedProductionPerTurn;206 int iCityLoop;207 RandomNumberDelegate fcn;208 BuildingTypes eSelection;209210 // Use the asynchronous random number generate if "no random" is set211 if(bUseAsyncRandom)212 {213 fcn = MakeDelegate(&GC.getGame(), &CvGame::getAsyncRandNum);214 }215 else216 {217 fcn = MakeDelegate(&GC.getGame(), &CvGame::getJonRandNum);218 }219220 // Reset list of all the possible wonders221 m_Buildables.clear();222223 // Guess which city will be producing this (doesn't matter that much since weights are all relative)224 CvCity* pWonderCity = m_pPlayer->GetCitySpecializationAI()->GetWonderBuildCity();225 if(pWonderCity == NULL)226 {227 pWonderCity = m_pPlayer->firstCity(&iCityLoop);228 }229230 CvAssertMsg(pWonderCity, "Trying to choose the next wonder to build and the player has no cities!");231 if(pWonderCity == NULL)232 return NO_BUILDING;233234 iEstimatedProductionPerTurn = pWonderCity->getCurrentProductionDifference(true, false);235 if(iEstimatedProductionPerTurn < 1)236 {237 iEstimatedProductionPerTurn = 1;238 }239240 // Loop through adding the available wonders241 for(iBldgLoop = 0; iBldgLoop < GC.GetGameBuildings()->GetNumBuildings(); iBldgLoop++)242 {243 const BuildingTypes eBuilding = static_cast<BuildingTypes>(iBldgLoop);244 CvBuildingEntry* pkBuildingInfo = m_pBuildings->GetEntry(eBuilding);245 if(pkBuildingInfo)246 {247 CvBuildingEntry& kBuilding = *pkBuildingInfo;248 const CvBuildingClassInfo& kBuildingClassInfo = kBuilding.GetBuildingClassInfo();249250 // Make sure this wonder can be built now251#if defined(MOD_AI_SMART_V3)252 bool bWonder = MOD_AI_SMART_V3 ? IsWonderNotNationalUnique(kBuilding) : IsWonder(kBuilding);253 if(bWonder && HaveCityToBuild((BuildingTypes)iBldgLoop))254#else255 if(IsWonder(kBuilding) && HaveCityToBuild((BuildingTypes)iBldgLoop))256#endif257 {258 iTurnsRequired = std::max(1, kBuilding.GetProductionCost() / iEstimatedProductionPerTurn);259260 // if we are forced to restart a wonder, give one that has been started already a huge bump261 bool bAlreadyStarted = pWonderCity->GetCityBuildings()->GetBuildingProduction(eBuilding) > 0;262 int iTempWeight = bAlreadyStarted ? m_WonderAIWeights.GetWeight(iBldgLoop) * 25 : m_WonderAIWeights.GetWeight(iBldgLoop);263264 // Don't build the UN if you aren't going for the diplo victory265 if(pkBuildingInfo->IsDiplomaticVoting())266 {267 int iVotesNeededToWin = GC.getGame().GetVotesNeededForDiploVictory();268 int iSecuredVotes = 0;269 TeamTypes myTeamID = m_pPlayer->getTeam();270 PlayerTypes myPlayerID = m_pPlayer->GetID();271272 // Loop through Players to see if they'll vote for this player273 PlayerTypes eLoopPlayer;274 TeamTypes eLoopTeam;275 for(int iPlayerLoop = 0; iPlayerLoop < MAX_CIV_PLAYERS; iPlayerLoop++)276 {277 eLoopPlayer = (PlayerTypes) iPlayerLoop;278279 if(GET_PLAYER(eLoopPlayer).isAlive())280 {281 eLoopTeam = GET_PLAYER(eLoopPlayer).getTeam();282283 // Liberated?284 if(GET_TEAM(eLoopTeam).GetLiberatedByTeam() == myTeamID)285 {286 iSecuredVotes++;287 }288289 // Minor civ?290 else if(GET_PLAYER(eLoopPlayer).isMinorCiv())291 {292 // Best Relations?293 if(GET_PLAYER(eLoopPlayer).GetMinorCivAI()->GetAlly() == myPlayerID)294 {295 iSecuredVotes++;296 }297 }298 }299 }300301 int iNumberOfPlayersWeNeedToBuyOff = MAX(0, iVotesNeededToWin - iSecuredVotes);302303 if(!m_pPlayer->GetDiplomacyAI() || !m_pPlayer->GetDiplomacyAI()->IsGoingForDiploVictory() || m_pPlayer->GetTreasury()->GetGold() < iNumberOfPlayersWeNeedToBuyOff * 500 )304 {305 iTempWeight = 0;306 }307 }308309 iWeight = CityStrategyAIHelpers::ReweightByTurnsLeft(iTempWeight, iTurnsRequired);310311 if(bAdjustForOtherPlayers && ::isWorldWonderClass(kBuildingClassInfo))312 {313 // Adjust weight for this wonder down based on number of other players currently working on it314 int iNumOthersConstructing = 0;315 for(int iPlayerLoop = 0; iPlayerLoop < MAX_MAJOR_CIVS; iPlayerLoop++)316 {317 PlayerTypes eLoopPlayer = (PlayerTypes) iPlayerLoop;318 if(GET_PLAYER(eLoopPlayer).getBuildingClassMaking((BuildingClassTypes)kBuilding.GetBuildingClassType()) > 0)319 {320 iNumOthersConstructing++;321 }322 }323 iWeight = iWeight / (1 + iNumOthersConstructing);324 }325326 m_Buildables.push_back(iBldgLoop, iWeight);327 }328 }329 }330331 // Sort items and grab the first one332 if(m_Buildables.size() > 0)333 {334 m_Buildables.SortItems();335 LogPossibleWonders();336337 if(m_Buildables.GetTotalWeight() > 0)338 {339 int iNumChoices = GC.getGame().getHandicapInfo().GetCityProductionNumOptions();340 eSelection = (BuildingTypes)m_Buildables.ChooseFromTopChoices(iNumChoices, &fcn, "Choosing wonder from Top Choices");341 iWonderWeight = m_Buildables.GetTotalWeight();342 return eSelection;343 }344345 // Nothing with any weight346 else347 {348 return NO_BUILDING;349 }350 }351352 // Unless we didn't find any353 else354 {355 return NO_BUILDING;356 }357}