Question Regarding AI City Maintenance

Vexalor

Chieftain
Joined
Aug 21, 2014
Messages
5
Hello, I am making a mod for Civ4 BtS, but while editing Civ4HandicapInfo.xml, I noticed something confusing.

While there are several variables relating to maintenance costs for the player, the AI's maintenance costs were never mentioned.

On Noble difficulty according to the XML, players receive the following modifiers for maintenance costs:

Distance Maintenance --> 75%
Number of Cities Maintenance --> 70%
Max # of Cities Maintenance per City --> 5 gpt
Civic Upkeep --> 80%
Corporate Upkeep --> 100%
Colony Maintenance --> 100%

However, the AI only has one of these particular values:

Civic Upkeep --> 100%


In GlobalDefines.xml, the game states that max distance maintenance (presumably in gpt, but it could be in units of distance since that would be rather high for one city) is 25, but it is unclear if this applies to the player, AI, or both.
A similar situation arises in Civ4WorldInfo.xml, where additional modifiers are defined but it is unclear to whom they apply (for the worldinfo, it's probably everyone).

Given that these value are not explicitly written for the AI (or only partially expressed in the worldinfo file), they are probably hard-coded and the same for all difficulty levels, so I'd like to know what these values are if that information is available.
 
I've looked all those handicap variables up in the source code a few months ago.

As a rule, the values in CIV4HandicapsInfo.xml affect all civs alike, i.e. not only the human players'. The iAI... values take precedence, e.g. iAIAnimalBonus, or work as multipliers for the standard values. Example iAICivicUpkeepPercent:

The (base) civic upkeep is computed using some arcane formula in CvPlayer.cpp, function getSingleCivicUpkeep:
Spoiler :
Code:
  iUpkeep = ((std::max(0, (getTotalPopulation() + GC.getDefineINT("UPKEEP_POPULATION_OFFSET") - GC.getCivicInfo(eCivic).getCivicOptionType())) * GC.getUpkeepInfo((UpkeepTypes)(GC.getCivicInfo(eCivic).getUpkeep())).getPopulationPercent()) / 100);
  iUpkeep += ((std::max(0, (getNumCities() + GC.getDefineINT("UPKEEP_CITY_OFFSET") + GC.getCivicInfo(eCivic).getCivicOptionType() - (GC.getNumCivicOptionInfos() / 2))) * GC.getUpkeepInfo((UpkeepTypes)(GC.getCivicInfo(eCivic).getUpkeep())).getCityPercent()) / 100);
  iUpkeep *= std::max(0, (getUpkeepModifier() + 100));
  iUpkeep /= 100;
The result is multiplied by iCivicUpkeepPercent / 100 for all "CvPlayers" (which include AI civs):
Code:
iUpkeep *= GC.getHandicapInfo(getHandicapType()).getCivicUpkeepPercent();
iUpkeep /= 100;
For AIs, the result is again mutiplied by iAICivicUpkeepPercent:
Code:
if (!isHuman() && !isBarbarian()) {
  iUpkeep *= GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getAICivicUpkeepPercent();
  iUpkeep /= 100;
  iUpkeep *= std::max(0, ((GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getAIPerEraModifier() * getCurrentEra()) + 100));
  iUpkeep /= 100;
}
All (or most?) of the AI percentages increase per era based on iAIPerEraModifier (which is, however, 0 on Noble difficulty).

CIV4WorldInfo.xml and CIV4EraInfo.xml should apply to all civs (I haven't looked into these in detail).

MAX_DISTANCE_CITY_MAINTENANCE is used (probably exclusively) in CvCity.cpp. I can't tell how it works exactly, but it evidently applies to both human and AI players.
Spoiler :
Code:
int CvCity::calculateDistanceMaintenanceTimes100() const
{
	CvCity* pLoopCity;
	int iWorstCityMaintenance;
	int iBestCapitalMaintenance;
	int iTempMaintenance;
	int iLoop;

	iWorstCityMaintenance = 0;
	iBestCapitalMaintenance = MAX_INT;

	for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
	{
		iTempMaintenance = 100 * (GC.getDefineINT("[COLOR="Red"]MAX_DISTANCE_CITY_MAINTENANCE[/COLOR]") * plotDistance(getX_INLINE(), getY_INLINE(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()));

		iTempMaintenance *= (getPopulation() + 7);
		iTempMaintenance /= 10;

		iTempMaintenance *= std::max(0, (GET_PLAYER(getOwnerINLINE()).getDistanceMaintenanceModifier() + 100));
		iTempMaintenance /= 100;

		iTempMaintenance *= GC.getWorldInfo(GC.getMapINLINE().getWorldSize()).getDistanceMaintenancePercent();
		iTempMaintenance /= 100;

		iTempMaintenance *= GC.getHandicapInfo(getHandicapType()).getDistanceMaintenancePercent();
		iTempMaintenance /= 100;

		iTempMaintenance /= GC.getMapINLINE().maxPlotDistance();

		iWorstCityMaintenance = std::max(iWorstCityMaintenance, iTempMaintenance);

		if (pLoopCity->isGovernmentCenter())
		{
			iBestCapitalMaintenance = std::min(iBestCapitalMaintenance, iTempMaintenance);
		}
	}

	iTempMaintenance = std::min(iWorstCityMaintenance, iBestCapitalMaintenance);
	FAssert(iTempMaintenance >= 0);

	return iTempMaintenance;
}
 
Ah that makes much more sense. So the AI values are merely modifiers or replacements for the other values.

That actually means that Noble difficulty is much more balanced between advantages/disadvantages for players and AI than I thought.

However, the only strange thing about this is that it means that on lower difficulty levels, the AI also has significant advantages related to anything without a special AI value. For instance, on Settler difficulty, the player only has to pay 45% distance maintenance, but since there is no AI variable for this, the AI would it seems also only have to pay 45% distance maintenance. Is this right or is there some caveat for more extreme difficulty levels that I'm missing. The situation would be likewise on higher difficulties, where the player's disadvantages would apparently bleed over to affect the AI as well.
 
After thinking on it for a little bit of time, does the AI use the HANDICAP_NOBLE values even when the player has a different handicap and simply replaces its own values with the AI values from the player's chosen handicap?

If so, how does it reconcile things unrelated to the AI and player civilizations like barbarians that are also mentioned in the handicap files?'

As an aside, I did some extensive tests to see how the game was calculating Distance maintenance, and it appears surprisingly that the game calculates it roughly as follows:

(Plot Distance between Cities) / (Grid width or grid height of map) * MAX_DISTANCE_CITY_MAINTENANCE * Handicap Modifiers * Mapsize Modifiers
 
Ah, yes, I forgot about that. The AI always plays on Noble, that is, unless you change STANDARD_HANDICAP and AI_HANDICAP in GlobalDefines.xml. (STANDARD_HANDICAP may suffice; I've changed both and also BARBARIAN_HANDICAP to be on the safe side for my own mod.) It's easy enough to verify by starting a game on Settler difficulty and inspecting an AI city in debug mode: it'll only have +4 "happiness -- we just enjoy life".

I hadn't thought about how this works exactly, so I took a look in the code now: Two different functions named getHandicapType are used: a) CvGame.getHandicapType and b) CvPlayer.getHandicapType. The former should yield the difficulty selected by the player; the latter the difficulty assigned to a specific (AI) player. All accesses to AITrainPercent go through function a), while accesses to HappyBonus go through b). So it seems to work just as you suspected. (Not very intuitive to me though.)

Barbarians are created based on the difficulty set by the player. They affect human and AI equally (for all I know). The AI does get a 25% combat bonus against them on all difficulties, and starts with Archery from Monarch onwards.
As an aside, I did some extensive tests to see how the game was calculating Distance maintenance, and it appears surprisingly that the game calculates it roughly as follows:

(Plot Distance between Cities) / (Grid width or grid height of map) * MAX_DISTANCE_CITY_MAINTENANCE * Handicap Modifiers * Mapsize Modifiers
Sounds plausible. So the MAX_DISTANCE_... may not be aptly named.
 
I do not believe that the AI has city maintenance.

In my experience switching from playing warlord to noble to prince difficulty, it seemed like the hardest part for me when playing higher difficulty levels was trying to handle city maintenance while trying to keep up with the the AI cranking out settlers like a machine gun and expanding seemingly without any limit. However, when I make a custom map really crowded so that there is little room to expand, there hardly seems to be any difference in difficulty between Noble and Prince. I think the reason is that the biggest handicap assigned to the player is his city maintenance, and that's hardly relevant when you have a small number of cities.

Also I have some unique experience since I modded the XML files to make each turn take 1 year, and to scale older techs to take longer (so I multiplied the cost of ancient techs by 10, classical by 8, medieval by 6, etc). The effect is to make the early periods like a crawl, while later periods fly by, and also to allow empires to rise and fall in the early period. Anyway, I noticed while doing this that AIs can build empires of 10+ cities before having researched sailing, the wheel, cottages, or writing (all of the earliest income boosters), while I am struggling to squeeze income greater than maintenance out of 3 cities. Due to this unusual situation in which I KNOW that the AI can't get a big income because he has none of the relevant techs, the only way he can manage such large empires is if his expenses are small to nonexistent.
 
Well, thanks for necroing my posts from 7 years ago. :o

In Debug mode (Ctrl+Z with cheat code "chipotle" entered in My Games\Beyond the Sword\CivilizationIV.ini), you can switch the Financial Advisor screen to the perspective of an AI civ (drop-down menu on the upper left). That should show their total city maintenance and, in hover text, a breakdown of that cost. You can also inspect AI city maintenance through the city screens. Some of the Debug info gets the perspective switching wrong (e.g. Espionage screen), but, by and large, it works.

On Prince, your distance maintenance multiplier should be, according to Civ4HandicapInfos.xml, 85%, the number-of-cities maintenance multiplier 80%, and the cap for the number of cities counted for number-of-cities maintenance should be 6, while the AI – due to playing on Noble difficulty – would have 10 points lower multipliers (75% and 70%) and a num-cities cap of 5. Later on, AI discounts on civic upkeep and inflation become relevant and increase with each era (iAIPerEraModifier), but those factors wouldn't matter in the very early game.

My guess is that the AI civs in your games keep their research sliders near 0. (They might also place their cities closer together than you, resulting in lower distance maintenance for them.)
 
I know you can look up handicap info like that, and I was looking it up today, but I think it is just wrong. There is something else going on that the game doesn't tell you.

I said in my earlier message that I was bankrupt with 3 cities (meaning my research slider was near 0), and the AI was not bankrupt with +10 cities. If I remember right, the AI was actually out-pacing me with research, even though he hadn't researched any techs yet that would help him improve his economy. This difference is WAY more than the roughly 10% difference stated in the difficulty modifiers.

In order to balance, a long time ago I set my city and civic upkeep to settler level in my mod. I kept everything else at prince level so that the AI would have a slight economic boost. For a while, it seemed balanced to me, so I didn't check it. But I saw today in my game that one of the AI's research was basically 0 (I can see because I have enough espionage), so I went to check out his economy and compare it to mine. I could see his income by looking at his base, and assumed that it was equal to all of his expenses, since his research was nothing. Based on info I could find online about how city and maintenance upkeep are calculated, it looked to me that his upkeep was very close to what mine would have been in his case. But that is in my mod with inflation turned off, and my upkeep costs set to settler level, while the game actually thinks I'm playing prince level.

So, I believe the AI's upkeep at prince level is actually similar to the human's at settler level, although I wouldn't be surprised if the manner in which the upkeep was calculated was quite different. I do not care if the handicap info says something different; that's obviously not what happens in game.
 
So you've set e.g. iNumCitiesMaintenancePercent to 40 (the Settler value) for HANDICAP_PRINCE and you play at Prince and the AI plays – as it normally does – at Noble. Right, in that case, the 40% should apply to your cities only and the AI should get the 70% modifier from Noble. And you say it doesn't add up given those modifiers. The code for calculating city maintenance (e.g. CvCity::calculateNumCitiesMaintenanceTimes100) and for displaying the result (e.g. CvDLLWidgetData:: parseMaintenanceHelp) is publicly available, but of course that doesn't rule out that posts explaining those rules in natural language get it wrong somehow. If you could reproduce the too low AI expenses in a game without a mod, then others could perhaps take a look at your savegame. Preferably early in the game, for simplicity. Or, I guess, uploading the mod along with a savegame should also work.
 
I started a new game without my mod and used the world-editor to make my civ look like the AI civ in the other game I was playing that was bankrupt (so that I could know its upkeep). I discovered 2 things:

1. On prince difficulty level, the AI actually gets a roughly 30% discount on upkeep vs the human on noble difficulty, even without inflation, at least in that one scenario that I tested. It should be something like 12% if the handicap info were right.
2. City maintenance depends on city population (it isn't supposed to).

I don't care enough anymore to submit game files. This game is frustrating me right now and I'm going to take a break.
 
The handicaps sure are complicated and obscure. (I'm not defending any of it.) As for your second point, yes, It's based on city population.
 
Top Bottom