Feature: Hide block signals in GUI by default (#8688)
[openttd-github.git] / src / settings_table.cpp
blob4b94a8be7813f9d769c1539bff5490861bdad83f
1 /*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
8 /**
9 * @file settings_table.cpp The tables of all the settings as well as the implementation of most of their callbacks.
12 #include "stdafx.h"
13 #include "settings_table.h"
14 #include "currency.h"
15 #include "screenshot.h"
16 #include "network/network.h"
17 #include "network/network_func.h"
18 #include "network/core/config.h"
19 #include "pathfinder/pathfinder_type.h"
20 #include "genworld.h"
21 #include "train.h"
22 #include "news_func.h"
23 #include "window_func.h"
24 #include "company_func.h"
25 #if defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA)
26 #define HAS_TRUETYPE_FONT
27 #include "fontcache.h"
28 #endif
29 #include "textbuf_gui.h"
30 #include "rail_gui.h"
31 #include "elrail_func.h"
32 #include "error.h"
33 #include "town.h"
34 #include "video/video_driver.hpp"
35 #include "sound/sound_driver.hpp"
36 #include "music/music_driver.hpp"
37 #include "blitter/factory.hpp"
38 #include "base_media_base.h"
39 #include "ai/ai_config.hpp"
40 #include "ai/ai.hpp"
41 #include "game/game_config.hpp"
42 #include "ship.h"
43 #include "smallmap_gui.h"
44 #include "roadveh.h"
45 #include "vehicle_func.h"
46 #include "void_map.h"
48 #include "table/strings.h"
49 #include "table/settings.h"
51 #include "safeguards.h"
53 SettingTable _company_settings{ _company_settings_table };
54 SettingTable _currency_settings{ _currency_settings_table };
55 SettingTable _difficulty_settings{ _difficulty_settings_table };
56 SettingTable _multimedia_settings{ _multimedia_settings_table };
57 SettingTable _economy_settings{ _economy_settings_table };
58 SettingTable _game_settings{ _game_settings_table };
59 SettingTable _gui_settings{ _gui_settings_table };
60 SettingTable _linkgraph_settings{ _linkgraph_settings_table };
61 SettingTable _locale_settings{ _locale_settings_table };
62 SettingTable _misc_settings{ _misc_settings_table };
63 SettingTable _network_private_settings{ _network_private_settings_table };
64 SettingTable _network_secrets_settings{ _network_secrets_settings_table };
65 SettingTable _network_settings{ _network_settings_table };
66 SettingTable _news_display_settings{ _news_display_settings_table };
67 SettingTable _old_gameopt_settings{ _old_gameopt_settings_table };
68 SettingTable _pathfinding_settings{ _pathfinding_settings_table };
69 SettingTable _script_settings{ _script_settings_table };
70 SettingTable _window_settings{ _window_settings_table };
71 SettingTable _world_settings{ _world_settings_table };
72 #if defined(_WIN32) && !defined(DEDICATED)
73 SettingTable _win32_settings{ _win32_settings_table };
74 #endif /* _WIN32 */
77 /* Begin - Callback Functions for the various settings. */
79 /** Reposition the main toolbar as the setting changed. */
80 static void v_PositionMainToolbar(int32 new_value)
82 if (_game_mode != GM_MENU) PositionMainToolbar(nullptr);
85 /** Reposition the statusbar as the setting changed. */
86 static void v_PositionStatusbar(int32 new_value)
88 if (_game_mode != GM_MENU) {
89 PositionStatusbar(nullptr);
90 PositionNewsMessage(nullptr);
91 PositionNetworkChatWindow(nullptr);
95 /**
96 * Redraw the smallmap after a colour scheme change.
97 * @param p1 Callback parameter.
99 static void RedrawSmallmap(int32 new_value)
101 BuildLandLegend();
102 BuildOwnerLegend();
103 SetWindowClassesDirty(WC_SMALLMAP);
106 static void StationSpreadChanged(int32 p1)
108 InvalidateWindowData(WC_SELECT_STATION, 0);
109 InvalidateWindowData(WC_BUILD_STATION, 0);
112 static void UpdateConsists(int32 new_value)
114 for (Train *t : Train::Iterate()) {
115 /* Update the consist of all trains so the maximum speed is set correctly. */
116 if (t->IsFrontEngine() || t->IsFreeWagon()) t->ConsistChanged(CCF_TRACK);
118 InvalidateWindowClassesData(WC_BUILD_VEHICLE, 0);
121 /* Check service intervals of vehicles, newvalue is value of % or day based servicing */
122 static void UpdateAllServiceInterval(int32 new_value)
124 bool update_vehicles;
125 VehicleDefaultSettings *vds;
126 if (_game_mode == GM_MENU || !Company::IsValidID(_current_company)) {
127 vds = &_settings_client.company.vehicle;
128 update_vehicles = false;
129 } else {
130 vds = &Company::Get(_current_company)->settings.vehicle;
131 update_vehicles = true;
134 if (new_value != 0) {
135 vds->servint_trains = 50;
136 vds->servint_roadveh = 50;
137 vds->servint_aircraft = 50;
138 vds->servint_ships = 50;
139 } else {
140 vds->servint_trains = 150;
141 vds->servint_roadveh = 150;
142 vds->servint_aircraft = 100;
143 vds->servint_ships = 360;
146 if (update_vehicles) {
147 const Company *c = Company::Get(_current_company);
148 for (Vehicle *v : Vehicle::Iterate()) {
149 if (v->owner == _current_company && v->IsPrimaryVehicle() && !v->ServiceIntervalIsCustom()) {
150 v->SetServiceInterval(CompanyServiceInterval(c, v->type));
151 v->SetServiceIntervalIsPercent(new_value != 0);
156 SetWindowClassesDirty(WC_VEHICLE_DETAILS);
159 static bool CanUpdateServiceInterval(VehicleType type, int32 &new_value)
161 VehicleDefaultSettings *vds;
162 if (_game_mode == GM_MENU || !Company::IsValidID(_current_company)) {
163 vds = &_settings_client.company.vehicle;
164 } else {
165 vds = &Company::Get(_current_company)->settings.vehicle;
168 /* Test if the interval is valid */
169 int32 interval = GetServiceIntervalClamped(new_value, vds->servint_ispercent);
170 return interval == new_value;
173 static void UpdateServiceInterval(VehicleType type, int32 new_value)
175 if (_game_mode != GM_MENU && Company::IsValidID(_current_company)) {
176 for (Vehicle *v : Vehicle::Iterate()) {
177 if (v->owner == _current_company && v->type == type && v->IsPrimaryVehicle() && !v->ServiceIntervalIsCustom()) {
178 v->SetServiceInterval(new_value);
183 SetWindowClassesDirty(WC_VEHICLE_DETAILS);
186 static void TrainAccelerationModelChanged(int32 new_value)
188 for (Train *t : Train::Iterate()) {
189 if (t->IsFrontEngine()) {
190 t->tcache.cached_max_curve_speed = t->GetCurveSpeedLimit();
191 t->UpdateAcceleration();
195 /* These windows show acceleration values only when realistic acceleration is on. They must be redrawn after a setting change. */
196 SetWindowClassesDirty(WC_ENGINE_PREVIEW);
197 InvalidateWindowClassesData(WC_BUILD_VEHICLE, 0);
198 SetWindowClassesDirty(WC_VEHICLE_DETAILS);
202 * This function updates the train acceleration cache after a steepness change.
203 * @param new_value Unused new value of setting.
205 static void TrainSlopeSteepnessChanged(int32 new_value)
207 for (Train *t : Train::Iterate()) {
208 if (t->IsFrontEngine()) t->CargoChanged();
213 * This function updates realistic acceleration caches when the setting "Road vehicle acceleration model" is set.
214 * @param new_value Unused new value of setting.
216 static void RoadVehAccelerationModelChanged(int32 new_value)
218 if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) {
219 for (RoadVehicle *rv : RoadVehicle::Iterate()) {
220 if (rv->IsFrontEngine()) {
221 rv->CargoChanged();
226 /* These windows show acceleration values only when realistic acceleration is on. They must be redrawn after a setting change. */
227 SetWindowClassesDirty(WC_ENGINE_PREVIEW);
228 InvalidateWindowClassesData(WC_BUILD_VEHICLE, 0);
229 SetWindowClassesDirty(WC_VEHICLE_DETAILS);
233 * This function updates the road vehicle acceleration cache after a steepness change.
234 * @param new_value Unused new value of setting.
236 static void RoadVehSlopeSteepnessChanged(int32 new_value)
238 for (RoadVehicle *rv : RoadVehicle::Iterate()) {
239 if (rv->IsFrontEngine()) rv->CargoChanged();
243 static void TownFoundingChanged(int32 new_value)
245 if (_game_mode != GM_EDITOR && _settings_game.economy.found_town == TF_FORBIDDEN) {
246 CloseWindowById(WC_FOUND_TOWN, 0);
247 } else {
248 InvalidateWindowData(WC_FOUND_TOWN, 0);
252 static void ZoomMinMaxChanged(int32 new_value)
254 extern void ConstrainAllViewportsZoom();
255 ConstrainAllViewportsZoom();
256 GfxClearSpriteCache();
257 if (_settings_client.gui.zoom_min > _gui_zoom) {
258 /* Restrict GUI zoom if it is no longer available. */
259 _gui_zoom = _settings_client.gui.zoom_min;
260 UpdateCursorSize();
261 LoadStringWidthTable();
265 static void SpriteZoomMinChanged(int32 new_value)
267 GfxClearSpriteCache();
268 /* Force all sprites to redraw at the new chosen zoom level */
269 MarkWholeScreenDirty();
273 * Update any possible saveload window and delete any newgrf dialogue as
274 * its widget parts might change. Reinit all windows as it allows access to the
275 * newgrf debug button.
276 * @param new_value unused.
278 static void InvalidateNewGRFChangeWindows(int32 new_value)
280 InvalidateWindowClassesData(WC_SAVELOAD);
281 CloseWindowByClass(WC_GAME_OPTIONS);
282 ReInitAllWindows(_gui_zoom_cfg);
285 static void InvalidateCompanyLiveryWindow(int32 new_value)
287 InvalidateWindowClassesData(WC_COMPANY_COLOUR, -1);
288 ResetVehicleColourMap();
291 static void DifficultyNoiseChange(int32 new_value)
293 if (_game_mode == GM_NORMAL) {
294 UpdateAirportsNoise();
295 if (_settings_game.economy.station_noise_level) {
296 InvalidateWindowClassesData(WC_TOWN_VIEW, 0);
301 static void MaxNoAIsChange(int32 new_value)
303 if (GetGameSettings().difficulty.max_no_competitors != 0 &&
304 AI::GetInfoList()->size() == 0 &&
305 (!_networking || _network_server)) {
306 ShowErrorMessage(STR_WARNING_NO_SUITABLE_AI, INVALID_STRING_ID, WL_CRITICAL);
309 InvalidateWindowClassesData(WC_GAME_OPTIONS, 0);
313 * Check whether the road side may be changed.
314 * @param new_value unused
315 * @return true if the road side may be changed.
317 static bool CheckRoadSide(int32 &new_value)
319 extern bool RoadVehiclesAreBuilt();
320 return _game_mode == GM_MENU || !RoadVehiclesAreBuilt();
324 * Conversion callback for _gameopt_settings_game.landscape
325 * It converts (or try) between old values and the new ones,
326 * without losing initial setting of the user
327 * @param value that was read from config file
328 * @return the "hopefully" converted value
330 static size_t ConvertLandscape(const char *value)
332 /* try with the old values */
333 static std::vector<std::string> _old_landscape_values{"normal", "hilly", "desert", "candy"};
334 return OneOfManySettingDesc::ParseSingleValue(value, strlen(value), _old_landscape_values);
337 static bool CheckFreeformEdges(int32 &new_value)
339 if (_game_mode == GM_MENU) return true;
340 if (new_value != 0) {
341 for (Ship *s : Ship::Iterate()) {
342 /* Check if there is a ship on the northern border. */
343 if (TileX(s->tile) == 0 || TileY(s->tile) == 0) {
344 ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_EMPTY, INVALID_STRING_ID, WL_ERROR);
345 return false;
348 for (const BaseStation *st : BaseStation::Iterate()) {
349 /* Check if there is a non-deleted buoy on the northern border. */
350 if (st->IsInUse() && (TileX(st->xy) == 0 || TileY(st->xy) == 0)) {
351 ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_EMPTY, INVALID_STRING_ID, WL_ERROR);
352 return false;
355 } else {
356 for (uint i = 0; i < MapMaxX(); i++) {
357 if (TileHeight(TileXY(i, 1)) != 0) {
358 ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, WL_ERROR);
359 return false;
362 for (uint i = 1; i < MapMaxX(); i++) {
363 if (!IsTileType(TileXY(i, MapMaxY() - 1), MP_WATER) || TileHeight(TileXY(1, MapMaxY())) != 0) {
364 ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, WL_ERROR);
365 return false;
368 for (uint i = 0; i < MapMaxY(); i++) {
369 if (TileHeight(TileXY(1, i)) != 0) {
370 ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, WL_ERROR);
371 return false;
374 for (uint i = 1; i < MapMaxY(); i++) {
375 if (!IsTileType(TileXY(MapMaxX() - 1, i), MP_WATER) || TileHeight(TileXY(MapMaxX(), i)) != 0) {
376 ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, WL_ERROR);
377 return false;
381 return true;
384 static void UpdateFreeformEdges(int32 new_value)
386 if (_game_mode == GM_MENU) return;
388 if (new_value != 0) {
389 for (uint x = 0; x < MapSizeX(); x++) MakeVoid(TileXY(x, 0));
390 for (uint y = 0; y < MapSizeY(); y++) MakeVoid(TileXY(0, y));
391 } else {
392 /* Make tiles at the border water again. */
393 for (uint i = 0; i < MapMaxX(); i++) {
394 SetTileHeight(TileXY(i, 0), 0);
395 SetTileType(TileXY(i, 0), MP_WATER);
397 for (uint i = 0; i < MapMaxY(); i++) {
398 SetTileHeight(TileXY(0, i), 0);
399 SetTileType(TileXY(0, i), MP_WATER);
402 MarkWholeScreenDirty();
406 * Changing the setting "allow multiple NewGRF sets" is not allowed
407 * if there are vehicles.
409 static bool CheckDynamicEngines(int32 &new_value)
411 if (_game_mode == GM_MENU) return true;
413 if (!EngineOverrideManager::ResetToCurrentNewGRFConfig()) {
414 ShowErrorMessage(STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES, INVALID_STRING_ID, WL_ERROR);
415 return false;
418 return true;
421 static bool CheckMaxHeightLevel(int32 &new_value)
423 if (_game_mode == GM_NORMAL) return false;
424 if (_game_mode != GM_EDITOR) return true;
426 /* Check if at least one mountain on the map is higher than the new value.
427 * If yes, disallow the change. */
428 for (TileIndex t = 0; t < MapSize(); t++) {
429 if ((int32)TileHeight(t) > new_value) {
430 ShowErrorMessage(STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN, INVALID_STRING_ID, WL_ERROR);
431 /* Return old, unchanged value */
432 return false;
436 return true;
439 static void StationCatchmentChanged(int32 new_value)
441 Station::RecomputeCatchmentForAll();
442 MarkWholeScreenDirty();
445 static void MaxVehiclesChanged(int32 new_value)
447 InvalidateWindowClassesData(WC_BUILD_TOOLBAR);
448 MarkWholeScreenDirty();
451 static void InvalidateShipPathCache(int32 new_value)
453 for (Ship *s : Ship::Iterate()) {
454 s->path.clear();
459 * Replace a passwords that are a literal asterisk with an empty string.
460 * @param newval The new string value for this password field.
461 * @return Always true.
463 static bool ReplaceAsteriskWithEmptyPassword(std::string &newval)
465 if (newval.compare("*") == 0) newval.clear();
466 return true;
469 /** Update the game info, and send it to the clients when we are running as a server. */
470 static void UpdateClientConfigValues()
472 NetworkServerUpdateGameInfo();
473 if (_network_server) NetworkServerSendConfigUpdate();
476 /* End - Callback Functions */