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.)