AddSetting
OpenTTD Development Documentation
External Links

OpenTTD GitHub
Contributing to OpenTTD - guidelines
OpenTTD Doxygen

General Reference

Coding style
Compiling OpenTTD
Debugging
Add a setting
Add a squirrel function
Understanding the SaveGame handler
Bumping the savegame version
Doing an OpenTTD release

Language and Strings

Manual of style
Format of langfiles
Using OpenTTD strings
List of special strings

Window System

Using the window system
Colour codes that exist in OpenTTD
Adding a text box
Understanding the widget focus system
GUI style guide

Multiplayer

The OpenTTD TCP protocol
The OpenTTD UDP protocol
Debugging desyncs
Server Admin Port development

Ingame Console

The console window
Console commands
Console variables
Using console scripting
Adding functions/commands to the console
Adding variables to the console
Console development history

Content APIs (modding frameworks)

Graphics and similar (NewGRF)
AI framework (NoAI)
GameScript framework (NoGO)
Social Integration

Other Reference

Map array (landscape grid)
Vehicles
Pathfinding
Train acceleration
Sound IDs

This article will briefly explain how a custom setting variable can be made by changing the source code of OpenTTD. The tutorial will describe the process of adding two additional options to the Advanced Settings dialog - one integer option and one bool.

Contents

Sections

The different settings categories can be seen from the Advanced Settings window:

When adding the variables, minor single line settings get squeezed into their appropriate position in the list, while larger groups of settings are added at the end of the section. In this tutorial we are going to add two attributes to the Economy->Town section:

It is strongly advised to use the doxygen documentation for reference while interacting with the source code.

Overview

During this tutorial, a number of files will be changed:

To understand this thoroughly - you are advised to look around in all these files and try to get a feeling with how they are structured and how things generally are done.

Translation file - english.txt

All text strings in OpenTTD are saved in language files. English is the only required translation - but if you know more languages you are welcome to add translations to those as well.

We want to add 4 strings: 2 variable names, and 2 descriptions of those variables. Please note that all setting strings should have a STR_CONFIG_SETTING_ prefix. extension.

STR_CONFIG_SETTING_ENABLE_GODZILLA                :{LTBLUE}Enable Godzilla mode {ORANGE}{STRING2}
STR_CONFIG_SETTING_ENABLE_GODZILLA_HELPTEXT       :Enable/disable Godzilla mode
STR_CONFIG_SETTING_NUMBER_GODZILLAS               :{LTBLUE}Number of Godzillas: {ORANGE}{STRING2} 
STR_CONFIG_SETTING_NUMBER_GODZILLAS_HELPTEXT      :Enter how many Godzillas that should be present in the game (0-100)

(take a look at the documentation for the Eints library if you want to learn more about the string system)

These variables should be placed in a natural place - I put them just after STR_CONFIG_SETTING_MODIFIED_ROAD_REBUILD_HELPTEXT. Note that there are no tabs in this file, only spaces.

Variable declaration and settings section - settings_type.h

The declaration of the variables are found in settings_type.h. We need to find a suitable category - these are the choices:

 struct GameSettings {
 	 DifficultySettings   difficulty;         ///< settings related to the difficulty
 	 GameCreationSettings game_creation;      ///< settings used during the creation of a game (map)
 	 ConstructionSettings construction;       ///< construction of things in-game
 	 AISettings           ai;                 ///< what may the AI do?
 	 ScriptSettings       script;             ///< settings for scripts
 	 class AIConfig      *ai_config[MAX_COMPANIES]; ///< settings per company
 	 class GameConfig    *game_config;        ///< settings for gamescript
 	 PathfinderSettings   pf;                 ///< settings for all pathfinders
 	 OrderSettings        order;              ///< settings related to orders
 	 VehicleSettings      vehicle;            ///< options for vehicles
 	 EconomySettings      economy;            ///< settings to change the economy
 	 LinkGraphSettings    linkgraph;          ///< settings for link graph calculations
 	 StationSettings      station;            ///< settings related to station management
 	 LocaleSettings       locale;             ///< settings related to used currency/unit system in the current game
 };

EconomySettings looks good - search for struct EconomySettings and add the declarations of the two variables:

 /** Settings related to the economy. */
 struct EconomySettings {
     // lots of other variables
     bool godzilla_mode;            ///< Enables Godzilla mode
     uint8 number_godzillas;        ///< Number of Godzillas
 }

Note that the comments has a /< prefix for creating documentation with doxygen.

Variable name in config file - settings_gui.cpp

The name that the variable will have in Openttd.cfg are defined in settings_gui.cpp. Here the specific subpage the variable will be shown on is also chosen.

The Economy->Town looks like a good match, so we'll add these entries to _settings_economy_towns[]:

 SettingsPage *towns = environment->Add(new SettingsPage(STR_CONFIG_SETTING_ENVIRONMENT_TOWNS));
 {
     \\ lots of other entries
     towns->Add(new SettingEntry("economy.godzilla_mode"));
     towns->Add(new SettingEntry("economy.number_godzillas"));
 }

Variable specifics - settings.ini

We need to add a set of instructions to OpenTTD so that it handles the data in the correct way. The way we are doing this is by adding blocks of data to settings.ini - each block representing one variable.

There are different data structures and advanced topics on this area, but we will focus on SDT_VAR and SDT_BOOL - the two most common used. Below is a sample configuration for our variables:

 [SDT_VAR]
 base     = GameSettings
 var      = economy.number_godzillas
 type     = SLE_UINT8
 from     = 189
 to       = SL_MAX_VERSION
 flags    = 0
 guiflags = SGF_NEWGAME_ONLY
 def      = 10
 min      = 0
 max      = 100
 interval = 5
 str      = STR_CONFIG_SETTING_NUMBER_GODZILLAS
 strhelp  = STR_CONFIG_SETTING_NUMBER_GODZILLAS_HELPTEXT
 strval   = STR_JUST_INT

Basically:

[SDT_BOOL]
base     = GameSettings
var      = economy.godzilla_mode
from     = 189
to       = SL_MAX_VERSION
guiflags = 0
def      = false
str      = STR_CONFIG_SETTING_ENABLE_GODZILLA
strhelp  = STR_CONFIG_SETTING_ENABLE_GODZILLA_HELPTEXT

The only change from above is that there is no gui flag - this setting may be altered inside a game.

Otherwise, if not specified, default values are used:

[defaults]
flags    = 0
guiflags = 0
interval = 0
str      = STR_NULL
strhelp  = STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT
strval   = STR_NULL
proc     = NULL
load     = NULL
from     = 0
to       = SL_MAX_VERSION
cat      = SC_ADVANCED

Try to find a natural place in the file for your settings. I placed it right below the economy.initial_city_size block.

Below is a detailed explanation of some of the attributes:

Variable configuration options

SLF_NOT_IN_SAVE - do not save with savegame, basically client-based
SLF_NOT_IN_CONFIG - do not save to config file
SLF_NO_NETWORK_SYNC - do not synchronize over network (but it is saved if SLF_NOT_IN_SAVE is not set)
SLF_ALLOW_CONTROL - allow control codes in the strings
SLF_ALLOW_NEWLINE - allow new lines in the strings
SGF_0ISDISABLED - The feature is disabled (greyed out)
SGF_DISPLAY_ABS - display absolute value of the setting
SGF_MULTISTRING - the value represents a limited number of string-options (internally integer)
SGF_NETWORK_ONLY - this setting only applies to network games
SGF_CURRENCY - the number represents money, so when reading value multiply by exchange rate
SGF_NO_NETWORK - this setting does not apply to network games; it may not be changed during the game
SGF_NEWGAME_ONLY - this setting cannot be changed in a game
SGF_SCENEDIT_TOO - this setting can be changed in the scenario editor (only makes sense when SGF_NEWGAME_ONLY is set)
SGF_PER_COMPANY - this setting can be different for each company (saved in company struct)

Making your build compatible with older savegames

Final result

If you don't use the flag SLF_NOT_IN_SAVE, OpenTTD will expect to find your variable in every savegame. Therefore, it's important to tell the game from which version this setting was added. The savegame version number is found near the start of saveload.cpp.

When OpenTTD loads a data chunk, it compares the savegame version it was compiled with, with the savegame version in the savegame. By checking the to and from attributes in the settings, it can see whether it supports the feature or not.

This way, you can control whether your feature is saved, and if it is, whether that save is compatible with previous versions.

Note: If you define any variables without the SLF_NOT_IN_SAVE flag in the settings, all saves made on your build will be incompatible with all other versions of OpenTTD.

To allow the opposite (load old games using your build), you'll have tell OpenTTD that you've introduced a new feature, and increase the savegame version. If the current trunk is at version 160, and you have a new feature that to be saved along with the savefile, simply increase the savegame version. This is known as a savegame bump.

When a normal build of OpenTTD tries to load a savegame from your system, it will notice the savegame bump, and gracefully say Sorry, I cant load that - it's too new for me".

However, when loading a game with a savegame version lower than the specified in your from attribute in your setting - OpenTTD will know that it wont find that setting in the savefile, and loading should go succeed.

So for our example above, we bump the savegame to 189 in saveload.cpp and set from to 161 and to to SL_MAX_VERSION in both our blocks in settings.ini.

Now there's only one thing left to do - compile! I you've everything correct, you should see something similar as the picture to the right.