src/settings_gui.cpp
branchNewGRF_ports
changeset 6872 1c4a4a609f85
parent 6871 5a9dc001e1ad
child 6877 889301acc299
equal deleted inserted replaced
6871:5a9dc001e1ad 6872:1c4a4a609f85
     3 /** @file settings_gui.cpp */
     3 /** @file settings_gui.cpp */
     4 
     4 
     5 #include "stdafx.h"
     5 #include "stdafx.h"
     6 #include "openttd.h"
     6 #include "openttd.h"
     7 #include "currency.h"
     7 #include "currency.h"
     8 #include "functions.h"
       
     9 #include "string.h"
       
    10 #include "strings.h" // XXX GetCurrentCurrencyRate()
       
    11 #include "table/sprites.h"
       
    12 #include "table/strings.h"
       
    13 #include "window.h"
       
    14 #include "gui.h"
     8 #include "gui.h"
    15 #include "gfx.h"
     9 #include "window_gui.h"
    16 #include "command.h"
    10 #include "textbuf_gui.h"
       
    11 #include "command_func.h"
    17 #include "engine.h"
    12 #include "engine.h"
    18 #include "screenshot.h"
    13 #include "screenshot.h"
    19 #include "newgrf.h"
    14 #include "newgrf.h"
    20 #include "network/network.h"
    15 #include "network/network.h"
    21 #include "town.h"
    16 #include "town.h"
    22 #include "variables.h"
    17 #include "variables.h"
    23 #include "settings.h"
    18 #include "settings_internal.h"
    24 #include "vehicle.h"
       
    25 #include "date.h"
       
    26 #include "helpers.hpp"
       
    27 #include "newgrf_townname.h"
    19 #include "newgrf_townname.h"
       
    20 #include "strings_func.h"
       
    21 #include "functions.h"
       
    22 #include "window_func.h"
       
    23 #include "vehicle_base.h"
       
    24 #include "core/alloc_func.hpp"
       
    25 #include "string_func.h"
       
    26 #include "gfx_func.h"
       
    27 #include "widgets/dropdown_type.h"
       
    28 #include "widgets/dropdown_func.h"
       
    29 
       
    30 #include "table/sprites.h"
       
    31 #include "table/strings.h"
    28 
    32 
    29 static uint32 _difficulty_click_a;
    33 static uint32 _difficulty_click_a;
    30 static uint32 _difficulty_click_b;
    34 static uint32 _difficulty_click_b;
    31 static byte _difficulty_timeout;
    35 static byte _difficulty_timeout;
    32 
    36 
    66 	*p = INVALID_STRING_ID;
    70 	*p = INVALID_STRING_ID;
    67 	return buf;
    71 	return buf;
    68 }
    72 }
    69 
    73 
    70 int _nb_orig_names = SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1;
    74 int _nb_orig_names = SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1;
    71 static StringID *_town_names = NULL;
       
    72 static StringID *_grf_names = NULL;
    75 static StringID *_grf_names = NULL;
    73 static int _nb_grf_names = 0;
    76 static int _nb_grf_names = 0;
    74 
    77 
    75 void SortTownGeneratorNames()
    78 void InitGRFTownGeneratorNames()
    76 {
    79 {
    77 	int n = 0;
       
    78 
       
    79 	/* Get Newgrf generators' names */
       
    80 	free(_grf_names);
    80 	free(_grf_names);
    81 	_grf_names = GetGRFTownNameList();
    81 	_grf_names = GetGRFTownNameList();
    82 	_nb_grf_names = 0;
    82 	_nb_grf_names = 0;
    83 	for (StringID *s = _grf_names; *s != INVALID_STRING_ID; s++) _nb_grf_names++;
    83 	for (StringID *s = _grf_names; *s != INVALID_STRING_ID; s++) _nb_grf_names++;
    84 
       
    85 	/* Prepare the list */
       
    86 	free(_town_names);
       
    87 	_town_names = MallocT<StringID>(_nb_orig_names + _nb_grf_names + 1);
       
    88 
       
    89 	/* Put the original strings */
       
    90 	for (int i = 0; i < _nb_orig_names; i++) _town_names[n++] = STR_TOWNNAME_ORIGINAL_ENGLISH + i;
       
    91 
       
    92 	/* Put the grf strings */
       
    93 	for (int i = 0; i < _nb_grf_names; i++) _town_names[n++] = _grf_names[i];
       
    94 
       
    95 	/* Put the terminator */
       
    96 	_town_names[n] = INVALID_STRING_ID;
       
    97 
       
    98 	/* Sort the strings */
       
    99 	qsort(&_town_names[0], _nb_orig_names + _nb_grf_names, sizeof(StringID), &StringIDSorter);
       
   100 }
    84 }
   101 
    85 
   102 static inline StringID TownName(int town_name)
    86 static inline StringID TownName(int town_name)
   103 {
    87 {
   104 	if (town_name < _nb_orig_names) return STR_TOWNNAME_ORIGINAL_ENGLISH + town_name;
    88 	if (town_name < _nb_orig_names) return STR_TOWNNAME_ORIGINAL_ENGLISH + town_name;
   129 	}
   113 	}
   130 	return false;
   114 	return false;
   131 }
   115 }
   132 
   116 
   133 
   117 
       
   118 enum GameOptionsWidgets {
       
   119 	GAMEOPT_CURRENCY_BTN    =  4,
       
   120 	GAMEOPT_DISTANCE_BTN    =  6,
       
   121 	GAMEOPT_ROADSIDE_BTN    =  8,
       
   122 	GAMEOPT_TOWNNAME_BTN    = 10,
       
   123 	GAMEOPT_AUTOSAVE_BTN    = 12,
       
   124 	GAMEOPT_VEHICLENAME_BTN = 14,
       
   125 	GAMEOPT_VEHICLENAME_SAVE,
       
   126 	GAMEOPT_LANG_BTN        = 17,
       
   127 	GAMEOPT_RESOLUTION_BTN  = 19,
       
   128 	GAMEOPT_FULLSCREEN,
       
   129 	GAMEOPT_SCREENSHOT_BTN  = 22,
       
   130 };
       
   131 
       
   132 /**
       
   133  * Update/redraw the townnames dropdown
       
   134  * @param w   the window the dropdown belongs to
       
   135  * @param sel the currently selected townname generator
       
   136  */
       
   137 static void ShowTownnameDropdown(Window *w, int sel)
       
   138 {
       
   139 	typedef std::map<StringID, int, StringIDCompare> TownList;
       
   140 	TownList townnames;
       
   141 
       
   142 	/* Add and sort original townnames generators */
       
   143 	for (int i = 0; i < _nb_orig_names; i++) townnames[STR_TOWNNAME_ORIGINAL_ENGLISH + i] = i;
       
   144 
       
   145 	/* Add and sort newgrf townnames generators */
       
   146 	for (int i = 0; i < _nb_grf_names; i++) townnames[_grf_names[i]] = _nb_orig_names + i;
       
   147 
       
   148 	DropDownList *list = new DropDownList();
       
   149 	for (TownList::iterator it = townnames.begin(); it != townnames.end(); it++) {
       
   150 		list->push_back(new DropDownListStringItem((*it).first, (*it).second, !(_game_mode == GM_MENU || (*it).second == sel)));
       
   151 	}
       
   152 
       
   153 	ShowDropDownList(w, list, sel, GAMEOPT_TOWNNAME_BTN);
       
   154 }
       
   155 
       
   156 /**
       
   157  * Update/redraw the languages dropdown
       
   158  * @param w   the window the dropdown belongs to
       
   159  */
       
   160 static void ShowLangDropdown(Window *w)
       
   161 {
       
   162 	typedef std::map<StringID, int, StringIDCompare> LangList;
       
   163 
       
   164 	/* Sort language names */
       
   165 	LangList langs;
       
   166 	for (int i = 0; i < _dynlang.num; i++) langs[SPECSTR_LANGUAGE_START + i] = i;
       
   167 
       
   168 	DropDownList *list = new DropDownList();
       
   169 	for (LangList::iterator it = langs.begin(); it != langs.end(); it++) {
       
   170 		list->push_back(new DropDownListStringItem((*it).first, (*it).second, false));
       
   171 	}
       
   172 
       
   173 	ShowDropDownList(w, list, _dynlang.curr, GAMEOPT_LANG_BTN);
       
   174 }
       
   175 
   134 static void ShowCustCurrency();
   176 static void ShowCustCurrency();
   135 
   177 
   136 static void GameOptionsWndProc(Window *w, WindowEvent *e)
   178 static void GameOptionsWndProc(Window *w, WindowEvent *e)
   137 {
   179 {
   138 	switch (e->event) {
   180 	switch (e->event) {
   139 	case WE_PAINT: {
   181 		case WE_PAINT: {
   140 		int i;
   182 			int i;
   141 		StringID str = STR_02BE_DEFAULT;
   183 			StringID str = STR_02BE_DEFAULT;
   142 
   184 
   143 		w->SetWidgetDisabledState(21, !(_vehicle_design_names & 1));
   185 			w->SetWidgetDisabledState(GAMEOPT_VEHICLENAME_SAVE, !(_vehicle_design_names & 1));
   144 		if (!w->IsWidgetDisabled(21)) str = STR_02BF_CUSTOM;
   186 			if (!w->IsWidgetDisabled(GAMEOPT_VEHICLENAME_SAVE)) str = STR_02BF_CUSTOM;
   145 		SetDParam(0, str);
   187 			SetDParam(0, str);
   146 		SetDParam(1, _currency_specs[_opt_ptr->currency].name);
   188 			SetDParam(1, _currency_specs[_opt_ptr->currency].name);
   147 		SetDParam(2, STR_UNITS_IMPERIAL + _opt_ptr->units);
   189 			SetDParam(2, STR_UNITS_IMPERIAL + _opt_ptr->units);
   148 		SetDParam(3, STR_02E9_DRIVE_ON_LEFT + _opt_ptr->road_side);
   190 			SetDParam(3, STR_02E9_DRIVE_ON_LEFT + _opt_ptr->road_side);
   149 		SetDParam(4, TownName(_opt_ptr->town_name));
   191 			SetDParam(4, TownName(_opt_ptr->town_name));
   150 		SetDParam(5, _autosave_dropdown[_opt_ptr->autosave]);
   192 			SetDParam(5, _autosave_dropdown[_opt_ptr->autosave]);
   151 		SetDParam(6, SPECSTR_LANGUAGE_START + _dynlang.curr);
   193 			SetDParam(6, SPECSTR_LANGUAGE_START + _dynlang.curr);
   152 		i = GetCurRes();
   194 			i = GetCurRes();
   153 		SetDParam(7, i == _num_resolutions ? STR_RES_OTHER : SPECSTR_RESOLUTION_START + i);
   195 			SetDParam(7, i == _num_resolutions ? STR_RES_OTHER : SPECSTR_RESOLUTION_START + i);
   154 		SetDParam(8, SPECSTR_SCREENSHOT_START + _cur_screenshot_format);
   196 			SetDParam(8, SPECSTR_SCREENSHOT_START + _cur_screenshot_format);
   155 		w->SetWidgetLoweredState(28, _fullscreen);
   197 			w->SetWidgetLoweredState(GAMEOPT_FULLSCREEN, _fullscreen);
   156 
   198 
   157 		DrawWindowWidgets(w);
   199 			DrawWindowWidgets(w);
   158 		DrawString(20, 175, STR_OPTIONS_FULLSCREEN, TC_FROMSTRING); // fullscreen
   200 			DrawString(20, 175, STR_OPTIONS_FULLSCREEN, TC_FROMSTRING); // fullscreen
   159 	} break;
   201 		} break;
   160 
   202 
   161 	case WE_CLICK:
   203 		case WE_CLICK:
   162 		switch (e->we.click.widget) {
   204 			switch (e->we.click.widget) {
   163 		case 4: case 5: /* Setup currencies dropdown */
   205 				case GAMEOPT_CURRENCY_BTN: /* Setup currencies dropdown */
   164 			ShowDropDownMenu(w, BuildCurrencyDropdown(), _opt_ptr->currency, 5, _game_mode == GM_MENU ? 0 : ~GetMaskOfAllowedCurrencies(), 0);;
   206 					ShowDropDownMenu(w, BuildCurrencyDropdown(), _opt_ptr->currency, GAMEOPT_CURRENCY_BTN, _game_mode == GM_MENU ? 0 : ~GetMaskOfAllowedCurrencies(), 0);
   165 			return;
   207 					break;
   166 		case 7: case 8: /* Setup distance unit dropdown */
   208 
   167 			ShowDropDownMenu(w, _units_dropdown, _opt_ptr->units, 8, 0, 0);
   209 				case GAMEOPT_DISTANCE_BTN: /* Setup distance unit dropdown */
   168 			return;
   210 					ShowDropDownMenu(w, _units_dropdown, _opt_ptr->units, GAMEOPT_DISTANCE_BTN, 0, 0);
   169 		case 10: case 11: { /* Setup road-side dropdown */
   211 					break;
   170 			int i = 0;
   212 
   171 
   213 				case GAMEOPT_ROADSIDE_BTN: { /* Setup road-side dropdown */
   172 			/* You can only change the drive side if you are in the menu or ingame with
   214 					int i = 0;
   173 			 * no vehicles present. In a networking game only the server can change it */
   215 
   174 			if ((_game_mode != GM_MENU && RoadVehiclesAreBuilt()) || (_networking && !_network_server))
   216 					/* You can only change the drive side if you are in the menu or ingame with
   175 				i = (-1) ^ (1 << _opt_ptr->road_side); // disable the other value
   217 					 * no vehicles present. In a networking game only the server can change it */
   176 
   218 					if ((_game_mode != GM_MENU && RoadVehiclesAreBuilt()) || (_networking && !_network_server))
   177 			ShowDropDownMenu(w, _driveside_dropdown, _opt_ptr->road_side, 11, i, 0);
   219 						i = (-1) ^ (1 << _opt_ptr->road_side); // disable the other value
   178 		} return;
   220 
   179 		case 13: case 14: { /* Setup townname dropdown */
   221 					ShowDropDownMenu(w, _driveside_dropdown, _opt_ptr->road_side, GAMEOPT_ROADSIDE_BTN, i, 0);
   180 			uint sel = 0;
   222 				} break;
   181 			for (uint i = 0; _town_names[i] != INVALID_STRING_ID; i++) {
   223 
   182 				if (_town_names[i] == TownName(_opt_ptr->town_name)) {
   224 				case GAMEOPT_TOWNNAME_BTN: /* Setup townname dropdown */
   183 					sel = i;
   225 					ShowTownnameDropdown(w, _opt_ptr->town_name);
   184 					break;
   226 					break;
   185 				}
   227 
   186 			}
   228 				case GAMEOPT_AUTOSAVE_BTN: /* Setup autosave dropdown */
   187 			ShowDropDownMenu(w, _town_names, sel, 14, (_game_mode == GM_MENU) ? 0 : (-1) ^ (1 << sel), 0);
   229 					ShowDropDownMenu(w, _autosave_dropdown, _opt_ptr->autosave, GAMEOPT_AUTOSAVE_BTN, 0, 0);
   188 			return;
   230 					break;
   189 		}
   231 
   190 		case 16: case 17: /* Setup autosave dropdown */
   232 				case GAMEOPT_VEHICLENAME_BTN: /* Setup customized vehicle-names dropdown */
   191 			ShowDropDownMenu(w, _autosave_dropdown, _opt_ptr->autosave, 17, 0, 0);
   233 					ShowDropDownMenu(w, _designnames_dropdown, (_vehicle_design_names & 1) ? 1 : 0, GAMEOPT_VEHICLENAME_BTN, (_vehicle_design_names & 2) ? 0 : 2, 0);
   192 			return;
   234 					break;
   193 		case 19: case 20: /* Setup customized vehicle-names dropdown */
   235 
   194 			ShowDropDownMenu(w, _designnames_dropdown, (_vehicle_design_names & 1) ? 1 : 0, 20, (_vehicle_design_names & 2) ? 0 : 2, 0);
   236 				case GAMEOPT_VEHICLENAME_SAVE: /* Save customized vehicle-names to disk */
   195 			return;
   237 					break;  // not implemented
   196 		case 21: /* Save customized vehicle-names to disk */
   238 
   197 			return;
   239 				case GAMEOPT_LANG_BTN: /* Setup interface language dropdown */
   198 		case 23: case 24: /* Setup interface language dropdown */
   240 					ShowLangDropdown(w);
   199 			ShowDropDownMenu(w, _dynlang.dropdown, _dynlang.curr, 24, 0, 0);
   241 					break;
   200 			return;
   242 
   201 		case 26: case 27: /* Setup resolution dropdown */
   243 				case GAMEOPT_RESOLUTION_BTN: /* Setup resolution dropdown */
   202 			ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_RESOLUTION_START, _num_resolutions), GetCurRes(), 27, 0, 0);
   244 					ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_RESOLUTION_START, _num_resolutions), GetCurRes(), GAMEOPT_RESOLUTION_BTN, 0, 0);
   203 			return;
   245 					break;
   204 		case 28: /* Click fullscreen on/off */
   246 
   205 			w->SetWidgetLoweredState(28, !_fullscreen);
   247 				case GAMEOPT_FULLSCREEN: /* Click fullscreen on/off */
   206 			ToggleFullScreen(!_fullscreen); // toggle full-screen on/off
   248 					/* try to toggle full-screen on/off */
   207 			SetWindowDirty(w);
   249 					if (!ToggleFullScreen(!_fullscreen)) {
   208 			return;
   250 						ShowErrorMessage(INVALID_STRING_ID, STR_FULLSCREEN_FAILED, 0, 0);
   209 		case 30: case 31: /* Setup screenshot format dropdown */
   251 					}
   210 			ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_SCREENSHOT_START, _num_screenshot_formats), _cur_screenshot_format, 31, 0, 0);
   252 					w->SetWidgetLoweredState(GAMEOPT_FULLSCREEN, _fullscreen);
   211 			return;
   253 					SetWindowDirty(w);
   212 		}
   254 					break;
   213 		break;
   255 
   214 
   256 				case GAMEOPT_SCREENSHOT_BTN: /* Setup screenshot format dropdown */
   215 	case WE_DROPDOWN_SELECT:
   257 					ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_SCREENSHOT_START, _num_screenshot_formats), _cur_screenshot_format, GAMEOPT_SCREENSHOT_BTN, 0, 0);
   216 		switch (e->we.dropdown.button) {
   258 					break;
   217 		case 20: /* Vehicle design names */
       
   218 			if (e->we.dropdown.index == 0) {
       
   219 				DeleteCustomEngineNames();
       
   220 				MarkWholeScreenDirty();
       
   221 			} else if (!(_vehicle_design_names & 1)) {
       
   222 				LoadCustomEngineNames();
       
   223 				MarkWholeScreenDirty();
       
   224 			}
   259 			}
   225 			break;
   260 			break;
   226 		case 5: /* Currency */
   261 
   227 			if (e->we.dropdown.index == CUSTOM_CURRENCY_ID) ShowCustCurrency();
   262 		case WE_DROPDOWN_SELECT:
   228 			_opt_ptr->currency = e->we.dropdown.index;
   263 			switch (e->we.dropdown.button) {
   229 			MarkWholeScreenDirty();
   264 				case GAMEOPT_VEHICLENAME_BTN: /* Vehicle design names */
   230 			break;
   265 					if (e->we.dropdown.index == 0) {
   231 		case 8: /* Measuring units */
   266 						DeleteCustomEngineNames();
   232 			_opt_ptr->units = e->we.dropdown.index;
   267 						MarkWholeScreenDirty();
   233 			MarkWholeScreenDirty();
   268 					} else if (!(_vehicle_design_names & 1)) {
   234 			break;
   269 						LoadCustomEngineNames();
   235 		case 11: /* Road side */
   270 						MarkWholeScreenDirty();
   236 			if (_opt_ptr->road_side != e->we.dropdown.index) { // only change if setting changed
   271 					}
   237 				DoCommandP(0, e->we.dropdown.index, 0, NULL, CMD_SET_ROAD_DRIVE_SIDE | CMD_MSG(STR_00B4_CAN_T_DO_THIS));
   272 					break;
   238 				MarkWholeScreenDirty();
   273 
       
   274 				case GAMEOPT_CURRENCY_BTN: /* Currency */
       
   275 					if (e->we.dropdown.index == CUSTOM_CURRENCY_ID) ShowCustCurrency();
       
   276 					_opt_ptr->currency = e->we.dropdown.index;
       
   277 					MarkWholeScreenDirty();
       
   278 					break;
       
   279 
       
   280 				case GAMEOPT_DISTANCE_BTN: /* Measuring units */
       
   281 					_opt_ptr->units = e->we.dropdown.index;
       
   282 					MarkWholeScreenDirty();
       
   283 					break;
       
   284 
       
   285 				case GAMEOPT_ROADSIDE_BTN: /* Road side */
       
   286 					if (_opt_ptr->road_side != e->we.dropdown.index) { // only change if setting changed
       
   287 						DoCommandP(0, e->we.dropdown.index, 0, NULL, CMD_SET_ROAD_DRIVE_SIDE | CMD_MSG(STR_00B4_CAN_T_DO_THIS));
       
   288 						MarkWholeScreenDirty();
       
   289 					}
       
   290 					break;
       
   291 
       
   292 				case GAMEOPT_TOWNNAME_BTN: /* Town names */
       
   293 					if (_game_mode == GM_MENU) {
       
   294 						_opt_ptr->town_name = e->we.dropdown.index;
       
   295 						InvalidateWindow(WC_GAME_OPTIONS, 0);
       
   296 					}
       
   297 					break;
       
   298 
       
   299 				case GAMEOPT_AUTOSAVE_BTN: /* Autosave options */
       
   300 					_opt.autosave = _opt_newgame.autosave = e->we.dropdown.index;
       
   301 					SetWindowDirty(w);
       
   302 					break;
       
   303 
       
   304 				case GAMEOPT_LANG_BTN: /* Change interface language */
       
   305 					ReadLanguagePack(e->we.dropdown.index);
       
   306 					CheckForMissingGlyphsInLoadedLanguagePack();
       
   307 					UpdateAllStationVirtCoord();
       
   308 					MarkWholeScreenDirty();
       
   309 					break;
       
   310 
       
   311 				case GAMEOPT_RESOLUTION_BTN: /* Change resolution */
       
   312 					if (e->we.dropdown.index < _num_resolutions && ChangeResInGame(_resolutions[e->we.dropdown.index][0],_resolutions[e->we.dropdown.index][1]))
       
   313 						SetWindowDirty(w);
       
   314 					break;
       
   315 
       
   316 				case GAMEOPT_SCREENSHOT_BTN: /* Change screenshot format */
       
   317 					SetScreenshotFormat(e->we.dropdown.index);
       
   318 					SetWindowDirty(w);
       
   319 					break;
   239 			}
   320 			}
   240 			break;
   321 			break;
   241 		case 14: /* Town names */
   322 
   242 			if (_game_mode == GM_MENU) {
   323 		case WE_DESTROY:
   243 				for (uint i = 0; _town_names[i] != INVALID_STRING_ID; i++) {
   324 			DeleteWindowById(WC_CUSTOM_CURRENCY, 0);
   244 					if (_town_names[e->we.dropdown.index] == TownName(i)) {
       
   245 						_opt_ptr->town_name = i;
       
   246 						break;
       
   247 					}
       
   248 				}
       
   249 				InvalidateWindow(WC_GAME_OPTIONS, 0);
       
   250 			}
       
   251 			break;
   325 			break;
   252 		case 17: /* Autosave options */
       
   253 			_opt.autosave = _opt_newgame.autosave = e->we.dropdown.index;
       
   254 			SetWindowDirty(w);
       
   255 			break;
       
   256 		case 24: /* Change interface language */
       
   257 			ReadLanguagePack(e->we.dropdown.index);
       
   258 			UpdateAllStationVirtCoord();
       
   259 			MarkWholeScreenDirty();
       
   260 			break;
       
   261 		case 27: /* Change resolution */
       
   262 			if (e->we.dropdown.index < _num_resolutions && ChangeResInGame(_resolutions[e->we.dropdown.index][0],_resolutions[e->we.dropdown.index][1]))
       
   263 				SetWindowDirty(w);
       
   264 			break;
       
   265 		case 31: /* Change screenshot format */
       
   266 			SetScreenshotFormat(e->we.dropdown.index);
       
   267 			SetWindowDirty(w);
       
   268 			break;
       
   269 		}
       
   270 		break;
       
   271 
       
   272 	case WE_DESTROY:
       
   273 		DeleteWindowById(WC_CUSTOM_CURRENCY, 0);
       
   274 		break;
       
   275 	}
   326 	}
   276 
   327 
   277 }
   328 }
   278 
   329 
   279 /** Change the side of the road vehicles drive on (server only).
   330 /** Change the side of the road vehicles drive on (server only).
   298 static const Widget _game_options_widgets[] = {
   349 static const Widget _game_options_widgets[] = {
   299 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                          STR_018B_CLOSE_WINDOW},
   350 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                          STR_018B_CLOSE_WINDOW},
   300 {    WWT_CAPTION,   RESIZE_NONE,    14,    11,   369,     0,    13, STR_00B1_GAME_OPTIONS,             STR_018C_WINDOW_TITLE_DRAG_THIS},
   351 {    WWT_CAPTION,   RESIZE_NONE,    14,    11,   369,     0,    13, STR_00B1_GAME_OPTIONS,             STR_018C_WINDOW_TITLE_DRAG_THIS},
   301 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   369,    14,   238, 0x0,                               STR_NULL},
   352 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   369,    14,   238, 0x0,                               STR_NULL},
   302 {      WWT_FRAME,   RESIZE_NONE,    14,    10,   179,    20,    55, STR_02E0_CURRENCY_UNITS,           STR_NULL},
   353 {      WWT_FRAME,   RESIZE_NONE,    14,    10,   179,    20,    55, STR_02E0_CURRENCY_UNITS,           STR_NULL},
   303 {      WWT_INSET,   RESIZE_NONE,    14,    20,   169,    34,    45, STR_02E1,                          STR_02E2_CURRENCY_UNITS_SELECTION},
   354 { WWT_DROPDOWNIN,   RESIZE_NONE,    14,    20,   169,    34,    45, STR_02E1,                          STR_02E2_CURRENCY_UNITS_SELECTION},
   304 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   158,   168,    35,    44, STR_0225,                          STR_02E2_CURRENCY_UNITS_SELECTION},
       
   305 {      WWT_FRAME,   RESIZE_NONE,    14,   190,   359,    20,    55, STR_MEASURING_UNITS,               STR_NULL},
   355 {      WWT_FRAME,   RESIZE_NONE,    14,   190,   359,    20,    55, STR_MEASURING_UNITS,               STR_NULL},
   306 {      WWT_INSET,   RESIZE_NONE,    14,   200,   349,    34,    45, STR_02E4,                          STR_MEASURING_UNITS_SELECTION},
   356 { WWT_DROPDOWNIN,   RESIZE_NONE,    14,   200,   349,    34,    45, STR_02E4,                          STR_MEASURING_UNITS_SELECTION},
   307 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   338,   348,    35,    44, STR_0225,                          STR_MEASURING_UNITS_SELECTION},
       
   308 {      WWT_FRAME,   RESIZE_NONE,    14,    10,   179,    62,    97, STR_02E6_ROAD_VEHICLES,            STR_NULL},
   357 {      WWT_FRAME,   RESIZE_NONE,    14,    10,   179,    62,    97, STR_02E6_ROAD_VEHICLES,            STR_NULL},
   309 {      WWT_INSET,   RESIZE_NONE,    14,    20,   169,    76,    87, STR_02E7,                          STR_02E8_SELECT_SIDE_OF_ROAD_FOR},
   358 { WWT_DROPDOWNIN,   RESIZE_NONE,    14,    20,   169,    76,    87, STR_02E7,                          STR_02E8_SELECT_SIDE_OF_ROAD_FOR},
   310 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   158,   168,    77,    86, STR_0225,                          STR_02E8_SELECT_SIDE_OF_ROAD_FOR},
       
   311 {      WWT_FRAME,   RESIZE_NONE,    14,   190,   359,    62,    97, STR_02EB_TOWN_NAMES,               STR_NULL},
   359 {      WWT_FRAME,   RESIZE_NONE,    14,   190,   359,    62,    97, STR_02EB_TOWN_NAMES,               STR_NULL},
   312 {      WWT_INSET,   RESIZE_NONE,    14,   200,   349,    76,    87, STR_02EC,                          STR_02ED_SELECT_STYLE_OF_TOWN_NAMES},
   360 { WWT_DROPDOWNIN,   RESIZE_NONE,    14,   200,   349,    76,    87, STR_02EC,                          STR_02ED_SELECT_STYLE_OF_TOWN_NAMES},
   313 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   338,   348,    77,    86, STR_0225,                          STR_02ED_SELECT_STYLE_OF_TOWN_NAMES},
       
   314 {      WWT_FRAME,   RESIZE_NONE,    14,    10,   179,   104,   139, STR_02F4_AUTOSAVE,                 STR_NULL},
   361 {      WWT_FRAME,   RESIZE_NONE,    14,    10,   179,   104,   139, STR_02F4_AUTOSAVE,                 STR_NULL},
   315 {      WWT_INSET,   RESIZE_NONE,    14,    20,   169,   118,   129, STR_02F5,                          STR_02F6_SELECT_INTERVAL_BETWEEN},
   362 { WWT_DROPDOWNIN,   RESIZE_NONE,    14,    20,   169,   118,   129, STR_02F5,                          STR_02F6_SELECT_INTERVAL_BETWEEN},
   316 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   158,   168,   119,   128, STR_0225,                          STR_02F6_SELECT_INTERVAL_BETWEEN},
       
   317 
   363 
   318 {      WWT_FRAME,   RESIZE_NONE,    14,    10,   359,   194,   228, STR_02BC_VEHICLE_DESIGN_NAMES,     STR_NULL},
   364 {      WWT_FRAME,   RESIZE_NONE,    14,    10,   359,   194,   228, STR_02BC_VEHICLE_DESIGN_NAMES,     STR_NULL},
   319 {      WWT_INSET,   RESIZE_NONE,    14,    20,   119,   207,   218, STR_02BD,                          STR_02C1_VEHICLE_DESIGN_NAMES_SELECTION},
   365 { WWT_DROPDOWNIN,   RESIZE_NONE,    14,    20,   119,   207,   218, STR_02BD,                          STR_02C1_VEHICLE_DESIGN_NAMES_SELECTION},
   320 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   108,   118,   208,   217, STR_0225,                          STR_02C1_VEHICLE_DESIGN_NAMES_SELECTION},
       
   321 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   130,   349,   207,   218, STR_02C0_SAVE_CUSTOM_NAMES,        STR_02C2_SAVE_CUSTOMIZED_VEHICLE},
   366 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   130,   349,   207,   218, STR_02C0_SAVE_CUSTOM_NAMES,        STR_02C2_SAVE_CUSTOMIZED_VEHICLE},
   322 
   367 
   323 {      WWT_FRAME,   RESIZE_NONE,    14,   190,   359,   104,   139, STR_OPTIONS_LANG,                  STR_NULL},
   368 {      WWT_FRAME,   RESIZE_NONE,    14,   190,   359,   104,   139, STR_OPTIONS_LANG,                  STR_NULL},
   324 {      WWT_INSET,   RESIZE_NONE,    14,   200,   349,   118,   129, STR_OPTIONS_LANG_CBO,              STR_OPTIONS_LANG_TIP},
   369 { WWT_DROPDOWNIN,   RESIZE_NONE,    14,   200,   349,   118,   129, STR_OPTIONS_LANG_CBO,              STR_OPTIONS_LANG_TIP},
   325 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   338,   348,   119,   128, STR_0225,                          STR_OPTIONS_LANG_TIP},
       
   326 
   370 
   327 {      WWT_FRAME,   RESIZE_NONE,    14,    10,   179,   146,   190, STR_OPTIONS_RES,                   STR_NULL},
   371 {      WWT_FRAME,   RESIZE_NONE,    14,    10,   179,   146,   190, STR_OPTIONS_RES,                   STR_NULL},
   328 {      WWT_INSET,   RESIZE_NONE,    14,    20,   169,   160,   171, STR_OPTIONS_RES_CBO,               STR_OPTIONS_RES_TIP},
   372 { WWT_DROPDOWNIN,   RESIZE_NONE,    14,    20,   169,   160,   171, STR_OPTIONS_RES_CBO,               STR_OPTIONS_RES_TIP},
   329 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   158,   168,   161,   170, STR_0225,                          STR_OPTIONS_RES_TIP},
       
   330 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   149,   169,   176,   184, STR_EMPTY,                         STR_OPTIONS_FULLSCREEN_TIP},
   373 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   149,   169,   176,   184, STR_EMPTY,                         STR_OPTIONS_FULLSCREEN_TIP},
   331 
   374 
   332 {      WWT_FRAME,   RESIZE_NONE,    14,   190,   359,   146,   190, STR_OPTIONS_SCREENSHOT_FORMAT,     STR_NULL},
   375 {      WWT_FRAME,   RESIZE_NONE,    14,   190,   359,   146,   190, STR_OPTIONS_SCREENSHOT_FORMAT,     STR_NULL},
   333 {      WWT_INSET,   RESIZE_NONE,    14,   200,   349,   160,   171, STR_OPTIONS_SCREENSHOT_FORMAT_CBO, STR_OPTIONS_SCREENSHOT_FORMAT_TIP},
   376 { WWT_DROPDOWNIN,   RESIZE_NONE,    14,   200,   349,   160,   171, STR_OPTIONS_SCREENSHOT_FORMAT_CBO, STR_OPTIONS_SCREENSHOT_FORMAT_TIP},
   334 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   338,   348,   161,   170, STR_0225,                          STR_OPTIONS_SCREENSHOT_FORMAT_TIP},
       
   335 
   377 
   336 {   WIDGETS_END},
   378 {   WIDGETS_END},
   337 };
   379 };
   338 
   380 
   339 static const WindowDesc _game_options_desc = {
   381 static const WindowDesc _game_options_desc = {
   445 /* Temporary holding place of values in the difficulty window until 'Save' is clicked */
   487 /* Temporary holding place of values in the difficulty window until 'Save' is clicked */
   446 static GameOptions _opt_mod_temp;
   488 static GameOptions _opt_mod_temp;
   447 // 0x383E = (1 << 13) | (1 << 12) | (1 << 11) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1)
   489 // 0x383E = (1 << 13) | (1 << 12) | (1 << 11) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1)
   448 #define DIFF_INGAME_DISABLED_BUTTONS 0x383E
   490 #define DIFF_INGAME_DISABLED_BUTTONS 0x383E
   449 
   491 
       
   492 /* Names of the game difficulty settings window */
       
   493 enum GameDifficultyWidgets {
       
   494 	GDW_CLOSEBOX = 0,
       
   495 	GDW_CAPTION,
       
   496 	GDW_UPPER_BG,
       
   497 	GDW_LVL_EASY,
       
   498 	GDW_LVL_MEDIUM,
       
   499 	GDW_LVL_HARD,
       
   500 	GDW_LVL_CUSTOM,
       
   501 	GDW_HIGHSCORE,
       
   502 	GDW_SETTING_BG,
       
   503 	GDW_LOWER_BG,
       
   504 	GDW_ACCEPT,
       
   505 	GDW_CANCEL,
       
   506 };
       
   507 
   450 static void GameDifficultyWndProc(Window *w, WindowEvent *e)
   508 static void GameDifficultyWndProc(Window *w, WindowEvent *e)
   451 {
   509 {
   452 	switch (e->event) {
   510 	switch (e->event) {
   453 	case WE_CREATE: // Setup disabled buttons when creating window
   511 		case WE_CREATE:
   454 		/* disable all other difficulty buttons during gameplay except for 'custom' */
   512 			/* Hide the closebox to make sure that the user aborts or confirms his changes */
   455 		w->SetWidgetDisabledState( 3, _game_mode == GM_NORMAL);
   513 			w->HideWidget(GDW_CLOSEBOX);
   456 		w->SetWidgetDisabledState( 4, _game_mode == GM_NORMAL);
   514 			w->widget[GDW_CAPTION].left = 0;
   457 		w->SetWidgetDisabledState( 5, _game_mode == GM_NORMAL);
   515 			/* Setup disabled buttons when creating window
   458 		w->SetWidgetDisabledState( 6, _game_mode == GM_NORMAL);
   516 			 * disable all other difficulty buttons during gameplay except for 'custom' */
   459 		w->SetWidgetDisabledState( 7, _game_mode == GM_EDITOR || _networking); // highscore chart in multiplayer
   517 			w->SetWidgetsDisabledState(_game_mode == GM_NORMAL,
   460 		w->SetWidgetDisabledState(10, _networking && !_network_server); // Save-button in multiplayer (and if client)
   518 				GDW_LVL_EASY,
   461 		w->LowerWidget(_opt_mod_temp.diff_level + 3);
   519 				GDW_LVL_MEDIUM,
   462 
   520 				GDW_LVL_HARD,
   463 		break;
   521 				GDW_LVL_CUSTOM,
   464 	case WE_PAINT: {
   522 				WIDGET_LIST_END);
   465 		uint32 click_a, click_b, disabled;
   523 			w->SetWidgetDisabledState(GDW_HIGHSCORE, _game_mode == GM_EDITOR || _networking); // highscore chart in multiplayer
   466 		int i;
   524 			w->SetWidgetDisabledState(GDW_ACCEPT, _networking && !_network_server); // Save-button in multiplayer (and if client)
   467 		int y, value;
   525 			w->LowerWidget(GDW_LVL_EASY + _opt_mod_temp.diff_level);
   468 
   526 			break;
   469 		DrawWindowWidgets(w);
   527 
   470 
   528 		case WE_PAINT: {
   471 		click_a = _difficulty_click_a;
   529 			DrawWindowWidgets(w);
   472 		click_b = _difficulty_click_b;
   530 
   473 
   531 			/* XXX - Disabled buttons in normal gameplay or during muliplayer as non server.
   474 		/* XXX - Disabled buttons in normal gameplay. Bitshifted for each button to see if
   532 			 *       Bitshifted for each button to see if that bit is set. If it is set, the
   475 		 * that bit is set. If it is set, the button is disabled */
   533 			 *       button is disabled */
   476 		disabled = (_game_mode == GM_NORMAL) ? DIFF_INGAME_DISABLED_BUTTONS : 0;
   534 			uint32 disabled = 0;
   477 
   535 			if (_networking && !_network_server) {
   478 		y = GAMEDIFF_WND_TOP_OFFSET;
   536 				disabled = MAX_UVALUE(uint32); // Disable all
   479 		for (i = 0; i != GAME_DIFFICULTY_NUM; i++) {
   537 			} else if (_game_mode == GM_NORMAL) {
   480 			DrawFrameRect( 5, y,  5 + 8, y + 8, 3, HasBit(click_a, i) ? FR_LOWERED : FR_NONE);
   538 				disabled = DIFF_INGAME_DISABLED_BUTTONS;
   481 			DrawFrameRect(15, y, 15 + 8, y + 8, 3, HasBit(click_b, i) ? FR_LOWERED : FR_NONE);
       
   482 			if (HasBit(disabled, i) || (_networking && !_network_server)) {
       
   483 				int color = (1 << PALETTE_MODIFIER_GREYOUT) | _colour_gradient[COLOUR_YELLOW][2];
       
   484 				GfxFillRect( 6, y + 1,  6 + 8, y + 8, color);
       
   485 				GfxFillRect(16, y + 1, 16 + 8, y + 8, color);
       
   486 			}
   539 			}
   487 
   540 
   488 			DrawStringCentered(10, y, STR_6819, TC_FROMSTRING);
   541 			int value;
   489 			DrawStringCentered(20, y, STR_681A, TC_FROMSTRING);
   542 			int y = GAMEDIFF_WND_TOP_OFFSET;
   490 
   543 			for (uint i = 0; i != GAME_DIFFICULTY_NUM; i++) {
   491 
   544 				const GameSettingData *gsd = &_game_setting_info[i];
   492 			value = _game_setting_info[i].str + ((GDType*)&_opt_mod_temp.diff)[i];
   545 				value = ((GDType*)&_opt_mod_temp.diff)[i];
   493 			if (i == 4) value *= 1000; // XXX - handle currency option
   546 
   494 			SetDParam(0, value);
   547 				DrawArrowButtons(5, y, 3,
   495 			DrawString(30, y, STR_6805_MAXIMUM_NO_COMPETITORS + i, TC_FROMSTRING);
   548 						!!HasBit(_difficulty_click_a, i) | !!HasBit(_difficulty_click_b, i) << 1,
   496 
   549 						!(HasBit(disabled, i) || gsd->min == value),
   497 			y += GAMEDIFF_WND_ROWSIZE + 2; // space items apart a bit
   550 						!(HasBit(disabled, i) || gsd->max == value));
   498 		}
   551 
   499 	} break;
   552 				value += _game_setting_info[i].str;
   500 
   553 				if (i == 4) value *= 1000; // XXX - handle currency option
   501 	case WE_CLICK:
   554 				SetDParam(0, value);
   502 		switch (e->we.click.widget) {
   555 				DrawString(30, y, STR_6805_MAXIMUM_NO_COMPETITORS + i, TC_FROMSTRING);
   503 		case 8: { /* Difficulty settings widget, decode click */
   556 
   504 			const GameSettingData *info;
   557 				y += GAMEDIFF_WND_ROWSIZE + 2; // space items apart a bit
   505 			int x, y;
       
   506 			uint btn, dis;
       
   507 			int16 val;
       
   508 
       
   509 			/* Don't allow clients to make any changes */
       
   510 			if  (_networking && !_network_server)
       
   511 				return;
       
   512 
       
   513 			x = e->we.click.pt.x - 5;
       
   514 			if (!IsInsideMM(x, 0, 21)) // Button area
       
   515 				return;
       
   516 
       
   517 			y = e->we.click.pt.y - GAMEDIFF_WND_TOP_OFFSET;
       
   518 			if (y < 0)
       
   519 				return;
       
   520 
       
   521 			/* Get button from Y coord. */
       
   522 			btn = y / (GAMEDIFF_WND_ROWSIZE + 2);
       
   523 			if (btn >= GAME_DIFFICULTY_NUM || y % (GAMEDIFF_WND_ROWSIZE + 2) >= 9)
       
   524 				return;
       
   525 
       
   526 			/* Clicked disabled button? */
       
   527 			dis = (_game_mode == GM_NORMAL) ? DIFF_INGAME_DISABLED_BUTTONS : 0;
       
   528 
       
   529 			if (HasBit(dis, btn))
       
   530 				return;
       
   531 
       
   532 			_difficulty_timeout = 5;
       
   533 
       
   534 			val = ((GDType*)&_opt_mod_temp.diff)[btn];
       
   535 
       
   536 			info = &_game_setting_info[btn]; // get information about the difficulty setting
       
   537 			if (x >= 10) {
       
   538 				// Increase button clicked
       
   539 				val = min(val + info->step, info->max);
       
   540 				SetBit(_difficulty_click_b, btn);
       
   541 			} else {
       
   542 				// Decrease button clicked
       
   543 				val -= info->step;
       
   544 				val = max(val,  info->min);
       
   545 				SetBit(_difficulty_click_a, btn);
       
   546 			}
   558 			}
   547 
       
   548 			// save value in temporary variable
       
   549 			((GDType*)&_opt_mod_temp.diff)[btn] = val;
       
   550 			w->RaiseWidget(_opt_mod_temp.diff_level + 3);
       
   551 			SetDifficultyLevel(3, &_opt_mod_temp); // set difficulty level to custom
       
   552 			w->LowerWidget(_opt_mod_temp.diff_level + 3);
       
   553 			SetWindowDirty(w);
       
   554 		} break;
   559 		} break;
   555 		case 3: case 4: case 5: case 6: /* Easy / Medium / Hard / Custom */
   560 
   556 			// temporarily change difficulty level
   561 		case WE_CLICK:
   557 			w->RaiseWidget(_opt_mod_temp.diff_level + 3);
   562 			switch (e->we.click.widget) {
   558 			SetDifficultyLevel(e->we.click.widget - 3, &_opt_mod_temp);
   563 				case GDW_SETTING_BG: { /* Difficulty settings widget, decode click */
   559 			w->LowerWidget(_opt_mod_temp.diff_level + 3);
   564 					/* Don't allow clients to make any changes */
   560 			SetWindowDirty(w);
   565 					if (_networking && !_network_server) return;
       
   566 
       
   567 					const int x = e->we.click.pt.x - 5;
       
   568 					if (!IsInsideMM(x, 0, 21)) // Button area
       
   569 						return;
       
   570 
       
   571 					const int y = e->we.click.pt.y - GAMEDIFF_WND_TOP_OFFSET;
       
   572 					if (y < 0) return;
       
   573 
       
   574 					/* Get button from Y coord. */
       
   575 					const uint btn = y / (GAMEDIFF_WND_ROWSIZE + 2);
       
   576 					if (btn >= GAME_DIFFICULTY_NUM || y % (GAMEDIFF_WND_ROWSIZE + 2) >= 9)
       
   577 						return;
       
   578 
       
   579 					/* Clicked disabled button? */
       
   580 					if (_game_mode == GM_NORMAL && HasBit(DIFF_INGAME_DISABLED_BUTTONS, btn))
       
   581 						return;
       
   582 
       
   583 					_difficulty_timeout = 5;
       
   584 
       
   585 					int16 val = ((GDType*)&_opt_mod_temp.diff)[btn];
       
   586 
       
   587 					const GameSettingData *info = &_game_setting_info[btn]; // get information about the difficulty setting
       
   588 					if (x >= 10) {
       
   589 						/* Increase button clicked */
       
   590 						val = min(val + info->step, info->max);
       
   591 						SetBit(_difficulty_click_b, btn);
       
   592 					} else {
       
   593 						/* Decrease button clicked */
       
   594 						val -= info->step;
       
   595 						val = max(val,  info->min);
       
   596 						SetBit(_difficulty_click_a, btn);
       
   597 					}
       
   598 
       
   599 					/* save value in temporary variable */
       
   600 					((GDType*)&_opt_mod_temp.diff)[btn] = val;
       
   601 					w->RaiseWidget(GDW_LVL_EASY + _opt_mod_temp.diff_level);
       
   602 					SetDifficultyLevel(3, &_opt_mod_temp); // set difficulty level to custom
       
   603 					w->LowerWidget(GDW_LVL_CUSTOM);
       
   604 					SetWindowDirty(w);
       
   605 				} break;
       
   606 
       
   607 				case GDW_LVL_EASY:
       
   608 				case GDW_LVL_MEDIUM:
       
   609 				case GDW_LVL_HARD:
       
   610 				case GDW_LVL_CUSTOM:
       
   611 					/* temporarily change difficulty level */
       
   612 					w->RaiseWidget(GDW_LVL_EASY + _opt_mod_temp.diff_level);
       
   613 					SetDifficultyLevel(e->we.click.widget - GDW_LVL_EASY, &_opt_mod_temp);
       
   614 					w->LowerWidget(GDW_LVL_EASY + _opt_mod_temp.diff_level);
       
   615 					SetWindowDirty(w);
       
   616 					break;
       
   617 
       
   618 				case GDW_HIGHSCORE: // Highscore Table
       
   619 					ShowHighscoreTable(_opt_mod_temp.diff_level, -1);
       
   620 					break;
       
   621 
       
   622 				case GDW_ACCEPT: { // Save button - save changes
       
   623 					GDType btn, val;
       
   624 					for (btn = 0; btn != GAME_DIFFICULTY_NUM; btn++) {
       
   625 						val = ((GDType*)&_opt_mod_temp.diff)[btn];
       
   626 						/* if setting has changed, change it */
       
   627 						if (val != ((GDType*)&_opt_ptr->diff)[btn])
       
   628 							DoCommandP(0, btn, val, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
       
   629 					}
       
   630 					DoCommandP(0, UINT_MAX, _opt_mod_temp.diff_level, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
       
   631 					DeleteWindow(w);
       
   632 					/* If we are in the editor, we should reload the economy.
       
   633 					 * This way when you load a game, the max loan and interest rate
       
   634 					 * are loaded correctly. */
       
   635 					if (_game_mode == GM_EDITOR) StartupEconomy();
       
   636 					break;
       
   637 				}
       
   638 
       
   639 				case GDW_CANCEL: // Cancel button - close window, abandon changes
       
   640 					DeleteWindow(w);
       
   641 					break;
       
   642 			} break;
       
   643 
       
   644 		case WE_MOUSELOOP: /* Handle the visual 'clicking' of the buttons */
       
   645 			if (_difficulty_timeout != 0 && !--_difficulty_timeout) {
       
   646 				_difficulty_click_a = 0;
       
   647 				_difficulty_click_b = 0;
       
   648 				SetWindowDirty(w);
       
   649 			}
   561 			break;
   650 			break;
   562 		case 7: /* Highscore Table */
       
   563 			ShowHighscoreTable(_opt_mod_temp.diff_level, -1);
       
   564 			break;
       
   565 		case 10: { /* Save button - save changes */
       
   566 			GDType btn, val;
       
   567 			for (btn = 0; btn != GAME_DIFFICULTY_NUM; btn++) {
       
   568 				val = ((GDType*)&_opt_mod_temp.diff)[btn];
       
   569 				// if setting has changed, change it
       
   570 				if (val != ((GDType*)&_opt_ptr->diff)[btn])
       
   571 					DoCommandP(0, btn, val, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
       
   572 			}
       
   573 			DoCommandP(0, UINT_MAX, _opt_mod_temp.diff_level, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
       
   574 			DeleteWindow(w);
       
   575 			// If we are in the editor, we should reload the economy.
       
   576 			//  This way when you load a game, the max loan and interest rate
       
   577 			//  are loaded correctly.
       
   578 			if (_game_mode == GM_EDITOR)
       
   579 				StartupEconomy();
       
   580 			break;
       
   581 		}
       
   582 		case 11: /* Cancel button - close window, abandon changes */
       
   583 			DeleteWindow(w);
       
   584 			break;
       
   585 	} break;
       
   586 
       
   587 	case WE_MOUSELOOP: /* Handle the visual 'clicking' of the buttons */
       
   588 		if (_difficulty_timeout != 0 && !--_difficulty_timeout) {
       
   589 			_difficulty_click_a = 0;
       
   590 			_difficulty_click_b = 0;
       
   591 			SetWindowDirty(w);
       
   592 		}
       
   593 		break;
       
   594 	}
   651 	}
   595 }
   652 }
   596 
       
   597 #undef DIFF_INGAME_DISABLED_BUTTONS
   653 #undef DIFF_INGAME_DISABLED_BUTTONS
   598 
   654 
       
   655 /* Widget definition for the game difficulty settings window */
   599 static const Widget _game_difficulty_widgets[] = {
   656 static const Widget _game_difficulty_widgets[] = {
   600 {   WWT_CLOSEBOX,   RESIZE_NONE,    10,     0,    10,     0,    13, STR_00C5,                     STR_018B_CLOSE_WINDOW},
   657 {   WWT_CLOSEBOX,   RESIZE_NONE,    10,     0,    10,     0,    13, STR_00C5,                     STR_018B_CLOSE_WINDOW},           // GDW_CLOSEBOX
   601 {    WWT_CAPTION,   RESIZE_NONE,    10,    11,   369,     0,    13, STR_6800_DIFFICULTY_LEVEL,    STR_018C_WINDOW_TITLE_DRAG_THIS},
   658 {    WWT_CAPTION,   RESIZE_NONE,    10,    11,   369,     0,    13, STR_6800_DIFFICULTY_LEVEL,    STR_018C_WINDOW_TITLE_DRAG_THIS}, // GDW_CAPTION
   602 {      WWT_PANEL,   RESIZE_NONE,    10,     0,   369,    14,    29, 0x0,                          STR_NULL},
   659 {      WWT_PANEL,   RESIZE_NONE,    10,     0,   369,    14,    41, 0x0,                          STR_NULL},                        // GDW_UPPER_BG
   603 { WWT_PUSHTXTBTN,   RESIZE_NONE,     3,    10,    96,    16,    27, STR_6801_EASY,                STR_NULL},
   660 { WWT_PUSHTXTBTN,   RESIZE_NONE,     3,    10,    96,    16,    27, STR_6801_EASY,                STR_NULL},                        // GDW_LVL_EASY
   604 { WWT_PUSHTXTBTN,   RESIZE_NONE,     3,    97,   183,    16,    27, STR_6802_MEDIUM,              STR_NULL},
   661 { WWT_PUSHTXTBTN,   RESIZE_NONE,     3,    97,   183,    16,    27, STR_6802_MEDIUM,              STR_NULL},                        // GDW_LVL_MEDIUM
   605 { WWT_PUSHTXTBTN,   RESIZE_NONE,     3,   184,   270,    16,    27, STR_6803_HARD,                STR_NULL},
   662 { WWT_PUSHTXTBTN,   RESIZE_NONE,     3,   184,   270,    16,    27, STR_6803_HARD,                STR_NULL},                        // GDW_LVL_HARD
   606 { WWT_PUSHTXTBTN,   RESIZE_NONE,     3,   271,   357,    16,    27, STR_6804_CUSTOM,              STR_NULL},
   663 { WWT_PUSHTXTBTN,   RESIZE_NONE,     3,   271,   357,    16,    27, STR_6804_CUSTOM,              STR_NULL},                        // GDW_LVL_CUSTOM
   607 {    WWT_TEXTBTN,   RESIZE_NONE,    10,     0,   369,    30,    41, STR_6838_SHOW_HI_SCORE_CHART, STR_NULL},
   664 {    WWT_TEXTBTN,   RESIZE_NONE,     6,    10,   357,    28,    39, STR_6838_SHOW_HI_SCORE_CHART, STR_NULL},                        // GDW_HIGHSCORE
   608 {      WWT_PANEL,   RESIZE_NONE,    10,     0,   369,    42,   262, 0x0,                          STR_NULL},
   665 {      WWT_PANEL,   RESIZE_NONE,    10,     0,   369,    42,   262, 0x0,                          STR_NULL},                        // GDW_SETTING_BG
   609 {      WWT_PANEL,   RESIZE_NONE,    10,     0,   369,   263,   278, 0x0,                          STR_NULL},
   666 {      WWT_PANEL,   RESIZE_NONE,    10,     0,   369,   263,   278, 0x0,                          STR_NULL},                        // GDW_LOWER_BG
   610 { WWT_PUSHTXTBTN,   RESIZE_NONE,     3,   105,   185,   265,   276, STR_OPTIONS_SAVE_CHANGES,     STR_NULL},
   667 { WWT_PUSHTXTBTN,   RESIZE_NONE,     3,   105,   185,   265,   276, STR_OPTIONS_SAVE_CHANGES,     STR_NULL},                        // GDW_ACCEPT
   611 { WWT_PUSHTXTBTN,   RESIZE_NONE,     3,   186,   266,   265,   276, STR_012E_CANCEL,              STR_NULL},
   668 { WWT_PUSHTXTBTN,   RESIZE_NONE,     3,   186,   266,   265,   276, STR_012E_CANCEL,              STR_NULL},                        // GDW_CANCEL
   612 {   WIDGETS_END},
   669 {   WIDGETS_END},
   613 };
   670 };
   614 
   671 
       
   672 /* Window definition for the game difficulty settings window */
   615 static const WindowDesc _game_difficulty_desc = {
   673 static const WindowDesc _game_difficulty_desc = {
   616 	WDP_CENTER, WDP_CENTER, 370, 279, 370, 279,
   674 	WDP_CENTER, WDP_CENTER, 370, 279, 370, 279,
   617 	WC_GAME_OPTIONS, WC_NONE,
   675 	WC_GAME_OPTIONS, WC_NONE,
   618 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
   676 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
   619 	_game_difficulty_widgets,
   677 	_game_difficulty_widgets,
   772 	{_patches_stations,     NULL, lengthof(_patches_stations)},
   830 	{_patches_stations,     NULL, lengthof(_patches_stations)},
   773 	{_patches_economy,      NULL, lengthof(_patches_economy)},
   831 	{_patches_economy,      NULL, lengthof(_patches_economy)},
   774 	{_patches_ai,           NULL, lengthof(_patches_ai)},
   832 	{_patches_ai,           NULL, lengthof(_patches_ai)},
   775 };
   833 };
   776 
   834 
       
   835 enum PatchesSelectionWidgets {
       
   836 	PATCHSEL_OPTIONSPANEL = 3,
       
   837 	PATCHSEL_INTERFACE,
       
   838 	PATCHSEL_CONSTRUCTION,
       
   839 	PATCHSEL_VEHICLES,
       
   840 	PATCHSEL_STATIONS,
       
   841 	PATCHSEL_ECONOMY,
       
   842 	PATCHSEL_COMPETITORS
       
   843 };
       
   844 
   777 /** The main patches window. Shows a number of categories on top and
   845 /** The main patches window. Shows a number of categories on top and
   778  * a selection of patches in that category.
   846  * a selection of patches in that category.
   779  * Uses WP(w, def_d) macro - data_1, data_2, data_3 */
   847  * Uses WP(w, def_d) macro - data_1, data_2, data_3 */
   780 static void PatchesSelectionWndProc(Window *w, WindowEvent *e)
   848 static void PatchesSelectionWndProc(Window *w, WindowEvent *e)
   781 {
   849 {
   782 	static Patches *patches_ptr;
   850 	static Patches *patches_ptr;
   783 
   851 
   784 	switch (e->event) {
   852 	switch (e->event) {
   785 	case WE_CREATE: {
   853 		case WE_CREATE: {
   786 		static bool first_time = true;
   854 			static bool first_time = true;
   787 
   855 
   788 		patches_ptr = (_game_mode == GM_MENU) ? &_patches_newgame : &_patches;
   856 			patches_ptr = (_game_mode == GM_MENU) ? &_patches_newgame : &_patches;
   789 
   857 
   790 		/* Build up the dynamic settings-array only once per OpenTTD session */
   858 			/* Build up the dynamic settings-array only once per OpenTTD session */
   791 		if (first_time) {
   859 			if (first_time) {
   792 			PatchPage *page;
   860 				PatchPage *page;
   793 			for (page = &_patches_page[0]; page != endof(_patches_page); page++) {
   861 				for (page = &_patches_page[0]; page != endof(_patches_page); page++) {
   794 				uint i;
   862 					uint i;
   795 
   863 
   796 				page->entries = MallocT<PatchEntry>(page->num);
   864 					page->entries = MallocT<PatchEntry>(page->num);
   797 				for (i = 0; i != page->num; i++) {
   865 					for (i = 0; i != page->num; i++) {
   798 					uint index;
   866 						uint index;
   799 					const SettingDesc *sd = GetPatchFromName(page->names[i], &index);
   867 						const SettingDesc *sd = GetPatchFromName(page->names[i], &index);
   800 					assert(sd != NULL);
   868 						assert(sd != NULL);
   801 
   869 
   802 					page->entries[i].setting = sd;
   870 						page->entries[i].setting = sd;
   803 					page->entries[i].index = index;
   871 						page->entries[i].index = index;
       
   872 					}
   804 				}
   873 				}
       
   874 				first_time = false;
   805 			}
   875 			}
   806 			first_time = false;
   876 			w->LowerWidget(4);
   807 		}
   877 		} break;
   808 		w->LowerWidget(4);
   878 
   809 	} break;
   879 		case WE_PAINT: {
   810 
   880 			int x, y;
   811 	case WE_PAINT: {
   881 			const PatchPage *page = &_patches_page[WP(w, def_d).data_1];
   812 		int x, y;
   882 			uint i;
   813 		const PatchPage *page = &_patches_page[WP(w,def_d).data_1];
   883 
   814 		uint i;
   884 			/* Set up selected category */
   815 
   885 			DrawWindowWidgets(w);
   816 		/* Set up selected category */
   886 
   817 		DrawWindowWidgets(w);
   887 			x = 5;
   818 
   888 			y = 47;
   819 		x = 5;
   889 			for (i = 0; i != page->num; i++) {
   820 		y = 47;
   890 				const SettingDesc *sd = page->entries[i].setting;
   821 		for (i = 0; i != page->num; i++) {
   891 				const SettingDescBase *sdb = &sd->desc;
   822 			const SettingDesc *sd = page->entries[i].setting;
   892 				const void *var = GetVariableAddress(patches_ptr, &sd->save);
   823 			const SettingDescBase *sdb = &sd->desc;
   893 				bool editable = true;
   824 			const void *var = GetVariableAddress(patches_ptr, &sd->save);
   894 				bool disabled = false;
   825 			bool editable = true;
   895 
   826 			bool disabled = false;
   896 				// We do not allow changes of some items when we are a client in a networkgame
   827 
   897 				if (!(sd->save.conv & SLF_NETWORK_NO) && _networking && !_network_server) editable = false;
   828 			// We do not allow changes of some items when we are a client in a networkgame
   898 				if ((sdb->flags & SGF_NETWORK_ONLY) && !_networking) editable = false;
   829 			if (!(sd->save.conv & SLF_NETWORK_NO) && _networking && !_network_server) editable = false;
   899 				if ((sdb->flags & SGF_NO_NETWORK) && _networking) editable = false;
   830 			if ((sdb->flags & SGF_NETWORK_ONLY) && !_networking) editable = false;
   900 
   831 			if ((sdb->flags & SGF_NO_NETWORK) && _networking) editable = false;
   901 				if (sdb->cmd == SDT_BOOLX) {
   832 
   902 					static const int _bool_ctabs[2][2] = {{9, 4}, {7, 6}};
   833 			if (sdb->cmd == SDT_BOOLX) {
   903 					/* Draw checkbox for boolean-value either on/off */
   834 				static const int _bool_ctabs[2][2] = {{9, 4}, {7, 6}};
   904 					bool on = (*(bool*)var);
   835 				/* Draw checkbox for boolean-value either on/off */
   905 
   836 				bool on = (*(bool*)var);
   906 					DrawFrameRect(x, y, x + 19, y + 8, _bool_ctabs[!!on][!!editable], on ? FR_LOWERED : FR_NONE);
   837 
   907 					SetDParam(0, on ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF);
   838 				DrawFrameRect(x, y, x + 19, y + 8, _bool_ctabs[!!on][!!editable], on ? FR_LOWERED : FR_NONE);
       
   839 				SetDParam(0, on ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF);
       
   840 			} else {
       
   841 				int32 value;
       
   842 
       
   843 				value = (int32)ReadValue(var, sd->save.conv);
       
   844 
       
   845 				/* Draw [<][>] boxes for settings of an integer-type */
       
   846 				DrawArrowButtons(x, y, 3, WP(w,def_d).data_2 - (i * 2), (editable && value != sdb->min), (editable && value != sdb->max));
       
   847 
       
   848 				disabled = (value == 0) && (sdb->flags & SGF_0ISDISABLED);
       
   849 				if (disabled) {
       
   850 					SetDParam(0, STR_CONFIG_PATCHES_DISABLED);
       
   851 				} else {
   908 				} else {
   852 					if (sdb->flags & SGF_CURRENCY) {
   909 					int32 value;
   853 						SetDParam(0, STR_CONFIG_PATCHES_CURRENCY);
   910 
   854 					} else if (sdb->flags & SGF_MULTISTRING) {
   911 					value = (int32)ReadValue(var, sd->save.conv);
   855 						SetDParam(0, sdb->str + value + 1);
   912 
       
   913 					/* Draw [<][>] boxes for settings of an integer-type */
       
   914 					DrawArrowButtons(x, y, 3, WP(w, def_d).data_2 - (i * 2), (editable && value != sdb->min), (editable && value != sdb->max));
       
   915 
       
   916 					disabled = (value == 0) && (sdb->flags & SGF_0ISDISABLED);
       
   917 					if (disabled) {
       
   918 						SetDParam(0, STR_CONFIG_PATCHES_DISABLED);
   856 					} else {
   919 					} else {
   857 						SetDParam(0, (sdb->flags & SGF_NOCOMMA) ? STR_CONFIG_PATCHES_INT32 : STR_7024);
   920 						if (sdb->flags & SGF_CURRENCY) {
       
   921 							SetDParam(0, STR_CONFIG_PATCHES_CURRENCY);
       
   922 						} else if (sdb->flags & SGF_MULTISTRING) {
       
   923 							SetDParam(0, sdb->str + value + 1);
       
   924 						} else {
       
   925 							SetDParam(0, (sdb->flags & SGF_NOCOMMA) ? STR_CONFIG_PATCHES_INT32 : STR_7024);
       
   926 						}
       
   927 						SetDParam(1, value);
   858 					}
   928 					}
   859 					SetDParam(1, value);
       
   860 				}
   929 				}
       
   930 				DrawString(30, y, (sdb->str) + disabled, TC_FROMSTRING);
       
   931 				y += 11;
   861 			}
   932 			}
   862 			DrawString(30, y, (sdb->str) + disabled, TC_FROMSTRING);
   933 		} break;
   863 			y += 11;
   934 
   864 		}
   935 		case WE_CLICK:
   865 		break;
   936 			switch (e->we.click.widget) {
   866 	}
   937 				case PATCHSEL_OPTIONSPANEL: {
   867 
   938 					const PatchPage *page = &_patches_page[WP(w, def_d).data_1];
   868 	case WE_CLICK:
   939 					const SettingDesc *sd;
   869 		switch (e->we.click.widget) {
   940 					void *var;
   870 		case 3: {
   941 					int32 value;
   871 			const PatchPage *page = &_patches_page[WP(w,def_d).data_1];
   942 					int x, y;
   872 			const SettingDesc *sd;
   943 					byte btn;
   873 			void *var;
   944 
   874 			int32 value;
   945 					y = e->we.click.pt.y - 46 - 1;
   875 			int x, y;
   946 					if (y < 0) return;
   876 			byte btn;
   947 
   877 
   948 					x = e->we.click.pt.x - 5;
   878 			y = e->we.click.pt.y - 46 - 1;
   949 					if (x < 0) return;
   879 			if (y < 0) return;
   950 
   880 
   951 					btn = y / 11;
   881 			x = e->we.click.pt.x - 5;
   952 					if (y % 11 > 9) return;
   882 			if (x < 0) return;
   953 					if (btn >= page->num) return;
   883 
   954 
   884 			btn = y / 11;
   955 					sd = page->entries[btn].setting;
   885 			if (y % 11 > 9) return;
   956 
   886 			if (btn >= page->num) return;
   957 					/* return if action is only active in network, or only settable by server */
   887 
   958 					if (!(sd->save.conv & SLF_NETWORK_NO) && _networking && !_network_server) return;
   888 			sd = page->entries[btn].setting;
   959 					if ((sd->desc.flags & SGF_NETWORK_ONLY) && !_networking) return;
   889 
   960 					if ((sd->desc.flags & SGF_NO_NETWORK) && _networking) return;
   890 			/* return if action is only active in network, or only settable by server */
   961 
   891 			if (!(sd->save.conv & SLF_NETWORK_NO) && _networking && !_network_server) return;
   962 					var = GetVariableAddress(patches_ptr, &sd->save);
   892 			if ((sd->desc.flags & SGF_NETWORK_ONLY) && !_networking) return;
   963 					value = (int32)ReadValue(var, sd->save.conv);
   893 			if ((sd->desc.flags & SGF_NO_NETWORK) && _networking) return;
   964 
   894 
   965 					/* clicked on the icon on the left side. Either scroller or bool on/off */
   895 			var = GetVariableAddress(patches_ptr, &sd->save);
   966 					if (x < 21) {
   896 			value = (int32)ReadValue(var, sd->save.conv);
   967 						const SettingDescBase *sdb = &sd->desc;
   897 
   968 						int32 oldvalue = value;
   898 			/* clicked on the icon on the left side. Either scroller or bool on/off */
   969 
   899 			if (x < 21) {
   970 						switch (sdb->cmd) {
   900 				const SettingDescBase *sdb = &sd->desc;
   971 						case SDT_BOOLX: value ^= 1; break;
   901 				int32 oldvalue = value;
   972 						case SDT_NUMX: {
   902 
   973 							/* Add a dynamic step-size to the scroller. In a maximum of
   903 				switch (sdb->cmd) {
   974 							 * 50-steps you should be able to get from min to max,
   904 				case SDT_BOOLX: value ^= 1; break;
   975 							 * unless specified otherwise in the 'interval' variable
   905 				case SDT_NUMX: {
   976 							 * of the current patch. */
   906 					/* Add a dynamic step-size to the scroller. In a maximum of
   977 							uint32 step = (sdb->interval == 0) ? ((sdb->max - sdb->min) / 50) : sdb->interval;
   907 					 * 50-steps you should be able to get from min to max,
   978 							if (step == 0) step = 1;
   908 					 * unless specified otherwise in the 'interval' variable
   979 
   909 					 * of the current patch. */
   980 							// don't allow too fast scrolling
   910 					uint32 step = (sdb->interval == 0) ? ((sdb->max - sdb->min) / 50) : sdb->interval;
   981 							if ((w->flags4 & WF_TIMEOUT_MASK) > 2 << WF_TIMEOUT_SHL) {
   911 					if (step == 0) step = 1;
   982 								_left_button_clicked = false;
   912 
   983 								return;
   913 					// don't allow too fast scrolling
   984 							}
   914 					if ((w->flags4 & WF_TIMEOUT_MASK) > 2 << WF_TIMEOUT_SHL) {
   985 
   915 						_left_button_clicked = false;
   986 							/* Increase or decrease the value and clamp it to extremes */
   916 						return;
   987 							if (x >= 10) {
   917 					}
   988 								value += step;
   918 
   989 								if (value > sdb->max) value = sdb->max;
   919 					/* Increase or decrease the value and clamp it to extremes */
   990 							} else {
   920 					if (x >= 10) {
   991 								value -= step;
   921 						value += step;
   992 								if (value < sdb->min) value = (sdb->flags & SGF_0ISDISABLED) ? 0 : sdb->min;
   922 						if (value > sdb->max) value = sdb->max;
   993 							}
       
   994 
       
   995 							/* Set up scroller timeout for numeric values */
       
   996 							if (value != oldvalue && !(sd->desc.flags & SGF_MULTISTRING)) {
       
   997 								WP(w, def_d).data_2 = btn * 2 + 1 + ((x >= 10) ? 1 : 0);
       
   998 								w->flags4 |= 5 << WF_TIMEOUT_SHL;
       
   999 								_left_button_clicked = false;
       
  1000 							}
       
  1001 						} break;
       
  1002 						default: NOT_REACHED();
       
  1003 						}
       
  1004 
       
  1005 						if (value != oldvalue) {
       
  1006 							SetPatchValue(page->entries[btn].index, patches_ptr, value);
       
  1007 							SetWindowDirty(w);
       
  1008 						}
   923 					} else {
  1009 					} else {
   924 						value -= step;
  1010 						/* only open editbox for types that its sensible for */
   925 						if (value < sdb->min) value = (sdb->flags & SGF_0ISDISABLED) ? 0 : sdb->min;
  1011 						if (sd->desc.cmd != SDT_BOOLX && !(sd->desc.flags & SGF_MULTISTRING)) {
   926 					}
  1012 							/* Show the correct currency-translated value */
   927 
  1013 							if (sd->desc.flags & SGF_CURRENCY) value *= _currency->rate;
   928 					/* Set up scroller timeout for numeric values */
  1014 
   929 					if (value != oldvalue && !(sd->desc.flags & SGF_MULTISTRING)) {
  1015 							WP(w, def_d).data_3 = btn;
   930 						WP(w,def_d).data_2 = btn * 2 + 1 + ((x >= 10) ? 1 : 0);
  1016 							SetDParam(0, value);
   931 						w->flags4 |= 5 << WF_TIMEOUT_SHL;
  1017 							ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_CONFIG_PATCHES_QUERY_CAPT, 10, 100, w, CS_NUMERAL);
   932 						_left_button_clicked = false;
  1018 						}
   933 					}
  1019 					}
   934 				} break;
  1020 				} break;
   935 				default: NOT_REACHED();
  1021 
   936 				}
  1022 				case PATCHSEL_INTERFACE: case PATCHSEL_CONSTRUCTION: case PATCHSEL_VEHICLES:
   937 
  1023 				case PATCHSEL_STATIONS:  case PATCHSEL_ECONOMY:      case PATCHSEL_COMPETITORS:
   938 				if (value != oldvalue) {
  1024 					w->RaiseWidget(WP(w, def_d).data_1 + PATCHSEL_INTERFACE);
   939 					SetPatchValue(page->entries[btn].index, patches_ptr, value);
  1025 					WP(w, def_d).data_1 = e->we.click.widget - PATCHSEL_INTERFACE;
       
  1026 					w->LowerWidget(WP(w, def_d).data_1 + PATCHSEL_INTERFACE);
       
  1027 					DeleteWindowById(WC_QUERY_STRING, 0);
   940 					SetWindowDirty(w);
  1028 					SetWindowDirty(w);
   941 				}
  1029 					break;
   942 			} else {
       
   943 				/* only open editbox for types that its sensible for */
       
   944 				if (sd->desc.cmd != SDT_BOOLX && !(sd->desc.flags & SGF_MULTISTRING)) {
       
   945 					/* Show the correct currency-translated value */
       
   946 					if (sd->desc.flags & SGF_CURRENCY) value *= _currency->rate;
       
   947 
       
   948 					WP(w,def_d).data_3 = btn;
       
   949 					SetDParam(0, value);
       
   950 					ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_CONFIG_PATCHES_QUERY_CAPT, 10, 100, w, CS_NUMERAL);
       
   951 				}
       
   952 			}
  1030 			}
   953 
       
   954 			break;
  1031 			break;
   955 		}
  1032 
   956 		case 4: case 5: case 6: case 7: case 8: case 9:
  1033 		case WE_TIMEOUT:
   957 			w->RaiseWidget(WP(w, def_d).data_1 + 4);
  1034 			WP(w, def_d).data_2 = 0;
   958 			WP(w, def_d).data_1 = e->we.click.widget - 4;
       
   959 			w->LowerWidget(WP(w, def_d).data_1 + 4);
       
   960 			DeleteWindowById(WC_QUERY_STRING, 0);
       
   961 			SetWindowDirty(w);
  1035 			SetWindowDirty(w);
   962 			break;
  1036 			break;
   963 		}
  1037 
   964 		break;
  1038 		case WE_ON_EDIT_TEXT:
   965 
  1039 			if (e->we.edittext.str != NULL) {
   966 	case WE_TIMEOUT:
  1040 				const PatchEntry *pe = &_patches_page[WP(w, def_d).data_1].entries[WP(w,def_d).data_3];
   967 		WP(w,def_d).data_2 = 0;
  1041 				const SettingDesc *sd = pe->setting;
   968 		SetWindowDirty(w);
  1042 				int32 value = atoi(e->we.edittext.str);
   969 		break;
  1043 
   970 
  1044 				/* Save the correct currency-translated value */
   971 	case WE_ON_EDIT_TEXT: {
  1045 				if (sd->desc.flags & SGF_CURRENCY) value /= _currency->rate;
   972 		if (e->we.edittext.str != NULL) {
  1046 
   973 			const PatchEntry *pe = &_patches_page[WP(w,def_d).data_1].entries[WP(w,def_d).data_3];
  1047 				SetPatchValue(pe->index, patches_ptr, value);
   974 			const SettingDesc *sd = pe->setting;
  1048 				SetWindowDirty(w);
   975 			int32 value = atoi(e->we.edittext.str);
  1049 			}
   976 
  1050 			break;
   977 			/* Save the correct currency-translated value */
  1051 
   978 			if (sd->desc.flags & SGF_CURRENCY) value /= _currency->rate;
  1052 		case WE_DESTROY:
   979 
  1053 			DeleteWindowById(WC_QUERY_STRING, 0);
   980 			SetPatchValue(pe->index, patches_ptr, value);
  1054 			break;
   981 			SetWindowDirty(w);
       
   982 		}
       
   983 		break;
       
   984 	}
       
   985 
       
   986 	case WE_DESTROY:
       
   987 		DeleteWindowById(WC_QUERY_STRING, 0);
       
   988 		break;
       
   989 	}
  1055 	}
   990 }
  1056 }
   991 
  1057 
   992 static const Widget _patches_selection_widgets[] = {
  1058 static const Widget _patches_selection_widgets[] = {
   993 {   WWT_CLOSEBOX,   RESIZE_NONE,    10,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
  1059 {   WWT_CLOSEBOX,   RESIZE_NONE,    10,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
  1042 		GfxFillRect(x +  1, y + 1, x +  1 + 8, y + 8, color);
  1108 		GfxFillRect(x +  1, y + 1, x +  1 + 8, y + 8, color);
  1043 	if (!clickable_right)
  1109 	if (!clickable_right)
  1044 		GfxFillRect(x + 11, y + 1, x + 11 + 8, y + 8, color);
  1110 		GfxFillRect(x + 11, y + 1, x + 11 + 8, y + 8, color);
  1045 }
  1111 }
  1046 
  1112 
       
  1113 /** These are not, strickly speaking, widget enums,
       
  1114  *  since they have been changed as line coordinates.
       
  1115  *  So, rather, they are more like order of appearance */
       
  1116 enum CustomCurrenciesWidgets {
       
  1117 	CUSTCURR_EXCHANGERATE = 0,
       
  1118 	CUSTCURR_SEPARATOR,
       
  1119 	CUSTCURR_PREFIX,
       
  1120 	CUSTCURR_SUFFIX,
       
  1121 	CUSTCURR_TO_EURO,
       
  1122 };
       
  1123 
  1047 static char _str_separator[2];
  1124 static char _str_separator[2];
  1048 
  1125 
  1049 static void CustCurrencyWndProc(Window *w, WindowEvent *e)
  1126 static void CustCurrencyWndProc(Window *w, WindowEvent *e)
  1050 {
  1127 {
  1051 	switch (e->event) {
  1128 	switch (e->event) {
  1052 		case WE_PAINT: {
  1129 		case WE_PAINT: {
  1053 			int x;
  1130 			int x;
  1054 			int y = 20;
  1131 			int y = 20;
  1055 			int clk = WP(w,def_d).data_1;
  1132 			int clk = WP(w, def_d).data_1;
  1056 			DrawWindowWidgets(w);
  1133 			DrawWindowWidgets(w);
  1057 
  1134 
  1058 			// exchange rate
  1135 			/* exchange rate */
  1059 			DrawArrowButtons(10, y, 3, GB(clk, 0, 2), true, true);
  1136 			DrawArrowButtons(10, y, 3, GB(clk, 0, 2), true, true);
  1060 			SetDParam(0, 1);
  1137 			SetDParam(0, 1);
  1061 			SetDParam(1, 1);
  1138 			SetDParam(1, 1);
  1062 			DrawString(35, y + 1, STR_CURRENCY_EXCHANGE_RATE, TC_FROMSTRING);
  1139 			DrawString(35, y + 1, STR_CURRENCY_EXCHANGE_RATE, TC_FROMSTRING);
  1063 			y += 12;
  1140 			y += 12;
  1064 
  1141 
  1065 			// separator
  1142 			/* separator */
  1066 			DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(clk, 2, 2) ? FR_LOWERED : FR_NONE);
  1143 			DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(clk, 2, 2) ? FR_LOWERED : FR_NONE);
  1067 			x = DrawString(35, y + 1, STR_CURRENCY_SEPARATOR, TC_FROMSTRING);
  1144 			x = DrawString(35, y + 1, STR_CURRENCY_SEPARATOR, TC_FROMSTRING);
  1068 			DoDrawString(_str_separator, x + 4, y + 1, TC_ORANGE);
  1145 			DoDrawString(_str_separator, x + 4, y + 1, TC_ORANGE);
  1069 			y += 12;
  1146 			y += 12;
  1070 
  1147 
  1071 			// prefix
  1148 			/* prefix */
  1072 			DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(clk, 4, 2) ? FR_LOWERED : FR_NONE);
  1149 			DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(clk, 4, 2) ? FR_LOWERED : FR_NONE);
  1073 			x = DrawString(35, y + 1, STR_CURRENCY_PREFIX, TC_FROMSTRING);
  1150 			x = DrawString(35, y + 1, STR_CURRENCY_PREFIX, TC_FROMSTRING);
  1074 			DoDrawString(_custom_currency.prefix, x + 4, y + 1, TC_ORANGE);
  1151 			DoDrawString(_custom_currency.prefix, x + 4, y + 1, TC_ORANGE);
  1075 			y += 12;
  1152 			y += 12;
  1076 
  1153 
  1077 			// suffix
  1154 			/* suffix */
  1078 			DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(clk, 6, 2) ? FR_LOWERED : FR_NONE);
  1155 			DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(clk, 6, 2) ? FR_LOWERED : FR_NONE);
  1079 			x = DrawString(35, y + 1, STR_CURRENCY_SUFFIX, TC_FROMSTRING);
  1156 			x = DrawString(35, y + 1, STR_CURRENCY_SUFFIX, TC_FROMSTRING);
  1080 			DoDrawString(_custom_currency.suffix, x + 4, y + 1, TC_ORANGE);
  1157 			DoDrawString(_custom_currency.suffix, x + 4, y + 1, TC_ORANGE);
  1081 			y += 12;
  1158 			y += 12;
  1082 
  1159 
  1083 			// switch to euro
  1160 			/* switch to euro */
  1084 			DrawArrowButtons(10, y, 3, GB(clk, 8, 2), true, true);
  1161 			DrawArrowButtons(10, y, 3, GB(clk, 8, 2), true, true);
  1085 			SetDParam(0, _custom_currency.to_euro);
  1162 			SetDParam(0, _custom_currency.to_euro);
  1086 			DrawString(35, y + 1, (_custom_currency.to_euro != CF_NOEURO) ? STR_CURRENCY_SWITCH_TO_EURO : STR_CURRENCY_SWITCH_TO_EURO_NEVER, TC_FROMSTRING);
  1163 			DrawString(35, y + 1, (_custom_currency.to_euro != CF_NOEURO) ? STR_CURRENCY_SWITCH_TO_EURO : STR_CURRENCY_SWITCH_TO_EURO_NEVER, TC_FROMSTRING);
  1087 			y += 12;
  1164 			y += 12;
  1088 
  1165 
  1089 			// Preview
  1166 			/* Preview */
  1090 			y += 12;
  1167 			y += 12;
  1091 			SetDParam(0, 10000);
  1168 			SetDParam(0, 10000);
  1092 			DrawString(35, y + 1, STR_CURRENCY_PREVIEW, TC_FROMSTRING);
  1169 			DrawString(35, y + 1, STR_CURRENCY_PREVIEW, TC_FROMSTRING);
  1093 			break;
  1170 		} break;
  1094 		}
       
  1095 
  1171 
  1096 		case WE_CLICK: {
  1172 		case WE_CLICK: {
  1097 			int line = (e->we.click.pt.y - 20) / 12;
  1173 			int line = (e->we.click.pt.y - 20) / 12;
  1098 			int len = 0;
  1174 			int len = 0;
  1099 			int x = e->we.click.pt.x;
  1175 			int x = e->we.click.pt.x;
  1100 			StringID str = 0;
  1176 			StringID str = 0;
  1101 			CharSetFilter afilter = CS_ALPHANUMERAL;
  1177 			CharSetFilter afilter = CS_ALPHANUMERAL;
  1102 
  1178 
  1103 			switch (line) {
  1179 			switch (line) {
  1104 				case 0: // rate
  1180 				case CUSTCURR_EXCHANGERATE:
  1105 					if (IsInsideMM(x, 10, 30)) { // clicked buttons
  1181 					if (IsInsideMM(x, 10, 30)) { // clicked buttons
  1106 						if (x < 20) {
  1182 						if (x < 20) {
  1107 							if (_custom_currency.rate > 1) _custom_currency.rate--;
  1183 							if (_custom_currency.rate > 1) _custom_currency.rate--;
  1108 							WP(w,def_d).data_1 = 1 << (line * 2 + 0);
  1184 							WP(w, def_d).data_1 = 1 << (line * 2 + 0);
  1109 						} else {
  1185 						} else {
  1110 							if (_custom_currency.rate < 5000) _custom_currency.rate++;
  1186 							if (_custom_currency.rate < 5000) _custom_currency.rate++;
  1111 							WP(w,def_d).data_1 = 1 << (line * 2 + 1);
  1187 							WP(w, def_d).data_1 = 1 << (line * 2 + 1);
  1112 						}
  1188 						}
  1113 					} else { // enter text
  1189 					} else { // enter text
  1114 						SetDParam(0, _custom_currency.rate);
  1190 						SetDParam(0, _custom_currency.rate);
  1115 						str = STR_CONFIG_PATCHES_INT32;
  1191 						str = STR_CONFIG_PATCHES_INT32;
  1116 						len = 4;
  1192 						len = 4;
  1117 						afilter = CS_NUMERAL;
  1193 						afilter = CS_NUMERAL;
  1118 					}
  1194 					}
  1119 					break;
  1195 					break;
  1120 
  1196 
  1121 				case 1: // separator
  1197 				case CUSTCURR_SEPARATOR:
  1122 					if (IsInsideMM(x, 10, 30)) { // clicked button
  1198 					if (IsInsideMM(x, 10, 30)) { // clicked button
  1123 						WP(w,def_d).data_1 = 1 << (line * 2 + 1);
  1199 						WP(w, def_d).data_1 = 1 << (line * 2 + 1);
  1124 					}
  1200 					}
  1125 					str = BindCString(_str_separator);
  1201 					str = BindCString(_str_separator);
  1126 					len = 1;
  1202 					len = 1;
  1127 					break;
  1203 					break;
  1128 
  1204 
  1129 				case 2: // prefix
  1205 				case CUSTCURR_PREFIX:
  1130 					if (IsInsideMM(x, 10, 30)) { // clicked button
  1206 					if (IsInsideMM(x, 10, 30)) { // clicked button
  1131 						WP(w,def_d).data_1 = 1 << (line * 2 + 1);
  1207 						WP(w, def_d).data_1 = 1 << (line * 2 + 1);
  1132 					}
  1208 					}
  1133 					str = BindCString(_custom_currency.prefix);
  1209 					str = BindCString(_custom_currency.prefix);
  1134 					len = 12;
  1210 					len = 12;
  1135 					break;
  1211 					break;
  1136 
  1212 
  1137 				case 3: // suffix
  1213 				case CUSTCURR_SUFFIX:
  1138 					if (IsInsideMM(x, 10, 30)) { // clicked button
  1214 					if (IsInsideMM(x, 10, 30)) { // clicked button
  1139 						WP(w,def_d).data_1 = 1 << (line * 2 + 1);
  1215 						WP(w, def_d).data_1 = 1 << (line * 2 + 1);
  1140 					}
  1216 					}
  1141 					str = BindCString(_custom_currency.suffix);
  1217 					str = BindCString(_custom_currency.suffix);
  1142 					len = 12;
  1218 					len = 12;
  1143 					break;
  1219 					break;
  1144 
  1220 
  1145 				case 4: // to euro
  1221 				case CUSTCURR_TO_EURO:
  1146 					if (IsInsideMM(x, 10, 30)) { // clicked buttons
  1222 					if (IsInsideMM(x, 10, 30)) { // clicked buttons
  1147 						if (x < 20) {
  1223 						if (x < 20) {
  1148 							_custom_currency.to_euro = (_custom_currency.to_euro <= 2000) ?
  1224 							_custom_currency.to_euro = (_custom_currency.to_euro <= 2000) ?
  1149 								CF_NOEURO : _custom_currency.to_euro - 1;
  1225 								CF_NOEURO : _custom_currency.to_euro - 1;
  1150 							WP(w,def_d).data_1 = 1 << (line * 2 + 0);
  1226 							WP(w, def_d).data_1 = 1 << (line * 2 + 0);
  1151 						} else {
  1227 						} else {
  1152 							_custom_currency.to_euro =
  1228 							_custom_currency.to_euro =
  1153 								Clamp(_custom_currency.to_euro + 1, 2000, MAX_YEAR);
  1229 								Clamp(_custom_currency.to_euro + 1, 2000, MAX_YEAR);
  1154 							WP(w,def_d).data_1 = 1 << (line * 2 + 1);
  1230 							WP(w, def_d).data_1 = 1 << (line * 2 + 1);
  1155 						}
  1231 						}
  1156 					} else { // enter text
  1232 					} else { // enter text
  1157 						SetDParam(0, _custom_currency.to_euro);
  1233 						SetDParam(0, _custom_currency.to_euro);
  1158 						str = STR_CONFIG_PATCHES_INT32;
  1234 						str = STR_CONFIG_PATCHES_INT32;
  1159 						len = 4;
  1235 						len = 4;
  1167 				ShowQueryString(str, STR_CURRENCY_CHANGE_PARAMETER, len + 1, 250, w, afilter);
  1243 				ShowQueryString(str, STR_CURRENCY_CHANGE_PARAMETER, len + 1, 250, w, afilter);
  1168 			}
  1244 			}
  1169 
  1245 
  1170 			w->flags4 |= 5 << WF_TIMEOUT_SHL;
  1246 			w->flags4 |= 5 << WF_TIMEOUT_SHL;
  1171 			SetWindowDirty(w);
  1247 			SetWindowDirty(w);
  1172 			break;
  1248 		} break;
  1173 		}
       
  1174 
  1249 
  1175 		case WE_ON_EDIT_TEXT: {
  1250 		case WE_ON_EDIT_TEXT: {
  1176 				const char *b = e->we.edittext.str;
  1251 			const char *b = e->we.edittext.str;
  1177 
  1252 
  1178 				switch (WP(w,def_d).data_2) {
  1253 			switch (WP(w, def_d).data_2) {
  1179 					case 0: /* Exchange rate */
  1254 				case CUSTCURR_EXCHANGERATE:
  1180 						_custom_currency.rate = Clamp(atoi(b), 1, 5000);
  1255 					_custom_currency.rate = Clamp(atoi(b), 1, 5000);
  1181 						break;
  1256 					break;
  1182 
  1257 
  1183 					case 1: /* Thousands seperator */
  1258 				case CUSTCURR_SEPARATOR: /* Thousands seperator */
  1184 						_custom_currency.separator = (b[0] == '\0') ? ' ' : b[0];
  1259 					_custom_currency.separator = (b[0] == '\0') ? ' ' : b[0];
  1185 						ttd_strlcpy(_str_separator, b, lengthof(_str_separator));
  1260 					ttd_strlcpy(_str_separator, b, lengthof(_str_separator));
  1186 						break;
  1261 					break;
  1187 
  1262 
  1188 					case 2: /* Currency prefix */
  1263 				case CUSTCURR_PREFIX:
  1189 						ttd_strlcpy(_custom_currency.prefix, b, lengthof(_custom_currency.prefix));
  1264 					ttd_strlcpy(_custom_currency.prefix, b, lengthof(_custom_currency.prefix));
  1190 						break;
  1265 					break;
  1191 
  1266 
  1192 					case 3: /* Currency suffix */
  1267 				case CUSTCURR_SUFFIX:
  1193 						ttd_strlcpy(_custom_currency.suffix, b, lengthof(_custom_currency.suffix));
  1268 					ttd_strlcpy(_custom_currency.suffix, b, lengthof(_custom_currency.suffix));
  1194 						break;
  1269 					break;
  1195 
  1270 
  1196 					case 4: { /* Year to switch to euro */
  1271 				case CUSTCURR_TO_EURO: { /* Year to switch to euro */
  1197 						int val = atoi(b);
  1272 					int val = atoi(b);
  1198 
  1273 
  1199 						_custom_currency.to_euro =
  1274 					_custom_currency.to_euro = (val < 2000 ? CF_NOEURO : min(val, MAX_YEAR));
  1200 							(val < 2000 ? CF_NOEURO : min(val, MAX_YEAR));
  1275 					break;
  1201 						break;
       
  1202 					}
       
  1203 				}
  1276 				}
       
  1277 			}
  1204 			MarkWholeScreenDirty();
  1278 			MarkWholeScreenDirty();
  1205 			break;
  1279 		} break;
  1206 		}
       
  1207 
  1280 
  1208 		case WE_TIMEOUT:
  1281 		case WE_TIMEOUT:
  1209 			WP(w,def_d).data_1 = 0;
  1282 			WP(w, def_d).data_1 = 0;
  1210 			SetWindowDirty(w);
  1283 			SetWindowDirty(w);
  1211 			break;
  1284 			break;
  1212 
  1285 
  1213 		case WE_DESTROY:
  1286 		case WE_DESTROY:
  1214 			DeleteWindowById(WC_QUERY_STRING, 0);
  1287 			DeleteWindowById(WC_QUERY_STRING, 0);