My personal thread: Clarification of certain game mechanics

A unit is healed one-half the damage it has taken when promoted. (Additionally, it might then receive the normal benefits from promotions such as March).

Exactly as Damerell says.
And when it comes in what order your want to heal, if you don't care to hold off promo comitting (for instantaneous specialization of units when the moment comes), always take the promo first for fastest healing.

When it comes to healing rates, they are constant in enemy lands (5 HP per turn IIRC), neutral lands/AI at peace lands (10 HP per turn) and yours (15 HP per turn). It's 20 HP per turn in any city. Your total HP for all units is 100 HP.

So, basically, when you take the promo first, you get half healing. If you waited one turn (and this healed), your half healing gain would be less.

Come to think, there's a really good article about it.

As my sig says, search function is your friend.

Most of the time, my works are related to inner mechanics that were overlooked like city liberation mechanics (that one was answered by DanF, but represent my first dabble in the code), freebee techs from AI's, AI spliting their empires into a colony and the master, etc.

And one motivation is like finding a nice mechanics to "abuse". Like the vassal from which you demand a resource cannot theoritically to DOW when you go a defensive pact. Nice trick for sure and impossible to know via experience as impossible to separate possible other cause than defensive pact.

Did you know the spread knowledge about barb spawning where units have 25 tiles of no barb spawning came first from a word DanF wrote about barbs? Before, no one knew about it. Now, it is common knowledge for a good game. But if we look backward, it was also abuse, but it came to be accepted now.
 
Oh haha. My bad! :) Thanks!!

A little over a day.

First, you should ashamed to ask something that was studied before. BUT it is a bit toned down because as far as I remember, that was done in a previous version of CIV4, thus have some differences in XML values IIRC. The mechanics are still the same.

As thought, it's located it CvPlayer.cpp:

Spoiler :
Code:
int CvPlayer::getSingleCivicUpkeep(CivicTypes eCivic, bool bIgnoreAnarchy) const
{
	int iUpkeep;

	if (eCivic == NO_CIVIC)
	{
		return 0;
	}

	if (isNoCivicUpkeep((CivicOptionTypes)(GC.getCivicInfo(eCivic).getCivicOptionType())))
	{
		return 0;
	}

	if (GC.getCivicInfo(eCivic).getUpkeep() == NO_UPKEEP)
	{
		return 0;
	}

	if (!bIgnoreAnarchy)
	{
		if (isAnarchy())
		{
			return 0;
		}
	}

	iUpkeep = 0;

	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;

	iUpkeep *= GC.getHandicapInfo(getHandicapType()).getCivicUpkeepPercent();
	iUpkeep /= 100;

	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;
	}

	return std::max(0, iUpkeep);
}

Won't make the whole explanation again as Roland Johansen+colony did the job before.

But certain values are off.

Just like the formula mentioned in that article, I shall update some values:

Code:
Government civics upkeep:
[D * [ O * ( [ P * (N-8) ] + [ C * (M-1) ] ) ] ]
Legal civics upkeep:
[D * [ O * ( [ P * (N-9) ] + [ C * M ] ) ] ]
Labor civics upkeep:
[D * [ O * ( [ P * (N-10) ] + [ C * (M+1) ] ) ] ]
Economy civics upkeep:
[D * [ O * ( [ P * (N-11) ] + [ C * (M+2) ] ) ] ]
Religion civics upkeep:
[D * [ O * ( [ P * (N-12) ] + [ C * (M+3) ] ) ] ]

D: Difficulty
O: Organized trait=0.5
P: (P stands for population) is the LOW, MEDIUM and HIGH cost thing. That value changed over versions of civ4.Seems not in the XML files...:confused:
N: Population. Yes, population ponderation has some offset values to avoid cost in the early game.
C: (C stands for City) is the LOW, MEDIUM and HIGH cost thing. Underwent changes too I think.
M: Number of Cities

Why are they two similar ponderations (LOW, MEDIUM and HIGH)?
I suppose they decided to part the effects of populations from cities.
Given in a game, you decidedly have more population than cities count, thus C>P.

[] brackets are the process of rounding down because the game only treats integers (mostly because people wants a performant game...I guess).

Now the values:

For D, it is still the same.
It's <iCivicUpkeepPercent>100,100,100,95,90,80,70,60,50</iCivicUpkeepPercent>
It's Deity/IMM/EMP/Monarch/Prince/Noble/Warlord/Chieftain and last Settler.
Often, people says, it is starting EMP where REXing too hard is bad.

O: 0.5 for organized trait
P: UPKEEP_LOW : 0.08
UPKEEP_MEDIUM : 0.12
UPKEEP_HIGH: 0.16
C: UPKEEP_LOW : 0.40
UPKEEP_MEDIUM : 0.5
UPKEEP_HIGH: 0.6

Linkie!
 
Can the values P and C be found somewhere in the xml files? Or are they hardcoded?

Edit: I suppose they wanted to weigh population and the number of cities differently, P only influencing the population part and C only influencing the number of cities part.
 
Can the values P and C be found somewhere in the xml files? Or are they hardcoded?

Edit: I suppose they wanted to weigh population and the number of cities differently, P only influencing the population part and C only influencing the number of cities part.

I found it in the XML files in Assets. IIRC, that was CIV4UpkeepInfo.xml and possibly CIV4HandicapInfos.xml.

In your edit part, yes they wanted to weigh differently and as I explained this is likely due to the fact in all games you end up with more population than cities.
 
^^Ah, there it is :) Great, thanks :)

Yes, it's kind of hard to have more cities than population...
 
What no way! It's easy to do that! Just whip every single one of your cities down to 1 pop, and spam cities on every single open tile.
 
And then you can't get less pops than cities, ZZZ.

That's ZZZ's empire after conquering the world.
 
@ Tachywaxon

Thank you for the detailed explanation. I searched and found that thread. Should have done that to begin with. :lol:

Thanks again for taking the time to explain the healing mechanics. :)
 
SYNOPSIS

Coming along BTS expansion pack, creation of colony was in pair with the concept of colonial expenses. Colony concept was to free one empire from oversea colonization expenses by allowing all cities within an area (a.k.a. landmass surrounded by waters; islands included) to join the rule of an semi-randomly assigned leader to form an independent colony attached by the vassality rule to the colony creator.
Although rules that allow to form a colony (F1 and fist icon) for the human player are simple, the AI decision to make one is hidden information.

Let display their thought process. First, just like the human player, the AI player is tied to same rules (canSplitEmpire() and canSplitArea()) to be see the colony creation option available.

Quick sight on colony creation rules for both human an AI players
  • If Vassal state option is turned off while setting up your game, no colony can be created.
  • Being a vassal disallows one to create colonies. Indeed, that is mainly for AI players as human player can't be vassal of someone.
  • When a colony is created, a derivative civ is chosen and a leader too. If the game can't return a leader because there is no mode available leaders, the colony creation is disabled. The game can recycle dead leaders.
  • Attempting to create a second colony on a same Area as another previous colony is forbidden. One Area, one colony.
  • A created colony cannot share the same area as master's capital original area.
  • A minimum of 2 cities to open possibilities to create a colony.

If the player can create a colony in the mechanical sense of the term, it doesn't mean the AI will automatically create a colony when the option is offered.
The AI ponders via the worth of those distant cities in group limited by areas.
Just like a human would think, does these cities are productive or just a burden?
Indeed, the human player will think ahead and judge to be patient until cities become potentionally productive. The AI doesn't think in the long term. It evaluates each turn a certain additive function (addition of each city worth) and once that turns out to be negative, the colony is created.

How the AI calculate the area worth? That is simply the gold+research+production rates brought by the whole area minus 3 times the colonial maintenance. Yes, only colonial maintenance is taken into account, no other types of city maintenances.

After summing up all cities worth, that gives the area worth and a negative value for 1 turn means a colony created.

Note that when the AI is under some type of wars/WHEOOH for that area, all cities return a value 0, thus a whole area worth 0, which means colony creation prospects are ignored for greater goals. Can be AREAAI_OFFENSIVE planning: AI being at war for that area, but (s)he's the agressor. Can be AREAAI_DEFENSIVE planning: Still an active war, but now being the target on that area. Can be AREAAI_MASSING planning: another war type, but I have to see what this macro is up to.

Knowing AI decision to free some of their cities for a colony seems few of use.
But exploiting the fact the AI is not thinking ahead is allowing us to trick the AI.
Given the only negative component that gives an area worth < 0 is colonial maintenance. How to boost colonial maintenance while keeping its productivity low while being peaceful? Give them cities at a crazy rate; annoy them with privateers, quick destructive war on pillaging side (but peace is necessary afterwards), etc. That way you boost chance AI will create a colony.

Uses? On lower levels, the uses are few. Really...
But on IMM or especially on deity, this may allows a strong AI to split his/her empire in half, making that one less fiercesome. And the good thing about new leader arrival mid-game and while being a colony: the derivative leader gets all the master techs at the creation of the colony, but does not get past WFYABTA and such denials. Clean diplo too. New possibilities in the most powerful game mechanics side: tech trading.

MATH AND CODE ANALYSIS

I'll be brief code-wise and math-wise:

That is the main code strip about AI decisional action to split their empire.
Spoiler :
Code:
void CvPlayerAI::AI_doSplit()
{
	PROFILE_FUNC();

	if (!canSplitEmpire())
	{
		return;
	}

	int iLoop;
	std::map<int, int> mapAreaValues;

	for (CvArea* pLoopArea = GC.getMapINLINE().firstArea(&iLoop); pLoopArea != NULL; pLoopArea = GC.getMapINLINE().nextArea(&iLoop))
	{
		mapAreaValues[pLoopArea->getID()] = 0;
	}

	for (CvCity* pLoopCity = firstCity(&iLoop); pLoopCity != NULL; pLoopCity = nextCity(&iLoop))
	{
		mapAreaValues[pLoopCity->area()->getID()] += pLoopCity->AI_cityValue();
	}

	std::map<int, int>::iterator it;
	for (it = mapAreaValues.begin(); it != mapAreaValues.end(); ++it)
	{
		if (it->second < 0)
		{
			int iAreaId = it->first;

			if (canSplitArea(iAreaId))
			{
				splitEmpire(iAreaId);

				for (CvUnit* pUnit = firstUnit(&iLoop); pUnit != NULL; pUnit = nextUnit(&iLoop))
				{
					if (pUnit->area()->getID() == iAreaId)
					{
						TeamTypes ePlotTeam = pUnit->plot()->getTeam();

						if (NO_TEAM != ePlotTeam)
						{
							CvTeam& kPlotTeam = GET_TEAM(ePlotTeam);
							if (kPlotTeam.isVassal(getTeam()) && GET_TEAM(getTeam()).isParent(ePlotTeam))
							{
								pUnit->gift();
							}
						}
					}
				}
				break;
			}
		}
	}
}

Basically, it checks first the mechanical capacity to even split their empire (check colony conditions I mentioned in the synopsis).
Then came the C++ thorny line std::map<int, int> mapAreaValues;, which turned out to be simple in term of superficial understanding. It is some sort of array of values under cuztomized local variable "mapAreaValues" and supposedly std::map is a function reputed to be efficient and used for high humongous arrays (and from Area definition, imagine the huge number of areas a huge-sized island archipelago map can create).

Then, this line is the code of AI decision (and I'm not really going to delve further as testing proved the calculus is simple without help of the code):

Code:
mapAreaValues[pLoopCity->area()->getID()] += pLoopCity->[COLOR="SeaGreen"][B]AI_cityValue()[/B][/COLOR];

That's the Area worth I was talking about and that is the sum of all cities worth in the area that pertains to the potential colony creator

Lastly, outside mechanics of a colony creation (conversion of culture, free units, momentary share of techs, etc.), the AI does another action over those mechanics: all units which were in that area are automatically given to the colony, inside or outside cultural borders. A human player is not forced to give its units.

Code:
if (kPlotTeam.isVassal(getTeam()) && GET_TEAM(getTeam()).isParent(ePlotTeam))
							{
								pUnit->gift();
							}

I made several tests to verify if I didn't miss anything and yes, it worked.

Here is one of them displayed in details:


First, I get Pericles' colonial expenses.
I got -7 per turn. Officially, it's -1.81 per oversea city in that area and he got 4 cities there for a total of -7.28. But the game always rounds down non-integer values.
Then, AI_cityValue() inflated that value by a factor 3: it turns out to be then -21.
Notice I highlighted he was 100% science (I gave him lots of gold) because a science slider between 0-100% would lead to more rounding down and more difficultlies in evaluating the theory.


Then, I calculated concerned outputs: beakers+gold+hammers. Food is ignored.

Details on image.

Next turn, I saw he kept control of his colony.



Afterwards, I converted his plain hill to a grass hill (to enforce food has no bearing in AI_cityValue().
It leads that the colony's returns is 0 (21 (total output)-21 (inflated expenses)=0).
Next turn, he relegated his colony to some stranger...

I don't know why exactly Pericles didn't follow the code which exactly specified negative returns (Area worth), but I don't really care. It's only a difference of 1 and perhaps I missed something in hidden game calculations. BTW, no trade routes for those cities.

So, as said, this AI decision is done each turn and the AI doesn't think long term at all.
I tested more and I thought that was easy to trap the AI to create a colony if we give him cities fast as colony expenses grow really fast. And slower the gamespeed, harder it is for the AI to avoid this.

Hereunder some saves of my testings.
 

Attachments

  • AI_doSplit() - Pericles Keeps control of its colony.CivBeyondSwordSave
    43.4 KB · Views: 161
  • AI_doSplit() - Pericles relegates its colony to some stranger.CivBeyondSwordSave
    43.4 KB · Views: 176
  • AI_doSplit() test game - Expenses(7.29) vs output(8) --- No Colony.CivBeyondSwordSave
    41.4 KB · Views: 199
And then you can't get less pops than cities, ZZZ.

That's ZZZ's empire after conquering the world.

I know, I was being sarcastic, but serious. x]

But yes my empire does look like that, except for my Capital will be 16-20 pop. But that is the only non 2 pop city I will have.
 
I know, I was being sarcastic, but serious. x]

But yes my empire does look like that, except for my Capital will be 16-20 pop. But that is the only non 2 pop city I will have.

No Heroic Epic City?

============================================
============================================

Knowing my semi-articles are boring as hell, I put some friendly images about AI creating colonies.
 
:lol: Then he must conquer fast or raze everything otherwise war cash won't sustain his empire long.
 
:lol: Then he must conquer fast or raze everything otherwise war cash won't sustain his empire long.

That single population unit might be working a Commerce plot like a Gold/Gems/Silver Mine, Fur Camp, Dye/Incense Plantation, Town/Village and possibly riverside as well. That may go a long way towards keeping the empire in the black. There is also pillaging improvements after getting pillaging Wealth from Razing Cities.

Sun Tzu Wu
 
SYNOPSIS

Even though the AI is reputed for receiving noticeable maintenance discounts, an AI still can weigh its financial health and here how that was implemented.

In the past expansion, only cases of AI having presently over 50% of their slider into gold could feel some financial pressure (meaning it needs such slider for keeping maintenance at bay), but that was revoked for some reason (which I don't want to go into).

Financial trouble is calculated via parameters such % of science slider output, % of gold slider output, maintenance after inflation calculation, net GPT (negative if the AI gives too much away or positive is receiving more than giving away).
Then, it is compared to a threshold, which is a representation of the circumstances.

Spoiler :


Now, some maths:

NetCommerce
: Positive output+income output
NetExpenses : Mainly maintenance+debts
FundedPercent: Percentage of funds that are active for use.
SafePercent: Percentage threshold below which is the financial troubles zone.


NetCommerce
= RESEARCH_OUTPUT+GOLD_OUTPUT+GPT (>0 only)

NetExpenses = Expenses + GPT (<0 only)

FundedPercent=
100*[NetCommerce-NetExpenses)/NetCommerce)]

Notice RESEARCH_OUTPUT and GOLD_OUTPUT is from commerce tab in financial advisor. See screenshot.
Important to make a difference between what comes from slider from constant incomes like GPT from other players, shrines, corporation HQ, settled GPeoples, etc.
GPT is only total income in the screenshot. GPT goes in

NetCommerce
if total is positive, otherwise in NetExpenses if total is being negative.

Expenses are simple a combination of Unit cost, Unit Supply, City Maintenance and Civic Upkeep summed up and multiplied with inflation rate. In the screenshot, it's only total expenses.

==============================

Then, FundedPercent is compared to SafePercent and if it goes under it, the AI is in state of financial trouble.

SafePercent is set to 40 (%) originally and decreases as negative situations are added.

Here are the three ones:

  1. -8 % if the AI is in the last stage in their goal of a cultural victory OR is looping in future techs.
  2. -12 % under WHEOOH or an active war
  3. -10 % if current research has a certain XML value called <bRepeat> set at 1. Only applied for future techs.

The most common in a game is the WHEOOH state indeed.

For the final relation:

If FundedPercent<SafePercent, then financial troubles.

In a nutshell, the AI is more resilient to financial shocks if under WHEOOH (pillage and sack prospects?) or during final stage of a cultural victory or simply at the end of the tech tree (obvious reason).

Otherwise, in normal situations, it is a threshold of 40%, which means if the AI sees his/her net commercial outputs less than 40% after consideration of expenses, then the AI is in financial troubles.

Finally, how do financial troubles affect AI behaviour:

  • Increase its odds of razing a city if the leader already a propensity to raze cities.
  • In considerations of allowing unit gifts. If in financial troubles, the AI will refuse all unit gifts except for missionaries, workboats and workers (that one only if the AI feels lacking in number). Yes, missionaries and workboats are ALWAYS accepted.
  • In accepting cities in diplo table (NOT city discharge like city liberation). Under financial trouble, the AI will deny the gift.
  • If financial troubles, then reduces to zilch espionage spending (slider).
  • Affects gold and GPT you see in diplo tables.
  • Affects a little bit tech choice.
  • Under financial trouble, workers will flock more on commerce tiles to improve.
  • AI is more pugnacious if in financial troubles and will continue war little more in hope to gain from pillaging and ransacking.
  • A multitude of consequences on city build planning that I won't go into.

SOURCE CODE

Spoiler :
Code:
bool CvPlayerAI::AI_isFinancialTrouble() const
{
	//if (getCommercePercent(COMMERCE_GOLD) > 50)
	{
		int iNetCommerce = 1 + getCommerceRate(COMMERCE_GOLD) + getCommerceRate(COMMERCE_RESEARCH) + std::max(0, getGoldPerTurn());
		int iNetExpenses = calculateInflatedCosts() + std::min(0, getGoldPerTurn());
		
		int iFundedPercent = (100 * (iNetCommerce - iNetExpenses)) / std::max(1, iNetCommerce);
		
		int iSafePercent = 40;
		if (AI_avoidScience())       //Mostly when AI is going culture or future techs 
		{
			iSafePercent -= 8;
		}
		
		if (GET_TEAM(getTeam()).getAnyWarPlanCount(true))   //Under WHEOOH or a true active war state
		{                                                   //Minor civ eternal war count is ignored
			iSafePercent -= 12;                             
		}
		
		if (isCurrentResearchRepeat())    //Only applied for future techs
		{
			iSafePercent -= 10;
		}
		
		if (iFundedPercent < iSafePercent)
		{
			return true;
		}
	}

	return false;
}

=====================================================================================
=====================================================================================

bool CvPlayer::isCurrentResearchRepeat() const
{
	TechTypes eCurrentResearch;

	eCurrentResearch = getCurrentResearch();

	if (eCurrentResearch == NO_TECH)
	{
		return false;
	}

	return GC.getTechInfo(eCurrentResearch).isRepeat();  //Only Future Techs return "TRUE" in XML
}

======================================================================================
======================================================================================

int CvTeam::getAnyWarPlanCount(bool bIgnoreMinors) const
{
	int iCount;
	int iI;

	iCount = 0;

	for (iI = 0; iI < MAX_CIV_TEAMS; iI++)
	{
		if (GET_TEAM((TeamTypes)iI).isAlive())
		{
			if (!bIgnoreMinors || !(GET_TEAM((TeamTypes)iI).isMinorCiv()))  //Minor civ ignored!
			{
				if (AI_getWarPlan((TeamTypes)iI) != NO_WARPLAN)
				{
					FAssert(iI != getID());
					iCount++;
				}
			}
		}
	}

	FAssert(iCount >= getAtWarCount(bIgnoreMinors));

	return iCount;
}


=======================================================================================
=======================================================================================

WarPlanTypes CvTeamAI::AI_getWarPlan(TeamTypes eIndex) const
{
	FAssert(eIndex >= 0);
	FAssert(eIndex < MAX_TEAMS);
	FAssert(eIndex != getID() || m_aeWarPlan[eIndex] == NO_WARPLAN);
	return m_aeWarPlan[eIndex];         //To clarify, it's either a WHEOOH or an active war
}


bool CvTeamAI::AI_isChosenWar(TeamTypes eIndex) const  
{
	switch (AI_getWarPlan(eIndex))   //The function is irrelevant, but shows possible war plans. 
	{
	case WARPLAN_ATTACKED_RECENT: 
	case WARPLAN_ATTACKED:
		return false;
		break;
	case WARPLAN_PREPARING_LIMITED:
	case WARPLAN_PREPARING_TOTAL:
	case WARPLAN_LIMITED:
	case WARPLAN_TOTAL:
	case WARPLAN_DOGPILE:
		return true;
		break;
	}

	return false;
}
	
	========================================================================
	========================================================================
	
	bool CvPlayerAI::AI_avoidScience() const
{
    if (AI_isDoStrategy(AI_STRATEGY_CULTURE4))  //Last level in AI masterplan for culture
    {
        return true;
    }
	if (isCurrentResearchRepeat())              //Only for future techs
	{
		return true;
	}

	if (isNoResearchAvailable())                //Always ignored in the unmodded game
	{
		return true;
	}

	return false;
}

====================================================================
====================================================================


bool CvPlayer::isNoResearchAvailable() const  //Never encountered as true unless some mods without 
{                                             //future techs
	int iI;

	if (getCurrentResearch() != NO_TECH)
	{
		return false;
	}

	for (iI = 0; iI < GC.getNumTechInfos(); iI++)
	{
		if (canResearch((TechTypes)iI))
		{
			return false;
		}
	}

	return true;
}
 
You stated that Missionaries are always accepted. It is understood that you meant under any economic circumstances. Missionaries are refused for other reasons:

An AI is not permitted to accept a Missionary of a particular Religion, if that AI already has three of them (including any in city queues).

Sun Tzu Wu
 
I haven't tested or saw in the code about that, but it makes sense for sure. Yes, I meant under any economic circumstances.

Why missionaries and workboats are always accepted? Well, because those units won't stand around for a long time. They are consumed compared to a regular unit.

Missionaries will spread religion asap. Workboats will be used in a fishing net. And even if there no more seafoods for using that WB, I saw in the code long time ago that WB have a lifespan of 10 turns before being disbanding if being idle all 10 turns. AI disbands rarely, but it happens in certain cases like the WB.
 
Yeah, pretty sketchy, but no one is gonna read anyways. :lol:
Need to accumulate and organize like squirrels.

Fair trade bonus is defined in CvPlayerAI:

Code:
int CvPlayerAI::AI_getTradeAttitude(PlayerTypes ePlayer) const
{
	// XXX human only?
	return range(((AI_getPeacetimeGrantValue(ePlayer) + std::max(0, (AI_getPeacetimeTradeValue(ePlayer) - GET_PLAYER(ePlayer).AI_getPeacetimeTradeValue(getID())))) / ((GET_TEAM(getTeam()).AI_getHasMetCounter(GET_PLAYER(ePlayer).getTeam()) + 1) * 5)), 0, 4);
}

In common terms:

AI_getPeacetimeGrantValue(): Pure gifts to the AI
AI_getPeacetimeTradeValue(): Trade value of one side
AI_getHasMetCounter(): Number of turns since first contact

It turns out,

[0, GiftValueToAI+ ((HumanPlayerTradeValue - AiPlayerTradeValue)/(10*NumofTurnsFirstContact)), 4]

Reduced to a range [0, FairtradeValue, 4] where 0 is min and max is 4.

Looking for AI_getPeacetimeGrantValue(), AI_getPeacetimeTradeValue() leads to nothing as those values are modified in CvDeal.cpp.

AI_getHasMetCounter() is simply a count of turns since the first contact PLUS 1 to avoid evil dividing by zero. Goes like that: i=1 and then i=i+1.

In CvDeal.cpp::doTurn()

Spoiler :
Code:
void CvDeal::doTurn()
{
	int iValue;

	if (!isPeaceDeal())
	{
		if (getLengthSecondTrades() > 0)
		{
			iValue = (GET_PLAYER(getFirstPlayer()).AI_dealVal(getSecondPlayer(), getSecondTrades()) / GC.getDefineINT("PEACE_TREATY_LENGTH"));

			if (getLengthFirstTrades() > 0)
			{
				GET_PLAYER(getFirstPlayer()).AI_changePeacetimeTradeValue(getSecondPlayer(), iValue);
			}
			else
			{
				GET_PLAYER(getFirstPlayer()).AI_changePeacetimeGrantValue(getSecondPlayer(), iValue);
			}
		}

		if (getLengthFirstTrades() > 0)
		{
			iValue = (GET_PLAYER(getSecondPlayer()).AI_dealVal(getFirstPlayer(), getFirstTrades()) / GC.getDefineINT("PEACE_TREATY_LENGTH"));

			if (getLengthSecondTrades() > 0)
			{
				GET_PLAYER(getSecondPlayer()).AI_changePeacetimeTradeValue(getFirstPlayer(), iValue);
			}
			else
			{
				GET_PLAYER(getSecondPlayer()).AI_changePeacetimeGrantValue(getFirstPlayer(), iValue);
			}
		}
	}
}

We got the missing link: AI_dealVal().

A return to CvPlayerAI::AI_dealVal() ; I'll only take the most common case in trying to leverage +4 fair trade: technologies.

Spoiler :
Code:
case TRADE_TECHNOLOGIES:
			iValue += GET_TEAM(getTeam()).AI_techTradeVal((TechTypes)(pNode->m_data.m_iData), GET_PLAYER(ePlayer).getTeam());
			break;

Lastly, in CvTeamAI::AI_techTradeVal (because trading techs are treated under team banner),

Spoiler :
Code:
int CvTeamAI::AI_techTradeVal(TechTypes eTech, TeamTypes eTeam) const
{
	FAssert(eTeam != getID());
	int iKnownCount;
	int iPossibleKnownCount;
	int iCost;
	int iValue;
	int iI;

	iCost = std::max(0, (getResearchCost(eTech) - getResearchProgress(eTech)));

	iValue = ((iCost * 3) / 2);

	iKnownCount = 0;
	iPossibleKnownCount = 0;

	for (iI = 0; iI < MAX_CIV_TEAMS; iI++)
	{
		if (GET_TEAM((TeamTypes)iI).isAlive())
		{
			if (iI != getID())
			{
				if (isHasMet((TeamTypes)iI))
				{
					if (GET_TEAM((TeamTypes)iI).isHasTech(eTech))
					{
						iKnownCount++;
					}

					iPossibleKnownCount++;
				}
			}
		}
	}

	iValue += (((iCost / 2) * (iPossibleKnownCount - iKnownCount)) / iPossibleKnownCount);

	iValue *= std::max(0, (GC.getTechInfo(eTech).getAITradeModifier() + 100));
	iValue /= 100;

	iValue -= (iValue % GC.getDefineINT("DIPLOMACY_VALUE_REMAINDER"));

	if (isHuman())
	{
		return std::max(iValue, GC.getDefineINT("DIPLOMACY_VALUE_REMAINDER"));
	}
	else
	{
		return iValue;
	}
}

Here how a tech value is calculated:

iCost
= TechCost - HowFarAiProgressedOnThatTech.
Indeed, for fresh techs, it's only the tech cost after considering mapsize, gamespeed and difficulty you are playing on.

Then

iValue= 1.5*iCost

Rounding down.

Then it defines variables to represent the trading potential of such tech based on many neighbours (s)he has met and how many of them has the tech.

iKnownCount : AI neighbour met and got that tech you want to know its value.
iPossibleKnownCount: AI neighbours met.

Then we add to the last iValue: (iCost/2)*((iPossibleKnownCount-iKnownCount)/iPossibleKnownCount)

Rounding down again.

Enfin,
we multiply to the last sum of iValue a factor I would call "military interest":
Something from XML: CIV4TechInfos and it is <iAITradeModifier>. And I see the value is always 10 (a.k.a. 10%) for mainly techs allowing military edge.

(Sum of iValue)*(1.1 OR 1)

It simply adds 10% of iValue to the original iValue.

Here the list of techs allowing 1.1 factor:

Spoiler :
  • Feudalism
  • Guild
  • Military Tradition
  • Ecology (Military-wise?)
  • Electricity
  • Fission
  • Flight
  • Advanced Flight
  • Composites
  • Stealth
  • Genetics
  • Fiber Optics SMF-28e
  • Fusion
  • Archery
  • HBR
  • Machinery
  • Gunpower
  • Rifling
  • Steel
  • Assembly Line
  • Railroad
  • Artillery
  • Industrialism
  • Rocketry
  • Satellites
  • Robotics

Third round down.

For the human player, you know it is not CivIII allowing increment of 1 gold, but now 10 gold per increment.

So, the value is adjusted to the modulo of 10, that is dividing your last value or iValue by 10 and the remaining (between 1 to 9) is substracted to iValue before dividing by 10.

Spoiler :
Code:
iValue -= (iValue % GC.getDefineINT("DIPLOMACY_VALUE_REMAINDER"));

For the AI, that modulo step is ignored. So basically, a human can have a tech value of 1330 but not 1337.
 
Top Bottom