Vassal and Leaderhead Mechanics

MessageMan

Prince
Joined
May 9, 2010
Messages
346
How come there's a limit on the number of vassals one can have? Is it to prevent a nation from becoming too dominant? From what I've seen in my limited RFC gameplay, if a country already has 5 vassals they are the superpower in the game, and a couple more vassals don't really make a difference.

I was thinking of removing this limit, but I don't know where in the code it would be located. Could somebody point me in the right direction?

And would that code also show what makes a country more or less likely to vassalize? It seems to me that the only time you can get a Euro civ to vassalize is early on, and I want to see if I'm correct.

I was also thinking of editing the dates when leaderheads change, so I was looking at CIV4LeadHeadInfo.xml to see if changing the leaders would radically alter gameplay. I understand Change and ChangeLimit, but what is Divisor?

The numbers themselves are a bit hard to compare and contrast. Is one of the leaders average in most everything so I could match him up with the others?
 
I also stumbled upon a loophole for the limit on vassals. If multiple civs ask in the same turn you can end up with more than 5 vassals. That's how I ended up with 7 vassals in a rather weird French game I recently completed.
 
The leaderhead changes work with Python.

I don't have the game files available at the moment, so excuse me if I get something wrong:

The file your looking for is Consts.py in the Assets/Python/ folder.

Assuming you don't want to add any new leaders, you find a list of all leaders in that Python file (such as iRamesses, iQinShiHuang etc.). This is what you refer them by.

There are also a tuple called tEarlyLeaders, which lists all leaders AI civs spawn with (in the order they spawn by) and another one called tLateLeaders. This contains another tuple for each civ. If the respective civ only has one leader, this leader is repeated there.

If it has one additional leader, the following information are listed:

1. the leaders id (iAlexander etc.)
2. the turn on which there is a chance for the leader to change
3.+4. the chance for the leader to switch after this turn for each turn, and the era in which this chance is doubled (not sure about the order, though), referenced by its number.

If it has two additional leaders, it's the same, but with eight entries, four for each.

I hope this helps enough for you to figure out the rest on yourself :)
 
The leaderhead changes work with Python.

I don't have the game files available at the moment, so excuse me if I get something wrong:

The file your looking for is Consts.py in the Assets/Python/ folder.

Assuming you don't want to add any new leaders, you find a list of all leaders in that Python file (such as iRamesses, iQinShiHuang etc.). This is what you refer them by.

There are also a tuple called tEarlyLeaders, which lists all leaders AI civs spawn with (in the order they spawn by) and another one called tLateLeaders. This contains another tuple for each civ. If the respective civ only has one leader, this leader is repeated there.

If it has one additional leader, the following information are listed:

1. the leaders id (iAlexander etc.)
2. the turn on which there is a chance for the leader to change
3.+4. the chance for the leader to switch after this turn for each turn, and the era in which this chance is doubled (not sure about the order, though), referenced by its number.

If it has two additional leaders, it's the same, but with eight entries, four for each.

I hope this helps enough for you to figure out the rest on yourself :)

Thanks! I was wondering what those numbers after the leader id were.

I don't know Python, but if I make small changes (say changing America's leaderhead switch to Lincoln in 1860 instead of 1800) could I do it in Notepad++ without screwing up the game?
 
I think I have vassalizing the Europeans down. If you conquer Italy and the Balkans before the Euros research Astronomy/start colonizing the New World, it should boost your score (or maybe power, don't exactly know what vassalization is based on) to the point where everybody wants to be under your protection. I did this on Viceroy as France, ie easiest starting conditions, and I still had to rush like crazy to get under the time limit. I'm not very good at this game though, so I don't even know if it's possible under harder difficulties.
 
I think I've found the code that limits the number of vassals in CvDeal.cpp.

For capitulation

Spoiler :
Code:
TeamTypes eFirstTeam = GET_PLAYER(getFirstPlayer()).getTeam();
	TeamTypes eSecondTeam = GET_PLAYER(getSecondPlayer()).getTeam();

	if (atWar(eFirstTeam, eSecondTeam))
	{
		// free vassals of capitulating team before peace is signed
		if (isVassalTrade(pSecondList))
		{
			for (int iI = 0; iI < MAX_TEAMS; iI++)
			{
				TeamTypes eLoopTeam = (TeamTypes) iI;
				CvTeam& kLoopTeam = GET_TEAM(eLoopTeam);
				if ((eLoopTeam != eFirstTeam) && (eLoopTeam != eSecondTeam))
				{
					if (kLoopTeam.isAlive() && kLoopTeam.isVassal(eSecondTeam))
					{
						GET_TEAM(eSecondTeam).freeVassal(eLoopTeam);
						int iSecondSuccess = GET_TEAM(eFirstTeam).AI_getWarSuccess(eSecondTeam) + GC.getDefineINT("WAR_SUCCESS_CITY_CAPTURING") * GET_TEAM(eSecondTeam).getNumCities();
						GET_TEAM(eFirstTeam).AI_setWarSuccess(eLoopTeam, std::max(iSecondSuccess, GET_TEAM(eFirstTeam).AI_getWarSuccess(eLoopTeam)));
					}
				}
			}
		}

For peaceful vassals

Spoiler :
Code:
if (isVassalTrade(pFirstList))
		{
			for (int iI = 0; iI < MAX_TEAMS; iI++)
			{
				TeamTypes eLoopTeam = (TeamTypes) iI;
				CvTeam& kLoopTeam = GET_TEAM(eLoopTeam);
				if ((eLoopTeam != eFirstTeam) && (eLoopTeam != eSecondTeam))
				{
					if (kLoopTeam.isAlive() && kLoopTeam.isVassal(eFirstTeam))
					{
						GET_TEAM(eFirstTeam).freeVassal(eLoopTeam);
						int iFirstSuccess = GET_TEAM(eSecondTeam).AI_getWarSuccess(eFirstTeam) + GC.getDefineINT("WAR_SUCCESS_CITY_CAPTURING") * GET_TEAM(eFirstTeam).getNumCities();
						GET_TEAM(eSecondTeam).AI_setWarSuccess(eLoopTeam, std::max(iFirstSuccess, GET_TEAM(eSecondTeam).AI_getWarSuccess(eLoopTeam)));
					}
				}
			}
		}

And I think this determines whether a civ will ask to be your vassal

Spoiler :
Code:
// Protected Functions...

// Returns true if the trade should be saved...
bool CvDeal::startTrade(TradeData trade, PlayerTypes eFromPlayer, PlayerTypes eToPlayer)
{
	CivicTypes* paeNewCivics;
	CvCity* pCity;
	CvPlot* pLoopPlot;
	bool bSave;
	int iI;

	bSave = false;

	switch (trade.m_eItemType)

case TRADE_SURRENDER:
	case TRADE_VASSAL:
		if (trade.m_iData == 0)
		{
			startTeamTrade(trade.m_eItemType, GET_PLAYER(eFromPlayer).getTeam(), GET_PLAYER(eToPlayer).getTeam(), false);
			GET_TEAM(GET_PLAYER(eFromPlayer).getTeam()).setVassal(GET_PLAYER(eToPlayer).getTeam(), true, TRADE_SURRENDER == trade.m_eItemType);
		}
		else
		{
			bSave = true;
		}

Python knowledge is mandatory, unfortunately.

Is Python a good first language to learn?
 
Python knowledge is mandatory, unfortunately.
I believe you are looking at some C++... Python modules use the .py file suffix.

Is Python a good first language to learn?
I'd say yes. I believe that it is straight forward enough to make sense for a non-computer scientist. It will enable you to do a lot with CivIV, but for some stuff you still need to learn some C++. But Python would be the place to start.
 
Both languages have different advantages. Python has the great advantage that it can be edited easily with Notepad or similar tools (which also answers you question above) and especially, doesn't need to be compiled (you can even change the files during civ's runtime). This allows better access for modders like us.

C++ on the other hand, is a whole lot more complex. The language has a more complicated syntax and is more difficult to learn, and you need a compiler for it (and setting one up deters most modders already). But in exchange it's much faster, and that's why even games like Civ that strive for high modability can't get around it.

Rule of thumb: if a method is performed multiple times in a single round, it's probably wise to implement it in C++ (think of things like calculating a plot's yield). Everything else can be done in Python, for easiness' sake.

And by the way, yes, I think Python's a good language to start learning. The only annoying thing is to keep up with the indentations :D
 
I think I found the vassal limit code in CvTeamAI.

Spoiler :
Code:
	//Rhye - start (5 vassals cap if already the strongest; 6 vas+all cap)	
	int mastersVassals = 0;
	int mastersAllies = 0;
	int mastersPower = kMasterTeam.getPower(true);
	bool bStrongest = true;
	for (int iLoopTeam = 0; iLoopTeam < NUM_MAJOR_PLAYERS; iLoopTeam++)
	{
		CvTeam& kLoopTeam = GET_TEAM((TeamTypes)iLoopTeam);
		if (kLoopTeam.isAlive() && kLoopTeam.isVassal(eTeam) && iLoopTeam != getID())
			mastersVassals++;
		if (kLoopTeam.isAlive() && kLoopTeam.isDefensivePact((TeamTypes)eTeam) && iLoopTeam != getID())
			mastersAllies++;
		if (kLoopTeam.getPower(true) > mastersPower)
			bStrongest = false;
	}

	if (mastersVassals >= 5 && bStrongest)
		return DENIAL_POWER_YOU;	
	if (mastersVassals + mastersAllies >= 6)
		return DENIAL_POWER_YOU;	
	//Rhye - end


If I change the "5" to a larger number and it screws up the game, could files become corrupted? I just don't want to screw up any save files.

Edit: Going through the code some more Rhye apparently made it easier to have defensive pacts, but capped the number of countries allied together.

Spoiler :
Code:
//now the cap
	int iCap = 3;
	if (iMaxEra >= 5 && iGameTurn > 420) //modern && year > 1940
		iCap = 4 + GC.getGameINLINE().countCivPlayersAlive()/17 + (bTech? 1:0); //16 Warlords, 13 vanilla (higher because of the addition of bTech)
	else if (iMaxEra >= 4 && iGameTurn > 355) //industrial && year > 1800
		iCap = 3 + GC.getGameINLINE().countCivPlayersAlive()/17 + (bTech? 1:0);
	/*char buf3[50];
	sprintf(buf3, "totalNodes: %d; iCap: %d; civsArray: [%d,%d,%d,%d,%d]", totalNodes, iCap, civsArray[0], civsArray[1], civsArray[2], civsArray[16], civsArray[26]);
	GC.getGameINLINE().logMsg(buf3);*/

	if (totalNodes > iCap)
	{	
		return DENIAL_NO_GAIN;
	}
	
	if (maxNumVassalsPlayer >= 5)
	{	
		if (totalNodes > 1)
		{	
			return DENIAL_NO_GAIN;
		}
	}if (maxNumVassalsPlayer >= 4)
	{	
		if (totalNodes > 2)
		{	
			return DENIAL_NO_GAIN;
		}
	}
	else if (maxNumVassalsPlayer == 3 && numVassalsCoalition > 3)
	{	
		if (totalNodes > 3)
		{	
			return DENIAL_NO_GAIN;
		}
	}
	else if (maxNumVassalsPlayer == 3)
	{	
		if (totalNodes > 4)
		{	
			return DENIAL_NO_GAIN;
		}
	}

	if (numVassalsCoalition >= 6) //5 in Warlords
	{	
		if (totalNodes > 4)
		{	
			return DENIAL_NO_GAIN;
		}
	}

	if (numVassalsCoalition >= 2) //1 in Warlords
	{	
		if (totalNodes > 5)
		{	
			return DENIAL_NO_GAIN;
		}
	}
	//Rhye - end

But my favorite part of the defensive pact code is this:

Spoiler :
Code:
if (GC.getGameINLINE().countCivTeamsAlive() == 2)
	{
		return DENIAL_NO_GAIN;
	}

:lol:
 
If I change the "5" to a larger number and it screws up the game, could files become corrupted? I just don't want to screw up any save files.
Any C++ code needs to be compiled first, and this is supposedly the tricky part. (This process results in the CvGameCoreDLL.dll file. I haven't even bothered trying it myself yet.

Python is different though. It is not compiled onto a file but rather loaded into memory. So it requires more resources and is slower, but you can actually edit the Python modules in mid-game! :eek:

The way the game works is that the application (the executable file) sub-contracts some stuff to the DLL (the compiled C++ code). This makes it possible to mod the game. The DLL file itself creates "hooks" for additional code to be added in Python. These can be any "game event" that takes place, like a city being lost or a Technology being granted. Then it is possible to fire custom Python code.

RFC is done in both C++ and Python - mostly in Python. The CvEventManager module is responsible for handling the game events, and is supplemented with the CvRFCEventManager and the CvRFCEventHandler modules. The rest of the Python in the mod is tied to these modules as add-on.
 
I guess I have to learn how to use the compiler then. Just to change a few stinkin' numbers.
 
If I change the "5" to a larger number and it screws up the game, could files become corrupted? I just don't want to screw up any save files.
I don't know what causes save game compatibility myself, but I strongly suggest that you always apply your changes to a separate copy of the RFC file.

I can highly recommend Kael's guide for setting up the SDK if you really want to go into DLL modding :)
 
Well, I got the compiler running, but when I went to build something went wrong.

Spoiler :
1>------ Build started: Project: CvGameCoreDLL, Configuration: Final_Release Win32 ------
1>Performing Makefile project actions
1>Microsoft (R) Program Maintenance Utility Version 8.00.50727.42
1>Copyright (C) Microsoft Corporation. All rights reserved.
1> "C:\Program Files\Microsoft Visual C++ Toolkit 2003/bin/cl.exe" /nologo /MD /Gd /G7 /GR /O2 /W3 /EHsc /DWIN32 /DNDEBUG /D_WINDOWS /D_USRDLL /DCVGAMECOREDLL_EXPORTS /DFINAL_RELEASE /IBoost-1.32.0/include /IPython24/include /I"C:\Program Files\Microsoft Visual C++ Toolkit 2003/include" /I"C:\Program Files\Microsoft Platform SDK for Windows Server 2003 R2/Include" /c CvArea.cpp /FoFinal_Release/CvArea.obj
1>CvArea.cpp
1>c:\Users\Household\Desktop\CvGameCoreDLL\CvGameCoreDLL.h(160) : fatal error C1083: Cannot open include file: 'boost/python/list.hpp': No such file or directory
1>NMAKE : fatal error U1077: '"C:\Program Files\Microsoft Visual C++ Toolkit 2003/bin/cl.exe"' : return code '0x2'
1>Stop.
1>Project : error PRJ0019: A tool returned an error code from "Performing Makefile project actions"
1>Build log was saved at "file://c:\Users\Household\Desktop\CvGameCoreDLL\Final_Release\BuildLog.htm"
1>CvGameCoreDLL - 3 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========


Not entirely sure what I'm doing wrong. I thought I followed all the instructions to the letter.

This is the top part of my makefile:

Spoiler :
### Variables used in this Makefile
TOOLKIT=C:\Program Files\Microsoft Visual C++ Toolkit 2003
PSDK=C:\Program Files\Microsoft Platform SDK for Windows Server 2003 R2
 
I get a headache just from reading about your efforts to compile the DLL... :(
 
Figured out my problem. Apparently I need a makefile specific to RFC, and not just for BTS. There's an old one available in 2008, but I don't think that'll work for the current version.
 
The guide I posted above doesn't require a makefile and thus worked flawlessly with RFC.
 
Plus according to the last page of the thread the guide doesn't really work anymore.
That is... too bad. :(

Now I really look forward tackling the compilation nonsense myself... :p
 
Back
Top Bottom