JoshW said:
I believe this question has been asked before BUT for the life of me I can't find that post and I don't think it got a thorough answer when it was asked.
The question is:
"Does anyone know what the mechanism in the game is that bans nukes when the NPT resolution is passed through the UN? I.e., how does the game disallow their production to the players/AI? What I am looking for is some way to create resolutions that ban production of other weapons."
Background info:
Looking through the XML files, it seems rather clear how the game is told to force civics, to ban nukes, etc, since I have seen via one fo the UN mods that the XML file "CIV4VoteInfo.xml" uses the <ForceCivics/> command. Using some additional code, one can tell it which civics to force. The <bNoNukes>1</bNoNukes> command tells the game "this resolution bans nukes," but how the nukes become unavailable to the player/AI is a mystery to me.
It's all done in the SDK.
When Civ4 first starts, all the different votes (from CIV4VoteInfo.xml) are read in. Their values are stored into a data structure (a c++ class called CvVoteInfo). One of the values is a boolean value about whether or not the vote disables nukes.
Whenever a vote is passed (either to enable or disable), this c++ function is called:
Code:
void CvGame::processVote(VoteTypes eVote, int iChange)
{
int iI;
changeTradeRoutes(GC.getVoteInfo(eVote).getTradeRoutes() * iChange);
changeFreeTradeCount((GC.getVoteInfo(eVote).isFreeTrade()) ? iChange : 0);
[b]changeNoNukesCount((GC.getVoteInfo(eVote).isNoNukes()) ? iChange : 0);[/b]
for (iI = 0; iI < GC.getNumCivicInfos(); iI++)
{
changeForceCivicCount(((CivicTypes)iI), ((GC.getVoteInfo(eVote).isForceCivic(iI)) ? iChange : 0));
}
}
The arguments are eVote (the vote that passed), and iChange (which will be 1 if the vote was to accept the new treaty, -1 if it was to revoke it). As you can see, "changeNoNukesCount" is a function that gets affected if the vote turns out to be a "no nukes" count. The function simply makes an integer value stored in the CvGame class 1 (or puts it back to zero if nukes were previously banned and then the ban was lifted).
You can check the value of this variable by using the CvGame::isNoNukes(). How nukes are actually allowed or disallowed to be trained is done in CvPlayer::canTrain, which is called to check for every unit if a player can or cannot build it.
Code:
if (GC.getGameINLINE().isNoNukes())
{
if (GC.getUnitInfo(eUnit).getNukeRange() != -1)
{
return false;
}
}
So, the game uses the definition of a unit with their iNukeRange value not -1 to determine if the unit is considered a "nuke".
Ok, so enough blathering. If you really want to go through with what you're doing, here is what you would have to do:
Using the SDK:
1.) Create your new resolutions in the Civ4VoteInfos.xml.
2.) Modify the SDK to allow for the Civ4VoteInfos.xml to have other tags similar to bNoNukes.
3.) Modify the CvPlayer::canTrain to disallow units in the same way that nukes are disallowed.
Without using the SDK:
1.) Create your new resolutions in the Civ4VoteInfos.xml
2.) Modify the CvGameUtils.py file. Add a dictionary of resolutions, and for each resolution their banned units, to the CvGameUtils class, and initialize it in the init:
Code:
def __init__(self):
self.m_dResolutionUnitBans = {
gc.getInfoTypeForString("MY_RESOLUTION_NAME_1") : ("UNIT_BANNED_1", "UNIT_BANNED_2")
gc.getInfoTypeForString("MY_RESOLUTION_NAME_2") : ("UNIT_BANNED_1", "UNIT_BANNED_2")
}
3.) Modify the cannotTrainUnit function in that file to return True (meaning that the unit cannot be built) if the resolution is passed.
Code:
if not bTestVisible:
for iVote in range(gc.getNumVoteInfos()):
if gc.getGame().isVotePassed(iVote):
if self.m_dResolutionUnitBans.has_key(iVote):
for szBannedUnit in self.m_dResolutionUnitBans[iVote]:
if gc.getInfoTypeForString(szBannedUnit) == eUnit:
return True
Obviously, doing it without the SDK is easier, but your data for unit bans won't be stored in the XML files, and not changing the SDK means you can't add "Can't build unit!" entries to the info pane when the unit is hovered over to be trained. However, that's a small enough problem that it may not be worth going through the trouble of doing everything to change the SDK.
Note: I haven't tested any of this code, I just wrote it right in the browser, so it may not work right away, but you can probably tweak it to work correctly.