• Civilization 7 has been announced. For more info please check the forum here .

AI trade valuation quest

Ghpstage

Deity
Joined
Jan 15, 2009
Messages
2,944
Location
Bristol, England
While its probably overly ambitious, being off work and bored for a while I thought about a pie in the sky idea I mentioned in Tachys game mechanics thread, that is figuring out how AI value everything in regards to trade. While parts have been ripped into before I don't think something of this scale has been done.

So, I thought, in order to not clog up Tachys thread anymore I may aswell make a thread specifically about it, hopefully roping in some people to help, perhaps by looking through code themselves, spotting my mistakes, testing, commenting on how to improve the presentation, suggesting where I should look next, or ways I can test. General comments, criticisms and related questions welcomed of course.

The stated purpose for this thread is to find and collect all the coding information needed to put numbers to trade deals, and hopefully explain just why the AI thinks corn for iron trades are a good deal if coming from an AI :lol:
If theres anything else of interest related to these I will probably have a look at those too.
Ideally this thread will eventually become a decent reference for trade matters.


Thread Layout
This thread is being made while much of the code-diving is being done rather than as a compilation of existing information, as a result the order of posting is going to reflect the order of functions I dive, which is likely to be illogical from a straight reading perspective. The plan is to link to other posts (not all from this thread or by me) where necessary to try and make it useable.
I know my presentation at this point is poor, part of this is because is due to it being a work in progress, but also partly due to me being pretty bad at that kind of thing. This should improve when I need to use this thread myself in order to test my claims, I will try to make a summary of useful points and equations at the start of each post when that section has run its course and i'm convinced of its validity.

I'm trying to colour code things for the most part, but I need to redo some things.
Red will be for the primary two functions that govern overall trade, Blue for individual component value functions, yellow for components of components, green for other functions of interest. But red unbolded text is also used for some notes.

Most of the code involved is found in either CvPlayerAI.cpp or CvTeamAI.cpp, some things cross into CvCityAI.cpp and other places, at some point i'll get around to sourcing each code extract.
By its very nature this is going to be extremely code heavy, if anyones going to find it useful it'll be the beancounter types. Perhaps some useful generalities useful to anybody will come out of this, but i'm not going to promise anything.


General Assumption of the Trade Table
As far as I know right now, the functions evaluate each side of the trade table from the Buyers perspective (as in both parties are 'buying' the others offer), giving a numerical value for each side.

There are two different minimum acceptable values to the AI, equal or greater than an AIs offer, and equal or greater than (1.1 * AIs offer).
offer =>AI Offer is the norm for tradings, while offer =>1.1 * AIs offer apprently only applies to resources/gpt trade renewals.

In general the human is going to give an AI more than the trade is worth, but fortunately the human does get some compensation for these unequal trades to AIs in the form of +diplo points for "fair trade", which has already been looked into by Tachywaxon link.
Tachy also covered the mechanics of another trade related diplo factor, "You have shared your technological discoveries with us"

The two parent functions governing all human-AI trades are;
CvPlayerAI::AI_considerOffer
Which is ultimately where the AI decides what trades with a human are acceptable, it also governs values for tribute and begging deals

CvPlayerAI::AI_dealVal
This is the utimate value function, all it does is add up the total value of everything on offer, the only part that acts slightly differently is AI_goldTradeValuePercent which is divided by 100 (giving 2 or 3) before being added. I'll spoiler the code for completion below,​
Spoiler :
Code:
int CvPlayerAI::AI_dealVal(PlayerTypes ePlayer, const CLinkList<TradeData>* pList, bool bIgnoreAnnual, int iChange) const
{
	CLLNode<TradeData>* pNode;
	CvCity* pCity;
	int iValue;

	FAssertMsg(ePlayer != getID(), "shouldn't call this function on ourselves");

	iValue = 0;

	if (atWar(getTeam(), GET_PLAYER(ePlayer).getTeam()))
	{
		iValue += GET_TEAM(getTeam()).AI_endWarVal(GET_PLAYER(ePlayer).getTeam());
	}

	for (pNode = pList->head(); pNode; pNode = pList->next(pNode))
	{
		FAssertMsg(!(pNode->m_data.m_bHidden), "(pNode->m_data.m_bHidden) did not return false as expected");

		switch (pNode->m_data.m_eItemType)
		{
		case TRADE_TECHNOLOGIES:
			iValue += GET_TEAM(getTeam()).AI_techTradeVal((TechTypes)(pNode->m_data.m_iData), GET_PLAYER(ePlayer).getTeam());
			break;
		case TRADE_RESOURCES:
			if (!bIgnoreAnnual)
			{
				iValue += AI_bonusTradeVal(((BonusTypes)(pNode->m_data.m_iData)), ePlayer, iChange);
			}
			break;
		case TRADE_CITIES:
			pCity = GET_PLAYER(ePlayer).getCity(pNode->m_data.m_iData);
			if (pCity != NULL)
			{
				iValue += AI_cityTradeVal(pCity);
			}
			break;
		case TRADE_GOLD:
			iValue += (pNode->m_data.m_iData * AI_goldTradeValuePercent()) / 100;
			break;
		case TRADE_GOLD_PER_TURN:
			if (!bIgnoreAnnual)
			{
				iValue += AI_goldPerTurnTradeVal(pNode->m_data.m_iData);
			}
			break;
		case TRADE_MAPS:
			iValue += GET_TEAM(getTeam()).AI_mapTradeVal(GET_PLAYER(ePlayer).getTeam());
			break;
		case TRADE_SURRENDER:
			if (!bIgnoreAnnual)
			{
				iValue += GET_TEAM(getTeam()).AI_surrenderTradeVal(GET_PLAYER(ePlayer).getTeam());
			}
			break;
		case TRADE_VASSAL:
			if (!bIgnoreAnnual)
			{
				iValue += GET_TEAM(getTeam()).AI_vassalTradeVal(GET_PLAYER(ePlayer).getTeam());
			}
			break;
		case TRADE_OPEN_BORDERS:
			iValue += GET_TEAM(getTeam()).AI_openBordersTradeVal(GET_PLAYER(ePlayer).getTeam());
			break;
		case TRADE_DEFENSIVE_PACT:
			iValue += GET_TEAM(getTeam()).AI_defensivePactTradeVal(GET_PLAYER(ePlayer).getTeam());
			break;
		case TRADE_PEACE:
			iValue += GET_TEAM(getTeam()).AI_makePeaceTradeVal(((TeamTypes)(pNode->m_data.m_iData)), GET_PLAYER(ePlayer).getTeam());
			break;
		case TRADE_WAR:
			iValue += GET_TEAM(getTeam()).AI_declareWarTradeVal(((TeamTypes)(pNode->m_data.m_iData)), GET_PLAYER(ePlayer).getTeam());
			break;
		case TRADE_EMBARGO:
			iValue += AI_stopTradingTradeVal(((TeamTypes)(pNode->m_data.m_iData)), ePlayer);
			break;
		case TRADE_CIVIC:
			iValue += AI_civicTradeVal(((CivicTypes)(pNode->m_data.m_iData)), ePlayer);
			break;
		case TRADE_RELIGION:
			iValue += AI_religionTradeVal(((ReligionTypes)(pNode->m_data.m_iData)), ePlayer);
			break;
		}
	}

	return iValue;
}

AI_techTradeVal
AI_bonusTradeVal
AI_cityTradeVal
AI_goldTradeValuePercent
AI_goldPerTurnTradeVal
AI_mapTradeVal
AI_makePeaceTradeVal
AI_declareWarTradeVal
AI_stopTradingTradeVal
AI_civicTradeVal
AI_religionTradeVal

AI_endWarVal



The four below are also in the dealval function, for trade table purposes we already know that you cannot trade anything for them in any way shape or form so their value must be equal. Open Borders and Defensive Pacts do have small values, (total city count of both teams for Open Borders, multiply that by 3 for Defensive Pacts) that could hypothetically trip diplomatic thresholds, but for reasonable use they are so small as to be safely ignored.
Strangely AI_Vassaltradeval may aswell not exist at all, as it just calls up AI_surrenderTradeVal which is 0....
This may be worth knowing in its own right, as it means that capitulating an AI doesn't eat into your war spoils
.
AI_surrenderTradeVal
AI_vassalTradeVal
AI_openBordersTradeVal
AI_defensivePactTradeVal

Some, if not all of the others have been done by others in the past, unfortunately I have't been able to find them so i've had to redo the work myself.

Theres a couple of other related functions I may check out later if I get success with the main part, most to do with when the I does something based on the same value used in the tradeval functions. So far i'm thinking about these,

CvPlayerAI::AI_commerceWeight
This gives weights to the different types of commerce depending on AI strategy. It is called up in CvPlayerAI::AI_civicVal
CvPlayerAI::AI_doPeace
CvPlayerAI::AI_counterPropose
This is what the AI goes through when you click "What would make this deal work?" Its another huge function.
CvPlayerAI::AI_doReligion
Controls AI state religion changes
CvPlayerAI::AI_doCivics
Controls AI civic swaps
CvPlayerAI::AI_isFinancialTrouble
Defines when an AI is in Financial trouble

There are quite a few places where the code asks if the AI is running various strategies, for now at least i'm not going to touch that function with a barge pole, and if I ever do it'll get its own thread.


To Do list

Unlinked functions
Testing for everything other than gold, GPT, map and tech values
AI_cityTradeval - awaiting AI_bonusTradeval
AI_declareWarTradeVal - Waiting to know what EstimateEndTurn is
AI_religionTradeVal - need to figure out end of AI_bestReligion
AI_endWarVal - quite a few bits and pieces to finish off
Proofreading to see if the summaries match the post after editing
AI_stopTradingTradeVal - deal value calcs
AI_civicvalue
Yellow links list
Tidying everything up
 
Summary for quick reference
Gold Value
AI_goldTradeValuePercent = 200, or 300 IF the AI is in Financial Trouble
In the Dealval AIgoldTradeValuePercent is divided by 100 to give 2 or 3 value points per gold, which will be familiar quite a few people.

This is a useful baseline for testing these values, and is useful ingame. To match a trade of value X, you can offer X/2 gold unless they are in Financial Trouble when its X/3 gold


GPT Value
AI_goldPerTurnTradeVal = (GPT*10) multiplied by 2, or 3 IF seller is in Financial Trouble.
Due to its impact on the values of gold and GPT, when an AI is in Financial Trouble you buy things from them on the cheap, but you make a loss selling things to them.

Map Value - Tested and correct
A value is applied only to tiles that the buyer has not yet uncovered, remembering this,
AI_mapTradeVal = 5 * (Number of land tiles + Number of water tiles) / 10

The value rounds down to the nearest 10


Below is code and Workings
First few, all been done by other people in the past
AI_goldTradeValuePercent
Code:
int CvPlayerAI::AI_goldTradeValuePercent() const
{
int iValue = 2;
if (AI_isFinancialTrouble())
{
iValue += 1;
}
return 100 * iValue;
}
Golds value is,
TradeValue = 200, or 300 IF the AI is in Financial Trouble

In the Dealval AI_goldTradeValuePercent is divided by 100 to give 2 or 3 value points per gold, which will be familiar quite a few people.

AI_goldPerTurnTradeVal
Code:
int CvPlayerAI::AI_goldPerTurnTradeVal(int iGoldPerTurn) const
{
int iValue = iGoldPerTurn * GC.getDefineINT("PEACE_TREATY_LENGTH");
iValue *= AI_goldTradeValuePercent();
iValue /= 100;

return iValue;
}
GPTs value
TradeValue = (GPT*10) multiplied by 2, or 3 IF seller is in Financial Trouble.
Due to its impact on the values of gold and GPT, when an AI is in Financial Trouble you buy things from them on the cheap, but you make a loss selling things to them.

AI_mapTradeVal
Code:
int CvTeamAI::AI_mapTradeVal(TeamTypes eTeam) const
{
	CvPlot* pLoopPlot;
	int iValue;
	int iI;

	FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");

	iValue = 0;

	for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);

		if (!(pLoopPlot->isRevealed(getID(), false)) && pLoopPlot->isRevealed(eTeam, false))
		{
			if (pLoopPlot->isWater())
			{
				iValue++;
			}
			else
			{
				iValue += 5;
			}
		}
	}

	iValue /= 10;

	if (GET_TEAM(eTeam).isVassal(getID()))
	{
		iValue /= 2;
	}

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

	if (isHuman())
	{
		return std::max(iValue, GC.getDefineINT("DIPLOMACY_VALUE_REMAINDER"));
	}
	else
	{
		return iValue;
	}
}
A value is applied only to tiles that the buyer has not yet uncovered, remembering this,
TradeValue = 5 * (Number of land tiles + Number of water tiles)


The value rounds down to the nearest 10

The DIPLOMACY_VALUE_REMAINDER bit at the end is from GlobalDefines xml and has a value of 10. It gives a minimum value of 10 points, which when converted to gold in most cases is 10/2=5 which is the typical minimum the AI asks for in most if not all trades.
 
Summary for quick reference
*Needs testing but is most probably right*
Peace Bribe Value
AI_makePeaceTradeVal = (50 + gameturn + (sellers citycount + targets citycount * 8)) * 40 / (Turns at war + 10) * AVG Diplo LVL Mod
AVG Diplo LVL refers to the average opinion of the seller and target of each other, rounded down.
AVG Diplo LVL Mod is then depending on the level
Furious = 5
Annoyed = 3
Cautious = 2
Pleased = 1.5
Friendly = 1

Minimum value of DIPLOMACY_VALUE_REMAINDER (10)


Code and working below

AI_makePeaceTradeVal
This refers to bribing an AI (seller) to stop a war against someone else (target)
Code:
int CvTeamAI::AI_makePeaceTradeVal(TeamTypes ePeaceTeam, TeamTypes eTeam) const
{
	int iModifier;
	int iValue;

	FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");
	FAssertMsg(ePeaceTeam != getID(), "shouldn't call this function on ourselves");
	FAssertMsg(GET_TEAM(ePeaceTeam).isAlive(), "GET_TEAM(ePeaceTeam).isAlive is expected to be true");
	FAssertMsg(atWar(ePeaceTeam, eTeam), "eTeam should be at war with ePeaceTeam");

	iValue = (50 + GC.getGameINLINE().getGameTurn());
	iValue += ((GET_TEAM(eTeam).getNumCities() + GET_TEAM(ePeaceTeam).getNumCities()) * 8);

	iModifier = 0;

	switch ((GET_TEAM(eTeam).AI_getAttitude(ePeaceTeam) + GET_TEAM(ePeaceTeam).AI_getAttitude(eTeam)) / 2)
	{
	case ATTITUDE_FURIOUS:
		iModifier += 400;
		break;

	case ATTITUDE_ANNOYED:
		iModifier += 200;
		break;

	case ATTITUDE_CAUTIOUS:
		iModifier += 100;
		break;

	case ATTITUDE_PLEASED:
		iModifier += 50;
		break;

	case ATTITUDE_FRIENDLY:
		break;

	default:
		FAssert(false);
		break;
	}

	iValue *= std::max(0, (iModifier + 100));
	iValue /= 100;

	iValue *= 40;
	iValue /= (GET_TEAM(eTeam).AI_getAtWarCounter(ePeaceTeam) + 10);

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

	if (isHuman())
	{
		return std::max(iValue, GC.getDefineINT("DIPLOMACY_VALUE_REMAINDER"));
	}
	else
	{
		return iValue;
	}
}
50 + gameturn + (sellers citycount + targets citycount * 8) = ivalue

This is all multiplied by a modifier based on the average diplomatic opinion they have of each other, and just like when you have a vassal its the average of diplo levels not points, might take a while to work out if theres a lot of vassals in play :lol:

But anyway, that average value gives the modifier value,
Furious = 400
Annoyed = 200
Cautious = 100
Pleased = 50
Friendly = 0
Though being at war its obviously more likely to be at the upper end.

Next its ivalue * ((modifier+100)/100) = ivalue(2)

This can be simplified to ivalue * modifier if you take the below instead.
Furious = 5
Annoyed = 3
Cautious = 2
Pleased = 1.5
Friendly = 1

Then,
ivalue(2) * 40 / (length of war in turns + 10)

Same minimum value of DIPLOMACY_VALUE_REMAINDER (10) as applies to maps
 
clog up Tachys thread anymore

Do not worry. I sure know people really want not clog up my threads. Learnt it the harsh way with my last triple write-ups.

Good luck with the project. It's one of the most useful concept about trade.
 
Summary
Tech Trade Value - Tested and seems reliable, still may not be 100% accurate
AI_techtradeval = (icost - (icost * ingame invested beakers / ingame cost)) * 3 / 2 + (icost / 2 * (Total number civs in game - number of civs you know with the tech ) / total number of civs in game * (AI Trade Modifiers + 100)

Where,
icost is the cost of the tech as per the XML
Brown is a conversion factor I had to add to make this work for human buying tech from AI at all difficulties and map sizes.
AI Trade Modifier is either 0 or 10, it comes from the XML and here is a list of techs with 10, compliments of Tachy.

There is still a possibility of an error in the number of civs factor, but I have tested it several times now.


Code and working below

AI_techTradeVal
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;
	}
}
The only part of this i'm not entirely sure about is the beginning
(getResearchCost(eTech) - getResearchProgress(eTech)
While its obviously cost - investment on incomplete techs, i'm not sure how it reacts to different difficulty levels as the ResearchCost part is the noble difficuly (xml) cost.
Unfortunately I don't know where 'ResearchProgress' is defined so i'm left to speculate that its modified to suit that.

My guess for how to get this is
Invested / Cost for your game to get a %
Noble cost - (noble cost * %)
But this will need testing


The rest starts
ivalue = 3 / 2 * icost (icost being what the above gives)

ivalue(2) = (ivalue + icost / 2) * (Total number civs in game - number of civs with the tech ) / total number of civs in game
The above line will just be ivalue(2) = ivalue when you know all AIs.

and finally,
ivalue(2) * (AITradeModifier + 100) /100



Do not worry. I sure know people really want not clog up my threads. Learnt it the harsh way with my last triple write-ups.
Lol I just thought it didn't really belong there without either being completed, or specifically asked about :p
Good luck with the project. It's one of the most useful concept about trade.
Thanks :goodjob:

EDIT - The list of techs with AITradeModifier value of 10 kindly provided by Tachy in the post below, the value for all other techs is 0
As Tachy mentioned theres also a link in that post into where Fair Trade diplo points, and Tachys version of tech trade values.
 
^
In the "Fair Trades Explained", I dabbled into tech values.

Hence, here is the list of techs with 10%. Yes, they tend to be military.



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


Will you mind if I lurk around? I'll tone down my typical @$$holeries. Promises. :mischief:
 
You should say in the intro those functions are calculated for both the AI and you. Then, it is substracted and the remainder (for whoever is the winner) needs to be paid to conclude the deal.

For deal objects that is the same for both like peace deals, it is there is becomes blurry. Otherwise, for techs, gold, etc. It is rather giving itself.
 
*Waiting for testing*

AI_cityTradeVal
While this can't be traded in the normal sense, it can be 'purchased' using war success and whatever else matters in AI_endwarval
Code:
int CvPlayerAI::AI_cityTradeVal(CvCity* pCity) const
{
	CvPlot* pLoopPlot;
	int iValue;
	int iI;

	FAssert(pCity->getOwnerINLINE() != getID());

	iValue = 300;

	iValue += (pCity->getPopulation() * 50);

	iValue += (pCity->getCultureLevel() * 200);

	iValue += (((((pCity->getPopulation() * 50) + GC.getGameINLINE().getElapsedGameTurns() + 100) * 4) * pCity->plot()->calculateCulturePercent(pCity->getOwnerINLINE())) / 100);

	for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
	{
		pLoopPlot = plotCity(pCity->getX_INLINE(), pCity->getY_INLINE(), iI);

		if (pLoopPlot != NULL)
		{
			if (pLoopPlot->getBonusType(getTeam()) != NO_BONUS)
			{
				iValue += (AI_bonusVal(pLoopPlot->getBonusType(getTeam())) * 10);
			}
		}
	}

	if (!(pCity->isEverOwned(getID())))
	{
		iValue *= 3;
		iValue /= 2;
	}

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

	if (isHuman())
	{
		return std::max(iValue, GC.getDefineINT("DIPLOMACY_VALUE_REMAINDER"));
	}
	else
	{
		return iValue;
	}
}
300 + (50 * city pop) + (200* city cuture level) = ivalue

ivalue(2) = ivalue + (((50 * city pop) + game turn number + 100) * 4) * (% of city culture owner has / 100))

IF city has resources then
ivalue(3) = ivalue 2 + (AI_bonusVal for all resources) * 10
IF not then ivalue(3) = ivalue(2)

IF city was ever owned by the recipient (i.e. returning a captured city) then,
ivalue(3) * 3 / 2 = Final value
IF not, then
ivalue(3) = Final value

Typical that this would call up AI_bonusVal.....
Which calls up some of the most horrific looking functions in the whole of CvPlayerAI.cpp. Think i'll leave that one for now :lol:



In the "Fair Trades Explained", I dabbled into tech values.

Hence, here is the list of techs with 10%. Yes, they tend to be military.
Thanks,
Will you mind if I lurk around? I'll tone down my typical @$$holeries. Promises.
Ha.
Of course feel free to lurk all you like.

You should say in the intro those functions are calculated for both the AI and you. Then, it is substracted and the remainder (for whoever is the winner) needs to be paid to conclude the deal.

For deal objects that is the same for both like peace deals, it is there is becomes blurry. Otherwise, for techs, gold, etc. It is rather giving itself.
Will get around to that sometime tomorrow, tiredness is finally starting to kick in :coffee:
 
I often let the AI purchased my cities. I sometimes purchased theirs. It's fun doing that...and abusive.

It just needs fairy fingers.

Typical that this would call up AI_bonusVal.....
Which calls up some of the most horrific looking functions in the whole of CvPlayerAI.cpp. Think i'll leave that one for now

I seriously SERIOUSLY counsel to leave the demon alone. For sanity's sake. It's an unnerving function. I did try that one (up to 60% I think) and got tired. Still got it on some papers somewhere....if I didn't burn it yet.
 
Ok, come to think, if I had chance to retrieve those papers, will you be interested?

Maybe we could join our forces (along DanF5771) to destroy the beast. :)
 
much reward from thread
so amaze
wow

Thanks for make, will maybe lead to abuse AI

Can help low skill player defeat detity.

(Seriously though, following with interest :)).
 
Did you let your shiba inu takes control of your control? Wait a min...you have a shiba inu?
 
I seriously SERIOUSLY counsel to leave the demon alone. For sanity's sake. It's an unnerving function. I did try that one (up to 60% I think) and got tired. Still got it on some papers somewhere....if I didn't burn it yet.
I have had a bit of a crack at it before so I know how longwinded and nasty it is, but without a challenge this wouldn't be as interesting. Besides, its needed for 3 of the trade values so this project is already a failure if it isn't even attempted!
Ok, come to think, if I had chance to retrieve those papers, will you be interested?

Maybe we could join our forces (along DanF5771) to destroy the beast.
This would probably be for the best, especially as my own code reading, and especially my presentation of it isn't really up to scratch yet :shifty:



AI_declareWarTradeVal
Code:
int CvTeamAI::AI_declareWarTradeVal(TeamTypes eWarTeam, TeamTypes eTeam) const
{
	PROFILE_FUNC();

	int iModifier;
	int iValue;

	FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");
	FAssertMsg(eWarTeam != getID(), "shouldn't call this function on ourselves");
	FAssertMsg(GET_TEAM(eWarTeam).isAlive(), "GET_TEAM(eWarTeam).isAlive is expected to be true");
	FAssertMsg(!atWar(eWarTeam, eTeam), "eTeam should be at peace with eWarTeam");

	iValue = 0;
	iValue += (GET_TEAM(eWarTeam).getNumCities() * 10);
	iValue += (GET_TEAM(eWarTeam).getTotalPopulation(true) * 2);

	iModifier = 0;

	switch (GET_TEAM(eTeam).AI_getAttitude(eWarTeam))
	{
	case ATTITUDE_FURIOUS:
		break;

	case ATTITUDE_ANNOYED:
		iModifier += 25;
		break;

	case ATTITUDE_CAUTIOUS:
		iModifier += 50;
		break;

	case ATTITUDE_PLEASED:
		iModifier += 150;
		break;

	case ATTITUDE_FRIENDLY:
		iModifier += 400;
		break;

	default:
		FAssert(false);
		break;
	}

	iValue *= std::max(0, (iModifier + 100));
	iValue /= 100;

	int iTheirPower = GET_TEAM(eTeam).getPower(true);
	int iWarTeamPower = GET_TEAM(eWarTeam).getPower(true);

	iValue *= 50 + ((100 * iWarTeamPower) / (iTheirPower + iWarTeamPower + 1));
	iValue /= 100;

	if (!(GET_TEAM(eTeam).AI_isAllyLandTarget(eWarTeam)))
	{
		iValue *= 2;
	}

	if (!isAtWar(eWarTeam))
	{
		iValue *= 3;
	}
	else
	{
		iValue *= 150;
		iValue /= 100 + ((50 * std::min(100, (100 * AI_getWarSuccess(eWarTeam)) / (8 + getTotalPopulation(false)))) / 100);
	}
	
	iValue += (GET_TEAM(eTeam).getNumCities() * 20);
	iValue += (GET_TEAM(eTeam).getTotalPopulation(true) * 15);
	
	if (isAtWar(eWarTeam))
	{
		switch (GET_TEAM(eTeam).AI_getAttitude(getID()))
		{
		case ATTITUDE_FURIOUS:
		case ATTITUDE_ANNOYED:
		case ATTITUDE_CAUTIOUS:
			iValue *= 100;
			break;

		case ATTITUDE_PLEASED:
			iValue *= std::max(75, 100 - getAtWarCount(true) * 10);
			break;

		case ATTITUDE_FRIENDLY:
			iValue *= std::max(50, 100 - getAtWarCount(true) * 20);
			break;

		default:
			FAssert(false);
			break;
		}
		iValue /= 100;
	}
	
	iValue += GET_TEAM(eWarTeam).getNumNukeUnits() * 250;//Don't want to get nuked
	iValue += GET_TEAM(eTeam).getNumNukeUnits() * 150;//Don't want to use nukes on another's behalf

	if (GET_TEAM(eWarTeam).getAtWarCount(false) == 0)
	{
		iValue *= 2;
	
		for (int iI = 0; iI < MAX_CIV_TEAMS; iI++)
		{
			if (GET_TEAM((TeamTypes)iI).isAlive())
			{
				if (iI != getID() && iI != eWarTeam && iI != eTeam)
				{
					if (GET_TEAM(eWarTeam).isDefensivePact((TeamTypes)iI))
					{
						iValue += (GET_TEAM((TeamTypes)iI).getNumCities() * 30);
						iValue += (GET_TEAM((TeamTypes)iI).getTotalPopulation(true) * 20);
					}
				}
			}
		}
	}

	iValue *= 60 + (140 * GC.getGameINLINE().getGameTurn()) / std::max(1, GC.getGameINLINE().getEstimateEndTurn());
	iValue /= 100;

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

	if (isHuman())
	{
		return std::max(iValue, GC.getDefineINT("DIPLOMACY_VALUE_REMAINDER"));
	}
	else
	{
		return iValue;
	}
}
This is a long one with a lot of IF statements

ivalue = ((targets city count * 10) + (targets total pop * 2)) * Attitude Modifier

Attitude modifier determined by what the bribed party thinks of the target
Furious = 1
Annoyed = 1.25
Cautious = 1.5
Pleased = 2.5
Friendly = 5

ivalue(2) takes power into account and whether target is a land target or not

ivalue(2) = 50 + ((100 * targets power) / ( targets power + bribed AIs power + 1))
IF target is landtarget then multiply all by 2.

The next part asks if the targets already at war, and if so who with

IF target isn't already at war
ivalue(3) = ivalue(2) * 3

IF it is at war then,
ivalue(3) = ivalue(2) * (150 / (100 + (50 * larger of 100 : 100 * targets war success) / (8 + world total pop))/100

Otherwise,
ivalue(3) = ivalue(2) + (bribed AIs city count * 20) + (bribed AIs pop * 15)


IF target is at war AND the bribed AIs opinion of the targets enemies is Pleased OR Friendy then
ivalue(4) = ivalue(3) * Attitude modifier
This time the attitude modifier is determined by what the bribed AI thinks of the targets war enemies. This just makes it cheaper to bribe to help friends.
Pleased = min of 75 : (100 - (turns at war * 10))
Friendly = min of 50 : (100 - (turns at war * 20))
Divide the relevant outcome by 100 to find the Attitude modifier

It isn't clear what happens if the target is at war with multiple enemies here, my guess is that if you have multiple it just multiplies all of them sequentially i.e. for 1 Pleased and one Friendly and minimums in use;
ivalue(4) = ivalue(3) * 0.5 * 0.75
Obviously will have to test this one


IF the target is not at war, or bribed AIs opinion of targets enemies is Cauious or lower then
ivalue(4) = ivalue(3)

Now some considerations for nukes
ivalue(5) = ivalue(4) + (targets nuke count * 250) + (bribed AIs nuke count * 150)
Until taking a fresh look at the DenialTypes I always thought it was impossible to bribe an AI into a war against a nuclear power under any circumstances.... but it is allowed if the nuclear power is already involved in a war.

IF the target isn't already at war and doesn't have a defensive pact
ivalue(6) = ivalue(5) * 2
IF target isn't at war AND has a defensive pact,
ivalue(6) = (ivalue(5) * 2) + (target teams city count * 30) + (targets total pop * 20)
This seems insane as even a 1 city vassal would call this up and seriously inflate the cost. Perhaps there is a potential positive impact from keeping a tiny vassal.... depending of course on how the AI-AI trades consider deals to be 'fair'.

Last bit finally
ivalue(7) = ivalue(6) * (60 + (140 * gameturn / minimum of 1 : EstimateEndTurn) / 100)
Unfortunately I don't yet know what the very last term means exactly :sad:. Added to todo list
Value is rounded down as usual, and while the mimimum cost is there, its not going to be possible to hit this :p
 
*waiting for testing*


CvPlayerAI::AI_religionTradeVal
This controls the cost of deals asking a party to change religions, which can only be bartered for if the AI is selling it, and only to the religion the human is running, the human can only be requested by AIs to change for free!

This function is a bit of a pain as it involves two functions,
CvPlayerAI::AI_bestReligion
CvPlayerAI::AI_religionValue


Both of which are also used in,
CvPlayerAI::AI_doReligion
which controls the whens and whats of changes in AI state religion.

First the final function
AI_religionTradeVal
Code:
int CvPlayerAI::AI_religionTradeVal(ReligionTypes eReligion, PlayerTypes ePlayer) const
{
	ReligionTypes eBestReligion;
	int iValue;

	iValue = (3 * (getTotalPopulation() + GET_PLAYER(ePlayer).getTotalPopulation())); // XXX

	eBestReligion = [COLOR="DarkOrange"]GET_PLAYER(ePlayer).AI_bestReligion()[/COLOR];

	if (eBestReligion != NO_RELIGION)
	{
		if (eBestReligion != eReligion)
		{
			iValue += std::max(0, (GET_PLAYER(ePlayer).AI_religionValue(eBestReligion) - [COLOR="DarkOrange"]GET_PLAYER(ePlayer).AI_religionValue(eReligion)))[/COLOR];
		}
	}

	if (GET_TEAM(GET_PLAYER(ePlayer).getTeam()).isVassal(getTeam()))
	{
		iValue /= 2;
	}

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

	if (isHuman())
	{
		return std::max(iValue, GC.getDefineINT("DIPLOMACY_VALUE_REMAINDER"));
	}
	else
	{
		return iValue;
	}
}
ivalue = 3 * (world total pop + offering civs total pop)

ivalue(2) = ivalue(1) + AI_religionVal of the offering civs best religion - AI_religionVal of proposed religion
Basically, add the value of the difference between the religions

IF offering civ is a vassal of buying civ then
AI_religionTradeVal = ivalue(2) / 2
IF not, then AI_religionTradeval = ivalue(2)


CvPlayerAI::AI_bestReligion
This just determines which of the 8 religions (including No State) is 'best'
It uses the AIs favourite religion which can be found in the leaderhead.xml file
Code:
ReligionTypes CvPlayerAI::AI_bestReligion() const
{
	ReligionTypes eBestReligion;
	int iValue;
	int iBestValue;
	int iI;

	iBestValue = 0;
	eBestReligion = NO_RELIGION;

	ReligionTypes eFavorite = (ReligionTypes)GC.getLeaderHeadInfo(getLeaderType()).getFavoriteReligion();

	for (iI = 0; iI < GC.getNumReligionInfos(); iI++)
	{
		if (canDoReligion((ReligionTypes)iI))
		{
			iValue = [COLOR="DarkOrange"]AI_religionValue((ReligionTypes)iI)[/COLOR];

			if (getStateReligion() == ((ReligionTypes)iI))
			{
				iValue *= 4;
				iValue /= 3;
			}

			if (eFavorite == iI)
			{
				iValue *= 5;
				iValue /= 4;
			}

			if (iValue > iBestValue)
			{
				iBestValue = iValue;
				eBestReligion = ((ReligionTypes)iI);
			}
		}
	}

	if ((NO_RELIGION == eBestReligion) || AI_isDoStrategy(AI_STRATEGY_MISSIONARY))
	{
		return eBestReligion;
	}
	
	int iBestCount = getHasReligionCount(eBestReligion);
	int iSpreadPercent = (iBestCount * 100) / std::max(1, getNumCities());
	int iPurityPercent = (iBestCount * 100) / std::max(1, countTotalHasReligion());
	if (iPurityPercent < 49)
	{
		if (iSpreadPercent > ((eBestReligion == eFavorite) ? 65 : 75))
		{
			if (iPurityPercent > ((eBestReligion == eFavorite) ? 25 : 32))
			{
				return eBestReligion;
			}
		}
		return NO_RELIGION;
	}
	
	return eBestReligion;
}
As default No State Religion starts as best

ivalue = religionValue

IF state religion then
ivalue(2) = ivalue * 4 / 3
IF not then ivalue(2) = ivalue

IF favourite religion
ivalue(3) = ivalue(2) * 5 / 4
IF not then ivalue(3) = ivalue(2)

Of note here is that the AIs favourite religion does have an impact, increasing the religions value by 25%,
and that there is a bias toward sticking in the current religion, increasing its value by 33%.
While we already know shrines and/holy cities have a massive impact that usually overwhelms these, it may well be worth considering for AIs that don't have holy cities!

It cycles through all available religions evaluating them all and then calls back the highest value as the AI_bestReligion

While you might expect that that wud be the end of it the AI calls up some weirdness.
Code:
	{
		return eBestReligion;
	}
	
	int iBestCount = getHasReligionCount(eBestReligion);
	int iSpreadPercent = (iBestCount * 100) / std::max(1, getNumCities());
	int iPurityPercent = (iBestCount * 100) / std::max(1, countTotalHasReligion())
IF the AI_bestReligion is No State Religion OR The AI is in the Missionary Strategy then, it considers two new value, ispreadpercent and ipuritypercent. This bit has me confused right now....

It uses the BestReligion gained earlier and,
Defines iBestCount as the number of cities with the BestReligion

iSpreadPercent is simply the percentage of the offering civs owned cities that have the bestReligion
iSpreadPurity I think this is the iBestCount / total nuber of religions in cities owned by the selling player.

Then theres this...
Code:
	if (iPurityPercent < 49)
	{
		if (iSpreadPercent > ((eBestReligion == eFavorite) ? 65 : 75))
		{
			if (iPurityPercent > ((eBestReligion == eFavorite) ? 25 : 32))
			{
				return eBestReligion;
			}
		}
		return NO_RELIGION;
	}
	
	return eBestReligion;
I'm going to have to throw my hands up here and say what the hell is that!?
The 65 OR 75 and 25 OR 32 values don't appear to have any purpose whatsoever :confused:
I would have though it would go through different religions to look for the best, but to me all this says is
BestReligion = BestReligion :confused:

But, IF the purity precent is less than 49% it goes through this, fortunatey all of this only happen if the AI is doing its Missionary Strategy OR No State Religion is AI_bestReligion

And the final part needed is how the AI put an initial value to religions,
AI_religionValue
Code:
int CvPlayerAI::AI_religionValue(ReligionTypes eReligion) const
{
	if (getHasReligionCount(eReligion) == 0)
	{
		return 0;
	}

	int iValue = GC.getGameINLINE().countReligionLevels(eReligion);

	int iLoop;
	CvCity* pLoopCity;
	for (pLoopCity = firstCity(&iLoop); pLoopCity != NULL; pLoopCity = nextCity(&iLoop))
	{
		if (pLoopCity->isHasReligion(eReligion))
		{
			iValue += pLoopCity->getPopulation();
		}
	}

	CvCity* pHolyCity = GC.getGameINLINE().getHolyCity(eReligion);
	if (pHolyCity != NULL)
	{
		bool bOurHolyCity = pHolyCity->getOwnerINLINE() == getID();
		bool bOurTeamHolyCity = pHolyCity->getTeam() == getTeam();

		if (bOurHolyCity || bOurTeamHolyCity)
	{
			int iCommerceCount = 0;

			for (int iI = 0; iI < GC.getNumBuildingInfos(); iI++)
		{
			if (pHolyCity->getNumActiveBuilding((BuildingTypes)iI) > 0)
			{
					for (int iJ = 0; iJ < NUM_COMMERCE_TYPES; iJ++)
				{
					if (GC.getBuildingInfo((BuildingTypes)iI).getGlobalReligionCommerce() == eReligion)
					{
						iCommerceCount += GC.getReligionInfo(eReligion).getGlobalReligionCommerce((CommerceTypes)iJ) * pHolyCity->getNumActiveBuilding((BuildingTypes)iI);
					}
				}
			}
		}

			if (bOurHolyCity)
		{
			iValue *= (3 + iCommerceCount);
			iValue /= 2;
		}
			else if (bOurTeamHolyCity)
		{
			iValue *= (4 + iCommerceCount);
			iValue /= 3;
		}
	}
	}

	return iValue;
}
It does this to get values for all religions, which are used in AI_bestReligion. If the civ doesn't have the religion in any city it gets a 0 at the first line and ends there.

This is actually pretty short, though i'm not 100% certain if the city count is only for the civs cities, or a global count though a quick test strongly suggested the former.

ivalue = (number of owned cities with religion + population in those cities) * Holy factor
The Holy factor depends on the civ, or one of its teammates owning the holy city, and how much shrine gold they are getting.

IF civs holy city,
Holy factor = (3 + shrine gold*2) / 2

IF teams holy city
Holy factor = (4 + shrine gold*2) / 3

This means that even without a shrine, a holy city does cause a significant bias, 3 / 2 fr own holy city and 4 / 3 for team.
 
*waiting for testing*

CvPlayerAI::AI_doReligion
Code:
void CvPlayerAI::AI_doReligion()
{
	ReligionTypes eBestReligion;

	FAssertMsg(!isHuman(), "isHuman did not return false as expected");

	if (AI_getReligionTimer() > 0)
	{
		AI_changeReligionTimer(-1);
		return;
	}

	if (!canChangeReligion())
	{
		return;
	}

	FAssertMsg(AI_getReligionTimer() == 0, "AI Religion timer is expected to be 0");

	eBestReligion = AI_bestReligion();

	if (eBestReligion == NO_RELIGION)
	{
		eBestReligion = getStateReligion();
	}

	if (canConvert(eBestReligion))
	{
		convert(eBestReligion);
		AI_setReligionTimer((getMaxAnarchyTurns() == 0) ? (GC.getDefineINT("MIN_CONVERSION_TURNS") * 2) : RELIGION_CHANGE_DELAY);
	}
}
All this really says is that an AI will swap to its best religion when a religion counter reaches zero.
The religion counter is set at the end of the function
AI_setReligionTimer((getMaxAnarchyTurns() == 0) ? (GC.getDefineINT("MIN_CONVERSION_TURNS") * 2) : RELIGION_CHANGE_DELAY);
Which means if Spiritual 10 turns, if not 15

Strangely there doesn't seem to be a AI_setReligionTimer reset that follows the trading of a religion change in CvPlayerAI.
It may be elsewhere, but I IRC the AI routinely swap back very quickly, so its likely it just doesn't happen.
 
CvTeamAI::AI_endWarVal
Spoiler :
Code:
int CvTeamAI::AI_endWarVal(TeamTypes eTeam) const
{
	int iValue;

	FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");
	FAssertMsg(isAtWar(eTeam), "Current AI Team instance is expected to be at war with eTeam");

	iValue = 100;

	iValue += (getNumCities() * 3);
	iValue += (GET_TEAM(eTeam).getNumCities() * 3);

	iValue += getTotalPopulation();
	iValue += GET_TEAM(eTeam).getTotalPopulation();

	iValue += (GET_TEAM(eTeam).AI_getWarSuccess(getID()) * 20);

	int iOurPower = std::max(1, getPower(true));
	int iTheirPower = std::max(1, GET_TEAM(eTeam).getDefensivePower());

	iValue *= iTheirPower + 10;
	iValue /= std::max(1, iOurPower + iTheirPower + 10);
	
	WarPlanTypes eWarPlan = AI_getWarPlan(eTeam);

	// if we not human, do we want to continue war for strategic reasons?
	// only check if our power is at least 120% of theirs
	if (!isHuman() && iOurPower > ((120 * iTheirPower) / 100))
	{
		bool bDagger = false;
		
		bool bAnyFinancialTrouble = false;
		for (int iI = 0; iI < MAX_PLAYERS; iI++)
		{
			if (GET_PLAYER((PlayerTypes)iI).isAlive())
			{
				if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
				{
					if (GET_PLAYER((PlayerTypes)iI).AI_isDoStrategy(AI_STRATEGY_DAGGER))
					{
						bDagger = true;
					}
					
					if (GET_PLAYER((PlayerTypes)iI).AI_isFinancialTrouble())
					{
						bAnyFinancialTrouble = true;
					}
				}
			}
		}
		
		// if dagger, value peace at 90% * power ratio
		if (bDagger)
		{
			iValue *= 9 * iTheirPower;
			iValue /= 10 * iOurPower;
		}
		
	    // for now, we will always do the land mass check for domination
		// if we have more than half the land, then value peace at 90% * land ratio 
		int iLandRatio = ((getTotalLand(true) * 100) / std::max(1, GET_TEAM(eTeam).getTotalLand(true)));
	    if (iLandRatio > 120)
	    {
			iValue *= 9 * 100;
			iValue /= 10 * iLandRatio;
	    }

		// if in financial trouble, warmongers will continue the fight to make more money
		if (bAnyFinancialTrouble)
		{
			switch (eWarPlan)
			{
				case WARPLAN_TOTAL:
					// if we total warmonger, value peace at 70% * power ratio factor
					if (bDagger || AI_maxWarRand() < 100)
					{
						iValue *= 7 * (5 * iTheirPower);
						iValue /= 10 * (iOurPower + (4 * iTheirPower));
					}
					break;

				case WARPLAN_LIMITED:
					// if we limited warmonger, value peace at 70% * power ratio factor
					if (AI_limitedWarRand() < 100)
					{
						iValue *= 7 * (5 * iTheirPower);
						iValue /= 10 * (iOurPower + (4 * iTheirPower));
					}
					break;

				case WARPLAN_DOGPILE:
					// if we dogpile warmonger, value peace at 70% * power ratio factor
					if (AI_dogpileWarRand() < 100)
					{
						iValue *= 7 * (5 * iTheirPower);
						iValue /= 10 * (iOurPower + (4 * iTheirPower));
					}
					break;

			}
		}
	}


	// XXX count units in enemy territory...

	if ((!(isHuman()) && (eWarPlan == WARPLAN_TOTAL)) ||
		  (!(GET_TEAM(eTeam).isHuman()) && (GET_TEAM(eTeam).AI_getWarPlan(getID()) == WARPLAN_TOTAL)))
	{
		iValue *= 2;
	}
	else if ((!(isHuman()) && (eWarPlan == WARPLAN_DOGPILE) && (GET_TEAM(eTeam).getAtWarCount(true) > 1)) ||
		       (!(GET_TEAM(eTeam).isHuman()) && (GET_TEAM(eTeam).AI_getWarPlan(getID()) == WARPLAN_DOGPILE) && (getAtWarCount(true) > 1)))
	{
		iValue *= 3;
		iValue /= 2;
	}

	if (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI))
	{
		int iOurEndangeredCities = 0;
		int iTheirEndangeredCities = 0;
		
		for (int iPlayer = 0; iPlayer < MAX_CIV_PLAYERS; iPlayer++)
		{
			CvPlayer& kPlayer = GET_PLAYER((PlayerTypes)iPlayer);
			
			if (kPlayer.getTeam() == eTeam)
			{
				int iLoop;
				CvCity* pTheirLoopCity;
				
				for (pTheirLoopCity = kPlayer.firstCity(&iLoop); pTheirLoopCity != NULL; pTheirLoopCity = kPlayer.nextCity(&iLoop))
				{
					if (pTheirLoopCity->AI_isDanger())
					{
						iTheirEndangeredCities++;
					}
				}
			}

			if (kPlayer.getTeam() == getID())
			{
				int iLoop;
				CvCity* pOurLoopCity;
				
				for (pOurLoopCity = kPlayer.firstCity(&iLoop); pOurLoopCity != NULL; pOurLoopCity = kPlayer.nextCity(&iLoop))
				{
					if (pOurLoopCity->AI_isDanger())
					{
						iOurEndangeredCities++;
					}
				}
			}
		}

		if (iTheirEndangeredCities > iOurEndangeredCities)
		{
			iValue /= 3;
		}
	}

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

	if (isHuman())
	{
		return std::max(iValue, GC.getDefineINT("DIPLOMACY_VALUE_REMAINDER"));
	}
	else
	{
		return iValue;
	}
}
This is made up of 3 parts, a base value, a modifier depending on AI war strategy which isn't used for the humans side (anti human bias!), and an endangered city check which is only made if the Aggresive AIs option is turned on. As an equation it'd be
Base * AIFactor * Aggfactor

To find the net value for who owes what to make peace you have to find the endwarval for both parties and subtract one from the other,

The code for what i've called the base value is found here
Code:
	iValue = 100;

	iValue += (getNumCities() * 3);
	iValue += (GET_TEAM(eTeam).getNumCities() * 3);

	iValue += getTotalPopulation();
	iValue += GET_TEAM(eTeam).getTotalPopulation();

	iValue += (GET_TEAM(eTeam).AI_getWarSuccess(getID()) * 20);

	int iOurPower = std::max(1, getPower(true));
	int iTheirPower = std::max(1, GET_TEAM(eTeam).getDefensivePower());

	iValue *= iTheirPower + 10;
	iValue /= std::max(1, iOurPower + iTheirPower + 10);
I'm writing this from the perspective of the buyer. In practice peace deals can only be offered by both teams at the same time, and only one team will be able to trade anything extra for it.
The cost of peace will depend on the difference in AI_endWarVal between both parties.

(100 + (our city count + their team city count) * 3 + (our total pop + their teams total pop) * 3 + 20 * their team war success) * (their power + 10) / (our team power + their team power + 10)

As this is pretty much the only factor involved when calculating human war success the main point of interest is the warsuccess bit, for each point of war success we get, the value increases by
20 * (their power + 10) / (our team power + their team power + 10).
While 20 per war success is the hypothetical max, its never going to be worth that much as its multpilied by the percentage of our power against the total power in play, which will always be less than 1. Also, war success is more valuable the more power you have.

The AIFactor doesn't make much sense in a lot of places to me....
Code:
	WarPlanTypes eWarPlan = AI_getWarPlan(eTeam);

	[COLOR="SandyBrown"]// if we not human, do we want to continue war for strategic reasons?
	// only check if our power is at least 120% of theirs
	if (!isHuman() && iOurPower > ((120 * iTheirPower) / 100))
	{
		bool bDagger = false;
		
		bool bAnyFinancialTrouble = false;
		for (int iI = 0; iI < MAX_PLAYERS; iI++)
		{
			if (GET_PLAYER((PlayerTypes)iI).isAlive())
			{
				if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
				{
					if (GET_PLAYER((PlayerTypes)iI).AI_isDoStrategy(AI_STRATEGY_DAGGER))
					{
						bDagger = true;
					}
					
					if (GET_PLAYER((PlayerTypes)iI).AI_isFinancialTrouble())
					{
						bAnyFinancialTrouble = true;
					}
				}
			}
		}[/COLOR]
		
		// if dagger, value peace at 90% * power ratio
		if (bDagger)
		{
			iValue *= 9 * iTheirPower;
			iValue /= 10 * iOurPower;
		}
		
	    // for now, we will always do the land mass check for domination
		// if we have more than half the land, then value peace at 90% * land ratio 
		int iLandRatio = ((getTotalLand(true) * 100) / std::max(1, GET_TEAM(eTeam).getTotalLand(true)));
	    if (iLandRatio > 120)
	    {
			iValue *= 9 * 100;
			iValue /= 10 * iLandRatio;
	    }

		// if in financial trouble, warmongers will continue the fight to make more money
		if (bAnyFinancialTrouble)
		{
			switch (eWarPlan)
			{
				case WARPLAN_TOTAL:
					// if we total warmonger, value peace at 70% * power ratio factor
					if (bDagger || AI_maxWarRand() < 100)
					{
						iValue *= 7 * (5 * iTheirPower);
						iValue /= 10 * (iOurPower + (4 * iTheirPower));
					}
					break;

				case WARPLAN_LIMITED:
					// if we limited warmonger, value peace at 70% * power ratio factor
					if (AI_limitedWarRand() < 100)
					{
						iValue *= 7 * (5 * iTheirPower);
						iValue /= 10 * (iOurPower + (4 * iTheirPower));
					}
					break;

				case WARPLAN_DOGPILE:
					// if we dogpile warmonger, value peace at 70% * power ratio factor
					if (AI_dogpileWarRand() < 100)
					{
						iValue *= 7 * (5 * iTheirPower);
						iValue /= 10 * (iOurPower + (4 * iTheirPower));
					}
					break;

			}
		}
	}


	// XXX count units in enemy territory...

	if ((!(isHuman()) && (eWarPlan == WARPLAN_TOTAL)) ||
		  (!(GET_TEAM(eTeam).isHuman()) && (GET_TEAM(eTeam).AI_getWarPlan(getID()) == WARPLAN_TOTAL)))
	{
		iValue *= 2;
	}
	else if ((!(isHuman()) && (eWarPlan == WARPLAN_DOGPILE) && (GET_TEAM(eTeam).getAtWarCount(true) > 1)) ||
		       (!(GET_TEAM(eTeam).isHuman()) && (GET_TEAM(eTeam).AI_getWarPlan(getID()) == WARPLAN_DOGPILE) && (getAtWarCount(true) > 1)))
	{
		iValue *= 3;
		iValue /= 2;
	}
The first part in brown looks out of place to me, If it really says what I think it does then I would have thought it would belong in DenialTypes,
IF our team power is 1.2 * their team power AND Dagger strategy OR in financial trouble then continue the war....

Otherwise
IF Dagger strat
0.9 * their power / our power

Then theres another bit that i'm going to have to look more deeply into, TotalLand.
// for now, we will always do the land mass check for domination
// if we have more than half the land, then value peace at 90% * land ratio
int iLandRatio = ((getTotalLand(true) * 100) / std::max(1, GET_TEAM(eTeam).getTotalLand(true)));
if (iLandRatio > 120)
{
iValue *= 9 * 100;
iValue /= 10 * iLandRatio;
I'd have thought that if they wanted to achieve what they set out in the // note lines then it would be easiest done if TotalLand was a simple tile count, and land ratio was
GlobalTotaLand / theirTotalLand, which IF > 50 would trigger some modified equation, but its obviously nothing like this....

To carry on, another confusing bit

IF in financial trouble
swap warplans?
The picks are random unless the AI started in Dagger, which forces it into TotalWar
Then, still IF Financial trouble
IF warplan is TotalWar OR LimitedWar OR Dogpile then,
* 0.7 * ((5 * their power) / (our power * (4 * their power)))


IF plan = Total War
*2

IF plan = Dogpile
*3 / 2
These last 2 bits are the probable cause of the seriously inflated values the AI has of how its doing in wars....

Last is the AggFactor which only applies if AggAI option is turned on
Code:
	if (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI))
	{
		int iOurEndangeredCities = 0;
		int iTheirEndangeredCities = 0;
		
		for (int iPlayer = 0; iPlayer < MAX_CIV_PLAYERS; iPlayer++)
		{
			CvPlayer& kPlayer = GET_PLAYER((PlayerTypes)iPlayer);
			
			if (kPlayer.getTeam() == eTeam)
			{
				int iLoop;
				CvCity* pTheirLoopCity;
				
				for (pTheirLoopCity = kPlayer.firstCity(&iLoop); pTheirLoopCity != NULL; pTheirLoopCity = kPlayer.nextCity(&iLoop))
				{
					if (pTheirLoopCity->AI_isDanger())
					{
						iTheirEndangeredCities++;
					}
				}
			}

			if (kPlayer.getTeam() == getID())
			{
				int iLoop;
				CvCity* pOurLoopCity;
				
				for (pOurLoopCity = kPlayer.firstCity(&iLoop); pOurLoopCity != NULL; pOurLoopCity = kPlayer.nextCity(&iLoop))
				{
					if (pOurLoopCity->AI_isDanger())
					{
						iOurEndangeredCities++;
					}
				}
			}
		}

		if (iTheirEndangeredCities > iOurEndangeredCities)
		{
			iValue /= 3;
		}
	}
It counts up the number of our and their cities that are in danger, and,
IF theres more of their cities in danger than ours then
AggFactor = / 3
Seems odd that this isn't considered in normal game rules too as having your cities under threat is a pretty good indication that your losing. Though I wouldn't be suprised if 'Endangered' means just one unit within 4 tiles or something....

After a quick look at how danger is determined it does seem like it could be abused to make huge war profits, or make peace very cheap, as it appears that any unit in moving range of a city will cause that city to be in danger......
 
Summary
Begging/Demanding
The value you can beg or deman increases over time and the equation is,
ivalue = (Turns you have known the civ + 50) * 2
IF landtarget then
ivalue(2) = ivalue*3

The final grant value = (ivalue(2) * givers power / beggars power) - total grants previously recieved.
If your not Pleased or Friendly it is considered a demand rather than a beg, which is automatically denied if ourpower * 4 / 3 < theirpower.

Resource Trade
Theres a special mention of resource type trades, where the amount the AI wants in return increase by 10% in renegotiations.

Vassal Tribute
Was covered here by Tachy, it may need a further looking to completely solve however.

CvPlayerAI::AI_considerOffer
Spoiler :
CvPlayerAI::AI_considerOffer
Code:
bool CvPlayerAI::AI_considerOffer(PlayerTypes ePlayer, const CLinkList<TradeData>* pTheirList, const CLinkList<TradeData>* pOurList, int iChange) const
{
	CLLNode<TradeData>* pNode;
	int iThreshold;

	FAssertMsg(ePlayer != getID(), "shouldn't call this function on ourselves");

	if (AI_goldDeal(pTheirList) && AI_goldDeal(pOurList))
	{
		return false;
	}

	if (iChange > -1)
	{
		for (pNode = pOurList->head(); pNode; pNode = pOurList->next(pNode))
		{
			if (getTradeDenial(ePlayer, pNode->m_data) != NO_DENIAL)
			{
				return false;
			}
		}
	}

	if (GET_PLAYER(ePlayer).getTeam() == getTeam())
	{
		return true;
	}

	if ((pOurList->getLength() == 0) && (pTheirList->getLength() > 0))
	{
		return true;
	}

	int iOurValue = GET_PLAYER(ePlayer).AI_dealVal(getID(), pOurList, false, iChange);
	int iTheirValue = AI_dealVal(ePlayer, pTheirList, false, iChange);

	if (iOurValue > 0 && 0 == pTheirList->getLength() && 0 == iTheirValue)
	{
		if (GET_TEAM(getTeam()).isVassal(GET_PLAYER(ePlayer).getTeam()) && CvDeal::isVassalTributeDeal(pOurList))
		{
			if (AI_getAttitude(ePlayer, false) <= GC.getLeaderHeadInfo(getPersonalityType()).getVassalRefuseAttitudeThreshold()
				&& GET_TEAM(getTeam()).getAtWarCount(true) == 0
				&& GET_TEAM(GET_PLAYER(ePlayer).getTeam()).getDefensivePactCount() == 0)
			{
				iOurValue *= (GET_TEAM(getTeam()).getPower(false) + 10);
				iOurValue /= (GET_TEAM(GET_PLAYER(ePlayer).getTeam()).getPower(false) + 10);
			}
			else
			{
				return true;
			}
		}
		else
		{
			if (AI_getAttitude(ePlayer) < ATTITUDE_PLEASED)
			{
				if (GET_TEAM(getTeam()).getPower(false) > ((GET_TEAM(GET_PLAYER(ePlayer).getTeam()).getPower(false) * 4) / 3))
				{
					return false;
				}
			}

			if (AI_getMemoryCount(ePlayer, MEMORY_MADE_DEMAND_RECENT) > 0)
			{
				return false;
			}
		}

		iThreshold = (GET_TEAM(getTeam()).AI_getHasMetCounter(GET_PLAYER(ePlayer).getTeam()) + 50);

		iThreshold *= 2;

		if (GET_TEAM(GET_PLAYER(ePlayer).getTeam()).AI_isLandTarget(getTeam()))
		{
			iThreshold *= 3;
		}

		iThreshold *= (GET_TEAM(GET_PLAYER(ePlayer).getTeam()).getPower(false) + 100);
		iThreshold /= (GET_TEAM(getTeam()).getPower(false) + 100);

		iThreshold -= GET_PLAYER(ePlayer).AI_getPeacetimeGrantValue(getID());

		return (iOurValue < iThreshold);
	}

	if (iChange < 0)
	{
		return (iTheirValue * 110 >= iOurValue * 100);
	}

	return (iTheirValue >= iOurValue);
}
First this checks if the trade is allowed and that the AIs aren't denying the trade for whatever reason (DenialTypes).

The acceptable values for trades are in here
if (iChange < 0)
{
return (iTheirValue * 110 >= iOurValue * 100);
}

return (iTheirValue >= iOurValue);
IF the iChange value is less than 0 then they expect 110% of what they offer, otherwise they want an equal or better trade from their perspective.
According to Tachys research, the 110% inflating factor applies when renewing resource trades, meaning they want more as time goes on.


In the case of begs and demands
Code:
	int iOurValue = GET_PLAYER(ePlayer).AI_dealVal(getID(), pOurList, false, iChange);
	int iTheirValue = AI_dealVal(ePlayer, pTheirList, false, iChange);

	if (iOurValue > 0 && 0 == pTheirList->getLength() && 0 == iTheirValue)
	{
		if (GET_TEAM(getTeam()).isVassal(GET_PLAYER(ePlayer).getTeam()) && CvDeal::isVassalTributeDeal(pOurList))
		{
			if (AI_getAttitude(ePlayer, false) <= GC.getLeaderHeadInfo(getPersonalityType()).getVassalRefuseAttitudeThreshold()
				&& GET_TEAM(getTeam()).getAtWarCount(true) == 0
				&& GET_TEAM(GET_PLAYER(ePlayer).getTeam()).getDefensivePactCount() == 0)
			{
				iOurValue *= (GET_TEAM(getTeam()).getPower(false) + 10);
				iOurValue /= (GET_TEAM(GET_PLAYER(ePlayer).getTeam()).getPower(false) + 10);
			}
			else
			{
				return true;
			}
		}
		else
		{
			if (AI_getAttitude(ePlayer) < ATTITUDE_PLEASED)
			{
				if (GET_TEAM(getTeam()).getPower(false) > ((GET_TEAM(GET_PLAYER(ePlayer).getTeam()).getPower(false) * 4) / 3))
				{
					return false;
				}
			}

			if (AI_getMemoryCount(ePlayer, MEMORY_MADE_DEMAND_RECENT) > 0)
			{
				return false;
			}
		}

		iThreshold = (GET_TEAM(getTeam()).AI_getHasMetCounter(GET_PLAYER(ePlayer).getTeam()) + 50);

		iThreshold *= 2;

		if (GET_TEAM(GET_PLAYER(ePlayer).getTeam()).AI_isLandTarget(getTeam()))
		{
			iThreshold *= 3;
		}

		iThreshold *= (GET_TEAM(GET_PLAYER(ePlayer).getTeam()).getPower(false) + 100);
		iThreshold /= (GET_TEAM(getTeam()).getPower(false) + 100);

		iThreshold -= GET_PLAYER(ePlayer).AI_getPeacetimeGrantValue(getID());

		return (iOurValue < iThreshold);
A value for allowable gbegs/demands (grants) is generated,

ivalue = (Turns you have known the civ + 50) * 2
IF landtarget then
ivalue(2) = ivalue*3

The final grant value = (ivalue(2) * givers power / beggars power) - total grants previously recieved.


Its common knowledge but if pleased or better then its a beg, and the only refusal conditions are not exceeding the iThreshold value, and the AI not remembering the last request.

Demands, when cautious or below however, need to meet those two conditions, AND are automatically turned down IF
Their power > 4 / 3 * our power

And theres another bit within that,
Code:
if (GET_TEAM(getTeam()).isVassal(GET_PLAYER(ePlayer).getTeam()) && CvDeal::isVassalTributeDeal(pOurList))
		{
			if (AI_getAttitude(ePlayer, false) <= GC.getLeaderHeadInfo(getPersonalityType()).getVassalRefuseAttitudeThreshold()
				&& GET_TEAM(getTeam()).getAtWarCount(true) == 0
				&& GET_TEAM(GET_PLAYER(ePlayer).getTeam()).getDefensivePactCount() == 0)
			{
				iOurValue *= (GET_TEAM(getTeam()).getPower(false) + 10);
				iOurValue /= (GET_TEAM(GET_PLAYER(ePlayer).getTeam()).getPower(false) + 10);
			}
			else
			{
				return true;
Has been covered by Tachy, and tells us that;
Tachywaxon said:
if you have at least one defensive pact, or have better relationship than <VassalRefuseAttitudeThreshold> , then resources are always granted!!!!
and that otherwise it gets treated like other begs with power scaling.
 
CvPlayerAI::AI_stopTradingTradeVal
Spoiler :
Code:
int CvPlayerAI::AI_stopTradingTradeVal(TeamTypes eTradeTeam, PlayerTypes ePlayer) const
{
	CvDeal* pLoopDeal;
	int iModifier;
	int iValue;
	int iLoop;

	FAssertMsg(ePlayer != getID(), "shouldn't call this function on ourselves");
	FAssertMsg(GET_PLAYER(ePlayer).getTeam() != getTeam(), "shouldn't call this function on ourselves");
	FAssertMsg(eTradeTeam != getTeam(), "shouldn't call this function on ourselves");
	FAssertMsg(GET_TEAM(eTradeTeam).isAlive(), "GET_TEAM(eWarTeam).isAlive is expected to be true");
	FAssertMsg(!atWar(eTradeTeam, GET_PLAYER(ePlayer).getTeam()), "eTeam should be at peace with eWarTeam");

	iValue = (50 + (GC.getGameINLINE().getGameTurn() / 2));
	iValue += (GET_TEAM(eTradeTeam).getNumCities() * 5);

	iModifier = 0;

	switch (GET_TEAM(GET_PLAYER(ePlayer).getTeam()).AI_getAttitude(eTradeTeam))
	{
	case ATTITUDE_FURIOUS:
		break;

	case ATTITUDE_ANNOYED:
		iModifier += 25;
		break;

	case ATTITUDE_CAUTIOUS:
		iModifier += 50;
		break;

	case ATTITUDE_PLEASED:
		iModifier += 100;
		break;

	case ATTITUDE_FRIENDLY:
		iModifier += 200;
		break;

	default:
		FAssert(false);
		break;
	}

	iValue *= std::max(0, (iModifier + 100));
	iValue /= 100;

	if (GET_TEAM(GET_PLAYER(ePlayer).getTeam()).isOpenBorders(eTradeTeam))
	{
		iValue *= 2;
	}

	if (GET_TEAM(GET_PLAYER(ePlayer).getTeam()).isDefensivePact(eTradeTeam))
	{
		iValue *= 3;
	}

	for(pLoopDeal = GC.getGameINLINE().firstDeal(&iLoop); pLoopDeal != NULL; pLoopDeal = GC.getGameINLINE().nextDeal(&iLoop))
	{
		if (pLoopDeal->isCancelable(getID()) && !(pLoopDeal->isPeaceDeal()))
		{
			if (GET_PLAYER(pLoopDeal->getFirstPlayer()).getTeam() == GET_PLAYER(ePlayer).getTeam())
			{
				if (pLoopDeal->getLengthSecondTrades() > 0)
				{
					iValue += (GET_PLAYER(pLoopDeal->getFirstPlayer()).AI_dealVal(pLoopDeal->getSecondPlayer(), pLoopDeal->getSecondTrades()) * ((pLoopDeal->getLengthFirstTrades() == 0) ? 2 : 1));
				}
			}

			if (GET_PLAYER(pLoopDeal->getSecondPlayer()).getTeam() == GET_PLAYER(ePlayer).getTeam())
			{
				if (pLoopDeal->getLengthFirstTrades() > 0)
				{
					iValue += (GET_PLAYER(pLoopDeal->getSecondPlayer()).AI_dealVal(pLoopDeal->getFirstPlayer(), pLoopDeal->getFirstTrades()) * ((pLoopDeal->getLengthSecondTrades() == 0) ? 2 : 1));
				}
			}
		}
	}

	if (GET_TEAM(GET_PLAYER(ePlayer).getTeam()).isVassal(getTeam()))
	{
		iValue /= 2;
	}

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

	if (isHuman())
	{
		return std::max(iValue, GC.getDefineINT("DIPLOMACY_VALUE_REMAINDER"));
	}
	else
	{
		return iValue;
	}
}
First bit
Code:
	iValue = (50 + (GC.getGameINLINE().getGameTurn() / 2));
	iValue += (GET_TEAM(eTradeTeam).getNumCities() * 5);

	iModifier = 0;

	switch (GET_TEAM(GET_PLAYER(ePlayer).getTeam()).AI_getAttitude(eTradeTeam))
	{
	case ATTITUDE_FURIOUS:
		break;

	case ATTITUDE_ANNOYED:
		iModifier += 25;
		break;

	case ATTITUDE_CAUTIOUS:
		iModifier += 50;
		break;

	case ATTITUDE_PLEASED:
		iModifier += 100;
		break;

	case ATTITUDE_FRIENDLY:
		iModifier += 200;
		break;

	default:
		FAssert(false);
		break;
	}

	iValue *= std::max(0, (iModifier + 100));
	iValue /= 100;
	
        if (GET_TEAM(GET_PLAYER(ePlayer).getTeam()).isOpenBorders(eTradeTeam))
	{
		iValue *= 2;
	}

	if (GET_TEAM(GET_PLAYER(ePlayer).getTeam()).isDefensivePact(eTradeTeam))
	{
		iValue *= 3;
From buyers (our) perspective buying from an AI (them/their) against another (target)

50 + (gameturn / 2) + their cities * 5 * Attitude Modifier * OBf * DPf
The Attitude Modifier depends on what they think of the target
Furious = 1
Annoyed = 1.25
Cautious = 1.5
Pleased = 2
Friendly = 3

OBf is
IF they have Open Border with target then 2, otherwise 1

DPf is
IF they have a Defensive packed with target then 3, otherwise 1
We'll call the current value, ivalue


Next block
Code:
for(pLoopDeal = GC.getGameINLINE().firstDeal(&iLoop); pLoopDeal != NULL; pLoopDeal = GC.getGameINLINE().nextDeal(&iLoop))
	{
		if (pLoopDeal->isCancelable(getID()) && !(pLoopDeal->isPeaceDeal()))
		{
			if (GET_PLAYER(pLoopDeal->getFirstPlayer()).getTeam() == GET_PLAYER(ePlayer).getTeam())
			{
				if (pLoopDeal->getLengthSecondTrades() > 0)
				{
					iValue += (GET_PLAYER(pLoopDeal->getFirstPlayer()).AI_dealVal(pLoopDeal->getSecondPlayer(), pLoopDeal->getSecondTrades()) * ((pLoopDeal->getLengthFirstTrades() == 0) ? 2 : 1));
				}
			}

			if (GET_PLAYER(pLoopDeal->getSecondPlayer()).getTeam() == GET_PLAYER(ePlayer).getTeam())
			{
				if (pLoopDeal->getLengthFirstTrades() > 0)
				{
					iValue += (GET_PLAYER(pLoopDeal->getSecondPlayer()).AI_dealVal(pLoopDeal->getFirstPlayer(), pLoopDeal->getFirstTrades()) * ((pLoopDeal->getLengthSecondTrades() == 0) ? 2 : 1));
				}
			}
		}
	}

	if (GET_TEAM(GET_PLAYER(ePlayer).getTeam()).isVassal(getTeam()))
	{
		iValue /= 2;
	}
Most of this is involved in the values of existing trade deals which I can't fully decipher yet so i'll just call them V1 and V2, so now its,
iValue +V1 + V2

IF they are our vassal then
(iValue +V1 + V2) / 2
Then round down to nearest 10



Still a fair few bits and pieces to fix and add, the two remaining untouched functions
AI_bonusTradeVal
AI_civicTradeVal

are long and horrible....
I'll probably go for the civics first as for the most part its a summation of a long series of mostly simple factors, a number of which aren't used in the vanilla game. It might be best in terms of usability and sanity to break it up to calculations for the individual civics
 
*under construction*

The initial function isn't too bad, nor is the bestCivic function it calls, but civicVal is a monster that calls up even more nasties. I'm going to break this into a few chunks, for now the plan is that the first post will cover
AI_civicTradeVal
AI_bestCivic
and set the stage for what needs to be done in
AI_civicVal
Including its code and some of the other functions it calls up,
AI_Happinessweight
AI_Healthweight
AI_Commerceweight


And from there link to posts containing the different civic groups, Government, Legal, Labour, Economic, Religion. It'll be better for comparison this way, and easier to actually do but it will stop it being immediately useful in many mods.

Its likely that even more will be called up, and even without more to add, these alone may take up enough space to justify a second post just for them.....
AI_doCivics has to go somewhere too.

CvPlayerAI::AI_civicTradeVal
Code:
int CvPlayerAI::AI_civicTradeVal(CivicTypes eCivic, PlayerTypes ePlayer) const
{
	CivicTypes eBestCivic;
	int iValue;

	iValue = (2 * (getTotalPopulation() + GET_PLAYER(ePlayer).getTotalPopulation())); // XXX

	eBestCivic = GET_PLAYER(ePlayer).AI_bestCivic((CivicOptionTypes)(GC.getCivicInfo(eCivic).getCivicOptionType()));

	if (eBestCivic != NO_CIVIC)
	{
		if (eBestCivic != eCivic)
		{
			iValue += std::max(0, ((GET_PLAYER(ePlayer).AI_civicValue(eBestCivic) - GET_PLAYER(ePlayer).AI_civicValue(eCivic)) * 2));
		}
	}

	if (GET_TEAM(GET_PLAYER(ePlayer).getTeam()).isVassal(getTeam()))
	{
		iValue /= 2;
	}

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

	if (isHuman())
	{
		return std::max(iValue, GC.getDefineINT("DIPLOMACY_VALUE_REMAINDER"));
	}
	else
	{
		return iValue;
	}
}
2 * (their pop + our pop) + (AI_civicValue of bestCivic - AI_civicValue of proposed civic * 2)
Value gets halved if its a vassal changing civics for its master
Rounded down to nearest 10.
IF a human is buying from an AI a minimum value of 10 is applied.


Code:
CivicTypes CvPlayerAI::AI_bestCivic(CivicOptionTypes eCivicOption) const
{
	CivicTypes eBestCivic;
	int iValue;
	int iBestValue;
	int iI;

	iBestValue = MIN_INT;
	eBestCivic = NO_CIVIC;

	for (iI = 0; iI < GC.getNumCivicInfos(); iI++)
	{
		if (GC.getCivicInfo((CivicTypes)iI).getCivicOptionType() == eCivicOption)
		{
			if (canDoCivics((CivicTypes)iI))
			{
				iValue = AI_civicValue((CivicTypes)iI);

				if (isCivic((CivicTypes)iI))
				{
					if (getMaxAnarchyTurns() > 0)
					{
						iValue *= 6;
						iValue /= 5;
					}
					else
					{
						iValue *= 16;
						iValue /= 15;
					}
				}

				if (iValue > iBestValue)
				{
					iBestValue = iValue;
					eBestCivic = ((CivicTypes)iI);
				}
			}
		}
	}

	return eBestCivic;
}
Determination of which Civic is best.
Unlike AI_bestReligion this does take account of Spiritual, and doesn't take account of favourite civics which is suprising.

The only thing this function does is give inertia to current civics, probably to prevent the AI jumping back and forth repeatedly
IF current civic AND IF Spiritual
AI_civicvalue * 6 / 5

IF not Spiritual
AI_civicvalue * 15 / 16
Highest value becomes eBestCivic

Now comes the bit where things start getting nasty.
In the spoilers is the entirity of AI_civicValue, as mentioned above theres no point in attacking it all at once, especially as more than 95% of it is irrelevant for any individual civic, and more than half of it is irrelevant in vanilla.
Spoiler :
Code:
int CvPlayerAI::AI_civicValue(CivicTypes eCivic) const
{
	PROFILE_FUNC();

	bool bWarPlan;
	int iConnectedForeignCities;
	int iTotalReligonCount;
	int iHighestReligionCount;
	int iWarmongerPercent;
	int iHappiness;
	int iValue;
	int iTempValue;
	int iI, iJ;

	bool bCultureVictory3 = AI_isDoStrategy(AI_STRATEGY_CULTURE3);
	bool bCultureVictory2 = AI_isDoStrategy(AI_STRATEGY_CULTURE2);

	FAssertMsg(eCivic < GC.getNumCivicInfos(), "eCivic is expected to be within maximum bounds (invalid Index)");
	FAssertMsg(eCivic >= 0, "eCivic is expected to be non-negative (invalid Index)");

	CvCivicInfo& kCivic = GC.getCivicInfo(eCivic);

	bWarPlan = (GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0);

	iConnectedForeignCities = countPotentialForeignTradeCitiesConnected();
	iTotalReligonCount = countTotalHasReligion();
	ReligionTypes eBestReligion = AI_bestReligion();
	if (eBestReligion == NO_RELIGION)
	{
		eBestReligion = getStateReligion();
	}
	iHighestReligionCount = ((eBestReligion == NO_RELIGION) ? 0 : getHasReligionCount(eBestReligion));
	iWarmongerPercent = 25000 / std::max(100, (100 + GC.getLeaderHeadInfo(getPersonalityType()).getMaxWarRand())); 

	iValue = (getNumCities() * 6);

	iValue += (GC.getCivicInfo(eCivic).getAIWeight() * getNumCities());

	iValue += (getCivicPercentAnger(eCivic) / 10);

	iValue += -(GC.getCivicInfo(eCivic).getAnarchyLength() * getNumCities());

	iValue += -(getSingleCivicUpkeep(eCivic, true));

	iValue += ((kCivic.getGreatPeopleRateModifier() * getNumCities()) / 10);
	iValue += ((kCivic.getGreatGeneralRateModifier() * getNumMilitaryUnits()) / 50);
	iValue += ((kCivic.getDomesticGreatGeneralRateModifier() * getNumMilitaryUnits()) / 100);
	iValue += -((kCivic.getDistanceMaintenanceModifier() * std::max(0, (getNumCities() - 3))) / 8);
	iValue += -((kCivic.getNumCitiesMaintenanceModifier() * std::max(0, (getNumCities() - 3))) / 8);
	iValue += (kCivic.getFreeExperience() * getNumCities() * (bWarPlan ? 8 : 5) * iWarmongerPercent) / 100; 
	iValue += ((kCivic.getWorkerSpeedModifier() * AI_getNumAIUnits(UNITAI_WORKER)) / 15);
	iValue += ((kCivic.getImprovementUpgradeRateModifier() * getNumCities()) / 50);
	iValue += (kCivic.getMilitaryProductionModifier() * getNumCities() * iWarmongerPercent) / (bWarPlan ? 300 : 500 ); 
	iValue += (kCivic.getBaseFreeUnits() / 2);
	iValue += (kCivic.getBaseFreeMilitaryUnits() / 3);
	iValue += ((kCivic.getFreeUnitsPopulationPercent() * getTotalPopulation()) / 200);
	iValue += ((kCivic.getFreeMilitaryUnitsPopulationPercent() * getTotalPopulation()) / 300);
	iValue += -(kCivic.getGoldPerUnit() * getNumUnits());
	iValue += -(kCivic.getGoldPerMilitaryUnit() * getNumMilitaryUnits() * iWarmongerPercent) / 200;

	//iValue += ((kCivic.isMilitaryFoodProduction()) ? 0 : 0);
	iValue += (getWorldSizeMaxConscript(eCivic) * ((bWarPlan) ? (20 + getNumCities()) : ((8 + getNumCities()) / 2)));
	iValue += ((kCivic.isNoUnhealthyPopulation()) ? (getTotalPopulation() / 3) : 0);
	if (bWarPlan)
	{
		iValue += ((kCivic.getExpInBorderModifier() * getNumMilitaryUnits()) / 200);
	}
	iValue += ((kCivic.isBuildingOnlyHealthy()) ? (getNumCities() * 3) : 0);
	iValue += -((kCivic.getWarWearinessModifier() * getNumCities()) / ((bWarPlan) ? 10 : 50));
	iValue += (kCivic.getFreeSpecialist() * getNumCities() * 12);
	iValue += ((kCivic.getTradeRoutes() * std::max(0, iConnectedForeignCities - getNumCities() * 3) * 6) + (getNumCities() * 2)); 
	iValue += -((kCivic.isNoForeignTrade()) ? (iConnectedForeignCities * 3) : 0);
	if (kCivic.isNoCorporations())
	{
		iValue -= countHeadquarters() * (40 + 3 * getNumCities());
	}
	if (kCivic.isNoForeignCorporations())
	{
		for (int iCorp = 0; iCorp < GC.getNumCorporationInfos(); ++iCorp)
		{
			if (!GET_TEAM(getTeam()).hasHeadquarters((CorporationTypes)iCorp))
			{
				iValue += countCorporations((CorporationTypes)iCorp) * 3;
			}
		}
	}
	if (kCivic.getCorporationMaintenanceModifier() != 0)
	{
		int iCorpCount = 0;
		int iHQCount = 0;
		for (int iCorp = 0; iCorp < GC.getNumCorporationInfos(); ++iCorp)
		{
			if (GET_TEAM(getTeam()).hasHeadquarters((CorporationTypes)iCorp))
			{
				iHQCount++;
			}
			iCorpCount += countCorporations((CorporationTypes)iCorp);
		}
		iValue += (-kCivic.getCorporationMaintenanceModifier() * (iHQCount * (25 + getNumCities() * 2) + iCorpCount * 7)) / 25;

	}

	if (kCivic.getCivicPercentAnger() != 0)
	{
		int iNumOtherCities = GC.getGameINLINE().getNumCities() - getNumCities();
		iValue += (30 * getNumCities() * getCivicPercentAnger(eCivic, true)) / kCivic.getCivicPercentAnger();
		
		int iTargetGameTurn = 2 * getNumCities() * GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getGrowthPercent();
		iTargetGameTurn /= GC.getGame().countCivPlayersEverAlive();
		iTargetGameTurn += GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getGrowthPercent() * 30;
		
		iTargetGameTurn /= 100;
		iTargetGameTurn = std::max(10, iTargetGameTurn);
		
		int iElapsedTurns = GC.getGame().getElapsedGameTurns();

		if (iElapsedTurns > iTargetGameTurn)
		{
			iValue += (std::min(iTargetGameTurn, iElapsedTurns - iTargetGameTurn) * (iNumOtherCities * kCivic.getCivicPercentAnger())) / (15 * iTargetGameTurn);
		}
	}

	if (kCivic.getExtraHealth() != 0)
	{
		iValue += (getNumCities() * 6 * AI_getHealthWeight(isCivic(eCivic) ? -kCivic.getExtraHealth() : kCivic.getExtraHealth(), 1)) / 100;
	}
			
	iTempValue = kCivic.getHappyPerMilitaryUnit() * 3;
	if (iTempValue != 0)
	{
		iValue += (getNumCities() * 9 * AI_getHappinessWeight(isCivic(eCivic) ? -iTempValue : iTempValue, 1)) / 100;
	}
		
	iTempValue = kCivic.getLargestCityHappiness();
	if (iTempValue != 0)
	{
		iValue += (12 * std::min(getNumCities(), GC.getWorldInfo(GC.getMapINLINE().getWorldSize()).getTargetNumCities()) * AI_getHappinessWeight(isCivic(eCivic) ? -iTempValue : iTempValue, 1)) / 100;
	}
	
	if (kCivic.getWarWearinessModifier() != 0)
	{
		int iAngerPercent = getWarWearinessPercentAnger();
		int iPopulation = 3 + (getTotalPopulation() / std::max(1, getNumCities()));

		int iTempValue = (-kCivic.getWarWearinessModifier() * iAngerPercent * iPopulation) / (GC.getPERCENT_ANGER_DIVISOR() * 100);
		if (iTempValue != 0)
		{
			iValue += (11 * getNumCities() * AI_getHappinessWeight(isCivic(eCivic) ? -iTempValue : iTempValue, 1)) / 100;
		}
	}
	
	iValue += (kCivic.getNonStateReligionHappiness() * (iTotalReligonCount - iHighestReligionCount) * 5);

	if (kCivic.isStateReligion())
	{
		if (iHighestReligionCount > 0)
		{
			iValue += iHighestReligionCount;

			iValue += ((kCivic.isNoNonStateReligionSpread()) ? ((getNumCities() - iHighestReligionCount) * 2) : 0);
			iValue += (kCivic.getStateReligionHappiness() * iHighestReligionCount * 4);
			iValue += ((kCivic.getStateReligionGreatPeopleRateModifier() * iHighestReligionCount) / 20);
			iValue += (kCivic.getStateReligionGreatPeopleRateModifier() / 4);
			iValue += ((kCivic.getStateReligionUnitProductionModifier() * iHighestReligionCount) / 4);
			iValue += ((kCivic.getStateReligionBuildingProductionModifier() * iHighestReligionCount) / 3);
			iValue += (kCivic.getStateReligionFreeExperience() * iHighestReligionCount * ((bWarPlan) ? 6 : 2));
		}
	}

	for (iI = 0; iI < NUM_YIELD_TYPES; iI++)
	{
		iTempValue = 0;

		iTempValue += ((kCivic.getYieldModifier(iI) * getNumCities()) / 2);
		iTempValue += ((kCivic.getCapitalYieldModifier(iI) * 3) / 4);
		CvCity* pCapital = getCapitalCity(); 
		if (pCapital) 
		{
			iTempValue += ((kCivic.getCapitalYieldModifier(iI) * pCapital->getBaseYieldRate((YieldTypes)iI)) / 80); 
		}
		iTempValue += ((kCivic.getTradeYieldModifier(iI) * getNumCities()) / 11);

		for (iJ = 0; iJ < GC.getNumImprovementInfos(); iJ++)
		{
			iTempValue += (AI_averageYieldMultiplier((YieldTypes)iI) * (kCivic.getImprovementYieldChanges(iJ, iI) * (getImprovementCount((ImprovementTypes)iJ) + getNumCities() * 2))) / 100;
		}

		if (iI == YIELD_FOOD) 
		{ 
			iTempValue *= 3; 
		} 
		else if (iI == YIELD_PRODUCTION) 
		{ 
			iTempValue *= ((AI_avoidScience()) ? 6 : 2); 
		} 
		else if (iI == YIELD_COMMERCE) 
		{ 
			iTempValue *= ((AI_avoidScience()) ? 1 : 2); 
		} 

		iValue += iTempValue;
	}

	for (iI = 0; iI < NUM_COMMERCE_TYPES; iI++)
	{
		iTempValue = 0;

		iTempValue += ((kCivic.getCommerceModifier(iI) * getNumCities()) / 3);
		iTempValue += (kCivic.getCapitalCommerceModifier(iI) / 2);
		if (iI == COMMERCE_ESPIONAGE)
		{
			iTempValue *= AI_getEspionageWeight();
			iTempValue /= 500;
		}
		iTempValue += ((kCivic.getSpecialistExtraCommerce(iI) * getTotalPopulation()) / 15);

		iTempValue *= AI_commerceWeight((CommerceTypes)iI);

		if ((iI == COMMERCE_CULTURE) && bCultureVictory2)
		{
		    iTempValue *= 2;
		    if (bCultureVictory3)
		    {
		        iTempValue *= 2;		        
		    }
		}
		iTempValue /= 100;

		iValue += iTempValue;
	}

	for (iI = 0; iI < GC.getNumBuildingClassInfos(); iI++)
	{
		if (kCivic.getBuildingHappinessChanges(iI) != 0)
		{
			iValue += (kCivic.getBuildingHappinessChanges(iI) * getBuildingClassCount((BuildingClassTypes)iI) * 3);
		}
	}

	for (iI = 0; iI < GC.getNumFeatureInfos(); iI++)
	{
		iHappiness = kCivic.getFeatureHappinessChanges(iI);

		if (iHappiness != 0)
		{
			iValue += (iHappiness * countCityFeatures((FeatureTypes)iI) * 5);
		}
	}

	for (iI = 0; iI < GC.getNumHurryInfos(); iI++)
	{
		if (kCivic.isHurry(iI))
		{
			iTempValue = 0;

			if (GC.getHurryInfo((HurryTypes)iI).getGoldPerProduction() > 0)
			{
				iTempValue += ((((AI_avoidScience()) ? 50 : 25) * getNumCities()) / GC.getHurryInfo((HurryTypes)iI).getGoldPerProduction());
			}
			iTempValue += (GC.getHurryInfo((HurryTypes)iI).getProductionPerPopulation() * getNumCities() * (bWarPlan ? 2 : 1)) / 5;
			iValue += iTempValue;
		}
	}

	for (iI = 0; iI < GC.getNumSpecialBuildingInfos(); iI++)
	{
		if (kCivic.isSpecialBuildingNotRequired(iI))
		{
			iValue += ((getNumCities() / 2) + 1); // XXX
		}
	}

	for (iI = 0; iI < GC.getNumSpecialistInfos(); iI++) 
	{ 
		iTempValue = 0; 
		if (kCivic.isSpecialistValid(iI)) 
		{ 
			iTempValue += ((getNumCities() *  (bCultureVictory3 ? 10 : 1)) + 6);
		} 
		iValue += (iTempValue / 2); 
	} 

	if (GC.getLeaderHeadInfo(getPersonalityType()).getFavoriteCivic() == eCivic)
	{
		if (!kCivic.isStateReligion() || iHighestReligionCount > 0)
		{
			iValue *= 5; 
			iValue /= 4; 
			iValue += 6 * getNumCities();
			iValue += 20; 
		}
	}

	if (AI_isDoStrategy(AI_STRATEGY_CULTURE2) && (GC.getCivicInfo(eCivic).isNoNonStateReligionSpread()))
	{
	    iValue /= 10;	    
	}

	return iValue;
}
Further functions are called up in it that have importance

AI_getHappinessWeight for civics involving happiness changes
Code:
int CvPlayerAI::AI_getHappinessWeight(int iHappy, int iExtraPop) const
{
	int iWorstHappy = 0;
	int iBestHappy = 0;
	int iTotalUnhappy = 0;
	int iTotalHappy = 0;
	int iLoop;
	CvCity* pLoopCity;
	int iCount = 0;
	
	if (0 == iHappy)
	{
		iHappy = 1;
	}
	int iValue = 0;
	for (pLoopCity = firstCity(&iLoop); pLoopCity != NULL; pLoopCity = nextCity(&iLoop))
	{
		int iCityHappy = pLoopCity->happyLevel() - pLoopCity->unhappyLevel(iExtraPop);
		
		iCityHappy -= std::max(0, pLoopCity->getCommerceHappiness());
		int iHappyNow = iCityHappy;
		int iHappyThen = iCityHappy + iHappy;
		
		//Integration
		int iTempValue = (((100 * iHappyThen - 10 * iHappyThen * iHappyThen)) - (100 * iHappyNow - 10 * iHappyNow * iHappyNow));
		if (iHappy > 0)
		{
			iValue += std::max(0, iTempValue);
		}
		else
		{
			iValue += std::max(0, -iTempValue);
		}
		
		iCount++;
		if (iCount > 6)
		{
			break;
		}
	}
	
	return (0 == iCount) ? 50 * iHappy : iValue / iCount;
}


AI_getHealthweight for civics involving heath changes
Code:
int CvPlayerAI::AI_getHealthWeight(int iHealth, int iExtraPop) const
{
	int iWorstHealth = 0;
	int iBestHealth = 0;
	int iTotalUnhappy = 0;
	int iTotalHealth = 0;
	int iLoop;
	CvCity* pLoopCity;
	int iCount = 0;
	
	if (0 == iHealth)
	{
		iHealth = 1;
	}
	int iValue = 0;
	for (pLoopCity = firstCity(&iLoop); pLoopCity != NULL; pLoopCity = nextCity(&iLoop))
	{
		int iCityHealth = pLoopCity->goodHealth() - pLoopCity->badHealth(false, iExtraPop);
		
		int iHealthNow = iCityHealth;
		int iHealthThen = iCityHealth + iHealth;
		
		//Integration
		int iTempValue = (((100 * iHealthThen - 6 * iHealthThen * iHealthThen)) - (100 * iHealthNow - 6 * iHealthNow * iHealthNow));
		if (iHealth > 0)
		{
			iValue += std::max(0, iTempValue);
		}
		else
		{
			iValue += std::max(0, -iTempValue);
		}
		iCount++;
		if (iCount > 6)
		{
			break;
		}
	}
	
	return (0 == iCount) ? 50 : iValue / iCount;
}


I'll link to evaluations of each civic group below
Government
Legal
Labour
Economic
Religion
 
*Problems with AI_Happinessweight slowing this down*

Part of this is common to all civics, and makes up the entirety of Despotism

SIZE="3"]Despotism[/SIZE]
Code:
	iValue = (getNumCities() * 6);


	iValue += -(GC.getCivicInfo(eCivic).getAnarchyLength() * getNumCities());

	iValue += -(getSingleCivicUpkeep(eCivic, true));
Citycount * 6 - city count - single civic upkeep (low)
I'm not going to repeat this code for every civic, so unless theres a change in anarchy length somewhere along the line I will just stick in the forumula without explanation. The bracketed (low) refers to the civic upkeep type which will govern the differences in the single civic upkeep cost

Citycount is the number of cities they own
Where, Single Civic Upkeep is the civic upkeep for the civic being bought from them


Hereditary Rule
Code:
	iTempValue = kCivic.getHappyPerMilitaryUnit() * 3;
	if (iTempValue != 0)
	{
		iValue += (getNumCities() * 9 * AI_getHappinessWeight(isCivic(eCivic) ? -iTempValue : iTempValue, 1)) / 100;
	}
What I get from this is,
Citycount * 6 - city count - single civic upkeep(low) + (citycount * 9 * AI_getHappinessWeight * +/-3 / 100)

Not sure about the meaning of
AI_getHappinessWeight(isCivic(eCivic) ? -iTempValue : iTempValue, 1)

AI_GetHappinessWeight is a seperate function I will have to attack, but the query at the end looks like it will flip the final value of the latter bracket negative if already in HR :s


Representation
Code:
	iTempValue = kCivic.getLargestCityHappiness();
	if (iTempValue != 0)
	{
		iValue += (12 * std::min(getNumCities(), GC.getWorldInfo(GC.getMapINLINE().getWorldSize()).getTargetNumCities()) * AI_getHappinessWeight(isCivic(eCivic) ? -iTempValue : iTempValue, 1)) / 100;
	}
	for (iI = 0; iI < NUM_COMMERCE_TYPES; iI++)
	{
		iTempValue = 0;

		iTempValue += ((kCivic.getCommerceModifier(iI) * getNumCities()) / 3);
		iTempValue += (kCivic.getCapitalCommerceModifier(iI) / 2);
		if (iI == COMMERCE_ESPIONAGE)
		{
			iTempValue *= AI_getEspionageWeight();
			iTempValue /= 500;
		}
		iTempValue += ((kCivic.getSpecialistExtraCommerce(iI) * getTotalPopulation()) / 15);

		iTempValue *= AI_commerceWeight((CommerceTypes)iI);

		if ((iI == COMMERCE_CULTURE) && bCultureVictory2)
		{
		    iTempValue *= 2;
		    if (bCultureVictory3)
		    {
		        iTempValue *= 2;		        
		    }
		}
		iTempValue /= 100;

		iValue += iTempValue;
	}
Citycount * 6 - city count - single civic upkeep + (12 * min of citycount, number of cities that get :) * 3)/100) + (3 * pop / 15) * AI_commerceweight:science:
(min of citycount, number of cities that get :)) is almost always going to be the number of cities that get :) unless the civ is a battered vassal or tiny colony, it's the happiness you get from Rep adjusted for map size and is 3 on standard.

AI_commerceweight:science: I plan to cover eventually, if I do i'll put a link here


Police State
Code:
	iValue += (kCivic.getMilitaryProductionModifier() * getNumCities() * iWarmongerPercent) / (bWarPlan ? 300 : 500 ); 

	iValue += -((kCivic.getWarWearinessModifier() * getNumCities()) / ((bWarPlan) ? 10 : 50));
City count * 6 - city count - single civic upkeep + (25 * citycount *iwarmongerpercent / IF warplan 300, IF not 500)

iwarmongerpercent is
Code:
	iWarmongerPercent = 25000 / std::max(100, (100 + GC.getLeaderHeadInfo(getPersonalityType()).getMaxWarRand()));
iWarmongerPercent = 25000 / 100 + MaxWarRand
MaxWarRand is from the leaderhead XML, I know someone (DanF5771?) already made a list of all the leaderhead XML values, i'll link it when I dig it up.


Universal Suffrage
Code:
	for (iI = 0; iI < GC.getNumHurryInfos(); iI++)
	{
		if (kCivic.isHurry(iI))
		{
			iTempValue = 0;

			if (GC.getHurryInfo((HurryTypes)iI).getGoldPerProduction() > 0)
			{
				iTempValue += ((((AI_avoidScience()) ? 50 : 25) * getNumCities()) / GC.getHurryInfo((HurryTypes)iI).getGoldPerProduction());
			}
			iTempValue += (GC.getHurryInfo((HurryTypes)iI).getProductionPerPopulation() * getNumCities() * (bWarPlan ? 2 : 1)) / 5;
			iValue += iTempValue;
		}
	}

		for (iJ = 0; iJ < GC.getNumImprovementInfos(); iJ++)
		{
			iTempValue += (AI_averageYieldMultiplier((YieldTypes)iI) * (kCivic.getImprovementYieldChanges(iJ, iI) * (getImprovementCount((ImprovementTypes)iJ) + getNumCities() * 2))) / 100;
		}

		if (iI == YIELD_FOOD) 
		{ 
			iTempValue *= 3; 
		} 
		else if (iI == YIELD_PRODUCTION) 
		{ 
			iTempValue *= ((AI_avoidScience()) ? 6 : 2); 
		} 
		else if (iI == YIELD_COMMERCE) 
		{ 
			iTempValue *= ((AI_avoidScience()) ? 1 : 2); 
		} 

		iValue += iTempValue;
	}
Citycount * 6 - city count - single civic upkeep + ((IF AI_avoid science 50, IF not 25 * citycount / 3) + AVG Yield Multipliers * (IF AI_avoid science 6, IF not 2) * towncount + (citycount * 2)) / 100
AVG yield multipliers is an odd one as theres no query on the type of yield, it may well mean
(total of all :hammers:, and if in Burea :commerce: modifiers) / citycount
Needs further investigation if noone else can help on this.

I don't now if those AI yield weightings are general in the code, or just specific to valueing civics,
but F = 3, H = 2, C = 2 is pretty questionable, and F = 3, H = 6, C = 1 when avoiding science really raises an eyebrow
 
Top Bottom