Help with DLL / Mastery Victory

Regarding my code, sorry, I quoted the wrong code, but I actually used

Code:
	for (iI = 0; iI < MAX_PLAYERS; iI++)
	{
	if (GET_PLAYER((PlayerTypes)iI).getBuildingClassCount((BuildingClassTypes)GC.getInfoTypeForString("BUILDINGCLASS_ASCENSION_GATE")) == 1);
		{
		iTotalVictoryScore += 100;
		}
	}

But if I use the ')' as you suggested I get the following error:
1>CvTeam.cpp(9381): error C2143: syntax error : missing ';' before '=='
1>CvTeam.cpp(9381): warning C4390: ';' : empty controlled statement found; is this the intent?

As for the Spaceship, I've found part of the code in CvVictoryScreen.py which looks:

Code:
	def teamLaunchedShip(self, teamID):

		iLoopTeam = 0
		
		#Bah still
		for iLoopTeam in range(gc.getMAX_CIV_PLAYERS()):
			if (gc.getPlayer(iLoopTeam).isAlive() and not gc.getPlayer(iLoopTeam).isMinorCiv() and not gc.getPlayer(iLoopTeam).isBarbarian()):
				if (gc.getPlayer(iLoopTeam).getTeam() == teamID):
					if (gc.getGame().getStarshipLaunched(iLoopTeam)):
						return 1		
		return -1

I also think there's a problem with StarshipLaunched.
I'll also have a look at the xml to try GE solution. :)
 
The first issue, the bug you're talking about... I'd have to look into getStarshipLaunched but its a bit suspicious in the naming 'get' which is usually an integer call rather than a boolean and it seems like there should be a boolean to that as in 'has the starship launched?' rather than what it seems to be saying being 'what's the number of starship(s) launched?'.

I've also found in CvGame.cpp
Code:
#if defined QC_MASTERY_VICTORY

bool CvGame::getStarshipLaunched(int ID)
{
  CvPlayer& kPlayer = GET_PLAYER((PlayerTypes)ID);
  
	return starshipLaunched[kPlayer.getTeam()];
}

so getStarshipLaunched is definetly a boolean.
 
Ok, I'm trying God-Emperor's method; but as you've understood I'm still a newbie at coding :D

So I should
1. loop over all building classes.
2. In each of those loop over all victory types.
3. In that loop check for a victory threshold that is greater than 0 for this victory type for this building class. When found one, check to see if the team has built enough to win. For AG, 1 is enough, in fact in Civ4BuildingClassInfos.xml I've found
Code:
		<BuildingClassInfo>
			<Type>BUILDINGCLASS_ASCENSION_GATE</Type>
			<Description>TXT_KEY_BUILDING_ASCENSION_GATE</Description>
			<iMaxGlobalInstances>1</iMaxGlobalInstances>
			<iMaxTeamInstances>-1</iMaxTeamInstances>
			<iMaxPlayerInstances>-1</iMaxPlayerInstances>
			<iExtraPlayerInstances>0</iExtraPlayerInstances>
			<bNoLimit>0</bNoLimit>
			<bMonument>1</bMonument>
			<DefaultBuilding>BUILDING_ASCENSION_GATE</DefaultBuilding>
			<VictoryThresholds>
				<VictoryThreshold>
					<VictoryType>VICTORY_SCIENTIFIC</VictoryType>
					<iThreshold>1</iThreshold>
				</VictoryThreshold>
			</VictoryThresholds>
		</BuildingClassInfo>
4. If the team has built that 1 AG, give the points.

Since I'm not an expert at coding, I've looked around using Google to see how to deal with those loops and checks; I'm pretty sure that the code is wrong but hopefully close enough to require some simple hints to put it right. :)

for iBuildingClass in range(gc.getNumBuildingClassInfos()): --> should loop through BuildingClasses

for iVictory < gc.getNumVictoryInfos()) --> should loop through Victory Types

Then if "the number of buildings of class iBuildingClass needed to win victory type iVictory" is 1, assign 100 points

if (GC.getBuildingClassInfo((BuildingClassTypes)iBuildingClass).getVictoryThreshold((VictoryTypes)iVictory)) == 1;
{
iTotalVictoryScore += 100;
}

Of course this code isn't working but I don't know the correct syntax to put it inside CvTeam.cpp. Right now after compiling I get

1>CvTeam.cpp(9378): error C2061: syntax error : identifier 'iBuildingClass'
1>CvTeam.cpp(9379): error C2059: syntax error : ')'

I know I'm probably making a bunch of stupid questions, but I'd be grateful if I could have some more help. Thank you guys!


Edit: Oh well, the loops look better like:

for (int iBuildingClass = 0; iBuildingClass < GC.getNumBuildingClassInfos(); ++iBuildingClass)
{
for (int iVictory = 0; iVictory < gc.getNumVictoryInfos(); ++iVictory)
{

(If I'm not mistaken)


Edit2: Ok, I've been able to put together a code that can be compiled:
Code:
	for (int iBuildingClass = 0; iBuildingClass < GC.getNumBuildingClassInfos(); ++iBuildingClass)
		{
		for (int iVictory = 0; iVictory < GC.getNumVictoryInfos(); ++iVictory) 
			{
			if (GC.getBuildingClassInfo((BuildingClassTypes)iBuildingClass).getVictoryThreshold((VictoryTypes)iVictory) == 1)
			{
			iTotalVictoryScore += 100;
			}
			}
		}

Problem is that it only gives 100 points to everyone from the start, either if you have built AG or not. And if you build AG, you get 100 points which actually come from a fake SS launch (again, I know it because I've set SS Launch to give 50 points and when I build AG with Worldbuilder that civ gets +50 points). Any other hint?
 
You are only checking to see if the number of the building class is needed to win is 1. It is always 1 for that specific building class so everybody always gets the point. You need to check if the needed number is the number the team (or just the player) has (or better: less than or equal to the number so in case it is changed to allow more than one to be built, or another such victory condition is added it will still work) if the number needed is greater than 0.

I'd suggest something like this:
Code:
	int iBuildingClass, iVictory, iNeeded;
	for (iBuildingClass = 0; iBuildingClass < GC.getNumBuildingClassInfos(); ++iBuildingClass)
	{
		CvBuildingClassInfo& kInfo = GC.getBuildingClassInfo((BuildingClassTypes)iBuildingClass);
		for (iVictory = 0; iVictory < GC.getNumVictoryInfos(); ++iVictory) 
		{
			iNeeded = kInfo.getVictoryThreshold((VictoryTypes)iVictory);
			if ((iNeeded > 0) && (iNeeded <= getBuildingClassCount((BuildingClassTypes)iBuildingClass)))
			{
				iTotalVictoryScore += 100;
			}
		}
	}
Untested, of course...

That is the team version (since getBuildingClassCount has no prefix, it is using the one that goes with the current object which is the current team since this function is part of CvTeam).

It should work for any victory condition where your team has to build X of one building class, for any value of X. If there is more than one such victory condition you'd get 100 points for each.

I would note that you could make this more efficient by moving the loop over victory conditions, and everything in it, into the already existing loop over all building classes, instead of looping over them all yet again. (Up near the start of the function, the first loop using using "iK" where this has "iBuildingClass". You'd probably want to set up kInfo at the start of that loop before its "if" and use it in the existing "if" condition too instead of calling GC.getBuildingClassInfo there, too.)
 
Thank you so much God-Emperor, it's working like a charm! :goodjob:

Now only the other problem remains, which is there in C2C too and was there before this modification: if you build the Ascension Gate, somehow the code understands that you have launched your spaceship so in the Victory Screen you see "Spaceship Launched" and you get 100 points more.

I've looked into the code where spaceship is involved and I've found:

CvTeam.cpp

Code:
	if (GC.getGame().getStarshipLaunched(getID()))
	{
		iTotalVictoryScore += 100;
	}

A function in CvVictory.py to check if the spaceship has been launched:

teamLaunchedShip

Code:
	def teamLaunchedShip(self, teamID):

		iLoopTeam = 0
		
		#Bah still
		for iLoopTeam in range(gc.getMAX_CIV_PLAYERS()):
			if (gc.getPlayer(iLoopTeam).isAlive() and not gc.getPlayer(iLoopTeam).isMinorCiv() and not gc.getPlayer(iLoopTeam).isBarbarian()):
				if (gc.getPlayer(iLoopTeam).getTeam() == teamID):
					if (gc.getGame().getStarshipLaunched(iLoopTeam)):
						return 1		
		return -1

and in CvGame.cpp

Code:
bool CvGame::getStarshipLaunched(int ID)
{
  CvPlayer& kPlayer = GET_PLAYER((PlayerTypes)ID);
  
	return starshipLaunched[kPlayer.getTeam()];
}

and

Code:
	if (bValid)
	{
/************************************************************************************************/
/* Afforess	                  Start		 12/26/09                                                */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/		


                if(GC.getUSE_IS_VICTORY_CALLBACK())
		{
			long lResult = 1;
			CyArgsList argsList;
			argsList.add(eVictory);
			PYTHON_CALL_FUNCTION4(__FUNCTION__, PYGameModule, "isVictory", argsList.makeFunctionArgs(), &lResult);
			if (0 == lResult)
			{
				bValid = false;
			}
		}
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/

/************************************************************************************************/
/* Afforess                                     12/7/09                                         */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
#if defined QC_MASTERY_VICTORY
//Sevo Begin--VCM
		else
	  {
			starshipLaunched[eTeam] = true;	  	
	  }
//Sevo End VCM
#endif
/************************************************************************************************/
/* Afforess	                         END                                                        */
/************************************************************************************************/	
	}

	return bValid;
}

So I suppose the bug is here somewhere; I'm particularly suspicious of the last part of the code above where you read "starshipLaunched[eTeam] = true" but then again I could be wrong given my coding skills.

I'll try some modification to see what happens. :)

Edit: It looks like I was partially right; changing "starshipLaunched[eTeam] = true" to "false" make it so that you don't get those extra 100 points when building AG and SS isn't "launched" anymore (although it's a fake launch). Now the problem is that I don't know what other consequences this part of the code is causing. I'll experiment some more with the coding.
 
45°38'N-13°47'E;12131249 said:
Edit: It looks like I was partially right; changing "starshipLaunched[eTeam] = true" to "false" make it so that you don't get those extra 100 points when building AG and SS isn't "launched" anymore (although it's a fake launch). Now the problem is that I don't know what other consequences this part of the code is causing. I'll experiment some more with the coding.

Ok, so changing this parameter to "false" allows correct SS launch and arrival anyway. With this change, Ascension Gate points work correctly inside Mastery Victory but now Space Ship points don't work anymore, although SS can be launched anyway.

It seems that this part of the code is overlapping for SS and AG victories.
A possible solution might be to introduce a new part of the code inside here (probably with a "if" condition)

Code:
#if defined QC_MASTERY_VICTORY
//Sevo Begin--VCM
		else
	  {
			starshipLaunched[eTeam] = true;	  	
	  }
//Sevo End VCM
#endif

placing "starshipLaunched[eTeam] = false" unless there is something else that's telling me that the spaceship has REALLY been launched and it's not a "false positive" due to the AG. But then again, I'm not sure that even placing such a condition won't again give players +100 points more when they have both built the AG and effectively launched the SS.
Any other idea/suggestion anyone? Thank you.
 
Got it!
This is the new code to check for AG and SS victories in Mastery Victory.
For Spaceship victory, instead of checking for (GC.getGame().getStarshipLaunched(getID())), I'm checking if there's a countdown going on. Since the only countdown going on when using Mastery Victory is the spaceship countdown... bingo! When it reaches 1 (or whatever you like), you get those 100 points.

Code:
	//Starship points!  Big money.
	for (int iI = 0; iI < GC.getNumVictoryInfos(); ++iI)
	{
		if (getVictoryCountdown((VictoryTypes)iI) == 1)
	{
		iTotalVictoryScore += 100;
	}
	else iTotalVictoryScore += 0;
	}
	//Ascension Gate points (Scientific Victory)!  Big money! (Thanks to God-Emperor @CivFanatics)
int iBuildingClass, iVictory, iNeeded;
	for (iBuildingClass = 0; iBuildingClass < GC.getNumBuildingClassInfos(); ++iBuildingClass)
	{
		CvBuildingClassInfo& kInfo = GC.getBuildingClassInfo((BuildingClassTypes)iBuildingClass);
		for (iVictory = 0; iVictory < GC.getNumVictoryInfos(); ++iVictory) 
		{
			iNeeded = kInfo.getVictoryThreshold((VictoryTypes)iVictory);
			if ((iNeeded > 0) && (iNeeded <= getBuildingClassCount((BuildingClassTypes)iBuildingClass)))
			{
				iTotalVictoryScore += 100;
			}
		}
	}

This change in the code of CvTeam.cpp, together with

Code:
#if defined QC_MASTERY_VICTORY
//Sevo Begin--VCM
		else
	  {
			starshipLaunched[eTeam] = false;	  	
	  }
//Sevo End VCM
#endif

inside CvGame.cpp should do the trick for Mastery Victory without causing problems to other victory conditions (when MV isn't used).
Now I only need to modify CvVictoryScreen.py accordingly to show those 100 points from AG and to show that a SS has been launched.

Edit: No, I'm wrong! There's another countdown beside that of the SS, and that's the final countdown for the last 100 turns, damn, I forgot!
 
Ok, I've almost done it! I've rewritten the code using God-Emperor's suggestion and now it works for both Spaceship & Ascension Gate, without that annoying bug which gives 100 points for SS Launch (and Victory Screen tells you that you've launched the SS) when you have in fact not launched anything but you've built AG.
I have only one (little, I hope) problem; in the code below how do I tell the code to set to "1" GC.getGame().getStarshipLaunchedMV for a specific Team/Player?

Code:
	//Starship points!  Big money.
int iProjectInfos, qVictory, qNeeded;
	for (iProjectInfos = 0; iProjectInfos < GC.getNumProjectInfos(); ++iProjectInfos)
	{
		CvProjectInfo& kInfo = GC.getProjectInfo((ProjectTypes)iProjectInfos);
		for (qVictory = 0; qVictory < GC.getNumVictoryInfos(); ++qVictory) 
		{
			qNeeded = kInfo.getVictoryThreshold((VictoryTypes)qVictory);
			if ((qNeeded > 0) && (qNeeded <= getProjectCount((ProjectTypes)iProjectInfos)) && ((getLaunchSuccessRate((VictoryTypes)qVictory)) == 100))
			{
				iTotalVictoryScore +=  20;
				[COLOR="Red"]GC.getGame().getStarshipLaunchedMV(???) = 1;  [/COLOR]
			}
		}
	}

I suppose there's something that I need to put in place of the "???" but I don't know what it is. I suppose that everything works if I place "1" or "2" or whatever in place of "???" but I need to tell the code to place there the number of the player that I'm working on in the lines before.
Anyone can give me a hint?

Edit: Actually I need to simply make it so that StarshipLaunchedMV(???) is true when I assign those 20 points, if there's another way to do it. That's exactly what I need.
 
I think there is a bug in CvGame's testVictory function (the one with parameters).

It currently is like this near the end, where all the relevant stuff is:
Code:
	if (bValid)
	{
		for (int iK = 0; iK < GC.getNumBuildingClassInfos(); iK++)
		{
			if (GC.getBuildingClassInfo((BuildingClassTypes) iK).getVictoryThreshold(eVictory) > GET_TEAM(eTeam).getBuildingClassCount((BuildingClassTypes)iK))
			{
				bValid = false;
				break;
			}
		}
	}

	if (bValid)
	{
		for (int iK = 0; iK < GC.getNumProjectInfos(); iK++)
		{
			if (GC.getProjectInfo((ProjectTypes) iK).getVictoryMinThreshold(eVictory) > GET_TEAM(eTeam).getProjectCount((ProjectTypes)iK))
			{
				bValid = false;
				break;
			}
		}
	}


	if (bValid)
	{
/****************************************************************/************************************************************************************************/
/* Afforess	                  Start		 12/26/09                                                */
/*                                                                                              */
/*                                                                                              */
/****************************************************************/************************************************************************************************/		


                if(GC.getUSE_IS_VICTORY_CALLBACK())
		{
			long lResult = 1;
			CyArgsList argsList;
			argsList.add(eVictory);
			PYTHON_CALL_FUNCTION4(__FUNCTION__, PYGameModule, "isVictory", argsList.makeFunctionArgs(), &lResult);
			if (0 == lResult)
			{
				bValid = false;
			}
		}
/****************************************************************/************************************************************************************************/
/* Afforess	                     END                                                            */
/****************************************************************/************************************************************************************************/

/****************************************************************/************************************************************************************************/
/* Afforess                                     12/7/09                                         */
/*                                                                                              */
/*                                                                                              */
/****************************************************************/************************************************************************************************/
#if defined QC_MASTERY_VICTORY
//Sevo Begin--VCM
		else
	  {
			starshipLaunched[eTeam] = true;	  	
	  }
//Sevo End VCM
#endif
/****************************************************************/************************************************************************************************/
/* Afforess	                         END                                                        */
/****************************************************************/************************************************************************************************/	
	}

	return bValid;
}

So consider what happens if the value of eVictory is the one for the ascension gate victory condition (VC). ASsume the team being checked has, in fact, built one.

1) bValid is "true" going into the first of the 3 "if (bValid)" statements, which does the check for the ascension gate VC.

2) It passes the test inside this "if" block since the gate has been built.

3) Since it passed the test, bValid is still "true" on exiting that "if" block.

4) It hits the spaceship test "if" and runs the test since bValid is still "true".

5) It passes the spaceship test. Since no project has any number of them required to win the ascension gate VC (they should all be 0, or maybe even -1, required) so there are never more of them required than you have built so bValid is not changed to "false".

6) It passed the spaceship test so bValid is still "true".

7) It hits the last "if (bValid)" block and enters it since bValid is still "true".

8) The isVictory callback is disabled in C2C so the GC.getUSE_IS_VICTORY_CALLBACK() function returns false.

9) Since the expression was false, the "else" block is run.

10) The value of starshipLaunched is set to "true" for this team.

11) The end of the function is hit and "true" is returned: the team has built an ascension gate.

12) Oops. That was the wrong thing to do back at step 10 (or even 9). The ship was not ready to be launched (and we were not even checking the relevant victory condition).

It will set the starshipLaunched value to true if any VC is met, not just those two.

Here is a way to fix this. Move the part that sets starshipLaunched to "true" to where it should have been in the first place: inside the starship section (technically speaking this is not necessary, but it is much clearer). Also add a check to see if there were actually any starship components with non-zero counts needed for this VC. Your spaceship is only ready if this VC required one or more projects with non-zero coutns for this VC and they included projects marked as being parts of the spaceship.

Here is the same end section of the function with that done:
Code:
	if (bValid)
	{
		for (int iK = 0; iK < GC.getNumBuildingClassInfos(); iK++)
		{
			if (GC.getBuildingClassInfo((BuildingClassTypes) iK).getVictoryThreshold(eVictory) > GET_TEAM(eTeam).getBuildingClassCount((BuildingClassTypes)iK))
			{
				bValid = false;
				break;
			}
		}
	}

	if (bValid)
	{// God-Emperor: fix the starshipLaunched setting by moving it in here and checking more carefully
		int iNeeded;
#if defined QC_MASTERY_VICTORY
		bool bSSParts = false; // God-Emperor: not just any projects, the spaceship parts projects
#endif
		for (int iK = 0; iK < GC.getNumProjectInfos(); iK++)
		{
			iNeeded = GC.getProjectInfo((ProjectTypes) iK).getVictoryMinThreshold(eVictory);
			if ( iNeeded > GET_TEAM(eTeam).getProjectCount((ProjectTypes)iK))
			{
				bValid = false;
				break;
			}
#if defined QC_MASTERY_VICTORY
			else if ((iNeeded > 0) && GC.getProjectInfo((ProjectTypes) iK).isSpaceship())
			{// God-Emperor: since only one of the two needs to be false to skip setting starshipLaunched this can be an "else if" rather than an "if".
				bSSParts = true;
			}
#endif
		}		
#if defined QC_MASTERY_VICTORY
//Sevo Begin--VCM
		if (bValid && bSSParts) // God-Emperor: do this here. If both are true there are enough SS parts done to launch.
		{
			starshipLaunched[eTeam] = true;	  	
		}
//Sevo End VCM
#endif
	}

	if (bValid)
	{
/****************************************************************/************************************************************************************************/
/* Afforess	                  Start		 12/26/09                                                */
/*                                                                                              */
/*                                                                                              */
/****************************************************************/************************************************************************************************/
		if(GC.getUSE_IS_VICTORY_CALLBACK())
		{
			long lResult = 1;
			CyArgsList argsList;
			argsList.add(eVictory);
			PYTHON_CALL_FUNCTION4(__FUNCTION__, PYGameModule, "isVictory", argsList.makeFunctionArgs(), &lResult);
			if (0 == lResult)
			{
				bValid = false;
			}
		}
/****************************************************************/************************************************************************************************/
/* Afforess	                     END                                                            */
/****************************************************************/************************************************************************************************/
	}

	return bValid;
}

In conjunction with the earlier code in CvTeam's getTotalVictoryScore function (with the ascension gate added but still checking starshipLaunched to see if it should assign the spaceship points) it should work.

Well, I have not (of course) actually test it. But it does compile. (It is in the R2R version of the DLL, ready for the next release assuming testing reveals no problem.)

By the way:
I also noticed another issue, but did nothing about it in R2R. In the CvTeam.h header file, the getTotalVictoryScore function's declaration is only present if QC_MASTERY_VICTORY is defined, but in the .cpp file it is always present. So if QC_MASTERY_VICTORY was not defined the thing would have an "issue". (I wrapped some relevant bits of the fixed code up above with checks for this definition even though it was not really necessary.)
 
Thank you again, God-Emperor. I've found an alternative solution in the meantime using an external variable in CvTeam but your solution looks a lot easier and perfectly working, so I've updated the latest SVN revision of AND with your code. I only had to make small changes to the Ascension Gate part to adapt the code to the new code I had to write in CvVictoryScreen.py to show 100 points given for building AG in Mastery Victory.
I'll also have a look at what you've pointed out about getTotalVictoryScore function's declaration. Thank you so much again! :)
 
I want to say Thanks to G-E too!

JosEPh :)
 
Back
Top Bottom