Skip to content

Commit df63b2d

Browse files
KungCheopsRecursiveVision
authored andcommitted
AI tweaks and improvements (LoneGazebo#11683)
Improvement planning AI improvement: Make improvement planning AI better at prioritizing improvements that buff nearby tiles. Will now prioritize building them next to tiles that are actively being worked by a city. Fix bug causing AI to sometimes get stuck improving the same tile over and over (was miscounting for monopoly bonuses). Unit Production AI tweaks: Make unit production AI more focused on trade units and building military units up to their supply limit. Add functionality to let the AI to include units currently being produced when considering how many units they currently have. This means they should no longer produce units way above their supply limit if they have many cities producing units at once.
1 parent 98b2fa3 commit df63b2d

File tree

4 files changed

+84
-40
lines changed

4 files changed

+84
-40
lines changed

CvGameCoreDLL_Expansion2/CvBuilderTaskingAI.cpp

+31-10
Original file line numberDiff line numberDiff line change
@@ -3355,14 +3355,20 @@ pair<int,int> CvBuilderTaskingAI::ScorePlotBuild(CvPlot* pPlot, ImprovementTypes
33553355
if (!pAdjacentOwningCity || pAdjacentOwningCity->IsRazing())
33563356
continue;
33573357

3358-
int iNewAdjacentYield = 0;
3358+
int iNewAdjacentWorkedYield = 0;
3359+
int iNewAdjacentUnworkedYield = 0;
3360+
3361+
bool bWorkingAdjacent = pAdjacentOwningCity->GetCityCitizens()->IsWorkingPlot(pAdjacentPlot);
33593362

33603363
// How much extra yield we give to adjacent tiles with a certain terrain
33613364
if (pAdjacentPlot->getTerrainType() != NO_TERRAIN)
33623365
{
33633366
int iAdjacentTerrainYieldChange = pkImprovementInfo ? pkImprovementInfo->GetAdjacentTerrainYieldChanges(pAdjacentPlot->getTerrainType(), eYield) : 0;
33643367
if (iAdjacentTerrainYieldChange != 0)
3365-
iNewAdjacentYield += iAdjacentTerrainYieldChange;
3368+
if (bWorkingAdjacent)
3369+
iNewAdjacentWorkedYield += iAdjacentTerrainYieldChange;
3370+
else
3371+
iNewAdjacentUnworkedYield += iAdjacentTerrainYieldChange;
33663372
}
33673373

33683374
ImprovementTypes eAdjacentImprovement = GetPlannedImprovementInPlot(pAdjacentPlot, sState);
@@ -3382,14 +3388,20 @@ pair<int,int> CvBuilderTaskingAI::ScorePlotBuild(CvPlot* pPlot, ImprovementTypes
33823388

33833389
int iDeltaTruncatedYield = (fCurrentAdjacentImprovementYield + fAdjacentImprovementYield).Truncate() - fCurrentAdjacentImprovementYield.Truncate();
33843390
if (iDeltaTruncatedYield != 0)
3385-
iNewAdjacentYield += iDeltaTruncatedYield;
3391+
if (bWorkingAdjacent)
3392+
iNewAdjacentWorkedYield += iDeltaTruncatedYield;
3393+
else
3394+
iNewAdjacentUnworkedYield += iDeltaTruncatedYield;
33863395

33873396
// How much extra yield an adjacent improvement will get if we create a resource
33883397
if (eResourceFromImprovement != NO_RESOURCE)
33893398
{
33903399
int iAdjacentResourceYieldChanges = pkAdjacentImprovementInfo->GetAdjacentResourceYieldChanges(eResourceFromImprovement, eYield);
33913400
if (iAdjacentResourceYieldChanges != 0)
3392-
iNewAdjacentYield += iAdjacentResourceYieldChanges;
3401+
if (bWorkingAdjacent)
3402+
iNewAdjacentWorkedYield += iAdjacentResourceYieldChanges;
3403+
else
3404+
iNewAdjacentUnworkedYield += iAdjacentResourceYieldChanges;
33933405
}
33943406

33953407
// How much extra yield an adjacent improvement will get if we create a feature (or keep the one that's here)
@@ -3398,15 +3410,19 @@ pair<int,int> CvBuilderTaskingAI::ScorePlotBuild(CvPlot* pPlot, ImprovementTypes
33983410
FeatureTypes eNewFeature = eFeatureFromImprovement != NO_FEATURE ? eFeatureFromImprovement : eFeature;
33993411
int iAdjacentFeatureYieldChanges = pkAdjacentImprovementInfo->GetAdjacentFeatureYieldChanges(eNewFeature, eYield);
34003412
if (iAdjacentFeatureYieldChanges != 0)
3401-
iNewAdjacentYield += iAdjacentFeatureYieldChanges;
3413+
if (bWorkingAdjacent)
3414+
iNewAdjacentWorkedYield += iAdjacentFeatureYieldChanges;
3415+
else
3416+
iNewAdjacentUnworkedYield += iAdjacentFeatureYieldChanges;
34023417
}
34033418
}
34043419
}
34053420

3406-
if (iNewAdjacentYield != 0)
3421+
if (iNewAdjacentWorkedYield != 0 || iNewAdjacentUnworkedYield != 0)
34073422
{
34083423
int iAdjacentCityYieldModifier = pAdjacentOwningCity ? GetYieldCityModifierTimes100(pAdjacentOwningCity, m_pPlayer, eYield) : 100;
3409-
iSecondaryScore += (iNewAdjacentYield * iYieldModifier * iAdjacentCityYieldModifier) / 100;
3424+
iSecondaryScore += (iNewAdjacentWorkedYield * iYieldModifier * iAdjacentCityYieldModifier) / 100;
3425+
iPotentialScore += (iNewAdjacentUnworkedYield * iYieldModifier * iAdjacentCityYieldModifier) / 100;
34103426
}
34113427
}
34123428
}
@@ -3519,7 +3535,7 @@ pair<int,int> CvBuilderTaskingAI::ScorePlotBuild(CvPlot* pPlot, ImprovementTypes
35193535
if (eOldImprovement != NO_IMPROVEMENT)
35203536
{
35213537
CvImprovementEntry* pkOldImprovementInfo = GC.getImprovementInfo(eOldImprovement);
3522-
if (pkOldImprovementInfo && (pkOldImprovementInfo->IsConnectsResource(eResource) || pkOldImprovementInfo->GetResourceFromImprovement() == eResourceFromImprovement))
3538+
if (pkOldImprovementInfo && (pkOldImprovementInfo->IsConnectsResource(eResource) || pkOldImprovementInfo->GetResourceFromImprovement() == eResource))
35233539
iExtraResource -= iResourceAmount;
35243540

35253541
}
@@ -3562,7 +3578,7 @@ pair<int,int> CvBuilderTaskingAI::ScorePlotBuild(CvPlot* pPlot, ImprovementTypes
35623578
}
35633579
int iTotalNumResource = GC.getMap().getNumResources(eConnectedResource);
35643580
if (bCreatesResource)
3565-
iTotalNumResource += iExtraResource;
3581+
iTotalNumResource += iResourceAmount;
35663582

35673583
int iCurrentMonopolyPercent = 0;
35683584
int iFutureMonopolyPercent = 0;
@@ -3582,7 +3598,8 @@ pair<int,int> CvBuilderTaskingAI::ScorePlotBuild(CvPlot* pPlot, ImprovementTypes
35823598
if (pkConnectedResource->getResourceUsage() == RESOURCEUSAGE_STRATEGIC)
35833599
iStrategicThreshold = /*25*/ GD_INT_GET(STRATEGIC_RESOURCE_MONOPOLY_THRESHOLD);
35843600

3585-
bool bCanReachGlobalMonopoly = iFutureMonopolyPercent > 50 || m_pPlayer->GetPlayerTraits()->IsImportsCountTowardsMonopolies() || (2 * (m_pPlayer->getResourceInOwnedPlots(eConnectedResource) + iResourceFromMinors) > iTotalNumResource);
3601+
bool bCanReachGlobalMonopoly = iFutureMonopolyPercent > iGlobalThreshold || m_pPlayer->GetPlayerTraits()->IsImportsCountTowardsMonopolies() || (100 * (m_pPlayer->getResourceInOwnedPlots(eConnectedResource) + iResourceFromMinors) > iGlobalThreshold * iTotalNumResource);
3602+
bool bCanReachStrategicMonopoly = iStrategicThreshold != 0 && (iFutureMonopolyPercent > iStrategicThreshold || m_pPlayer->GetPlayerTraits()->IsImportsCountTowardsMonopolies() || (100 * (m_pPlayer->getResourceInOwnedPlots(eConnectedResource) + iResourceFromMinors) > iStrategicThreshold * iTotalNumResource));
35863603

35873604
if (iCurrentMonopolyPercent <= iGlobalThreshold)
35883605
{
@@ -3603,6 +3620,10 @@ pair<int,int> CvBuilderTaskingAI::ScorePlotBuild(CvPlot* pPlot, ImprovementTypes
36033620
// We can get a global monopoly eventually
36043621
iPotentialScore += 2000;
36053622
}
3623+
else if (bCanReachStrategicMonopoly)
3624+
{
3625+
iPotentialScore += 1000;
3626+
}
36063627
}
36073628
}
36083629
}

CvGameCoreDLL_Expansion2/CvPlayer.cpp

+26
Original file line numberDiff line numberDiff line change
@@ -9662,6 +9662,32 @@ int CvPlayer::GetNumUnitPromotions(PromotionTypes ePromotion)
96629662
return iNum;
96639663
}
96649664

9665+
int CvPlayer::GetNumUnitsInProduction(DomainTypes eDomain, bool bMilitaryOnly)
9666+
{
9667+
int iNumUnits = 0;
9668+
9669+
CvCity* pLoopCity = NULL;
9670+
int iLoop = 0;
9671+
9672+
for (pLoopCity = firstCity(&iLoop); pLoopCity != NULL; pLoopCity = nextCity(&iLoop))
9673+
{
9674+
UnitTypes eUnitType = pLoopCity->getProductionUnit();
9675+
9676+
if (eUnitType == NO_UNIT)
9677+
continue;
9678+
9679+
CvUnitEntry* pkUnitInfo = GC.getUnitInfo(eUnitType);
9680+
9681+
if (pkUnitInfo == NULL)
9682+
continue;
9683+
9684+
if (pkUnitInfo->GetDomainType() == eDomain && (!bMilitaryOnly || pkUnitInfo->GetCombat() > 0))
9685+
iNumUnits++;
9686+
}
9687+
9688+
return iNumUnits;
9689+
}
9690+
96659691
// -----------------------------------------------------------------------------------------------
96669692
void CvPlayer::UpdateDangerPlots()
96679693
{

CvGameCoreDLL_Expansion2/CvPlayer.h

+1
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ class CvPlayer
197197
int GetNumUnitsWithUnitCombat(UnitCombatTypes eUnitCombat);
198198
int GetNumUnitsOfType(UnitTypes eUnit, bool bIncludeBeingTrained = false);
199199
int GetNumUnitPromotions(PromotionTypes ePromotion);
200+
int GetNumUnitsInProduction(DomainTypes eDomain, bool bMilitaryOnly);
200201
void UpdateDangerPlots();
201202
void SetDangerPlotsDirty();
202203

CvGameCoreDLL_Expansion2/CvUnitProductionAI.cpp

+26-30
Original file line numberDiff line numberDiff line change
@@ -256,25 +256,29 @@ int CvUnitProductionAI::CheckUnitBuildSanity(UnitTypes eUnit, bool bForOperation
256256
return SR_IMPOSSIBLE;
257257
}
258258

259+
int iNumLandUnits = kPlayer.getNumMilitaryLandUnits() + kPlayer.GetNumUnitsInProduction(DOMAIN_LAND, true);
260+
int iNumSeaUnits = kPlayer.getNumMilitarySeaUnits() + kPlayer.GetNumUnitsInProduction(DOMAIN_SEA, true);
261+
int iNumTotalUnits = iNumLandUnits + iNumSeaUnits;
262+
int iNumTotalUnitsToSupply = iNumTotalUnits - kPlayer.getNumUnitsSupplyFree();
263+
259264
//only war with majors count
260265
bool bAtWar = (kPlayer.GetMilitaryAI()->GetNumberCivsAtWarWith(false) > 0);
261266
if (!bFree && kPlayer.isMinorCiv())
262267
{
263268
if (bCombat)
264269
{
265-
if (kPlayer.getNumMilitaryUnits() > max(4, ((kPlayer.GetCurrentEra() + 3) * max(1, kPlayer.getNumCities()))))
270+
if (iNumTotalUnits > max(4, ((kPlayer.GetCurrentEra() + 3) * max(1, kPlayer.getNumCities()))))
266271
return SR_UNITSUPPLY;
267272

268273
if (pkUnitEntry->GetDomainType() == DOMAIN_SEA)
269274
{
270-
int iNumUnits = kPlayer.GetNumUnitsWithDomain(DOMAIN_SEA, true);
271-
if (iNumUnits <= 2)
272-
iBonus += max(0, 300 - (iNumUnits * 100));
275+
if (iNumSeaUnits <= 2)
276+
iBonus += max(0, 300 - (iNumSeaUnits * 100));
273277

274278
int iLimit = kPlayer.GetMilitaryAI()->GetRecommendNavySize();
275-
if (iNumUnits <= iLimit)
279+
if (iNumSeaUnits < iLimit)
276280
{
277-
iBonus += (iLimit - iNumUnits) * 100;
281+
iBonus += (iLimit - iNumSeaUnits) * 100;
278282
if (kPlayer.GetMinorCivAI()->IsRecentlyBulliedByAnyMajor())
279283
{
280284
iBonus += 100;
@@ -285,14 +289,13 @@ int CvUnitProductionAI::CheckUnitBuildSanity(UnitTypes eUnit, bool bForOperation
285289
}
286290
else if (pkUnitEntry->GetDomainType() == DOMAIN_LAND)
287291
{
288-
int iNumUnits = kPlayer.GetNumUnitsWithDomain(DOMAIN_LAND, true);
289-
if (iNumUnits <= 2)
290-
iBonus += max(0, 800 - (iNumUnits * 100));
292+
if (iNumLandUnits <= 2)
293+
iBonus += max(0, 800 - (iNumLandUnits * 100));
291294

292295
int iLimit = kPlayer.GetMilitaryAI()->GetRecommendLandArmySize();
293-
if (iNumUnits <= iLimit)
296+
if (iNumLandUnits < iLimit)
294297
{
295-
iBonus += (iLimit - iNumUnits) * 150;
298+
iBonus += (iLimit - iNumLandUnits) * 150;
296299
if (kPlayer.GetMinorCivAI()->IsRecentlyBulliedByAnyMajor())
297300
{
298301
iBonus += 250;
@@ -309,7 +312,7 @@ int CvUnitProductionAI::CheckUnitBuildSanity(UnitTypes eUnit, bool bForOperation
309312
if (bCombat && !bFree)
310313
{
311314
int iSupply = max(1, kPlayer.GetNumUnitsSupplied());
312-
int iDemand = kPlayer.GetNumUnitsToSupply();
315+
int iDemand = iNumTotalUnitsToSupply;
313316
if (bAtWar || bForOperation)
314317
{
315318
//hard limit, don't go too far into negative supply
@@ -923,21 +926,16 @@ int CvUnitProductionAI::CheckUnitBuildSanity(UnitTypes eUnit, bool bForOperation
923926
{
924927
return SR_USELESS;
925928
}
926-
929+
927930
if (pkUnitEntry->GetDomainType() == DOMAIN_LAND)
928931
{
929-
iBonus += m_pCity->GetTradePriorityLand()*10;
932+
iBonus += m_pCity->GetTradePriorityLand() * 10;
930933
}
931934
else
932935
{
933-
iBonus += m_pCity->GetTradePrioritySea()*10;
936+
iBonus += m_pCity->GetTradePrioritySea() * 10;
934937
}
935938

936-
int iUnhappyGold = m_pCity->GetPoverty(false);
937-
if (iUnhappyGold > 0)
938-
{
939-
iBonus += (iUnhappyGold * 10);
940-
}
941939
//Less often if at war.
942940
if (bAtWar)
943941
{
@@ -946,13 +944,11 @@ int CvUnitProductionAI::CheckUnitBuildSanity(UnitTypes eUnit, bool bForOperation
946944

947945
if (kPlayer.GetPlayerTraits()->IsDiplomat())
948946
{
949-
int NumMissingTRs = kPlayer.GetTrade()->GetNumTradeRoutesPossible() - kPlayer.GetTrade()->GetNumTradeUnits(true);
950-
iBonus += 100 * NumMissingTRs;
947+
iBonus += 750;
951948
}
952949
else
953950
{
954-
int NumMissingTRs = kPlayer.GetTrade()->GetNumTradeRoutesPossible() - kPlayer.GetTrade()->GetNumTradeUnits(true);
955-
iBonus += 50 * NumMissingTRs;
951+
iBonus += 700;
956952
}
957953
}
958954

@@ -1373,16 +1369,16 @@ int CvUnitProductionAI::CheckUnitBuildSanity(UnitTypes eUnit, bool bForOperation
13731369
}
13741370
}
13751371
//Tiny army? Eek!
1376-
if (kPlayer.getNumMilitaryUnits() <= (kPlayer.getNumCities() * 2) && pkUnitEntry->GetDomainType() == DOMAIN_LAND && pkUnitEntry->GetDefaultUnitAIType() != UNITAI_EXPLORE)
1372+
if (iNumLandUnits <= (kPlayer.getNumCities() * 2) && pkUnitEntry->GetDomainType() == DOMAIN_LAND && pkUnitEntry->GetDefaultUnitAIType() != UNITAI_EXPLORE)
13771373
{
13781374
if(bCombat)
13791375
{
1380-
iBonus += 100;
1376+
iBonus += 300;
13811377
}
13821378
//Fewer civilians til we rectify this!
13831379
else
13841380
{
1385-
iBonus -= 100;
1381+
iBonus -= 300;
13861382
}
13871383
}
13881384

@@ -1394,18 +1390,18 @@ int CvUnitProductionAI::CheckUnitBuildSanity(UnitTypes eUnit, bool bForOperation
13941390
iBonus -= 500;
13951391
}
13961392

1397-
if (bCombat && pkUnitEntry->GetRangedCombat() <= 0 && pkUnitEntry->GetDomainType() == DOMAIN_LAND)
1393+
if (bCombat && pkUnitEntry->GetDomainType() == DOMAIN_LAND && pkUnitEntry->GetDefaultUnitAIType() != UNITAI_EXPLORE)
13981394
{
13991395
static MilitaryAIStrategyTypes eStrategyBarbs = (MilitaryAIStrategyTypes)GC.getInfoTypeForString("MILITARYAISTRATEGY_ERADICATE_BARBARIANS");
14001396
static MilitaryAIStrategyTypes eStrategyBarbsCritical = (MilitaryAIStrategyTypes)GC.getInfoTypeForString("MILITARYAISTRATEGY_ERADICATE_BARBARIANS_CRITICAL");
14011397

14021398
if (kPlayer.GetMilitaryAI()->IsUsingStrategy(eStrategyBarbs))
14031399
{
1404-
iBonus += 25;
1400+
iBonus += 250;
14051401
}
14061402
else if (kPlayer.GetMilitaryAI()->IsUsingStrategy(eStrategyBarbsCritical))
14071403
{
1408-
iBonus += 50;
1404+
iBonus += 500;
14091405
}
14101406
}
14111407

0 commit comments

Comments
 (0)