[SDK] How to add game options like 'Raging Barbarians' for your own settings

Seven05

Warmonger
Joined
Dec 5, 2005
Messages
2,056
Location
USA
Ok, I couldn't believe how easy this was when I added it to my mod tonight so I'll put up a short tutorial so everybody else can start using it to. In my opinion, this is thousands of times more user friendly that having XML or ini file configuration options. This also means you can maintain both flexible configurations and MP compatability easily since the players won't be changing anything in XML or Python. This is an SDK change to add the new options to the list, once you've added them they can be used in python scripts as well.

First, we have the CIV4GameOptionInfos.xml file in your GameInfo folder which needs the new option type added to it, it's also helpful to add in the text too. My change was to add an option to enable/disable my SDK based tile stack limit, here's the new XML entry for the option type:
Code:
		<GameOptionInfo>
			<Type>GAMEOPTION_STACK_LIMIT</Type>
			<Description>TXT_KEY_GAME_OPTION_STACK_LIMIT</Description>
			<Help>TXT_KEY_GAME_OPTION_STACK_LIMIT_HELP</Help>
			<bDefault>1</bDefault>
			<bVisible>1</bVisible>
		</GameOptionInfo>
The description is the text that shows up next to the checkbox in the custom game screen or staging area for MP games. The help text shows up when you mouse-over the option in the menu. bDefault determines the initial state of the checkbox and bVisible can be used to hide the checkbox, both are boolean values, 1 is 'true' and 0 is 'false' or 'on' and 'off' if you prefer.

In the SDK we need to add the enum for our new OptionType to CvEnums.h. Order is important here, make sure you place your new option(s) in the same order both in the enum list and the xml file. Here's my complete list in CvEnums.h:
Code:
	NO_GAMEOPTION = -1,

	GAMEOPTION_ADVANCED_START,
	GAMEOPTION_NO_CITY_RAZING,
	GAMEOPTION_NO_CITY_FLIPPING,
	GAMEOPTION_FLIPPING_AFTER_CONQUEST,
	GAMEOPTION_NO_BARBARIANS,
	GAMEOPTION_RAGING_BARBARIANS,
	GAMEOPTION_AGGRESSIVE_AI,
	GAMEOPTION_LEAD_ANY_CIV,
	GAMEOPTION_RANDOM_PERSONALITIES,
	GAMEOPTION_PICK_RELIGION,
	GAMEOPTION_NO_TECH_TRADING,
	GAMEOPTION_NO_TECH_BROKERING,
	GAMEOPTION_PERMANENT_ALLIANCES,
	GAMEOPTION_ALWAYS_WAR,
	GAMEOPTION_ALWAYS_PEACE,
	GAMEOPTION_ONE_CITY_CHALLENGE,
	GAMEOPTION_NO_CHANGING_WAR_PEACE,
	GAMEOPTION_NEW_RANDOM_SEED,
	GAMEOPTION_LOCK_MODS,
	GAMEOPTION_COMPLETE_KILLS,
	GAMEOPTION_NO_VASSAL_STATES,
	GAMEOPTION_NO_GOODY_HUTS,
	GAMEOPTION_NO_EVENTS,
	GAMEOPTION_STACK_LIMIT, // World Piece
GAMEOPTION_NO_EVENTS is line # 729.

Once we have a valid enum setup we need to expose it to python in CyEnumsInterface.cpp. Search for python::enum_<GameOptionTypes>("GameOptionTypes") and add yours to the list, here is my change:
Code:
		.value("GAMEOPTION_NO_EVENTS", GAMEOPTION_NO_EVENTS)
/*** World Piece Begin ***/
		.value("GAMEOPTION_STACK_LIMIT", GAMEOPTION_STACK_LIMIT)
/*** World Piece End ***/
		.value("NUM_GAMEOPTION_TYPES", NUM_GAMEOPTION_TYPES)

Your basically done right there if you're going to use it in python. To use it in custom SDK code you can test the setting of the option like this:
Code:
GC.getGameINLINE().isOption(GAMEOPTION_STACK_LIMIT)
That will return true or false depending on whether the box was checked (true) or un-checked (false) when the player started the game. For my stack limit, I used it in my modified canMoveInto() method in CvUnit.cpp to encapsulate the entire code and only run it if the option was enabled with a simple if statement:
Code:
if ( GC.getGameINLINE().isOption(GAMEOPTION_STACK_LIMIT) )
Like I said at the begining, I was amazed at how easy this was. Just make sure you remember to do a clean build otherwise your new options won't display since the NUM_GAMEOPTIONS value will not update otherwise and if that doesn't update no addition options will showup in the game.

Oh, the python code for checking a game option is (assume gc = CyGlobalContext()):
Code:
gc.getGame().isOption(GameOptionTypes.GAMEOPTION_STACK_LIMIT))
So if custom options are important and you're sick of trying to explain how to enable/disable features of your mod here's your solution :)
 
No problem.

One thing I just noticed that I did put in there (or maybe I missed it) is that you have to do a clean build of the DLL for any changes in CvEnums.h to take effect. So if you have problems seeing your new option in the game that's why :)
 
Sometimes you answer the questions before I even think of them!!!

I do have one follow-up though. You say:

Your basically done right there if you're going to use it in python.

Well, if I use this, it WILL be in Python. Question is: how do I designate the code that I want to allow the players to enable/disable in Python itself?
 
That depends on what you're trying to do. All you need to do to make it work is read the state of the option which is always either on or off, basically true or false.

So if you have code that will only execute when a specific option is enable it would look something like this:
Code:
if gc.getGame().isOption(GameOptionTypes.GAMEOPTION_YOUR_OPTION)):
    #Execute your code here

This is an SDK tutorial though, so if you have no intention of doing anything in the DLL you'll be better of reading global defines or options from your own ini file. Well, not only will you be better off but that's what you'll have to do unless you ready to dive into the SDK :)
 
That depends on what you're trying to do. All you need to do to make it work is read the state of the option which is always either on or off, basically true or false.

So if you have code that will only execute when a specific option is enable it would look something like this:
Code:
if gc.getGame().isOption(GameOptionTypes.GAMEOPTION_YOUR_OPTION)):
    #Execute your code here
This is an SDK tutorial though, so if you have no intention of doing anything in the DLL you'll be better of reading global defines or options from your own ini file. Well, not only will you be better off but that's what you'll have to do unless you ready to dive into the SDK :)

True that, true that. Well, if I can get my hands on a compiler, I suppose I'm ready to stop worrying and love the DLL. :crazyeye:
 
True that, true that. Well, if I can get my hands on a compiler, I suppose I'm ready to stop worrying and love the DLL. :crazyeye:
MS Visual Studio 2005 express is free... can't get a better deal :)

You could do that whole resource depletion code a lot better in the DLL too.
 
Yeah, but I heard there were some problems using 2005.....that it was best to use 2003 for the SDK.

And you're no doubt right about the resource code, but whereas I can speak broken Python, I'm still functionally illiterate in C++. Let me get the code working in python first, then we'll talk. :)
 
Delete all of the 'intermediate files' and then build the DLL. The intermediate files are the *.obj files that the compiler typically puts in your output folder (final_release if you followed the tutorials here). Those are the compiled source files that the linker then assembles into the final dll. Be prepared, after deleting them a 'clean build' will take considerably longer since it will re-compile every file in the project.

If your curious, you have to do this because of the way the enum types are defined in the header files. You don't actually have to delete ALL intermediate files, but I can't remember exactly whichs ones need to go for this to work with these changes so if you nuke them all you'll get the ones you need to :)
 
Keep getting a runtime error....I suppose this means I didn't compile correctly. Oh well -- will try again tomorrow. :P

My kingdom for Visual C++ 2003!
 
That depends on what you're trying to do. All you need to do to make it work is read the state of the option which is always either on or off, basically true or false.

So if you have code that will only execute when a specific option is enable it would look something like this:
Code:
if gc.getGame().isOption(GameOptionTypes.GAMEOPTION_YOUR_OPTION)):
    #Execute your code here

This is an SDK tutorial though, so if you have no intention of doing anything in the DLL you'll be better of reading global defines or options from your own ini file. Well, not only will you be better off but that's what you'll have to do unless you ready to dive into the SDK :)

I'm unsure where exactly where I should put the if gc.getGame.... string if the SDK code is spread over several files.
 
is it possible to make multioptional options?

for example a drop down box with 3 different options: peaceful, rebellious, furious?
 
Here is some more code that may help others:

Say you have an xml GlobalDefines addition and you want to make it intoa gameoption.

Origional Code:
Code:
	// Dale - SA: Stack Attack START
	if (GC.isDCM_STACK_ATTACK())
	{
		updateStackCombat(bQuick);
		return;
	}
	// Dale - SA: Stack Attack END

Option Added:
Code:
	// Dale - SA: Stack Attack START
	if (GC.isDCM_STACK_ATTACK() [COLOR="Blue"]&& GC.getGameINLINE().isOption(GAMEOPTION_DCM)[/COLOR])
	{
		updateStackCombat(bQuick);
		return;
	}
	// Dale - SA: Stack Attack END

The method shown above enables you to still turn off individual parts of a Mod such as DCM, while the others are still operational.

Code for a player option is:
Code:
if (GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_BATTLEFIELD_PROMO))
 
Top Bottom