Variable setting to improper value on "Restart Game"

Putmalk

Deity
Joined
Sep 26, 2010
Messages
2,652
Location
New York
I am entirely confused here, and this seems like improper behavior. I'm sure it's an error on my part but this time, I'm completely stumped. Maybe some fresh eyes can help me, because I'm considering this inconsistent behavior unless I'm really dumb and missed something obvious.

So when you "Restart Game" that's the turn 0 function that regenerates the map, to ensure everyone is on the same page when I'm talking here.

I have a variable m_eMaster as part of CvTeam. It is set to NO_TEAM (enum for -1) in CvTeam::uninit():

Code:
#if defined(MOD_DIPLOMACY_CIV4_FEATURES)
	m_bIsVoluntaryVassal = false;
	m_iNumTurnsIsVassal = -1;
	m_iNumCitiesWhenVassalMade = 0;
	m_iTotalPopulationWhenVassalMade = 0;
	[B]m_eMaster = NO_TEAM;[/B]

	for(int i = 0; i < MAX_MAJOR_CIVS; i++)
	{
		m_aiNumTurnsSinceVassalTaxSet[i] = -1;
		m_aiVassalTax[i] = 0;
	}
#endif

Which is run by all teams when the game is restarted and re-initialized. So every m_eMaster should be -1, right?

During player creation the following function chain is called:

Code:
// CvPlayer::DoUpdateHappiness()

#if defined(MOD_DIPLOMACY_CIV4_FEATURES)
	if (MOD_DIPLOMACY_CIV4_FEATURES) {
		// Increase from Vassals
		m_iHappiness += GetHappinessFromVassals();
	}
#endif

// CvPlayer::GetHappinessFromVassals()

int iHappiness = 0;

PlayerTypes ePlayer;
for(int iPlayerLoop = 0; iPlayerLoop < MAX_MAJOR_CIVS; iPlayerLoop++)
{
	ePlayer = (PlayerTypes) iPlayerLoop;
	iHappiness += GetHappinessFromVassal(ePlayer);

}
return iHappiness;


// CvPlayer::GetHappinessFromVassal()

int iAmount = 0;

[B]if(GET_TEAM(GET_PLAYER(ePlayer).getTeam()).IsVassal(getTeam()))[/B]
{
	iAmount += GET_PLAYER(ePlayer).GetExcessHappiness() * GC.getVASSAL_HAPPINESS_PERCENT();
	iAmount /= 100;
}
return iAmount;

The bolded line, IsVassal() returns true. A closer look at the function...

Code:
bool CvTeam::IsVassal(TeamTypes eIndex) const
{
   return eIndex!=NO_TEAM && [B]eIndex==m_eMaster[/B];
}

Okay, so check the variables:

Code:
eIndex = 0
m_eMaster= 0

WTH???? Why is m_eMaster = 0?

The only other places m_eMaster is ever assigned are:

Code:
CvTeam::Read()

#if defined(MOD_DIPLOMACY_CIV4_FEATURES)
	kStream >> m_iVassalageTradingAllowedCount;
	[B]kStream >> m_eMaster;[/B]
	kStream >> m_bIsVoluntaryVassal;
	kStream >> m_iNumTurnsIsVassal;
	kStream >> m_iNumCitiesWhenVassalMade;
	kStream >> m_iTotalPopulationWhenVassalMade;

	ArrayWrapper<int> kNumTurnsSinceVassalEndedWrapper(MAX_TEAMS, &m_aiNumTurnsSinceVassalEnded[0]);
	kStream >> kNumTurnsSinceVassalEndedWrapper;

	ArrayWrapper<int> kNumTurnsSinceVassalTaxSetWrapper(MAX_MAJOR_CIVS, &m_aiNumTurnsSinceVassalTaxSet[0]);
	kStream >> kNumTurnsSinceVassalTaxSetWrapper;

	ArrayWrapper<int> kVassalTaxWrapper(MAX_MAJOR_CIVS, &m_aiVassalTax[0]);
	kStream >> kVassalTaxWrapper;
#endif



void CvTeam::setVassal(TeamTypes eIndex, bool bNewValue, bool bVoluntary)
{
	//can't be our own master
	if(eIndex==GetID())
		return;

	[B]m_eMaster = bNewValue ? (TeamTypes) eIndex : NO_TEAM;[/B]
	m_bIsVoluntaryVassal = bNewValue ? bVoluntary : false;
}

And no... neither of these functions are called.

Am I missing something? Did I forget to reset the variable somewhere?

And the fix....:

Code:
//	--------------------------------------------------------------------------------
// Are we a vassal of eIndex?
bool CvTeam::IsVassal(TeamTypes eIndex) const
{
	[B]if(!isAlive() || !GET_TEAM(eIndex).isAlive())
		return false;[/B]

	return eIndex!=NO_TEAM && eIndex==m_eMaster;
}

Is this my error? A potential issue with Restart Game?
 
What's the value of m_eMaster right after the assignment in uninit(). If it's -1 (as I suspect it will be), then my guess is you have some array initialisation tramping over the CvTeam data structure somewhere - as most int arrays are init'ed to 0 and most bool arrays to false (which is also 0)

Very much doubt it's an issue in the Restart code, as I use that a lot and have never hit anything similar.
 
What's the value of m_eMaster right after the assignment in uninit(). If it's -1 (as I suspect it will be), then my guess is you have some array initialisation tramping over the CvTeam data structure somewhere - as most int arrays are init'ed to 0 and most bool arrays to false (which is also 0)

Very much doubt it's an issue in the Restart code, as I use that a lot and have never hit anything similar.

This is interesting, because I haven't modified CvTeam in a way to cause this. m_eMaster is just a member variable (not an array) and it's not referenced anywhere else except for the code snippets I've provided, so I'm not sure why this is happening.

I doubt it's an issue with the Restart code too.

The only thing I can think of (at the moment) is that m_eMaster wasn't actually reset for some reason, or this:

Code:
int CvPlayer::GetHappinessFromVassals() const
{
	int iHappiness = 0;

	PlayerTypes ePlayer;
	for(int iPlayerLoop = 0; iPlayerLoop < MAX_MAJOR_CIVS; iPlayerLoop++)
	{
		ePlayer = (PlayerTypes) iPlayerLoop;
		iHappiness += GetHappinessFromVassal(ePlayer);
	}

	return iHappiness;
}

Doesn't work on the restart game call because those players were not initialized yet.
 
m_eMaster is just a member variable (not an array).

Code:
#if defined(MOD_DIPLOMACY_CIV4_FEATURES)
	int m_iVassalageTradingAllowedCount;
	[COLOR="Red"]bool* m_pabTradeTech;[/COLOR]

	TeamTypes m_eMaster;
	bool m_bIsVoluntaryVassal;
	int m_iNumTurnsIsVassal;
	int m_iNumCitiesWhenVassalMade;
	int m_iTotalPopulationWhenVassalMade;
	[COLOR="red"]Firaxis::Array< int, REALLY_MAX_TEAMS > m_aiNumTurnsSinceVassalEnded;
[/COLOR]
	// Only major civs can be taxed
	[COLOR="red"]Firaxis::Array< int, MAX_MAJOR_CIVS > m_aiNumTurnsSinceVassalTaxSet;[/COLOR]
	[COLOR="red"]Firaxis::Array< int, MAX_MAJOR_CIVS > m_aiVassalTax;
[/COLOR]#endif

Every thing in red is a C4DF array in the CvTeam object so should be a suspect. My money would be on m_pabTradeTech (as it's before m_eMaster)
 
Doesn't work on the restart game call because those players were not initialized yet.

Printing the contents of m_eMaster in uninit() will quickly show if the CvTeam objects are cleared before the CvPlayer objects, or interleaved
 
One thing I forgot to mention is that other instances of m_eMaster are actually -1 in the IsVassal() function. So it's inconsistent (some are -1, some are 0). I'm gonna pursue the player happiness function loop theory for a bit.

Printing the contents of m_eMaster in uninit() will quickly show if the CvTeam objects are cleared before the CvPlayer objects, or interleaved

This is also a good idea, I should set up some quick logging.
 
So did some logging. m_eMaster are all -1 so that's fine. However, MY suspicious is also correct. This is the output in GetHappinessFromVassal():

ePlayer team = GET_PLAYER(ePlayer).getTeam()
getTeam() = getTeam()

Code:
ePlayer team: 0 getTeam(): 0
ePlayer team: -1 getTeam(): 0
ePlayer team: -1 getTeam(): 0
ePlayer team: -1 getTeam(): 0
ePlayer team: -1 getTeam(): 0
ePlayer team: -1 getTeam(): 0
ePlayer team: -1 getTeam(): 0
ePlayer team: -1 getTeam(): 0
ePlayer team: -1 getTeam(): 0
ePlayer team: -1 getTeam(): 0
ePlayer team: -1 getTeam(): 0
ePlayer team: -1 getTeam(): 0
ePlayer team: -1 getTeam(): 0
ePlayer team: -1 getTeam(): 0
ePlayer team: -1 getTeam(): 0
ePlayer team: -1 getTeam(): 0
ePlayer team: -1 getTeam(): 0
ePlayer team: -1 getTeam(): 0
ePlayer team: -1 getTeam(): 0
ePlayer team: -1 getTeam(): 0
ePlayer team: -1 getTeam(): 0
ePlayer team: -1 getTeam(): 0
ePlayer team: 0 getTeam(): 0
ePlayer team: 1 getTeam(): 0
ePlayer team: 2 getTeam(): 0
ePlayer team: 3 getTeam(): 0
ePlayer team: 4 getTeam(): 0
ePlayer team: 5 getTeam(): 0
ePlayer team: 6 getTeam(): 0
ePlayer team: 7 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 0 getTeam(): 1
ePlayer team: 1 getTeam(): 1
ePlayer team: 2 getTeam(): 1
ePlayer team: 3 getTeam(): 1
ePlayer team: 4 getTeam(): 1
ePlayer team: 5 getTeam(): 1
ePlayer team: 6 getTeam(): 1
ePlayer team: 7 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 0 getTeam(): 2
ePlayer team: 1 getTeam(): 2
ePlayer team: 2 getTeam(): 2
ePlayer team: 3 getTeam(): 2
ePlayer team: 4 getTeam(): 2
ePlayer team: 5 getTeam(): 2
ePlayer team: 6 getTeam(): 2
ePlayer team: 7 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 0 getTeam(): 3
ePlayer team: 1 getTeam(): 3
ePlayer team: 2 getTeam(): 3
ePlayer team: 3 getTeam(): 3
ePlayer team: 4 getTeam(): 3
ePlayer team: 5 getTeam(): 3
ePlayer team: 6 getTeam(): 3
ePlayer team: 7 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 0 getTeam(): 4
ePlayer team: 1 getTeam(): 4
ePlayer team: 2 getTeam(): 4
ePlayer team: 3 getTeam(): 4
ePlayer team: 4 getTeam(): 4
ePlayer team: 5 getTeam(): 4
ePlayer team: 6 getTeam(): 4
ePlayer team: 7 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 0 getTeam(): 5
ePlayer team: 1 getTeam(): 5
ePlayer team: 2 getTeam(): 5
ePlayer team: 3 getTeam(): 5
ePlayer team: 4 getTeam(): 5
ePlayer team: 5 getTeam(): 5
ePlayer team: 6 getTeam(): 5
ePlayer team: 7 getTeam(): 5
ePlayer team: 21 getTeam(): 5
ePlayer team: 21 getTeam(): 5
ePlayer team: 21 getTeam(): 5
ePlayer team: 21 getTeam(): 5
ePlayer team: 21 getTeam(): 5
ePlayer team: 21 getTeam(): 5
ePlayer team: 21 getTeam(): 5
ePlayer team: 21 getTeam(): 5
ePlayer team: 21 getTeam(): 5
ePlayer team: 21 getTeam(): 5
ePlayer team: 21 getTeam(): 5
ePlayer team: 21 getTeam(): 5
ePlayer team: 21 getTeam(): 5
ePlayer team: 21 getTeam(): 5
ePlayer team: 0 getTeam(): 6
ePlayer team: 1 getTeam(): 6
ePlayer team: 2 getTeam(): 6
ePlayer team: 3 getTeam(): 6
ePlayer team: 4 getTeam(): 6
ePlayer team: 5 getTeam(): 6
ePlayer team: 6 getTeam(): 6
ePlayer team: 7 getTeam(): 6
ePlayer team: 21 getTeam(): 6
ePlayer team: 21 getTeam(): 6
ePlayer team: 21 getTeam(): 6
ePlayer team: 21 getTeam(): 6
ePlayer team: 21 getTeam(): 6
ePlayer team: 21 getTeam(): 6
ePlayer team: 21 getTeam(): 6
ePlayer team: 21 getTeam(): 6
ePlayer team: 21 getTeam(): 6
ePlayer team: 21 getTeam(): 6
ePlayer team: 21 getTeam(): 6
ePlayer team: 21 getTeam(): 6
ePlayer team: 21 getTeam(): 6
ePlayer team: 21 getTeam(): 6
ePlayer team: 0 getTeam(): 7
ePlayer team: 1 getTeam(): 7
ePlayer team: 2 getTeam(): 7
ePlayer team: 3 getTeam(): 7
ePlayer team: 4 getTeam(): 7
ePlayer team: 5 getTeam(): 7
ePlayer team: 6 getTeam(): 7
ePlayer team: 7 getTeam(): 7
ePlayer team: 21 getTeam(): 7
ePlayer team: 21 getTeam(): 7
ePlayer team: 21 getTeam(): 7
ePlayer team: 21 getTeam(): 7
ePlayer team: 21 getTeam(): 7
ePlayer team: 21 getTeam(): 7
ePlayer team: 21 getTeam(): 7
ePlayer team: 21 getTeam(): 7
ePlayer team: 21 getTeam(): 7
ePlayer team: 21 getTeam(): 7
ePlayer team: 21 getTeam(): 7
ePlayer team: 21 getTeam(): 7
ePlayer team: 21 getTeam(): 7
ePlayer team: 21 getTeam(): 7
ePlayer team: 0 getTeam(): 0
ePlayer team: 1 getTeam(): 0
ePlayer team: 2 getTeam(): 0
ePlayer team: 3 getTeam(): 0
ePlayer team: 4 getTeam(): 0
ePlayer team: 5 getTeam(): 0
ePlayer team: 6 getTeam(): 0
ePlayer team: 7 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 21 getTeam(): 0
ePlayer team: 0 getTeam(): 1
ePlayer team: 1 getTeam(): 1
ePlayer team: 2 getTeam(): 1
ePlayer team: 3 getTeam(): 1
ePlayer team: 4 getTeam(): 1
ePlayer team: 5 getTeam(): 1
ePlayer team: 6 getTeam(): 1
ePlayer team: 7 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 21 getTeam(): 1
ePlayer team: 0 getTeam(): 2
ePlayer team: 1 getTeam(): 2
ePlayer team: 2 getTeam(): 2
ePlayer team: 3 getTeam(): 2
ePlayer team: 4 getTeam(): 2
ePlayer team: 5 getTeam(): 2
ePlayer team: 6 getTeam(): 2
ePlayer team: 7 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 21 getTeam(): 2
ePlayer team: 0 getTeam(): 3
ePlayer team: 1 getTeam(): 3
ePlayer team: 2 getTeam(): 3
ePlayer team: 3 getTeam(): 3
ePlayer team: 4 getTeam(): 3
ePlayer team: 5 getTeam(): 3
ePlayer team: 6 getTeam(): 3
ePlayer team: 7 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 21 getTeam(): 3
ePlayer team: 0 getTeam(): 4
ePlayer team: 1 getTeam(): 4
ePlayer team: 2 getTeam(): 4
ePlayer team: 3 getTeam(): 4
ePlayer team: 4 getTeam(): 4
ePlayer team: 5 getTeam(): 4
ePlayer team: 6 getTeam(): 4
ePlayer team: 7 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4
ePlayer team: 21 getTeam(): 4

Think I'm being stupid here. Should add a check for CvPlayer::isEverAlive() and CvPlayer::isAlive() in this function.
 
I should set up some quick logging.

There are some macros at the end of my first DLL tutorial that set up quick logging.

Also, have you added the CvMiniDump code? (Or just search for MOD_DEBUG_MINIDUMP in the VMC/CP code base)
 
There are some macros at the end of my first DLL tutorial that set up quick logging.

Also, have you added the CvMiniDump code? (Or just search for MOD_DEBUG_MINIDUMP in the VMC/CP code base)

No. I do things the hard way. For standalone (which I'm debugging this on) I just use the base civ 5 vanilla code base as a backbone. Also, any idea why the first pass of GetHappinessFromVassal() is causing the logs to appear like that?
 
Changing GetHappinessFromVassals() to this fixed the issue:

Code:
//	--------------------------------------------------------------------------------
///	Get the amount of Happiness we're getting from our vassals
int CvPlayer::GetHappinessFromVassals() const
{
	int iHappiness = 0;

	PlayerTypes ePlayer;
	for(int iPlayerLoop = 0; iPlayerLoop < MAX_MAJOR_CIVS; iPlayerLoop++)
	{
		ePlayer = (PlayerTypes) iPlayerLoop;[B]
		if(GetID() != ePlayer && GET_PLAYER(ePlayer).isAlive())[/B]
		{
			iHappiness += GetHappinessFromVassal(ePlayer);
		}
	}

	return iHappiness;
}
 
Shouldn't the check be in GetHappinessFromVassal(ePlayer)

Code:
if (!GET_PLAYER(ePlayer).isAlive()) return 0;

To protect against calls from elsewhere running into the same issue?
 
Shouldn't the check be in GetHappinessFromVassal(ePlayer)

Code:
if (!GET_PLAYER(ePlayer).isAlive()) return 0;

To protect against calls from elsewhere running into the same issue?

You are absolutely correct, and I will make that change and bundle it into the next version. Thankfully, however, the function is only called from that one right now so I don't have to re-push a fix and then test it until then. :)
 
Top Bottom