Civ Illustrated #1 (Know Your Enemy)

I have completed testing for the first 13 AIs. They give +1, +2 and +3 after giving them 20 Technologies each:

Code:
+2 20/2=10 Alexander
+1 20/1=20 Asoka  
+2 20/2=10 Augustus
+1 20/1=20 Bismarck
+3 20/3=07 Boudica
+2 20/2=10 Brennus
+3 20/3=07 Catherine
+2 20/2=10 Charlemagne
+2 20/2=10 Churchill
+2 20/2=10 Cyrus
+2 20/2=10 Darius I
+2 20/2=10 De Gaulle
+3 20/3=07 Elizabeth

Notice that Boudica, Catherine and Elizabeth will provide +1 after 7 Techs, +2 after 14 Techs and +3 after 20 Techs. So ignoring the AI's less than perfect memory, the +3 bonus applies after giving just 20 Techs. Thus 7 = ceiling[20/3] and 14 = ceiling[20*2/3].

Notice that Alexander, Augustus, Brennus, Charlemagne, Churchill, Cyrus, Darius I and De Gaulle will provide +1 after 10 Techs and +2 after 20 Techs. So ignoring the AI's less than perfect memory, the +2 bonus applies after giving 20 Techs.

Notice that Asoka and Bismarck will provide +1 only after 20 Techs. So ignoring the AI's less than perfect memory, the +1 bonus applies only after giving 20 Techs.

I have attached two game save files. First one is a turn 1 save where the player was given Mediaevil Era Technologies and all AIs had all their starting Technologies removed to make it easier to verify that each AI was given exactly the same number of Techs. The second save is a turn 3 save after each AI was given the 19 Technologies they possess over the previous 2 turns. You can verify the above results from either save; in the latter one, 19 technology trades are completed for you and the 20th trade should answer the question of how big this bonus is after giving 20 technologies. Every AI will increase their bonus with the 20th technology, ignoring their imperfect memory which should be excellent after just 2 turns.

Enjoy! I'll complete the remaining 3 games as soon as I am able. BTW, I foolishly started this first test game with Tribal Villages on, but Boudica popped Technology from a Hut, so I reloaded and manually removed all Huts. I won't make that mistake with the remaining 3 games.

Sun Tzu Wu
 
Good research Sun Tzu Wu. Given you enthusiasm, I'll look into the code about it.
I definitely think if it wasn't defined in XML files as an individual value, it is because that mechanics use another unrelated XML value. I happen to see this for resource demands at vassals.
 
I have completed testing for the first 13 AIs. They give +1, +2 and +3 after giving them 20 Technologies each:
Sun Tzu Wu
Thanks a lot, that was really informative :goodjob:
 
You probably meant Mansa Musa instead of Gandhi above.

Sun Tzu Wu

I double checked and Gandhi was an ok choice to illustrate the clashing of "Worst Enemy" mechanic vs. attitute thresholds at Annoyed and Furious. Mansa might be a better example since he is more consistent in regards to using the Annoyed threshold throughout the entire example but Gandhi was chosen because he was the most extreme. Trading techs with Gandhi at Furious is rather quite hard since you need another AI whom he hates even more.
 
I have completed testing for the first 13 AIs. They give +1, +2 and +3 after giving them 20 Technologies each:

Code:
+2 20/2=10 Alexander
+1 20/1=20 Asoka  
+2 20/2=10 Augustus
+1 20/1=20 Bismarck
+3 20/3=07 Boudica
+2 20/2=10 Brennus
+3 20/3=07 Catherine
+2 20/2=10 Charlemagne
+2 20/2=10 Churchill
+2 20/2=10 Cyrus
+2 20/2=10 Darius I
+2 20/2=10 De Gaulle
+3 20/3=07 Elizabeth

Notice that Boudica, Catherine and Elizabeth will provide +1 after 7 Techs, +2 after 14 Techs and +3 after 20 Techs. So ignoring the AI's less than perfect memory, the +3 bonus applies after giving just 20 Techs. Thus 7 = ceiling[20/3] and 14 = ceiling[20*2/3].

Notice that Alexander, Augustus, Brennus, Charlemagne, Churchill, Cyrus, Darius I and De Gaulle will provide +1 after 10 Techs and +2 after 20 Techs. So ignoring the AI's less than perfect memory, the +2 bonus applies after giving 20 Techs.

Notice that Asoka and Bismarck will provide +1 only after 20 Techs. So ignoring the AI's less than perfect memory, the +1 bonus applies only after giving 20 Techs.

I have attached two game save files. First one is a turn 1 save where the player was given Mediaevil Era Technologies and all AIs had all their starting Technologies removed to make it easier to verify that each AI was given exactly the same number of Techs. The second save is a turn 3 save after each AI was given the 19 Technologies they possess over the previous 2 turns. You can verify the above results from either save; in the latter one, 19 technology trades are completed for you and the 20th trade should answer the question of how big this bonus is after giving 20 technologies. Every AI will increase their bonus with the 20th technology, ignoring their imperfect memory which should be excellent after just 2 turns.

Enjoy! I'll complete the remaining 3 games as soon as I am able. BTW, I foolishly started this first test game with Tribal Villages on, but Boudica popped Technology from a Hut, so I reloaded and manually removed all Huts. I won't make that mistake with the remaining 3 games.

Sun Tzu Wu

:dance:[party]:banana: You are absolutely right Sun Tzu Wu! The guide will be fixed as soon as possible later today. Finding the +3 bonus at 20 tech trades is also quite appreciated. No idea why the AI gives +1/+2/+3 at 7/14/20 techs instead of 7/14/21. That is so strange. :crazyeye:

For testing it is worthwhile to turn on "no tech brokering" as it allows unlimited tech trades to occur without having to press next turn. Corners were cut a little to maintain sanity for 52 AI's by giving the AI's techs in batches of 5 during testing so very sorry for the mistake! :sad:

Thanks for helping fix this :goodjob:
 
Hey guys. Don't do unnecessary testings. I finally found it. The mechanics. Will post.
 
In XML serie of <tag>values</tag> (CIV4LeaderHeadInfos.xml), there is indeed a location for how many techs trigger a particular attitude modifier called TXT_KEY_MEMORY_TRADED_TECH_TO_US ("You have shared your technological discoveries with us.").

In Civ4 game, there are two types of attitude: those who are eternal and those affected by some decay process.
The second category has two values: decay odd and some attitude indicator (which is finally processed in the SDK, that is C++/header files in CvGameCoreDLL folder).

In CIV4LeaderHeadInfos:

Decay:

Spoiler :
Code:
<MemoryDecay>
					<MemoryType>MEMORY_TRADED_TECH_TO_US</MemoryType>
					<iMemoryRand>100</iMemoryRand>
				</MemoryDecay>

Attitude Indicator:

Spoiler :
Code:
<MemoryAttitudePercent>
					<MemoryType>MEMORY_TRADED_TECH_TO_US</MemoryType>
					<iMemoryAttitudePercent>5,10,15</iMemoryAttitudePercent>
				</MemoryAttitudePercent>


All leaders have same memory capacity; no one forgets faster than others.
But some leaders are more sensitive to other player propensity (and I said player, because AI-AI works too; not human exclusive) to freely share their discoveries.

Here's the list:

Spoiler :
Code:
LEADERS     <iMemoryAttitudePercent>

ALEXANDER 	10             
ASOKA       	 5              
AUGUSTUS	        10
BISMARCK   	 5
BOUDICA     	15
BRENNUS    	10
CATHERINE  	15
CHARLEMAGNE	10
CHURCHILL  	10
CYRUS        	10
DARIUS       	10
DE_GAULLE  	10
ELIZABETH  	15
ROOSEVELT  	10
FREDERICK  	15
GANDHI      	5
GENGHIS_KHAN 	10
GILGAMESH  	15
HAMMURABI 	10
HANNIBAL   	15
HATSHEPSUT	10
HUAYNA_CAPAC	10
ISABELLA    	5
JOAO          	15
JULIUS_CAESAR 	10
JUSTINIAN  	15
KUBLAI_KHAN	15
LINCOLN     	15
LOUIS_XIV  	10
MANSA_MUSA	20
MAO_ZEDONG	5
MEHMED     	10
MONTEZUMA    	15
NAPOLEON  	10
PACAL        	10
PERICLES    	10
PETER        	20
QIN_SHI_HUANG	10
RAGNAR      	5
RAMESSES   	10
SALADIN     	10
SHAKA        	5
SITTING_BULL	5
STALIN       	5
SULEIMAN    	5
SURYAVARMAN	5
TOKUGAWA   	5
VICTORIA	        5
WANGKON   	5
WASHINGTON	5
WILLEM      	5
ZARA_YAQOB	5

Now how to process those numbers in an actual number of received techs (point of view of the tech receiver).

In CvPlayerAI.cpp:

Spoiler :
Code:
int CvPlayerAI::AI_getAttitudeVal(PlayerTypes ePlayer, bool bForced) const
{
	PROFILE_FUNC();

	int iRankDifference;
	int iAttitude;
	int iI;

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

	if (bForced)
	{
		if (getTeam() == GET_PLAYER(ePlayer).getTeam() || (GET_TEAM(getTeam()).isVassal(GET_PLAYER(ePlayer).getTeam()) && !GET_TEAM(getTeam()).isCapitulated()))
		{
			return 100;
		}

		if (isBarbarian() || GET_PLAYER(ePlayer).isBarbarian())
		{
			return -100;
		}
	}

	iAttitude = GC.getLeaderHeadInfo(getPersonalityType()).getBaseAttitude();

	iAttitude += GC.getHandicapInfo(GET_PLAYER(ePlayer).getHandicapType()).getAttitudeChange();

//	if (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI))
//	{
//		if (GET_PLAYER(ePlayer).isHuman())
//		{
//			iAttitude -= 2;
//		}
//	}

	if (!(GET_PLAYER(ePlayer).isHuman()))
	{
		iAttitude += (4 - abs(AI_getPeaceWeight() - GET_PLAYER(ePlayer).AI_getPeaceWeight()));
		iAttitude += std::min(GC.getLeaderHeadInfo(getPersonalityType()).getWarmongerRespect(), GC.getLeaderHeadInfo(GET_PLAYER(ePlayer).getPersonalityType()).getWarmongerRespect());
	}

	iAttitude -= std::max(0, (GET_TEAM(GET_PLAYER(ePlayer).getTeam()).getNumMembers() - GET_TEAM(getTeam()).getNumMembers()));

	iRankDifference = (GC.getGameINLINE().getPlayerRank(getID()) - GC.getGameINLINE().getPlayerRank(ePlayer));

	if (iRankDifference > 0)
	{
		iAttitude += ((GC.getLeaderHeadInfo(getPersonalityType()).getWorseRankDifferenceAttitudeChange() * iRankDifference) / (GC.getGameINLINE().countCivPlayersEverAlive() + 1));
	}
	else
	{
		iAttitude += ((GC.getLeaderHeadInfo(getPersonalityType()).getBetterRankDifferenceAttitudeChange() * -(iRankDifference)) / (GC.getGameINLINE().countCivPlayersEverAlive() + 1));
	}

	if ((GC.getGameINLINE().getPlayerRank(getID()) >= (GC.getGameINLINE().countCivPlayersEverAlive() / 2)) &&
		  (GC.getGameINLINE().getPlayerRank(ePlayer) >= (GC.getGameINLINE().countCivPlayersEverAlive() / 2)))
	{
		iAttitude++;
	}

	if (GET_TEAM(GET_PLAYER(ePlayer).getTeam()).AI_getWarSuccess(getTeam()) > GET_TEAM(getTeam()).AI_getWarSuccess(GET_PLAYER(ePlayer).getTeam()))
	{
		iAttitude += GC.getLeaderHeadInfo(getPersonalityType()).getLostWarAttitudeChange();
	}

	iAttitude += AI_getCloseBordersAttitude(ePlayer);
	iAttitude += AI_getWarAttitude(ePlayer);
	iAttitude += AI_getPeaceAttitude(ePlayer);
	iAttitude += AI_getSameReligionAttitude(ePlayer);
	iAttitude += AI_getDifferentReligionAttitude(ePlayer);
	iAttitude += AI_getBonusTradeAttitude(ePlayer);
	iAttitude += AI_getOpenBordersAttitude(ePlayer);
	iAttitude += AI_getDefensivePactAttitude(ePlayer);
	iAttitude += AI_getRivalDefensivePactAttitude(ePlayer);
	iAttitude += AI_getRivalVassalAttitude(ePlayer);
	iAttitude += AI_getShareWarAttitude(ePlayer);
	iAttitude += AI_getFavoriteCivicAttitude(ePlayer);
	iAttitude += AI_getTradeAttitude(ePlayer);
	iAttitude += AI_getRivalTradeAttitude(ePlayer);

	for (iI = 0; iI < NUM_MEMORY_TYPES; iI++)
	{
		iAttitude += AI_getMemoryAttitude(ePlayer, ((MemoryTypes)iI));
	}

	iAttitude += AI_getColonyAttitude(ePlayer);
	iAttitude += AI_getAttitudeExtra(ePlayer);

	return range(iAttitude, -100, 100);
}

The very part that interests us is:

Code:
for (iI = 0; iI < NUM_MEMORY_TYPES; iI++)
	{
		iAttitude += AI_getMemoryAttitude(ePlayer, ((MemoryTypes)iI));
	}

Basically making some enumeration of memory types, and #26 is the concerned one.

Becomes
Code:
iAttitude += AI_getMemoryAttitude(TechReceiver, ((MEMORY_TRADED_TECH_TO_US)26));

And bit farther in CvPlayerAI...

we have our definition for AI_getMemoryAttitude:

Code:
int CvPlayerAI::AI_getMemoryAttitude(PlayerTypes ePlayer, MemoryTypes eMemory) const
{
	return ((AI_getMemoryCount(ePlayer, eMemory) * GC.getLeaderHeadInfo(getPersonalityType()).getMemoryAttitudePercent(eMemory)) / 100);
}

Basically that in understandable formula:

iAttitude= [#TechsReceived*<iMemoryAttitudePercent> / 100]

[] meaning you have to round down after the calculus.

For instance, for Cathy, let's take instances of 7, 14 and 20 given techs.

7 techs:
iAttitude = [7*15/100] = [1.05]=1
14 techs:
iAttitude = [14*15/100] = [2.1]=2
20 techs:
iAttitude = [20*15/100] = [3]=3

And that is why for those with <iMemoryAttitudePercent> as 15, for getting diplo modifiers up to +3, it goes 7,7,6 techs.

Important thing to remember, those with <iMemoryAttitudePercent> as 5 need 20 techs for +1, those with <iMemoryAttitudePercent> as 10 need 10 techs +1 modifier and those with <iMemoryAttitudePercent> as 15 need 7,7,6 techs for +1,+2,+3 modifier.

Trivia

  • Interestingly, I was thinking that was better in CvTeamAI.cpp because tech trading is a matter of teams more of individuals. Now come the thought, if you trade a tech to a team, the other partner automatically receives the tech. Does it have a tech count for both or just the leader you traded/gave the tech? Food for thought.
  • The decay process is defined in CvPlayerAI::AI_doCounter() ; nothing particular but basic Soren Johnson's RNG that rolls a number from 0 to 100 (for 101 possible values?). If rolling 0, then the count decreases by one. That RNG is processed each turn. And it is worth for each leader as roughly 1% per turn of Alzheimer.
  • Most code parts are trifles. Mostly for me. ;)
 
My list matched yours until:

SULEIMAN 5
SURYAVARMAN 5
TOKUGAWA 5
VICTORIA 5
WANGKON 5
WASHINGTON 5
WILLEM 5
ZARA_YAQOB 5

SULEIMAN 10
SURYAVARMAN 10
TOKUGAWA 5
VICTORIA 10
WANGKON 10
WASHINGTON 10
WILLEM 15
ZARA_YAQOB 10

My list was based on the MEMORY_TRADED_TECH_TO_US row in a BtS 3.13 spreadsheet. I'm not sure whether these values were correct for 3.13, but I know that I gave Zara Yaqob a few more than 10 technologies long ago and never got +1 for sharing technologies, so I'm sure the spreadsheet maker got 7 of 8 wrong.

The raw 3.19 CIV4LeaderHeadsInfo.xml was easy enough to read until I got to Suleiman. There seem to be trivial bugs there in the XML that bother a human reader. I finally downloaded an eval copy of xmlspy and was finally able to verify your values quoted above as correct.

How did you create that list so easily?

Thanks for producing the list. I ended up verifying it with my raw 3.19 CIV4LeaderHeadsInfo.xml with the last eight via xmlspy. So I'd agree that no further testing is needed, except ...

We have seen three Leaders (Boudica, Catherine and Elizabeth) get to +3 via 20 technology trades. Is there a limit to how big this bonus can go?

@Kaitzilla: Thanks for the testing tip of using "no tech brokering". That would eliminate the slim chance of an AI forgetting about one tech trade in the range of 2t that I was using.

Sun Tzu Wu
 
How did you create that list so easily?

DanF's spreadsheet was said to be complete on XML variables, so I just went copy-paste columns. I tried one by one in CIV4LeaderHeadInfos.xml, but that takes more time for no gains. I trust DanF.


Thanks for producing the list. I ended up verifying it with my raw 3.19 CIV4LeaderHeadsInfo.xml with the last eight via xmlspy. So I'd agree that no further testing is needed, except ...

Good thing to look for the actual assets of the most updated version of the game. Always reliable as informations spread on the forums can be obsolete.

We have seen three Leaders (Boudica, Catherine and Elizabeth) get to +3 via 20 technology trades. Is there a limit to how big this bonus can go?

My hunch is no limit on paper. Practically, of course for a unmodded game, this is limited by the actual tech tree except future techs.

Again, I cite the part that deals with that type of Memory attitude:

Code:
for (iI = 0; iI < NUM_MEMORY_TYPES; iI++)
	{
		iAttitude += AI_getMemoryAttitude(ePlayer, ((MemoryTypes)iI));
	}

I suppose if there was some limit, I would put like this:

Code:
for (iI = 0; iI < NUM_MEMORY_TYPES; iI++)
	{
		iAttitude += std::min(AI_getMemoryAttitude(ePlayer, ((MemoryTypes)iI)), 3);
	}
With that modification, it would be impossible to get over +3.

Nonetheless, there is actually a limit on overall attitude points (all types included). Minimum is -100 and max is +100. That is determined by range(actual value, min, max).
Code:
return range(iAttitude, -100, 100);

But honestly, that's way beyond typical game. Only city liberation or wardec abuses can reach such limits.

Comments in blue. BTW, I can't confirm with citations of other works because no one worked on
"You have shared your technological discoveries with us." before. It's original work.
 
I couldn't find MEMORY_TRADED_TECH_TO_US in DanF5771's spreadsheet.

Thank you very much for your explanation!

Sun Tzu Wu
 
I couldn't find MEMORY_TRADED_TECH_TO_US in DanF5771's spreadsheet.

Thank you very much for your explanation!

Sun Tzu Wu

It's because he cut the MEMORY part given he organized in sections.

Give a try on TRADED_TECH_TO_US.
 
It's because he cut the MEMORY part given he organized in sections.

Give a try on TRADED_TECH_TO_US.

OK, that worked great. Thanks!

DanF5771's Spreadsheet is now just over an year old (2012/10/19). That is likely to be the most up to date spread sheet on CIV4LeaderHeadInfo.xml and stay up to date.

I'm looking for a more versatile XML viewer than xmlspy. One that is perpetually free. The grid view of xmlspy was ok, but ackward to use; in 30 days the eval license expires too.

Sun Tzu Wu
 
I'm not really a know-it-all (in fact I'm a know-it-null) in applications but I simply use Notepad++. That app is free source.
Before I was simply using simple notepad (roughest terrain).

BTW, funny how Kakumeika team looks so much of a highly bureaucratic team. Numbers, proofs, spreadsheets, etc.

BTW2: Don't forget to put your thread score. I did.
 
I'm not really a know-it-all (in fact I'm a know-it-null) in applications but I simply use Notepad++. That app is free source.
Before I was simply using simple notepad (roughest terrain).

BTW, funny how Kakumeika team looks so much of a highly bureaucratic team. Numbers, proofs, spreadsheets, etc.

BTW2: Don't forget to put your thread score. I did.

Don't be too modest. Your code diving skills are becoming legendary!

notepad++ is a great application; I use it daily.

Agreed, Kakumeika is a highly technical, micromanaging team.

"thread score?" :lol: A microbrew is in order when ours goes past 5000. You will beat me no doubt. Or did you mean team thread score?

Sun Tzu Wu
 
I continued my test game trading more technologies to Elizabeth, until she received 60 techs and became +9 "shared your technological discoveries with us." See the attached save game file with 59 technologies traded (given) to her. Give her one more. There are plenty more technologies to trade away too, including Future Tech <n> where n is huge! In any case, +9 should be more than enough to get Friendly with her. In fact, she said something about sacrificing 50 Warriors in honor of our friendship.

This verifies, in a practical sense, your code analysis that there is no limit to this bonus, other than Research rate (Beat the the AI to every technology and one can realistically give every such technology away, especially with well timed Great Person bulbs).

Sun Tzu Wu
 
Finally, I was able to mostly gather about capitulee resource demands.
That always was a random part for me as I never knew how the AI would react. Sometimes, I got automatic war state in ridiculous situations (like the AI being far weaker than me).

Thus, this XML value (and following explanations) have a real strategic value in CIV4 gaming.

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

SYNOPSIS

Two types of vassals exist: peacevassals and capitulee. While peacevassals have an automatic mechanics that force the AI to be FRIENDLY with you (even without enough attitude modifier), capitulee won't be necessary pleased with you as master. Both types enable disabled WFYABTA, many disabled reddened diplo items and right to demands single resources for free along other kind of bonuses/maluses.

Depending of the leader that has capitulated, if you have the right attitude, you can ask as many resources without risk at all of breaking the vassal treaty.
Indeed, under vassality, asking resources for free is some kind of animal intimidation fight: if one thinks have no chance, it flees. Otherwise it attacks.
Here the vassal revolts and enter war state when (s)he deemed the demand(s) was abusive.

It turns out that resource demands are either free-revolt if correct attitude or is under the same rules as a normal demand you do to a non-capitulee AI, but with war as result of refusal.

First demand is not protected from revolt and the vassal treaty can be broken even in the 10 first turns after capitulation. If there was some rumors of the first resource demand was free of dangers, it is often because on how long you knew/met the AI until deciding to capitulate him/her. This boost the chance of a granted first free resource. But once the first grant done, the magnitude of the second grant is reset to zero and you have to wait a certain number of turns before it worth a resource.

ANALYSIS

It all starts with CvPlayerAI.cpp (the SDK files that deal with individual AI leader behaviours)::AI_doDiplo().

For a willing to talk vassal, here's the code:

Spoiler :
Code:
if (GET_TEAM(GET_PLAYER((PlayerTypes)iI).getTeam()).isVassal(getTeam()))
								{
									iBestValue = 0;
									eBestGiveBonus = NO_BONUS;

									for (iJ = 0; iJ < GC.getNumBonusInfos(); iJ++)
									{
										if (GET_PLAYER((PlayerTypes)iI).getNumTradeableBonuses((BonusTypes)iJ) > 0 && getNumAvailableBonuses((BonusTypes)iJ) == 0)
										{
											iValue = AI_bonusTradeVal((BonusTypes)iJ, (PlayerTypes)iI, 1);

											if (iValue > iBestValue)
											{
												iBestValue = iValue;
												eBestGiveBonus = ((BonusTypes)iJ);
											}
										}
									}

									if (eBestGiveBonus != NO_BONUS)
									{
										theirList.clear();
										ourList.clear();

										setTradeItem(&item, TRADE_RESOURCES, eBestGiveBonus);
										theirList.insertAtEnd(item);

										if (GET_PLAYER((PlayerTypes)iI).isHuman())
										{
											if (!(abContacted[GET_PLAYER((PlayerTypes)iI).getTeam()]))
											{
												CvPopupInfo* pInfo = new CvPopupInfo(BUTTONPOPUP_VASSAL_GRANT_TRIBUTE, getID(), eBestGiveBonus);
												if (pInfo)
												{
													gDLL->getInterfaceIFace()->addPopup(pInfo, (PlayerTypes)iI);
													abContacted[GET_PLAYER((PlayerTypes)iI).getTeam()] = true;
												}
											}
										}
										else
										{
											GC.getGameINLINE().implementDeal(getID(), ((PlayerTypes)iI), &ourList, &theirList);
										}
									}
								}

It is basically how a code block on vassal-master trade of resources, with both side to offer or only one side (master) asking. Here is our part:

Spoiler :
Code:
if (GET_PLAYER((PlayerTypes)iI).isHuman())
										{
											if (!(abContacted[GET_PLAYER((PlayerTypes)iI).getTeam()]))
											{
												CvPopupInfo* pInfo = new CvPopupInfo(BUTTONPOPUP_VASSAL_GRANT_TRIBUTE, getID(), eBestGiveBonus);
												if (pInfo)
												{
													gDLL->getInterfaceIFace()->addPopup(pInfo, (PlayerTypes)iI);
													abContacted[GET_PLAYER((PlayerTypes)iI).getTeam()] = true;
												}
											}
										}

First, demanding resources is excusive to human player! That means no one should ever see some war between AI vassal-AI master due to some resource denial.
BUTTONPOPUP_VASSAL_GRANT_TRIBUTE is some kind of action made by the human player and let's see it in details in CvDLLButtomPopup.ccp.

That's almost the core of the subject:

Spoiler :
Code:
case BUTTONPOPUP_VASSAL_DEMAND_TRIBUTE:
                if (pPopupReturn->getButtonClicked() < GC.getNumBonusInfos())
                {
                        PlayerTypes eVassal = (PlayerTypes)info.getData1();
                        if (GET_PLAYER(eVassal).isHuman())
                        {
                                CvPopupInfo* pInfo = new CvPopupInfo(BUTTONPOPUP_VASSAL_GRANT_TRIBUTE, GC.getGameINLINE().getActivePlayer(), pPopupReturn->getButtonClicked());
                                if (NULL != pInfo)
                                {
                                        gDLL->sendPopup(eVassal, pInfo);
                                }
                        }
                        else
                        {
                                TradeData item;
                                setTradeItem(&item, TRADE_RESOURCES, pPopupReturn->getButtonClicked());

                                CLinkList<TradeData> ourList;
                                CLinkList<TradeData> theirList;
                                theirList.insertAtEnd(item);

                                if (GET_PLAYER(eVassal).AI_considerOffer(GC.getGameINLINE().getActivePlayer(), &ourList, &theirList))
                                {
                                        gDLL->sendImplementDealMessage(eVassal, &ourList, &theirList);

                                        CvWString szBuffer = gDLL->getText("TXT_KEY_VASSAL_GRANT_TRIBUTE_ACCEPTED", GET_PLAYER(eVassal).getNameKey(), GET_PLAYER(GC.getGameINLINE().getActivePlayer()).getNameKey(), GC.getBonusInfo((BonusTypes)pPopupReturn->getButtonClicked()).getTextKeyWide());
                                        gDLL->getInterfaceIFace()->addMessage(GC.getGameINLINE().getActivePlayer(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer);
                                }
                                else
                                {
                                        gDLL->sendChangeWar(GET_PLAYER(eVassal).getTeam(), true);
                                }
                        }
                }
                break;

Let cut the fat of uninteresting:
Spoiler :
Code:
if (GET_PLAYER(eVassal).AI_considerOffer(GC.getGameINLINE().getActivePlayer(), &ourList, &theirList))
                                {
                                        gDLL->sendImplementDealMessage(eVassal, &ourList, &theirList);

                                        CvWString szBuffer = gDLL->getText("TXT_KEY_VASSAL_GRANT_TRIBUTE_ACCEPTED", GET_PLAYER(eVassal).getNameKey(), GET_PLAYER(GC.getGameINLINE().getActivePlayer()).getNameKey(), GC.getBonusInfo((BonusTypes)pPopupReturn->getButtonClicked()).getTextKeyWide());
                                        gDLL->getInterfaceIFace()->addMessage(GC.getGameINLINE().getActivePlayer(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer);
                                }
                                else
                                {
                                        gDLL->sendChangeWar(GET_PLAYER(eVassal).getTeam(), true);
                                }

Basically, it goes like this: if the AI (via AI_considerOffer() function) finds your demand reasonable, that function is returning true and the capitulee simply return a grumble plus the resource.
But if AI_considerOffer() returns false, then war is triggered. I haven't find the exact link between sending info a war and the actual war triggering, but I don't really care.
sendChangeWar() function is prolly obvious.

Here the code anyways:

Spoiler :
Code:
void CvMessageControl::sendChangeWar(TeamTypes eRivalTeam, bool bWar)
{
	if (NO_PLAYER != GC.getGameINLINE().getActivePlayer())
	{
		gDLL->sendMessageData(new CvNetChangeWar(GC.getGameINLINE().getActivePlayer(), eRivalTeam, bWar));
	}
}

Now where lies the acceptance of bullying from the capitulee lies in AI_considerOffer().
Yes, the same place as begging/demands functions.

Now the core of the subject (with fat cut):

Spoiler :
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()).getif()
				&& 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;
			}
		}
Basically for a player that is vassal and has the vassal treaty in their balance (i.e. a capitulee or peacevassal),
if the vassal attitude is lower or equal to <VassalRefuseAttitudeThreshold> (an XML value in CIV4LeaderHeadInfos.xml and the same used for peacevassal!!!!) AND not already at war (well duh!) AND the master does not have some defensive pact, then comes some calculi equivalent to normal demands.
BUT if you have at least one defensive pact, or have better relationship than <VassalRefuseAttitudeThreshold> , then resources are always granted!!!!
Peacevassals have an automatic FRIENDLY stance mechanics just to avoid refusal btw.

Now we now the ensured paths to get free-risk demands, let's see demands that are tied some many calculi and possibly I won't end this work being too heavy.

First, the AI ponders the demand via AI_dealVal() function:

Code:
iOurValue = GET_PLAYER(ePlayer).AI_dealVal(getID(), pOurList, false, iChange);

In CvPlayerAI::AI_dealVal(), hereunder the case for resources valuing:

Code:
case TRADE_RESOURCES:
			if (!bIgnoreAnnual)
			{
				iValue += AI_bonusTradeVal(((BonusTypes)(pNode->m_data.m_iData)), ePlayer, iChange);
			}
			break;
Thenb AI_bonusTradeVal is a simple function (where one can see vassals see their worth halved; for peacevassals only it seems, weird...), but it calls a big big and big function that gives the value of resources (AI_bonusVal). Despite I already unraveled this big scumbag function in the past for another reason, I won't display its ugliness for now unless begged.

At least, let show AI_bonusTradeVal():

Spoiler :
Code:
int CvPlayerAI::AI_bonusTradeVal(BonusTypes eBonus, PlayerTypes ePlayer, int iChange) const
{
	int iValue;

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

	iValue = AI_bonusVal(eBonus, iChange);

	iValue *= ((std::min(getNumCities(), GET_PLAYER(ePlayer).getNumCities()) + 3) * 30);
	iValue /= 100;

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

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

	return (iValue * GC.getDefineINT("PEACE_TREATY_LENGTH"));
}

To come back on iOurValue, then it is processed to a power inflating factor. Basically the power of the team (master+vassal(s)) over the power of the master power (I think).

I'll stop there. I need to rethink. I'm confusing things I think.

//cut
 
"thread score?" :lol: A microbrew is in order when ours goes past 5000. You will beat me no doubt. Or did you mean team thread score?

No need for Kaku is have score. :lol:

I meant Civ Illustrated thread (mainly Kaitzilla's work). I did give my score. Perhaps, that will attract newcoming players. You see, some people judge by score. :sad:
 
Don't be too modest. Your code diving skills are becoming legendary!

You clearly haven't seen monsters in Civ4 - Creation & Customization. There are possibly bigger monsters than DanF. There's not only SDK (C++, header files, etc.). There's python and other stuff to know.

Most of them have possible actual courses that backs them in their modding while I am working from scratch.

One thing I want to do is to use python to create events (just like events you see in the blackish tab in the upper middle screen; e.g. wonders) when functions are called. That would help me greatly in how to decipher functions. DanF can do this (I saw a screen with this) but he never mentioned anywhere how to do it).
 
@Kaitzilla

Let's test our friendship. (Irony of my latest work)

I demand you to add close border XML values, <VassalRefuseAttitudeThreshold> (that is adding a line below "Will possibly peace vassal to human player: Friendly" about demanding resources from vassal for same attitude is risk-free) and corrections for "shared your technological discoveries with us".

If refused, we enter a war state of eternal râleries... :groucho:
 
Top Bottom