OpenTTD Source: src/console_cmds.cpp Source File

OpenTTD Source 15.0-RC2

console_cmds.cpp
Go to the documentation of this file.
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
10#include "stdafx.h"
11#include "core/string_consumer.hpp"
12#include "console_internal.h"
13#include "debug.h"
14#include "engine_func.h"
15#include "landscape.h"
16#include "saveload/saveload.h"
17#include "network/core/network_game_info.h"
18#include "network/network.h"
19#include "network/network_func.h"
20#include "network/network_base.h"
21#include "network/network_admin.h"
22#include "network/network_client.h"
23#include "command_func.h"
24#include "settings_func.h"
25#include "fios.h"
26#include "fileio_func.h"
27#include "fontcache.h"
28#include "screenshot.h"
29#include "genworld.h"
30#include "strings_func.h"
31#include "viewport_func.h"
32#include "window_func.h"
33#include "timer/timer.h"
34#include "company_func.h"
35#include "gamelog.h"
36#include "ai/ai.hpp"
37#include "ai/ai_config.hpp"
38#include "newgrf.h"
39#include "newgrf_profiling.h"
40#include "console_func.h"
41#include "engine_base.h"
42#include "road.h"
43#include "rail.h"
44#include "game/game.hpp"
45#include "3rdparty/fmt/chrono.h"
46#include "company_cmd.h"
47#include "misc_cmd.h"
48
49#if defined(WITH_ZLIB)
50#include "network/network_content.h"
51#endif /* WITH_ZLIB */
52
53#include "table/strings.h"
54
55#include "safeguards.h"
56
57/* scriptfile handling */
58 static uint _script_current_depth;
59
60/* Scheduled execution handling. */
61 static std::string _scheduled_monthly_script;
62
64 static const IntervalTimer<TimerGameCalendar> _scheduled_monthly_timer = {{TimerGameCalendar::MONTH, TimerGameCalendar::Priority::NONE}, [](auto) {
65 if (_scheduled_monthly_script.empty()) {
66 return;
67 }
68
69 /* Clear the schedule before rather than after the script to allow the script to itself call
70 * schedule without it getting immediately cleared. */
71 const std::string filename = _scheduled_monthly_script;
72 _scheduled_monthly_script.clear();
73
74 IConsolePrint(CC_DEFAULT, "Executing scheduled script file '{}'...", filename);
75 IConsoleCmdExec(fmt::format("exec {}", filename));
76}};
77
84template <typename T>
85 static std::optional<T> ParseType(std::string_view arg)
86{
87 auto i = ParseInteger(arg);
88 if (i.has_value()) return static_cast<T>(*i);
89 return std::nullopt;
90}
91
93 class ConsoleFileList : public FileList {
94public:
95 ConsoleFileList(AbstractFileType abstract_filetype, bool show_dirs) : FileList(), abstract_filetype(abstract_filetype), show_dirs(show_dirs)
96 {
97 }
98
100 void InvalidateFileList()
101 {
102 this->clear();
103 this->file_list_valid = false;
104 }
105
110 void ValidateFileList(bool force_reload = false)
111 {
112 if (force_reload || !this->file_list_valid) {
113 this->BuildFileList(this->abstract_filetype, SLO_LOAD, this->show_dirs);
114 this->file_list_valid = true;
115 }
116 }
117
118 AbstractFileType abstract_filetype;
119 bool show_dirs;
120 bool file_list_valid = false;
121};
122
123 static ConsoleFileList _console_file_list_savegame{FT_SAVEGAME, true};
124 static ConsoleFileList _console_file_list_scenario{FT_SCENARIO, false};
125 static ConsoleFileList _console_file_list_heightmap{FT_HEIGHTMAP, false};
126
127/****************
128 * command hooks
129 ****************/
130
135 static inline bool NetworkAvailable(bool echo)
136{
137 if (!_network_available) {
138 if (echo) IConsolePrint(CC_ERROR, "You cannot use this command because there is no network available.");
139 return false;
140 }
141 return true;
142}
143
148 static ConsoleHookResult ConHookServerOnly(bool echo)
149{
150 if (!NetworkAvailable(echo)) return CHR_DISALLOW;
151
152 if (!_network_server) {
153 if (echo) IConsolePrint(CC_ERROR, "This command is only available to a network server.");
154 return CHR_DISALLOW;
155 }
156 return CHR_ALLOW;
157}
158
163 static ConsoleHookResult ConHookClientOnly(bool echo)
164{
165 if (!NetworkAvailable(echo)) return CHR_DISALLOW;
166
167 if (_network_server) {
168 if (echo) IConsolePrint(CC_ERROR, "This command is not available to a network server.");
169 return CHR_DISALLOW;
170 }
171 return CHR_ALLOW;
172}
173
178 static ConsoleHookResult ConHookNeedNetwork(bool echo)
179{
180 if (!NetworkAvailable(echo)) return CHR_DISALLOW;
181
182 if (!_networking || (!_network_server && !MyClient::IsConnected())) {
183 if (echo) IConsolePrint(CC_ERROR, "Not connected. This command is only available in multiplayer.");
184 return CHR_DISALLOW;
185 }
186 return CHR_ALLOW;
187}
188
193 static ConsoleHookResult ConHookNeedNonDedicatedNetwork(bool echo)
194{
195 if (!NetworkAvailable(echo)) return CHR_DISALLOW;
196
197 if (_network_dedicated) {
198 if (echo) IConsolePrint(CC_ERROR, "This command is not available to a dedicated network server.");
199 return CHR_DISALLOW;
200 }
201 return CHR_ALLOW;
202}
203
208 static ConsoleHookResult ConHookNoNetwork(bool echo)
209{
210 if (_networking) {
211 if (echo) IConsolePrint(CC_ERROR, "This command is forbidden in multiplayer.");
212 return CHR_DISALLOW;
213 }
214 return CHR_ALLOW;
215}
216
221 static ConsoleHookResult ConHookServerOrNoNetwork(bool echo)
222{
223 if (_networking && !_network_server) {
224 if (echo) IConsolePrint(CC_ERROR, "This command is only available to a network server.");
225 return CHR_DISALLOW;
226 }
227 return CHR_ALLOW;
228}
229
230static ConsoleHookResult ConHookNewGRFDeveloperTool(bool echo)
231{
232 if (_settings_client.gui.newgrf_developer_tools) {
233 if (_game_mode == GM_MENU) {
234 if (echo) IConsolePrint(CC_ERROR, "This command is only available in-game and in the editor.");
235 return CHR_DISALLOW;
236 }
237 return ConHookNoNetwork(echo);
238 }
239 return CHR_HIDE;
240}
241
246 static bool ConResetEngines(std::span<std::string_view> argv)
247{
248 if (argv.empty()) {
249 IConsolePrint(CC_HELP, "Reset status data of all engines. This might solve some issues with 'lost' engines. Usage: 'resetengines'.");
250 return true;
251 }
252
253 StartupEngines();
254 return true;
255}
256
262 static bool ConResetEnginePool(std::span<std::string_view> argv)
263{
264 if (argv.empty()) {
265 IConsolePrint(CC_HELP, "Reset NewGRF allocations of engine slots. This will remove invalid engine definitions, and might make default engines available again.");
266 return true;
267 }
268
269 if (_game_mode == GM_MENU) {
270 IConsolePrint(CC_ERROR, "This command is only available in-game and in the editor.");
271 return true;
272 }
273
274 if (!EngineOverrideManager::ResetToCurrentNewGRFConfig()) {
275 IConsolePrint(CC_ERROR, "This can only be done when there are no vehicles in the game.");
276 return true;
277 }
278
279 return true;
280}
281
282#ifdef _DEBUG
288static bool ConResetTile(std::span<std::string_view> argv)
289{
290 if (argv.empty()) {
291 IConsolePrint(CC_HELP, "Reset a tile to bare land. Usage: 'resettile <tile>'.");
292 IConsolePrint(CC_HELP, "Tile can be either decimal (34161) or hexadecimal (0x4a5B).");
293 return true;
294 }
295
296 if (argv.size() == 2) {
297 auto result = ParseInteger(argv[1], 0);
298 if (result.has_value() && IsValidTile(*result)) {
299 DoClearSquare(TileIndex{*result});
300 return true;
301 }
302 }
303
304 return false;
305}
306#endif /* _DEBUG */
307
313 static bool ConZoomToLevel(std::span<std::string_view> argv)
314{
315 switch (argv.size()) {
316 case 0:
317 IConsolePrint(CC_HELP, "Set the current zoom level of the main viewport.");
318 IConsolePrint(CC_HELP, "Usage: 'zoomto <level>'.");
319
320 if (ZoomLevel::Min < _settings_client.gui.zoom_min) {
321 IConsolePrint(CC_HELP, "The lowest zoom-in level allowed by current client settings is {}.", std::max(ZoomLevel::Min, _settings_client.gui.zoom_min));
322 } else {
323 IConsolePrint(CC_HELP, "The lowest supported zoom-in level is {}.", std::max(ZoomLevel::Min, _settings_client.gui.zoom_min));
324 }
325
326 if (_settings_client.gui.zoom_max < ZoomLevel::Max) {
327 IConsolePrint(CC_HELP, "The highest zoom-out level allowed by current client settings is {}.", std::min(_settings_client.gui.zoom_max, ZoomLevel::Max));
328 } else {
329 IConsolePrint(CC_HELP, "The highest supported zoom-out level is {}.", std::min(_settings_client.gui.zoom_max, ZoomLevel::Max));
330 }
331 return true;
332
333 case 2: {
334 auto level = ParseInteger<std::underlying_type_t<ZoomLevel>>(argv[1]);
335 if (level.has_value()) {
336 auto zoom_lvl = static_cast<ZoomLevel>(*level);
337 if (!IsInsideMM(zoom_lvl, ZoomLevel::Begin, ZoomLevel::End)) {
338 IConsolePrint(CC_ERROR, "Invalid zoom level. Valid range is {} to {}.", ZoomLevel::Min, ZoomLevel::Max);
339 } else if (!IsInsideMM(zoom_lvl, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max + 1)) {
340 IConsolePrint(CC_ERROR, "Current client settings limit zoom levels to range {} to {}.", _settings_client.gui.zoom_min, _settings_client.gui.zoom_max);
341 } else {
342 Window *w = GetMainWindow();
343 Viewport &vp = *w->viewport;
344 while (vp.zoom > zoom_lvl) DoZoomInOutWindow(ZOOM_IN, w);
345 while (vp.zoom < zoom_lvl) DoZoomInOutWindow(ZOOM_OUT, w);
346 }
347 return true;
348 }
349 break;
350 }
351 }
352
353 return false;
354}
355
365 static bool ConScrollToTile(std::span<std::string_view> argv)
366{
367 if (argv.empty()) {
368 IConsolePrint(CC_HELP, "Center the screen on a given tile.");
369 IConsolePrint(CC_HELP, "Usage: 'scrollto [instant] <tile>' or 'scrollto [instant] <x> <y>'.");
370 IConsolePrint(CC_HELP, "Numbers can be either decimal (34161) or hexadecimal (0x4a5B).");
371 IConsolePrint(CC_HELP, "'instant' will immediately move and redraw viewport without smooth scrolling.");
372 return true;
373 }
374 if (argv.size() < 2) return false;
375
376 uint32_t arg_index = 1;
377 bool instant = false;
378 if (argv[arg_index] == "instant") {
379 ++arg_index;
380 instant = true;
381 }
382
383 switch (argv.size() - arg_index) {
384 case 1: {
385 auto result = ParseInteger(argv[arg_index], 0);
386 if (result.has_value()) {
387 if (*result >= Map::Size()) {
388 IConsolePrint(CC_ERROR, "Tile does not exist.");
389 return true;
390 }
391 ScrollMainWindowToTile(TileIndex{*result}, instant);
392 return true;
393 }
394 break;
395 }
396
397 case 2: {
398 auto x = ParseInteger(argv[arg_index], 0);
399 auto y = ParseInteger(argv[arg_index + 1], 0);
400 if (x.has_value() && y.has_value()) {
401 if (*x >= Map::SizeX() || *y >= Map::SizeY()) {
402 IConsolePrint(CC_ERROR, "Tile does not exist.");
403 return true;
404 }
405 ScrollMainWindowToTile(TileXY(*x, *y), instant);
406 return true;
407 }
408 break;
409 }
410 }
411
412 return false;
413}
414
420 static bool ConSave(std::span<std::string_view> argv)
421{
422 if (argv.empty()) {
423 IConsolePrint(CC_HELP, "Save the current game. Usage: 'save <filename>'.");
424 return true;
425 }
426
427 if (argv.size() == 2) {
428 std::string filename = fmt::format("{}.sav", argv[1]);
429 IConsolePrint(CC_DEFAULT, "Saving map...");
430
431 if (SaveOrLoad(filename, SLO_SAVE, DFT_GAME_FILE, SAVE_DIR) != SL_OK) {
432 IConsolePrint(CC_ERROR, "Saving map failed.");
433 } else {
434 IConsolePrint(CC_INFO, "Map successfully saved to '{}'.", filename);
435 }
436 return true;
437 }
438
439 return false;
440}
441
446 static bool ConSaveConfig(std::span<std::string_view> argv)
447{
448 if (argv.empty()) {
449 IConsolePrint(CC_HELP, "Saves the configuration for new games to the configuration file, typically 'openttd.cfg'.");
450 IConsolePrint(CC_HELP, "It does not save the configuration of the current game to the configuration file.");
451 return true;
452 }
453
454 SaveToConfig();
455 IConsolePrint(CC_DEFAULT, "Saved config.");
456 return true;
457}
458
459static bool ConLoad(std::span<std::string_view> argv)
460{
461 if (argv.empty()) {
462 IConsolePrint(CC_HELP, "Load a game by name or index. Usage: 'load <file | number>'.");
463 return true;
464 }
465
466 if (argv.size() != 2) return false;
467
468 std::string_view file = argv[1];
469 _console_file_list_savegame.ValidateFileList();
470 const FiosItem *item = _console_file_list_savegame.FindItem(file);
471 if (item != nullptr) {
472 if (item->type.abstract == FT_SAVEGAME) {
473 _switch_mode = SM_LOAD_GAME;
474 _file_to_saveload.Set(*item);
475 } else {
476 IConsolePrint(CC_ERROR, "'{}' is not a savegame.", file);
477 }
478 } else {
479 IConsolePrint(CC_ERROR, "'{}' cannot be found.", file);
480 }
481
482 return true;
483}
484
485static bool ConLoadScenario(std::span<std::string_view> argv)
486{
487 if (argv.empty()) {
488 IConsolePrint(CC_HELP, "Load a scenario by name or index. Usage: 'load_scenario <file | number>'.");
489 return true;
490 }
491
492 if (argv.size() != 2) return false;
493
494 std::string_view file = argv[1];
495 _console_file_list_scenario.ValidateFileList();
496 const FiosItem *item = _console_file_list_scenario.FindItem(file);
497 if (item != nullptr) {
498 if (item->type.abstract == FT_SCENARIO) {
499 _switch_mode = SM_LOAD_GAME;
500 _file_to_saveload.Set(*item);
501 } else {
502 IConsolePrint(CC_ERROR, "'{}' is not a scenario.", file);
503 }
504 } else {
505 IConsolePrint(CC_ERROR, "'{}' cannot be found.", file);
506 }
507
508 return true;
509}
510
511static bool ConLoadHeightmap(std::span<std::string_view> argv)
512{
513 if (argv.empty()) {
514 IConsolePrint(CC_HELP, "Load a heightmap by name or index. Usage: 'load_heightmap <file | number>'.");
515 return true;
516 }
517
518 if (argv.size() != 2) return false;
519
520 std::string_view file = argv[1];
521 _console_file_list_heightmap.ValidateFileList();
522 const FiosItem *item = _console_file_list_heightmap.FindItem(file);
523 if (item != nullptr) {
524 if (item->type.abstract == FT_HEIGHTMAP) {
525 _switch_mode = SM_START_HEIGHTMAP;
526 _file_to_saveload.Set(*item);
527 } else {
528 IConsolePrint(CC_ERROR, "'{}' is not a heightmap.", file);
529 }
530 } else {
531 IConsolePrint(CC_ERROR, "'{}' cannot be found.", file);
532 }
533
534 return true;
535}
536
537static bool ConRemove(std::span<std::string_view> argv)
538{
539 if (argv.empty()) {
540 IConsolePrint(CC_HELP, "Remove a savegame by name or index. Usage: 'rm <file | number>'.");
541 return true;
542 }
543
544 if (argv.size() != 2) return false;
545
546 std::string_view file = argv[1];
547 _console_file_list_savegame.ValidateFileList();
548 const FiosItem *item = _console_file_list_savegame.FindItem(file);
549 if (item != nullptr) {
550 if (item->type.abstract == FT_SAVEGAME) {
551 if (!FioRemove(item->name)) {
552 IConsolePrint(CC_ERROR, "Failed to delete '{}'.", item->name);
553 }
554 } else {
555 IConsolePrint(CC_ERROR, "'{}' is not a savegame.", file);
556 }
557 } else {
558 IConsolePrint(CC_ERROR, "'{}' could not be found.", file);
559 }
560
561 _console_file_list_savegame.InvalidateFileList();
562 return true;
563}
564
565
566/* List all the files in the current dir via console */
567static bool ConListFiles(std::span<std::string_view> argv)
568{
569 if (argv.empty()) {
570 IConsolePrint(CC_HELP, "List all loadable savegames and directories in the current dir via console. Usage: 'ls | dir'.");
571 return true;
572 }
573
574 _console_file_list_savegame.ValidateFileList(true);
575 for (uint i = 0; i < _console_file_list_savegame.size(); i++) {
576 IConsolePrint(CC_DEFAULT, "{}) {}", i, _console_file_list_savegame[i].title.GetDecodedString());
577 }
578
579 return true;
580}
581
582/* List all the scenarios */
583static bool ConListScenarios(std::span<std::string_view> argv)
584{
585 if (argv.empty()) {
586 IConsolePrint(CC_HELP, "List all loadable scenarios. Usage: 'list_scenarios'.");
587 return true;
588 }
589
590 _console_file_list_scenario.ValidateFileList(true);
591 for (uint i = 0; i < _console_file_list_scenario.size(); i++) {
592 IConsolePrint(CC_DEFAULT, "{}) {}", i, _console_file_list_scenario[i].title.GetDecodedString());
593 }
594
595 return true;
596}
597
598/* List all the heightmaps */
599static bool ConListHeightmaps(std::span<std::string_view> argv)
600{
601 if (argv.empty()) {
602 IConsolePrint(CC_HELP, "List all loadable heightmaps. Usage: 'list_heightmaps'.");
603 return true;
604 }
605
606 _console_file_list_heightmap.ValidateFileList(true);
607 for (uint i = 0; i < _console_file_list_heightmap.size(); i++) {
608 IConsolePrint(CC_DEFAULT, "{}) {}", i, _console_file_list_heightmap[i].title.GetDecodedString());
609 }
610
611 return true;
612}
613
614/* Change the dir via console */
615static bool ConChangeDirectory(std::span<std::string_view> argv)
616{
617 if (argv.empty()) {
618 IConsolePrint(CC_HELP, "Change the dir via console. Usage: 'cd <directory | number>'.");
619 return true;
620 }
621
622 if (argv.size() != 2) return false;
623
624 std::string_view file = argv[1];
625 _console_file_list_savegame.ValidateFileList(true);
626 const FiosItem *item = _console_file_list_savegame.FindItem(file);
627 if (item != nullptr) {
628 switch (item->type.detailed) {
629 case DFT_FIOS_DIR:
630 case DFT_FIOS_DRIVE:
631 case DFT_FIOS_PARENT:
632 FiosBrowseTo(item);
633 break;
634 default: IConsolePrint(CC_ERROR, "{}: Not a directory.", file);
635 }
636 } else {
637 IConsolePrint(CC_ERROR, "{}: No such file or directory.", file);
638 }
639
640 _console_file_list_savegame.InvalidateFileList();
641 return true;
642}
643
644static bool ConPrintWorkingDirectory(std::span<std::string_view> argv)
645{
646 if (argv.empty()) {
647 IConsolePrint(CC_HELP, "Print out the current working directory. Usage: 'pwd'.");
648 return true;
649 }
650
651 /* XXX - Workaround for broken file handling */
652 _console_file_list_savegame.ValidateFileList(true);
653 _console_file_list_savegame.InvalidateFileList();
654
655 IConsolePrint(CC_DEFAULT, FiosGetCurrentPath());
656 return true;
657}
658
659static bool ConClearBuffer(std::span<std::string_view> argv)
660{
661 if (argv.empty()) {
662 IConsolePrint(CC_HELP, "Clear the console buffer. Usage: 'clear'.");
663 return true;
664 }
665
666 IConsoleClearBuffer();
667 SetWindowDirty(WC_CONSOLE, 0);
668 return true;
669}
670
671
672/**********************************
673 * Network Core Console Commands
674 **********************************/
675
676static bool ConKickOrBan(std::string_view arg, bool ban, std::string_view reason)
677{
678 uint n;
679
680 if (arg.find_first_of(".:") == std::string::npos) { // banning with ID
681 auto client_id = ParseType<ClientID>(arg);
682 if (!client_id.has_value()) {
683 IConsolePrint(CC_ERROR, "The given client-id is not a valid number.");
684 return true;
685 }
686
687 /* Don't kill the server, or the client doing the rcon. The latter can't be kicked because
688 * kicking frees closes and subsequently free the connection related instances, which we
689 * would be reading from and writing to after returning. So we would read or write data
690 * from freed memory up till the segfault triggers. */
691 if (*client_id == CLIENT_ID_SERVER || *client_id == _redirect_console_to_client) {
692 IConsolePrint(CC_ERROR, "You can not {} yourself!", ban ? "ban" : "kick");
693 return true;
694 }
695
696 NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(*client_id);
697 if (ci == nullptr) {
698 IConsolePrint(CC_ERROR, "Invalid client-id.");
699 return true;
700 }
701
702 if (!ban) {
703 /* Kick only this client, not all clients with that IP */
704 NetworkServerKickClient(*client_id, reason);
705 return true;
706 }
707
708 /* When banning, kick+ban all clients with that IP */
709 n = NetworkServerKickOrBanIP(*client_id, ban, reason);
710 } else {
711 n = NetworkServerKickOrBanIP(arg, ban, reason);
712 }
713
714 if (n == 0) {
715 IConsolePrint(CC_DEFAULT, ban ? "Client not online, address added to banlist." : "Client not found.");
716 } else {
717 IConsolePrint(CC_DEFAULT, "{}ed {} client(s).", ban ? "Bann" : "Kick", n);
718 }
719
720 return true;
721}
722
723static bool ConKick(std::span<std::string_view> argv)
724{
725 if (argv.empty()) {
726 IConsolePrint(CC_HELP, "Kick a client from a network game. Usage: 'kick <ip | client-id> [<kick-reason>]'.");
727 IConsolePrint(CC_HELP, "For client-id's, see the command 'clients'.");
728 return true;
729 }
730
731 if (argv.size() != 2 && argv.size() != 3) return false;
732
733 /* No reason supplied for kicking */
734 if (argv.size() == 2) return ConKickOrBan(argv[1], false, {});
735
736 /* Reason for kicking supplied */
737 size_t kick_message_length = argv[2].size();
738 if (kick_message_length >= 255) {
739 IConsolePrint(CC_ERROR, "Maximum kick message length is 254 characters. You entered {} characters.", kick_message_length);
740 return false;
741 } else {
742 return ConKickOrBan(argv[1], false, argv[2]);
743 }
744}
745
746static bool ConBan(std::span<std::string_view> argv)
747{
748 if (argv.empty()) {
749 IConsolePrint(CC_HELP, "Ban a client from a network game. Usage: 'ban <ip | client-id> [<ban-reason>]'.");
750 IConsolePrint(CC_HELP, "For client-id's, see the command 'clients'.");
751 IConsolePrint(CC_HELP, "If the client is no longer online, you can still ban their IP.");
752 return true;
753 }
754
755 if (argv.size() != 2 && argv.size() != 3) return false;
756
757 /* No reason supplied for kicking */
758 if (argv.size() == 2) return ConKickOrBan(argv[1], true, {});
759
760 /* Reason for kicking supplied */
761 size_t kick_message_length = argv[2].size();
762 if (kick_message_length >= 255) {
763 IConsolePrint(CC_ERROR, "Maximum kick message length is 254 characters. You entered {} characters.", kick_message_length);
764 return false;
765 } else {
766 return ConKickOrBan(argv[1], true, argv[2]);
767 }
768}
769
770static bool ConUnBan(std::span<std::string_view> argv)
771{
772 if (argv.empty()) {
773 IConsolePrint(CC_HELP, "Unban a client from a network game. Usage: 'unban <ip | banlist-index>'.");
774 IConsolePrint(CC_HELP, "For a list of banned IP's, see the command 'banlist'.");
775 return true;
776 }
777
778 if (argv.size() != 2) return false;
779
780 /* Try by IP. */
781 uint index;
782 for (index = 0; index < _network_ban_list.size(); index++) {
783 if (_network_ban_list[index] == argv[1]) break;
784 }
785
786 /* Try by index. */
787 if (index >= _network_ban_list.size()) {
788 index = ParseInteger(argv[1]).value_or(0) - 1U; // let it wrap
789 }
790
791 if (index < _network_ban_list.size()) {
792 IConsolePrint(CC_DEFAULT, "Unbanned {}.", _network_ban_list[index]);
793 _network_ban_list.erase(_network_ban_list.begin() + index);
794 } else {
795 IConsolePrint(CC_DEFAULT, "Invalid list index or IP not in ban-list.");
796 IConsolePrint(CC_DEFAULT, "For a list of banned IP's, see the command 'banlist'.");
797 }
798
799 return true;
800}
801
802static bool ConBanList(std::span<std::string_view> argv)
803{
804 if (argv.empty()) {
805 IConsolePrint(CC_HELP, "List the IP's of banned clients: Usage 'banlist'.");
806 return true;
807 }
808
809 IConsolePrint(CC_DEFAULT, "Banlist:");
810
811 uint i = 1;
812 for (const auto &entry : _network_ban_list) {
813 IConsolePrint(CC_DEFAULT, " {}) {}", i, entry);
814 i++;
815 }
816
817 return true;
818}
819
820static bool ConPauseGame(std::span<std::string_view> argv)
821{
822 if (argv.empty()) {
823 IConsolePrint(CC_HELP, "Pause a network game. Usage: 'pause'.");
824 return true;
825 }
826
827 if (_game_mode == GM_MENU) {
828 IConsolePrint(CC_ERROR, "This command is only available in-game and in the editor.");
829 return true;
830 }
831
832 if (!_pause_mode.Test(PauseMode::Normal)) {
833 Command<CMD_PAUSE>::Post(PauseMode::Normal, true);
834 if (!_networking) IConsolePrint(CC_DEFAULT, "Game paused.");
835 } else {
836 IConsolePrint(CC_DEFAULT, "Game is already paused.");
837 }
838
839 return true;
840}
841
842static bool ConUnpauseGame(std::span<std::string_view> argv)
843{
844 if (argv.empty()) {
845 IConsolePrint(CC_HELP, "Unpause a network game. Usage: 'unpause'.");
846 return true;
847 }
848
849 if (_game_mode == GM_MENU) {
850 IConsolePrint(CC_ERROR, "This command is only available in-game and in the editor.");
851 return true;
852 }
853
854 if (_pause_mode.Test(PauseMode::Normal)) {
855 Command<CMD_PAUSE>::Post(PauseMode::Normal, false);
856 if (!_networking) IConsolePrint(CC_DEFAULT, "Game unpaused.");
857 } else if (_pause_mode.Test(PauseMode::Error)) {
858 IConsolePrint(CC_DEFAULT, "Game is in error state and cannot be unpaused via console.");
859 } else if (_pause_mode.Any()) {
860 IConsolePrint(CC_DEFAULT, "Game cannot be unpaused manually; disable pause_on_join/min_active_clients.");
861 } else {
862 IConsolePrint(CC_DEFAULT, "Game is already unpaused.");
863 }
864
865 return true;
866}
867
868static bool ConRcon(std::span<std::string_view> argv)
869{
870 if (argv.empty()) {
871 IConsolePrint(CC_HELP, "Remote control the server from another client. Usage: 'rcon <password> <command>'.");
872 IConsolePrint(CC_HELP, "Remember to enclose the command in quotes, otherwise only the first parameter is sent.");
873 IConsolePrint(CC_HELP, "When your client's public key is in the 'authorized keys' for 'rcon', the password is not checked and may be '*'.");
874 return true;
875 }
876
877 if (argv.size() < 3) return false;
878
879 if (_network_server) {
880 IConsoleCmdExec(argv[2]);
881 } else {
882 NetworkClientSendRcon(argv[1], argv[2]);
883 }
884 return true;
885}
886
887static bool ConStatus(std::span<std::string_view> argv)
888{
889 if (argv.empty()) {
890 IConsolePrint(CC_HELP, "List the status of all clients connected to the server. Usage 'status'.");
891 return true;
892 }
893
894 NetworkServerShowStatusToConsole();
895 return true;
896}
897
898static bool ConServerInfo(std::span<std::string_view> argv)
899{
900 if (argv.empty()) {
901 IConsolePrint(CC_HELP, "List current and maximum client/company limits. Usage 'server_info'.");
902 IConsolePrint(CC_HELP, "You can change these values by modifying settings 'network.max_clients' and 'network.max_companies'.");
903 return true;
904 }
905
906 IConsolePrint(CC_DEFAULT, "Invite code: {}", _network_server_invite_code);
907 IConsolePrint(CC_DEFAULT, "Current/maximum clients: {:3d}/{:3d}", _network_game_info.clients_on, _settings_client.network.max_clients);
908 IConsolePrint(CC_DEFAULT, "Current/maximum companies: {:3d}/{:3d}", Company::GetNumItems(), _settings_client.network.max_companies);
909 IConsolePrint(CC_DEFAULT, "Current spectators: {:3d}", NetworkSpectatorCount());
910
911 return true;
912}
913
914static bool ConClientNickChange(std::span<std::string_view> argv)
915{
916 if (argv.size() != 3) {
917 IConsolePrint(CC_HELP, "Change the nickname of a connected client. Usage: 'client_name <client-id> <new-name>'.");
918 IConsolePrint(CC_HELP, "For client-id's, see the command 'clients'.");
919 return true;
920 }
921
922 auto client_id = ParseType<ClientID>(argv[1]);
923 if (!client_id.has_value()) {
924 IConsolePrint(CC_ERROR, "The given client-id is not a valid number.");
925 return true;
926 }
927
928 if (*client_id == CLIENT_ID_SERVER) {
929 IConsolePrint(CC_ERROR, "Please use the command 'name' to change your own name!");
930 return true;
931 }
932
933 if (NetworkClientInfo::GetByClientID(*client_id) == nullptr) {
934 IConsolePrint(CC_ERROR, "Invalid client-id.");
935 return true;
936 }
937
938 std::string client_name{StrTrimView(argv[2], StringConsumer::WHITESPACE_NO_NEWLINE)};
939 if (!NetworkIsValidClientName(client_name)) {
940 IConsolePrint(CC_ERROR, "Cannot give a client an empty name.");
941 return true;
942 }
943
944 if (!NetworkServerChangeClientName(*client_id, client_name)) {
945 IConsolePrint(CC_ERROR, "Cannot give a client a duplicate name.");
946 }
947
948 return true;
949}
950
951static std::optional<CompanyID> ParseCompanyID(std::string_view arg)
952{
953 auto company_id = ParseType<CompanyID>(arg);
954 if (company_id.has_value() && *company_id <= MAX_COMPANIES) return static_cast<CompanyID>(*company_id - 1);
955 return company_id;
956}
957
958static bool ConJoinCompany(std::span<std::string_view> argv)
959{
960 if (argv.size() < 2) {
961 IConsolePrint(CC_HELP, "Request joining another company. Usage: 'join <company-id>'.");
962 IConsolePrint(CC_HELP, "For valid company-id see company list, use 255 for spectator.");
963 return true;
964 }
965
966 auto company_id = ParseCompanyID(argv[1]);
967 if (!company_id.has_value()) {
968 IConsolePrint(CC_ERROR, "The given company-id is not a valid number.");
969 return true;
970 }
971
972 const NetworkClientInfo *info = NetworkClientInfo::GetByClientID(_network_own_client_id);
973 if (info == nullptr) {
974 IConsolePrint(CC_ERROR, "You have not joined the game yet!");
975 return true;
976 }
977
978 /* Check we have a valid company id! */
979 if (!Company::IsValidID(*company_id) && *company_id != COMPANY_SPECTATOR) {
980 IConsolePrint(CC_ERROR, "Company does not exist. Company-id must be between 1 and {}.", MAX_COMPANIES);
981 return true;
982 }
983
984 if (info->client_playas == *company_id) {
985 IConsolePrint(CC_ERROR, "You are already there!");
986 return true;
987 }
988
989 if (*company_id != COMPANY_SPECTATOR && !Company::IsHumanID(*company_id)) {
990 IConsolePrint(CC_ERROR, "Cannot join AI company.");
991 return true;
992 }
993
994 if (!info->CanJoinCompany(*company_id)) {
995 IConsolePrint(CC_ERROR, "You are not allowed to join this company.");
996 return true;
997 }
998
999 /* non-dedicated server may just do the move! */
1000 if (_network_server) {
1001 NetworkServerDoMove(CLIENT_ID_SERVER, *company_id);
1002 } else {
1003 NetworkClientRequestMove(*company_id);
1004 }
1005
1006 return true;
1007}
1008
1009static bool ConMoveClient(std::span<std::string_view> argv)
1010{
1011 if (argv.size() < 3) {
1012 IConsolePrint(CC_HELP, "Move a client to another company. Usage: 'move <client-id> <company-id>'.");
1013 IConsolePrint(CC_HELP, "For valid client-id see 'clients', for valid company-id see 'companies', use 255 for moving to spectators.");
1014 return true;
1015 }
1016
1017 auto client_id = ParseType<ClientID>(argv[1]);
1018 if (!client_id.has_value()) {
1019 IConsolePrint(CC_ERROR, "The given client-id is not a valid number.");
1020 return true;
1021 }
1022 const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(*client_id);
1023
1024 auto company_id = ParseCompanyID(argv[2]);
1025 if (!company_id.has_value()) {
1026 IConsolePrint(CC_ERROR, "The given company-id is not a valid number.");
1027 return true;
1028 }
1029
1030 /* check the client exists */
1031 if (ci == nullptr) {
1032 IConsolePrint(CC_ERROR, "Invalid client-id, check the command 'clients' for valid client-id's.");
1033 return true;
1034 }
1035
1036 if (!Company::IsValidID(*company_id) && *company_id != COMPANY_SPECTATOR) {
1037 IConsolePrint(CC_ERROR, "Company does not exist. Company-id must be between 1 and {}.", MAX_COMPANIES);
1038 return true;
1039 }
1040
1041 if (*company_id != COMPANY_SPECTATOR && !Company::IsHumanID(*company_id)) {
1042 IConsolePrint(CC_ERROR, "You cannot move clients to AI companies.");
1043 return true;
1044 }
1045
1046 if (ci->client_id == CLIENT_ID_SERVER && _network_dedicated) {
1047 IConsolePrint(CC_ERROR, "You cannot move the server!");
1048 return true;
1049 }
1050
1051 if (ci->client_playas == *company_id) {
1052 IConsolePrint(CC_ERROR, "You cannot move someone to where they already are!");
1053 return true;
1054 }
1055
1056 /* we are the server, so force the update */
1057 NetworkServerDoMove(ci->client_id, *company_id);
1058
1059 return true;
1060}
1061
1062static bool ConResetCompany(std::span<std::string_view> argv)
1063{
1064 if (argv.empty()) {
1065 IConsolePrint(CC_HELP, "Remove an idle company from the game. Usage: 'reset_company <company-id>'.");
1066 IConsolePrint(CC_HELP, "For company-id's, see the list of companies from the dropdown menu. Company 1 is 1, etc.");
1067 return true;
1068 }
1069
1070 if (argv.size() != 2) return false;
1071
1072 auto index = ParseCompanyID(argv[1]);
1073 if (!index.has_value()) {
1074 IConsolePrint(CC_ERROR, "The given company-id is not a valid number.");
1075 return true;
1076 }
1077
1078 /* Check valid range */
1079 if (!Company::IsValidID(*index)) {
1080 IConsolePrint(CC_ERROR, "Company does not exist. company-id must be between 1 and {}.", MAX_COMPANIES);
1081 return true;
1082 }
1083
1084 if (!Company::IsHumanID(*index)) {
1085 IConsolePrint(CC_ERROR, "Company is owned by an AI.");
1086 return true;
1087 }
1088
1089 if (NetworkCompanyHasClients(*index)) {
1090 IConsolePrint(CC_ERROR, "Cannot remove company: a client is connected to that company.");
1091 return false;
1092 }
1093 const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER);
1094 assert(ci != nullptr);
1095 if (ci->client_playas == *index) {
1096 IConsolePrint(CC_ERROR, "Cannot remove company: the server is connected to that company.");
1097 return true;
1098 }
1099
1100 /* It is safe to remove this company */
1101 Command<CMD_COMPANY_CTRL>::Post(CCA_DELETE, *index, CRR_MANUAL, INVALID_CLIENT_ID);
1102 IConsolePrint(CC_DEFAULT, "Company deleted.");
1103
1104 return true;
1105}
1106
1107static bool ConNetworkClients(std::span<std::string_view> argv)
1108{
1109 if (argv.empty()) {
1110 IConsolePrint(CC_HELP, "Get a list of connected clients including their ID, name, company-id, and IP. Usage: 'clients'.");
1111 return true;
1112 }
1113
1114 NetworkPrintClients();
1115
1116 return true;
1117}
1118
1119static bool ConNetworkReconnect(std::span<std::string_view> argv)
1120{
1121 if (argv.empty()) {
1122 IConsolePrint(CC_HELP, "Reconnect to server to which you were connected last time. Usage: 'reconnect [<company-id>]'.");
1123 IConsolePrint(CC_HELP, "Company 255 is spectator (default, if not specified), 254 means creating new company.");
1124 IConsolePrint(CC_HELP, "All others are a certain company with Company 1 being #1.");
1125 return true;
1126 }
1127
1128 CompanyID playas = COMPANY_SPECTATOR;
1129 if (argv.size() >= 2) {
1130 auto company_id = ParseCompanyID(argv[1]);
1131 if (!company_id.has_value()) {
1132 IConsolePrint(CC_ERROR, "The given company-id is not a valid number.");
1133 return true;
1134 }
1135 if (*company_id >= MAX_COMPANIES && *company_id != COMPANY_NEW_COMPANY && *company_id != COMPANY_SPECTATOR) return false;
1136 playas = *company_id;
1137 }
1138
1139 if (_settings_client.network.last_joined.empty()) {
1140 IConsolePrint(CC_DEFAULT, "No server for reconnecting.");
1141 return true;
1142 }
1143
1144 /* Don't resolve the address first, just print it directly as it comes from the config file. */
1145 IConsolePrint(CC_DEFAULT, "Reconnecting to {} ...", _settings_client.network.last_joined);
1146
1147 return NetworkClientConnectGame(_settings_client.network.last_joined, playas);
1148}
1149
1150static bool ConNetworkConnect(std::span<std::string_view> argv)
1151{
1152 if (argv.empty()) {
1153 IConsolePrint(CC_HELP, "Connect to a remote OTTD server and join the game. Usage: 'connect <ip>'.");
1154 IConsolePrint(CC_HELP, "IP can contain port and company: 'IP[:Port][#Company]', eg: 'server.ottd.org:443#2'.");
1155 IConsolePrint(CC_HELP, "Company #255 is spectator all others are a certain company with Company 1 being #1.");
1156 return true;
1157 }
1158
1159 if (argv.size() < 2) return false;
1160
1161 return NetworkClientConnectGame(argv[1], COMPANY_NEW_COMPANY);
1162}
1163
1164/*********************************
1165 * script file console commands
1166 *********************************/
1167
1168static bool ConExec(std::span<std::string_view> argv)
1169{
1170 if (argv.empty()) {
1171 IConsolePrint(CC_HELP, "Execute a local script file. Usage: 'exec <script> [0]'.");
1172 IConsolePrint(CC_HELP, "By passing '0' after the script name, no warning about a missing script file will be shown.");
1173 return true;
1174 }
1175
1176 if (argv.size() < 2) return false;
1177
1178 auto script_file = FioFOpenFile(argv[1], "r", BASE_DIR);
1179
1180 if (!script_file.has_value()) {
1181 if (argv.size() == 2 || argv[2] != "0") IConsolePrint(CC_ERROR, "Script file '{}' not found.", argv[1]);
1182 return true;
1183 }
1184
1185 if (_script_current_depth == 11) {
1186 IConsolePrint(CC_ERROR, "Maximum 'exec' depth reached; script A is calling script B is calling script C ... more than 10 times.");
1187 return true;
1188 }
1189
1190 _script_current_depth++;
1191 uint script_depth = _script_current_depth;
1192
1193 char buffer[ICON_CMDLN_SIZE];
1194 while (fgets(buffer, sizeof(buffer), *script_file) != nullptr) {
1195 /* Remove newline characters from the executing script */
1196 std::string_view cmdline{buffer};
1197 auto last_non_newline = cmdline.find_last_not_of("\r\n");
1198 if (last_non_newline != std::string_view::npos) cmdline = cmdline.substr(0, last_non_newline + 1);
1199
1200 IConsoleCmdExec(cmdline);
1201 /* Ensure that we are still on the same depth or that we returned via 'return'. */
1202 assert(_script_current_depth == script_depth || _script_current_depth == script_depth - 1);
1203
1204 /* The 'return' command was executed. */
1205 if (_script_current_depth == script_depth - 1) break;
1206 }
1207
1208 if (ferror(*script_file) != 0) {
1209 IConsolePrint(CC_ERROR, "Encountered error while trying to read from script file '{}'.", argv[1]);
1210 }
1211
1212 if (_script_current_depth == script_depth) _script_current_depth--;
1213 return true;
1214}
1215
1216static bool ConSchedule(std::span<std::string_view> argv)
1217{
1218 if (argv.size() < 3 || std::string_view(argv[1]) != "on-next-calendar-month") {
1219 IConsolePrint(CC_HELP, "Schedule a local script to execute later. Usage: 'schedule on-next-calendar-month <script>'.");
1220 return true;
1221 }
1222
1223 /* Check if the file exists. It might still go away later, but helpful to show an error now. */
1224 if (!FioCheckFileExists(argv[2], BASE_DIR)) {
1225 IConsolePrint(CC_ERROR, "Script file '{}' not found.", argv[2]);
1226 return true;
1227 }
1228
1229 /* We only support a single script scheduled, so we tell the user what's happening if there was already one. */
1230 std::string_view filename = std::string_view(argv[2]);
1231 if (!_scheduled_monthly_script.empty() && filename == _scheduled_monthly_script) {
1232 IConsolePrint(CC_INFO, "Script file '{}' was already scheduled to execute at the start of next calendar month.", filename);
1233 } else if (!_scheduled_monthly_script.empty() && filename != _scheduled_monthly_script) {
1234 IConsolePrint(CC_INFO, "Script file '{}' scheduled to execute at the start of next calendar month, replacing the previously scheduled script file '{}'.", filename, _scheduled_monthly_script);
1235 } else {
1236 IConsolePrint(CC_INFO, "Script file '{}' scheduled to execute at the start of next calendar month.", filename);
1237 }
1238
1239 /* Store the filename to be used by _schedule_timer on the start of next calendar month. */
1240 _scheduled_monthly_script = filename;
1241
1242 return true;
1243}
1244
1245static bool ConReturn(std::span<std::string_view> argv)
1246{
1247 if (argv.empty()) {
1248 IConsolePrint(CC_HELP, "Stop executing a running script. Usage: 'return'.");
1249 return true;
1250 }
1251
1252 _script_current_depth--;
1253 return true;
1254}
1255
1256/*****************************
1257 * default console commands
1258 ******************************/
1259extern bool CloseConsoleLogIfActive();
1260extern std::span<const GRFFile> GetAllGRFFiles();
1261extern void ConPrintFramerate(); // framerate_gui.cpp
1262extern void ShowFramerateWindow();
1263
1264static bool ConScript(std::span<std::string_view> argv)
1265{
1266 extern std::optional<FileHandle> _iconsole_output_file;
1267
1268 if (argv.empty()) {
1269 IConsolePrint(CC_HELP, "Start or stop logging console output to a file. Usage: 'script <filename>'.");
1270 IConsolePrint(CC_HELP, "If filename is omitted, a running log is stopped if it is active.");
1271 return true;
1272 }
1273
1274 if (!CloseConsoleLogIfActive()) {
1275 if (argv.size() < 2) return false;
1276
1277 _iconsole_output_file = FileHandle::Open(argv[1], "ab");
1278 if (!_iconsole_output_file.has_value()) {
1279 IConsolePrint(CC_ERROR, "Could not open console log file '{}'.", argv[1]);
1280 } else {
1281 IConsolePrint(CC_INFO, "Console log output started to '{}'.", argv[1]);
1282 }
1283 }
1284
1285 return true;
1286}
1287
1288static bool ConEcho(std::span<std::string_view> argv)
1289{
1290 if (argv.empty()) {
1291 IConsolePrint(CC_HELP, "Print back the first argument to the console. Usage: 'echo <arg>'.");
1292 return true;
1293 }
1294
1295 if (argv.size() < 2) return false;
1296 IConsolePrint(CC_DEFAULT, "{}", argv[1]);
1297 return true;
1298}
1299
1300static bool ConEchoC(std::span<std::string_view> argv)
1301{
1302 if (argv.empty()) {
1303 IConsolePrint(CC_HELP, "Print back the first argument to the console in a given colour. Usage: 'echoc <colour> <arg2>'.");
1304 return true;
1305 }
1306
1307 if (argv.size() < 3) return false;
1308
1309 auto colour = ParseInteger(argv[1]);
1310 if (!colour.has_value() || !IsInsideMM(*colour, TC_BEGIN, TC_END)) {
1311 IConsolePrint(CC_ERROR, "The colour must be a number between {} and {}.", TC_BEGIN, TC_END - 1);
1312 return true;
1313 }
1314
1315 IConsolePrint(static_cast<TextColour>(*colour), "{}", argv[2]);
1316 return true;
1317}
1318
1319static bool ConNewGame(std::span<std::string_view> argv)
1320{
1321 if (argv.empty()) {
1322 IConsolePrint(CC_HELP, "Start a new game. Usage: 'newgame [seed]'.");
1323 IConsolePrint(CC_HELP, "The server can force a new game using 'newgame'; any client joined will rejoin after the server is done generating the new game.");
1324 return true;
1325 }
1326
1327 uint32_t seed = GENERATE_NEW_SEED;
1328 if (argv.size() >= 2) {
1329 auto param = ParseInteger(argv[1]);
1330 if (!param.has_value()) {
1331 IConsolePrint(CC_ERROR, "The given seed must be a valid number.");
1332 return true;
1333 }
1334 seed = *param;
1335 }
1336
1337 StartNewGameWithoutGUI(seed);
1338 return true;
1339}
1340
1341static bool ConRestart(std::span<std::string_view> argv)
1342{
1343 if (argv.empty() || argv.size() > 2) {
1344 IConsolePrint(CC_HELP, "Restart game. Usage: 'restart [current|newgame]'.");
1345 IConsolePrint(CC_HELP, "Restarts a game, using either the current or newgame (default) settings.");
1346 IConsolePrint(CC_HELP, " * if you started from a new game, and your current/newgame settings haven't changed, the game will be identical to when you started it.");
1347 IConsolePrint(CC_HELP, " * if you started from a savegame / scenario / heightmap, the game might be different, because the current/newgame settings might differ.");
1348 return true;
1349 }
1350
1351 if (argv.size() == 1 || std::string_view(argv[1]) == "newgame") {
1352 StartNewGameWithoutGUI(_settings_game.game_creation.generation_seed);
1353 } else {
1354 _settings_game.game_creation.map_x = Map::LogX();
1355 _settings_game.game_creation.map_y = Map::LogY();
1356 _switch_mode = SM_RESTARTGAME;
1357 }
1358
1359 return true;
1360}
1361
1362static bool ConReload(std::span<std::string_view> argv)
1363{
1364 if (argv.empty()) {
1365 IConsolePrint(CC_HELP, "Reload game. Usage: 'reload'.");
1366 IConsolePrint(CC_HELP, "Reloads a game if loaded via savegame / scenario / heightmap.");
1367 return true;
1368 }
1369
1370 if (_file_to_saveload.ftype.abstract == FT_NONE || _file_to_saveload.ftype.abstract == FT_INVALID) {
1371 IConsolePrint(CC_ERROR, "No game loaded to reload.");
1372 return true;
1373 }
1374
1375 /* Use a switch-mode to prevent copying over newgame settings to active settings. */
1376 _settings_game.game_creation.map_x = Map::LogX();
1377 _settings_game.game_creation.map_y = Map::LogY();
1378 _switch_mode = SM_RELOADGAME;
1379 return true;
1380}
1381
1386 static void PrintLineByLine(const std::string &full_string)
1387{
1388 std::istringstream in(full_string);
1389 std::string line;
1390 while (std::getline(in, line)) {
1391 IConsolePrint(CC_DEFAULT, line);
1392 }
1393}
1394
1395template <typename F, typename ... Args>
1396bool PrintList(F list_function, Args... args)
1397{
1398 std::string output_str;
1399 auto inserter = std::back_inserter(output_str);
1400 list_function(inserter, args...);
1401 PrintLineByLine(output_str);
1402
1403 return true;
1404}
1405
1406static bool ConListAILibs(std::span<std::string_view> argv)
1407{
1408 if (argv.empty()) {
1409 IConsolePrint(CC_HELP, "List installed AI libraries. Usage: 'list_ai_libs'.");
1410 return true;
1411 }
1412
1413 return PrintList(AI::GetConsoleLibraryList);
1414}
1415
1416static bool ConListAI(std::span<std::string_view> argv)
1417{
1418 if (argv.empty()) {
1419 IConsolePrint(CC_HELP, "List installed AIs. Usage: 'list_ai'.");
1420 return true;
1421 }
1422
1423 return PrintList(AI::GetConsoleList, false);
1424}
1425
1426static bool ConListGameLibs(std::span<std::string_view> argv)
1427{
1428 if (argv.empty()) {
1429 IConsolePrint(CC_HELP, "List installed Game Script libraries. Usage: 'list_game_libs'.");
1430 return true;
1431 }
1432
1433 return PrintList(Game::GetConsoleLibraryList);
1434}
1435
1436static bool ConListGame(std::span<std::string_view> argv)
1437{
1438 if (argv.empty()) {
1439 IConsolePrint(CC_HELP, "List installed Game Scripts. Usage: 'list_game'.");
1440 return true;
1441 }
1442
1443 return PrintList(Game::GetConsoleList, false);
1444}
1445
1446static bool ConStartAI(std::span<std::string_view> argv)
1447{
1448 if (argv.empty() || argv.size() > 3) {
1449 IConsolePrint(CC_HELP, "Start a new AI. Usage: 'start_ai [<AI>] [<settings>]'.");
1450 IConsolePrint(CC_HELP, "Start a new AI. If <AI> is given, it starts that specific AI (if found).");
1451 IConsolePrint(CC_HELP, "If <settings> is given, it is parsed and the AI settings are set to that.");
1452 return true;
1453 }
1454
1455 if (_game_mode != GM_NORMAL) {
1456 IConsolePrint(CC_ERROR, "AIs can only be managed in a game.");
1457 return true;
1458 }
1459
1460 if (Company::GetNumItems() == CompanyPool::MAX_SIZE) {
1461 IConsolePrint(CC_ERROR, "Can't start a new AI (no more free slots).");
1462 return true;
1463 }
1464 if (_networking && !_network_server) {
1465 IConsolePrint(CC_ERROR, "Only the server can start a new AI.");
1466 return true;
1467 }
1468 if (_networking && !_settings_game.ai.ai_in_multiplayer) {
1469 IConsolePrint(CC_ERROR, "AIs are not allowed in multiplayer by configuration.");
1470 IConsolePrint(CC_ERROR, "Switch AI -> AI in multiplayer to True.");
1471 return true;
1472 }
1473 if (!AI::CanStartNew()) {
1474 IConsolePrint(CC_ERROR, "Can't start a new AI.");
1475 return true;
1476 }
1477
1478 int n = 0;
1479 /* Find the next free slot */
1480 for (const Company *c : Company::Iterate()) {
1481 if (c->index != n) break;
1482 n++;
1483 }
1484
1485 AIConfig *config = AIConfig::GetConfig((CompanyID)n);
1486 if (argv.size() >= 2) {
1487 config->Change(argv[1], -1, false);
1488
1489 /* If the name is not found, and there is a dot in the name,
1490 * try again with the assumption everything right of the dot is
1491 * the version the user wants to load. */
1492 if (!config->HasScript()) {
1493 StringConsumer consumer{std::string_view{argv[1]}};
1494 auto name = consumer.ReadUntilChar('.', StringConsumer::SKIP_ONE_SEPARATOR);
1495 if (consumer.AnyBytesLeft()) {
1496 auto version = consumer.TryReadIntegerBase<uint32_t>(10);
1497 if (!version.has_value()) {
1498 IConsolePrint(CC_ERROR, "The version is not a valid number.");
1499 return true;
1500 }
1501 config->Change(name, *version, true);
1502 }
1503 }
1504
1505 if (!config->HasScript()) {
1506 IConsolePrint(CC_ERROR, "Failed to load the specified AI.");
1507 return true;
1508 }
1509 if (argv.size() == 3) {
1510 config->StringToSettings(argv[2]);
1511 }
1512 }
1513
1514 /* Start a new AI company */
1515 Command<CMD_COMPANY_CTRL>::Post(CCA_NEW_AI, CompanyID::Invalid(), CRR_NONE, INVALID_CLIENT_ID);
1516
1517 return true;
1518}
1519
1520static bool ConReloadAI(std::span<std::string_view> argv)
1521{
1522 if (argv.size() != 2) {
1523 IConsolePrint(CC_HELP, "Reload an AI. Usage: 'reload_ai <company-id>'.");
1524 IConsolePrint(CC_HELP, "Reload the AI with the given company id. For company-id's, see the list of companies from the dropdown menu. Company 1 is 1, etc.");
1525 return true;
1526 }
1527
1528 if (_game_mode != GM_NORMAL) {
1529 IConsolePrint(CC_ERROR, "AIs can only be managed in a game.");
1530 return true;
1531 }
1532
1533 if (_networking && !_network_server) {
1534 IConsolePrint(CC_ERROR, "Only the server can reload an AI.");
1535 return true;
1536 }
1537
1538 auto company_id = ParseCompanyID(argv[1]);
1539 if (!company_id.has_value()) {
1540 IConsolePrint(CC_ERROR, "The given company-id is not a valid number.");
1541 return true;
1542 }
1543
1544 if (!Company::IsValidID(*company_id)) {
1545 IConsolePrint(CC_ERROR, "Unknown company. Company range is between 1 and {}.", MAX_COMPANIES);
1546 return true;
1547 }
1548
1549 /* In singleplayer mode the player can be in an AI company, after cheating or loading network save with an AI in first slot. */
1550 if (Company::IsHumanID(*company_id) || *company_id == _local_company) {
1551 IConsolePrint(CC_ERROR, "Company is not controlled by an AI.");
1552 return true;
1553 }
1554
1555 /* First kill the company of the AI, then start a new one. This should start the current AI again */
1556 Command<CMD_COMPANY_CTRL>::Post(CCA_DELETE, *company_id, CRR_MANUAL, INVALID_CLIENT_ID);
1557 Command<CMD_COMPANY_CTRL>::Post(CCA_NEW_AI, *company_id, CRR_NONE, INVALID_CLIENT_ID);
1558 IConsolePrint(CC_DEFAULT, "AI reloaded.");
1559
1560 return true;
1561}
1562
1563static bool ConStopAI(std::span<std::string_view> argv)
1564{
1565 if (argv.size() != 2) {
1566 IConsolePrint(CC_HELP, "Stop an AI. Usage: 'stop_ai <company-id>'.");
1567 IConsolePrint(CC_HELP, "Stop the AI with the given company id. For company-id's, see the list of companies from the dropdown menu. Company 1 is 1, etc.");
1568 return true;
1569 }
1570
1571 if (_game_mode != GM_NORMAL) {
1572 IConsolePrint(CC_ERROR, "AIs can only be managed in a game.");
1573 return true;
1574 }
1575
1576 if (_networking && !_network_server) {
1577 IConsolePrint(CC_ERROR, "Only the server can stop an AI.");
1578 return true;
1579 }
1580
1581 auto company_id = ParseCompanyID(argv[1]);
1582 if (!company_id.has_value()) {
1583 IConsolePrint(CC_ERROR, "The given company-id is not a valid number.");
1584 return true;
1585 }
1586
1587 if (!Company::IsValidID(*company_id)) {
1588 IConsolePrint(CC_ERROR, "Unknown company. Company range is between 1 and {}.", MAX_COMPANIES);
1589 return true;
1590 }
1591
1592 /* In singleplayer mode the player can be in an AI company, after cheating or loading network save with an AI in first slot. */
1593 if (Company::IsHumanID(*company_id) || *company_id == _local_company) {
1594 IConsolePrint(CC_ERROR, "Company is not controlled by an AI.");
1595 return true;
1596 }
1597
1598 /* Now kill the company of the AI. */
1599 Command<CMD_COMPANY_CTRL>::Post(CCA_DELETE, *company_id, CRR_MANUAL, INVALID_CLIENT_ID);
1600 IConsolePrint(CC_DEFAULT, "AI stopped, company deleted.");
1601
1602 return true;
1603}
1604
1605static bool ConRescanAI(std::span<std::string_view> argv)
1606{
1607 if (argv.empty()) {
1608 IConsolePrint(CC_HELP, "Rescan the AI dir for scripts. Usage: 'rescan_ai'.");
1609 return true;
1610 }
1611
1612 if (_networking && !_network_server) {
1613 IConsolePrint(CC_ERROR, "Only the server can rescan the AI dir for scripts.");
1614 return true;
1615 }
1616
1617 AI::Rescan();
1618
1619 return true;
1620}
1621
1622static bool ConRescanGame(std::span<std::string_view> argv)
1623{
1624 if (argv.empty()) {
1625 IConsolePrint(CC_HELP, "Rescan the Game Script dir for scripts. Usage: 'rescan_game'.");
1626 return true;
1627 }
1628
1629 if (_networking && !_network_server) {
1630 IConsolePrint(CC_ERROR, "Only the server can rescan the Game Script dir for scripts.");
1631 return true;
1632 }
1633
1634 Game::Rescan();
1635
1636 return true;
1637}
1638
1639static bool ConRescanNewGRF(std::span<std::string_view> argv)
1640{
1641 if (argv.empty()) {
1642 IConsolePrint(CC_HELP, "Rescan the data dir for NewGRFs. Usage: 'rescan_newgrf'.");
1643 return true;
1644 }
1645
1646 if (!RequestNewGRFScan()) {
1647 IConsolePrint(CC_ERROR, "NewGRF scanning is already running. Please wait until completed to run again.");
1648 }
1649
1650 return true;
1651}
1652
1653static bool ConGetSeed(std::span<std::string_view> argv)
1654{
1655 if (argv.empty()) {
1656 IConsolePrint(CC_HELP, "Returns the seed used to create this game. Usage: 'getseed'.");
1657 IConsolePrint(CC_HELP, "The seed can be used to reproduce the exact same map as the game started with.");
1658 return true;
1659 }
1660
1661 IConsolePrint(CC_DEFAULT, "Generation Seed: {}", _settings_game.game_creation.generation_seed);
1662 return true;
1663}
1664
1665static bool ConGetDate(std::span<std::string_view> argv)
1666{
1667 if (argv.empty()) {
1668 IConsolePrint(CC_HELP, "Returns the current date (year-month-day) of the game. Usage: 'getdate'.");
1669 return true;
1670 }
1671
1672 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date);
1673 IConsolePrint(CC_DEFAULT, "Date: {:04d}-{:02d}-{:02d}", ymd.year, ymd.month + 1, ymd.day);
1674 return true;
1675}
1676
1677static bool ConGetSysDate(std::span<std::string_view> argv)
1678{
1679 if (argv.empty()) {
1680 IConsolePrint(CC_HELP, "Returns the current date (year-month-day) of your system. Usage: 'getsysdate'.");
1681 return true;
1682 }
1683
1684 IConsolePrint(CC_DEFAULT, "System Date: {:%Y-%m-%d %H:%M:%S}", fmt::localtime(time(nullptr)));
1685 return true;
1686}
1687
1688static bool ConAlias(std::span<std::string_view> argv)
1689{
1690 IConsoleAlias *alias;
1691
1692 if (argv.empty()) {
1693 IConsolePrint(CC_HELP, "Add a new alias, or redefine the behaviour of an existing alias . Usage: 'alias <name> <command>'.");
1694 return true;
1695 }
1696
1697 if (argv.size() < 3) return false;
1698
1699 alias = IConsole::AliasGet(std::string(argv[1]));
1700 if (alias == nullptr) {
1701 IConsole::AliasRegister(std::string(argv[1]), argv[2]);
1702 } else {
1703 alias->cmdline = argv[2];
1704 }
1705 return true;
1706}
1707
1708static bool ConScreenShot(std::span<std::string_view> argv)
1709{
1710 if (argv.empty()) {
1711 IConsolePrint(CC_HELP, "Create a screenshot of the game. Usage: 'screenshot [viewport | normal | big | giant | heightmap | minimap] [no_con] [size <width> <height>] [<filename>]'.");
1712 IConsolePrint(CC_HELP, " 'viewport' (default) makes a screenshot of the current viewport (including menus, windows).");
1713 IConsolePrint(CC_HELP, " 'normal' makes a screenshot of the visible area.");
1714 IConsolePrint(CC_HELP, " 'big' makes a zoomed-in screenshot of the visible area.");
1715 IConsolePrint(CC_HELP, " 'giant' makes a screenshot of the whole map.");
1716 IConsolePrint(CC_HELP, " 'heightmap' makes a heightmap screenshot of the map that can be loaded in as heightmap.");
1717 IConsolePrint(CC_HELP, " 'minimap' makes a top-viewed minimap screenshot of the whole world which represents one tile by one pixel.");
1718 IConsolePrint(CC_HELP, " 'no_con' hides the console to create the screenshot (only useful in combination with 'viewport').");
1719 IConsolePrint(CC_HELP, " 'size' sets the width and height of the viewport to make a screenshot of (only useful in combination with 'normal' or 'big').");
1720 IConsolePrint(CC_HELP, " A filename ending in # will prevent overwriting existing files and will number files counting upwards.");
1721 return true;
1722 }
1723
1724 if (argv.size() > 7) return false;
1725
1726 ScreenshotType type = SC_VIEWPORT;
1727 uint32_t width = 0;
1728 uint32_t height = 0;
1729 std::string name{};
1730 uint32_t arg_index = 1;
1731
1732 if (argv.size() > arg_index) {
1733 if (argv[arg_index] == "viewport") {
1734 type = SC_VIEWPORT;
1735 arg_index += 1;
1736 } else if (argv[arg_index] == "normal") {
1737 type = SC_DEFAULTZOOM;
1738 arg_index += 1;
1739 } else if (argv[arg_index] == "big") {
1740 type = SC_ZOOMEDIN;
1741 arg_index += 1;
1742 } else if (argv[arg_index] == "giant") {
1743 type = SC_WORLD;
1744 arg_index += 1;
1745 } else if (argv[arg_index] == "heightmap") {
1746 type = SC_HEIGHTMAP;
1747 arg_index += 1;
1748 } else if (argv[arg_index] == "minimap") {
1749 type = SC_MINIMAP;
1750 arg_index += 1;
1751 }
1752 }
1753
1754 if (argv.size() > arg_index && argv[arg_index] == "no_con") {
1755 if (type != SC_VIEWPORT) {
1756 IConsolePrint(CC_ERROR, "'no_con' can only be used in combination with 'viewport'.");
1757 return true;
1758 }
1759 IConsoleClose();
1760 arg_index += 1;
1761 }
1762
1763 if (argv.size() > arg_index + 2 && argv[arg_index] == "size") {
1764 /* size <width> <height> */
1765 if (type != SC_DEFAULTZOOM && type != SC_ZOOMEDIN) {
1766 IConsolePrint(CC_ERROR, "'size' can only be used in combination with 'normal' or 'big'.");
1767 return true;
1768 }
1769 auto t = ParseInteger(argv[arg_index + 1]);
1770 if (!t.has_value()) {
1771 IConsolePrint(CC_ERROR, "Invalid width '{}'", argv[arg_index + 1]);
1772 return true;
1773 }
1774 width = *t;
1775
1776 t = ParseInteger(argv[arg_index + 2]);
1777 if (!t.has_value()) {
1778 IConsolePrint(CC_ERROR, "Invalid height '{}'", argv[arg_index + 2]);
1779 return true;
1780 }
1781 height = *t;
1782 arg_index += 3;
1783 }
1784
1785 if (argv.size() > arg_index) {
1786 /* Last parameter that was not one of the keywords must be the filename. */
1787 name = argv[arg_index];
1788 arg_index += 1;
1789 }
1790
1791 if (argv.size() > arg_index) {
1792 /* We have parameters we did not process; means we misunderstood any of the above. */
1793 return false;
1794 }
1795
1796 MakeScreenshot(type, std::move(name), width, height);
1797 return true;
1798}
1799
1800static bool ConInfoCmd(std::span<std::string_view> argv)
1801{
1802 if (argv.empty()) {
1803 IConsolePrint(CC_HELP, "Print out debugging information about a command. Usage: 'info_cmd <cmd>'.");
1804 return true;
1805 }
1806
1807 if (argv.size() < 2) return false;
1808
1809 const IConsoleCmd *cmd = IConsole::CmdGet(std::string(argv[1]));
1810 if (cmd == nullptr) {
1811 IConsolePrint(CC_ERROR, "The given command was not found.");
1812 return true;
1813 }
1814
1815 IConsolePrint(CC_DEFAULT, "Command name: '{}'", cmd->name);
1816
1817 if (cmd->hook != nullptr) IConsolePrint(CC_DEFAULT, "Command is hooked.");
1818
1819 return true;
1820}
1821
1822static bool ConDebugLevel(std::span<std::string_view> argv)
1823{
1824 if (argv.empty()) {
1825 IConsolePrint(CC_HELP, "Get/set the default debugging level for the game. Usage: 'debug_level [<level>]'.");
1826 IConsolePrint(CC_HELP, "Level can be any combination of names, levels. Eg 'net=5 ms=4'. Remember to enclose it in \"'\"s.");
1827 return true;
1828 }
1829
1830 if (argv.size() > 2) return false;
1831
1832 if (argv.size() == 1) {
1833 IConsolePrint(CC_DEFAULT, "Current debug-level: '{}'", GetDebugString());
1834 } else {
1835 SetDebugString(argv[1], [](std::string_view err) { IConsolePrint(CC_ERROR, "{}", err); });
1836 }
1837
1838 return true;
1839}
1840
1841static bool ConExit(std::span<std::string_view> argv)
1842{
1843 if (argv.empty()) {
1844 IConsolePrint(CC_HELP, "Exit the game. Usage: 'exit'.");
1845 return true;
1846 }
1847
1848 if (_game_mode == GM_NORMAL && _settings_client.gui.autosave_on_exit) DoExitSave();
1849
1850 _exit_game = true;
1851 return true;
1852}
1853
1854static bool ConPart(std::span<std::string_view> argv)
1855{
1856 if (argv.empty()) {
1857 IConsolePrint(CC_HELP, "Leave the currently joined/running game (only ingame). Usage: 'part'.");
1858 return true;
1859 }
1860
1861 if (_game_mode != GM_NORMAL) return false;
1862
1863 if (_network_dedicated) {
1864 IConsolePrint(CC_ERROR, "A dedicated server can not leave the game.");
1865 return false;
1866 }
1867
1868 _switch_mode = SM_MENU;
1869 return true;
1870}
1871
1872static bool ConHelp(std::span<std::string_view> argv)
1873{
1874 if (argv.size() == 2) {
1875 const IConsoleCmd *cmd;
1876 const IConsoleAlias *alias;
1877
1878 cmd = IConsole::CmdGet(std::string(argv[1]));
1879 if (cmd != nullptr) {
1880 cmd->proc({});
1881 return true;
1882 }
1883
1884 alias = IConsole::AliasGet(std::string(argv[1]));
1885 if (alias != nullptr) {
1886 cmd = IConsole::CmdGet(alias->cmdline);
1887 if (cmd != nullptr) {
1888 cmd->proc({});
1889 return true;
1890 }
1891 IConsolePrint(CC_ERROR, "Alias is of special type, please see its execution-line: '{}'.", alias->cmdline);
1892 return true;
1893 }
1894
1895 IConsolePrint(CC_ERROR, "Command not found.");
1896 return true;
1897 }
1898
1899 IConsolePrint(TC_LIGHT_BLUE, " ---- OpenTTD Console Help ---- ");
1900 IConsolePrint(CC_DEFAULT, " - commands: the command to list all commands is 'list_cmds'.");
1901 IConsolePrint(CC_DEFAULT, " call commands with '<command> <arg2> <arg3>...'");
1902 IConsolePrint(CC_DEFAULT, " - to assign strings, or use them as arguments, enclose it within quotes.");
1903 IConsolePrint(CC_DEFAULT, " like this: '<command> \"string argument with spaces\"'.");
1904 IConsolePrint(CC_DEFAULT, " - use 'help <command>' to get specific information.");
1905 IConsolePrint(CC_DEFAULT, " - scroll console output with shift + (up | down | pageup | pagedown).");
1906 IConsolePrint(CC_DEFAULT, " - scroll console input history with the up or down arrows.");
1907 IConsolePrint(CC_DEFAULT, "");
1908 return true;
1909}
1910
1911static bool ConListCommands(std::span<std::string_view> argv)
1912{
1913 if (argv.empty()) {
1914 IConsolePrint(CC_HELP, "List all registered commands. Usage: 'list_cmds [<pre-filter>]'.");
1915 return true;
1916 }
1917
1918 for (auto &it : IConsole::Commands()) {
1919 const IConsoleCmd *cmd = &it.second;
1920 if (argv.size() <= 1|| cmd->name.find(argv[1]) != std::string::npos) {
1921 if (cmd->hook == nullptr || cmd->hook(false) != CHR_HIDE) IConsolePrint(CC_DEFAULT, cmd->name);
1922 }
1923 }
1924
1925 return true;
1926}
1927
1928static bool ConListAliases(std::span<std::string_view> argv)
1929{
1930 if (argv.empty()) {
1931 IConsolePrint(CC_HELP, "List all registered aliases. Usage: 'list_aliases [<pre-filter>]'.");
1932 return true;
1933 }
1934
1935 for (auto &it : IConsole::Aliases()) {
1936 const IConsoleAlias *alias = &it.second;
1937 if (argv.size() <= 1 || alias->name.find(argv[1]) != std::string::npos) {
1938 IConsolePrint(CC_DEFAULT, "{} => {}", alias->name, alias->cmdline);
1939 }
1940 }
1941
1942 return true;
1943}
1944
1945static bool ConCompanies(std::span<std::string_view> argv)
1946{
1947 if (argv.empty()) {
1948 IConsolePrint(CC_HELP, "List the details of all companies in the game. Usage 'companies'.");
1949 return true;
1950 }
1951
1952 for (const Company *c : Company::Iterate()) {
1953 /* Grab the company name */
1954 std::string company_name = GetString(STR_COMPANY_NAME, c->index);
1955
1956 std::string colour = GetString(STR_COLOUR_DARK_BLUE + _company_colours[c->index]);
1957 IConsolePrint(CC_INFO, "#:{}({}) Company Name: '{}' Year Founded: {} Money: {} Loan: {} Value: {} (T:{}, R:{}, P:{}, S:{}) {}",
1958 c->index + 1, colour, company_name,
1959 c->inaugurated_year, (int64_t)c->money, (int64_t)c->current_loan, (int64_t)CalculateCompanyValue(c),
1960 c->group_all[VEH_TRAIN].num_vehicle,
1961 c->group_all[VEH_ROAD].num_vehicle,
1962 c->group_all[VEH_AIRCRAFT].num_vehicle,
1963 c->group_all[VEH_SHIP].num_vehicle,
1964 c->is_ai ? "AI" : "");
1965 }
1966
1967 return true;
1968}
1969
1970static bool ConSay(std::span<std::string_view> argv)
1971{
1972 if (argv.empty()) {
1973 IConsolePrint(CC_HELP, "Chat to your fellow players in a multiplayer game. Usage: 'say \"<msg>\"'.");
1974 return true;
1975 }
1976
1977 if (argv.size() != 2) return false;
1978
1979 if (!_network_server) {
1980 NetworkClientSendChat(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0 /* param does not matter */, argv[1]);
1981 } else {
1982 bool from_admin = (_redirect_console_to_admin < AdminID::Invalid());
1983 NetworkServerSendChat(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0, argv[1], CLIENT_ID_SERVER, from_admin);
1984 }
1985
1986 return true;
1987}
1988
1989static bool ConSayCompany(std::span<std::string_view> argv)
1990{
1991 if (argv.empty()) {
1992 IConsolePrint(CC_HELP, "Chat to a certain company in a multiplayer game. Usage: 'say_company <company-no> \"<msg>\"'.");
1993 IConsolePrint(CC_HELP, "CompanyNo is the company that plays as company <companyno>, 1 through max_companies.");
1994 return true;
1995 }
1996
1997 if (argv.size() != 3) return false;
1998
1999 auto company_id = ParseCompanyID(argv[1]);
2000 if (!company_id.has_value()) {
2001 IConsolePrint(CC_ERROR, "The given company-id is not a valid number.");
2002 return true;
2003 }
2004
2005 if (!Company::IsValidID(*company_id)) {
2006 IConsolePrint(CC_DEFAULT, "Unknown company. Company range is between 1 and {}.", MAX_COMPANIES);
2007 return true;
2008 }
2009
2010 if (!_network_server) {
2011 NetworkClientSendChat(NETWORK_ACTION_CHAT_COMPANY, DESTTYPE_TEAM, company_id->base(), argv[2]);
2012 } else {
2013 bool from_admin = (_redirect_console_to_admin < AdminID::Invalid());
2014 NetworkServerSendChat(NETWORK_ACTION_CHAT_COMPANY, DESTTYPE_TEAM, company_id->base(), argv[2], CLIENT_ID_SERVER, from_admin);
2015 }
2016
2017 return true;
2018}
2019
2020static bool ConSayClient(std::span<std::string_view> argv)
2021{
2022 if (argv.empty()) {
2023 IConsolePrint(CC_HELP, "Chat to a certain client in a multiplayer game. Usage: 'say_client <client-id> \"<msg>\"'.");
2024 IConsolePrint(CC_HELP, "For client-id's, see the command 'clients'.");
2025 return true;
2026 }
2027
2028 if (argv.size() != 3) return false;
2029
2030 auto client_id = ParseType<ClientID>(argv[1]);
2031 if (!client_id.has_value()) {
2032 IConsolePrint(CC_ERROR, "The given client-id is not a valid number.");
2033 return true;
2034 }
2035
2036 if (!_network_server) {
2037 NetworkClientSendChat(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, *client_id, argv[2]);
2038 } else {
2039 bool from_admin = (_redirect_console_to_admin < AdminID::Invalid());
2040 NetworkServerSendChat(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, *client_id, argv[2], CLIENT_ID_SERVER, from_admin);
2041 }
2042
2043 return true;
2044}
2045
2047 static const std::initializer_list<std::pair<std::string_view, NetworkAuthorizedKeys *>> _console_cmd_authorized_keys{
2048 { "admin", &_settings_client.network.admin_authorized_keys },
2049 { "rcon", &_settings_client.network.rcon_authorized_keys },
2050 { "server", &_settings_client.network.server_authorized_keys },
2051};
2052
2053enum ConNetworkAuthorizedKeyAction : uint8_t {
2054 CNAKA_LIST,
2055 CNAKA_ADD,
2056 CNAKA_REMOVE,
2057};
2058
2059static void PerformNetworkAuthorizedKeyAction(std::string_view name, NetworkAuthorizedKeys *authorized_keys, ConNetworkAuthorizedKeyAction action, const std::string &authorized_key, CompanyID company = CompanyID::Invalid())
2060{
2061 switch (action) {
2062 case CNAKA_LIST:
2063 IConsolePrint(CC_WHITE, "The authorized keys for {} are:", name);
2064 for (auto &ak : *authorized_keys) IConsolePrint(CC_INFO, " {}", ak);
2065 return;
2066
2067 case CNAKA_ADD:
2068 if (authorized_keys->Contains(authorized_key)) {
2069 IConsolePrint(CC_WARNING, "Not added {} to {} as it already exists.", authorized_key, name);
2070 return;
2071 }
2072
2073 if (company == CompanyID::Invalid()) {
2074 authorized_keys->Add(authorized_key);
2075 } else {
2076 AutoRestoreBackup backup(_current_company, company);
2077 Command<CMD_COMPANY_ALLOW_LIST_CTRL>::Post(CALCA_ADD, authorized_key);
2078 }
2079 IConsolePrint(CC_INFO, "Added {} to {}.", authorized_key, name);
2080 return;
2081
2082 case CNAKA_REMOVE:
2083 if (!authorized_keys->Contains(authorized_key)) {
2084 IConsolePrint(CC_WARNING, "Not removed {} from {} as it does not exist.", authorized_key, name);
2085 return;
2086 }
2087
2088 if (company == CompanyID::Invalid()) {
2089 authorized_keys->Remove(authorized_key);
2090 } else {
2091 AutoRestoreBackup backup(_current_company, company);
2092 Command<CMD_COMPANY_ALLOW_LIST_CTRL>::Post(CALCA_REMOVE, authorized_key);
2093 }
2094 IConsolePrint(CC_INFO, "Removed {} from {}.", authorized_key, name);
2095 return;
2096 }
2097}
2098
2099static bool ConNetworkAuthorizedKey(std::span<std::string_view> argv)
2100{
2101 if (argv.size() <= 2) {
2102 IConsolePrint(CC_HELP, "List and update authorized keys. Usage: 'authorized_key list [type]|add [type] [key]|remove [type] [key]'.");
2103 IConsolePrint(CC_HELP, " list: list all the authorized keys of the given type.");
2104 IConsolePrint(CC_HELP, " add: add the given key to the authorized keys of the given type.");
2105 IConsolePrint(CC_HELP, " remove: remove the given key from the authorized keys of the given type; use 'all' to remove all authorized keys.");
2106 IConsolePrint(CC_HELP, "Instead of a key, use 'client:<id>' to add/remove the key of that given client.");
2107
2108 std::string buffer;
2109 for (auto [name, _] : _console_cmd_authorized_keys) format_append(buffer, ", {}", name);
2110 IConsolePrint(CC_HELP, "The supported types are: all{} and company:<id>.", buffer);
2111 return true;
2112 }
2113
2114 ConNetworkAuthorizedKeyAction action;
2115 std::string_view action_string = argv[1];
2116 if (StrEqualsIgnoreCase(action_string, "list")) {
2117 action = CNAKA_LIST;
2118 } else if (StrEqualsIgnoreCase(action_string, "add")) {
2119 action = CNAKA_ADD;
2120 } else if (StrEqualsIgnoreCase(action_string, "remove") || StrEqualsIgnoreCase(action_string, "delete")) {
2121 action = CNAKA_REMOVE;
2122 } else {
2123 IConsolePrint(CC_WARNING, "No valid action was given.");
2124 return false;
2125 }
2126
2127 std::string authorized_key;
2128 if (action != CNAKA_LIST) {
2129 if (argv.size() <= 3) {
2130 IConsolePrint(CC_ERROR, "You must enter the key.");
2131 return false;
2132 }
2133
2134 authorized_key = argv[3];
2135 if (StrStartsWithIgnoreCase(authorized_key, "client:")) {
2136 auto value = ParseInteger<uint32_t>(authorized_key.substr(7));
2137 if (value.has_value()) authorized_key = NetworkGetPublicKeyOfClient(static_cast<ClientID>(*value));
2138 if (!value.has_value() || authorized_key.empty()) {
2139 IConsolePrint(CC_ERROR, "You must enter a valid client id; see 'clients'.");
2140 return false;
2141 }
2142 }
2143
2144 if (authorized_key.size() != NETWORK_PUBLIC_KEY_LENGTH - 1) {
2145 IConsolePrint(CC_ERROR, "You must enter a valid authorized key.");
2146 return false;
2147 }
2148 }
2149
2150 std::string_view type = argv[2];
2151 if (StrEqualsIgnoreCase(type, "all")) {
2152 for (auto [name, authorized_keys] : _console_cmd_authorized_keys) PerformNetworkAuthorizedKeyAction(name, authorized_keys, action, authorized_key);
2153 for (Company *c : Company::Iterate()) PerformNetworkAuthorizedKeyAction(fmt::format("company:{}", c->index + 1), &c->allow_list, action, authorized_key, c->index);
2154 return true;
2155 }
2156
2157 if (StrStartsWithIgnoreCase(type, "company:")) {
2158 auto value = ParseInteger<uint32_t>(type.substr(8));
2159 Company *c = value.has_value() ? Company::GetIfValid(*value - 1) : nullptr;
2160 if (c == nullptr) {
2161 IConsolePrint(CC_ERROR, "You must enter a valid company id; see 'companies'.");
2162 return false;
2163 }
2164
2165 PerformNetworkAuthorizedKeyAction(type, &c->allow_list, action, authorized_key, c->index);
2166 return true;
2167 }
2168
2169 for (auto [name, authorized_keys] : _console_cmd_authorized_keys) {
2170 if (!StrEqualsIgnoreCase(type, name)) continue;
2171
2172 PerformNetworkAuthorizedKeyAction(name, authorized_keys, action, authorized_key);
2173 return true;
2174 }
2175
2176 IConsolePrint(CC_WARNING, "No valid type was given.");
2177 return false;
2178}
2179
2180
2181/* Content downloading only is available with ZLIB */
2182#if defined(WITH_ZLIB)
2183
2185 static ContentType StringToContentType(std::string_view str)
2186{
2187 static const std::initializer_list<std::pair<std::string_view, ContentType>> content_types = {
2188 {"base", CONTENT_TYPE_BASE_GRAPHICS},
2189 {"newgrf", CONTENT_TYPE_NEWGRF},
2190 {"ai", CONTENT_TYPE_AI},
2191 {"ailib", CONTENT_TYPE_AI_LIBRARY},
2192 {"scenario", CONTENT_TYPE_SCENARIO},
2193 {"heightmap", CONTENT_TYPE_HEIGHTMAP},
2194 };
2195 for (const auto &ct : content_types) {
2196 if (StrEqualsIgnoreCase(str, ct.first)) return ct.second;
2197 }
2198 return CONTENT_TYPE_END;
2199}
2200
2202 struct ConsoleContentCallback : public ContentCallback {
2203 void OnConnect(bool success) override
2204 {
2205 IConsolePrint(CC_DEFAULT, "Content server connection {}.", success ? "established" : "failed");
2206 }
2207
2208 void OnDisconnect() override
2209 {
2210 IConsolePrint(CC_DEFAULT, "Content server connection closed.");
2211 }
2212
2213 void OnDownloadComplete(ContentID cid) override
2214 {
2215 IConsolePrint(CC_DEFAULT, "Completed download of {}.", cid);
2216 }
2217};
2218
2223 static void OutputContentState(const ContentInfo &ci)
2224{
2225 static const std::string_view types[] = { "Base graphics", "NewGRF", "AI", "AI library", "Scenario", "Heightmap", "Base sound", "Base music", "Game script", "GS library" };
2226 static_assert(lengthof(types) == CONTENT_TYPE_END - CONTENT_TYPE_BEGIN);
2227 static const std::string_view states[] = { "Not selected", "Selected", "Dep Selected", "Installed", "Unknown" };
2228 static const TextColour state_to_colour[] = { CC_COMMAND, CC_INFO, CC_INFO, CC_WHITE, CC_ERROR };
2229
2230 IConsolePrint(state_to_colour[to_underlying(ci.state)], "{}, {}, {}, {}, {:08X}, {}", ci.id, types[ci.type - 1], states[to_underlying(ci.state)], ci.name, ci.unique_id, FormatArrayAsHex(ci.md5sum));
2231}
2232
2233static bool ConContent(std::span<std::string_view> argv)
2234{
2235 [[maybe_unused]] static ContentCallback *const cb = []() {
2236 auto res = new ConsoleContentCallback();
2237 _network_content_client.AddCallback(res);
2238 return res;
2239 }();
2240
2241 if (argv.size() <= 1) {
2242 IConsolePrint(CC_HELP, "Query, select and download content. Usage: 'content update|upgrade|select [id]|unselect [all|id]|state [filter]|download'.");
2243 IConsolePrint(CC_HELP, " update: get a new list of downloadable content; must be run first.");
2244 IConsolePrint(CC_HELP, " upgrade: select all items that are upgrades.");
2245 IConsolePrint(CC_HELP, " select: select a specific item given by its id. If no parameter is given, all selected content will be listed.");
2246 IConsolePrint(CC_HELP, " unselect: unselect a specific item given by its id or 'all' to unselect all.");
2247 IConsolePrint(CC_HELP, " state: show the download/select state of all downloadable content. Optionally give a filter string.");
2248 IConsolePrint(CC_HELP, " download: download all content you've selected.");
2249 return true;
2250 }
2251
2252 if (StrEqualsIgnoreCase(argv[1], "update")) {
2253 _network_content_client.RequestContentList((argv.size() > 2) ? StringToContentType(argv[2]) : CONTENT_TYPE_END);
2254 return true;
2255 }
2256
2257 if (StrEqualsIgnoreCase(argv[1], "upgrade")) {
2258 _network_content_client.SelectUpgrade();
2259 return true;
2260 }
2261
2262 if (StrEqualsIgnoreCase(argv[1], "select")) {
2263 if (argv.size() <= 2) {
2264 /* List selected content */
2265 IConsolePrint(CC_WHITE, "id, type, state, name");
2266 for (const ContentInfo &ci : _network_content_client.Info()) {
2267 if (ci.state != ContentInfo::State::Selected && ci.state != ContentInfo::State::Autoselected) continue;
2268 OutputContentState(ci);
2269 }
2270 } else if (StrEqualsIgnoreCase(argv[2], "all")) {
2271 /* The intention of this function was that you could download
2272 * everything after a filter was applied; but this never really
2273 * took off. Instead, a select few people used this functionality
2274 * to download every available package on BaNaNaS. This is not in
2275 * the spirit of this service. Additionally, these few people were
2276 * good for 70% of the consumed bandwidth of BaNaNaS. */
2277 IConsolePrint(CC_ERROR, "'select all' is no longer supported since 1.11.");
2278 } else if (auto content_id = ParseType<ContentID>(argv[2]); content_id.has_value()) {
2279 _network_content_client.Select(*content_id);
2280 } else {
2281 IConsolePrint(CC_ERROR, "The given content-id is not a number or 'all'");
2282 }
2283 return true;
2284 }
2285
2286 if (StrEqualsIgnoreCase(argv[1], "unselect")) {
2287 if (argv.size() <= 2) {
2288 IConsolePrint(CC_ERROR, "You must enter the id.");
2289 return false;
2290 }
2291 if (StrEqualsIgnoreCase(argv[2], "all")) {
2292 _network_content_client.UnselectAll();
2293 } else if (auto content_id = ParseType<ContentID>(argv[2]); content_id.has_value()) {
2294 _network_content_client.Unselect(*content_id);
2295 } else {
2296 IConsolePrint(CC_ERROR, "The given content-id is not a number or 'all'");
2297 }
2298 return true;
2299 }
2300
2301 if (StrEqualsIgnoreCase(argv[1], "state")) {
2302 IConsolePrint(CC_WHITE, "id, type, state, name");
2303 for (const ContentInfo &ci : _network_content_client.Info()) {
2304 if (argv.size() > 2 && !StrContainsIgnoreCase(ci.name, argv[2])) continue;
2305 OutputContentState(ci);
2306 }
2307 return true;
2308 }
2309
2310 if (StrEqualsIgnoreCase(argv[1], "download")) {
2311 uint files;
2312 uint bytes;
2313 _network_content_client.DownloadSelectedContent(files, bytes);
2314 IConsolePrint(CC_DEFAULT, "Downloading {} file(s) ({} bytes).", files, bytes);
2315 return true;
2316 }
2317
2318 return false;
2319}
2320#endif /* defined(WITH_ZLIB) */
2321
2322static bool ConFont(std::span<std::string_view> argv)
2323{
2324 if (argv.empty()) {
2325 IConsolePrint(CC_HELP, "Manage the fonts configuration.");
2326 IConsolePrint(CC_HELP, "Usage 'font'.");
2327 IConsolePrint(CC_HELP, " Print out the fonts configuration.");
2328 IConsolePrint(CC_HELP, " The \"Currently active\" configuration is the one actually in effect (after interface scaling and replacing unavailable fonts).");
2329 IConsolePrint(CC_HELP, " The \"Requested\" configuration is the one requested via console command or config file.");
2330 IConsolePrint(CC_HELP, "Usage 'font [medium|small|large|mono] [<font name>] [<size>]'.");
2331 IConsolePrint(CC_HELP, " Change the configuration for a font.");
2332 IConsolePrint(CC_HELP, " Omitting an argument will keep the current value.");
2333 IConsolePrint(CC_HELP, " Set <font name> to \"\" for the default font. Note that <size> has no effect if the default font is in use, and fixed defaults are used instead.");
2334 IConsolePrint(CC_HELP, " If the sprite font is enabled in Game Options, it is used instead of the default font.");
2335 IConsolePrint(CC_HELP, " The <size> is automatically multiplied by the current interface scaling.");
2336 return true;
2337 }
2338
2339 FontSize argfs;
2340 for (argfs = FS_BEGIN; argfs < FS_END; argfs++) {
2341 if (argv.size() > 1 && StrEqualsIgnoreCase(argv[1], FontSizeToName(argfs))) break;
2342 }
2343
2344 /* First argument must be a FontSize. */
2345 if (argv.size() > 1 && argfs == FS_END) return false;
2346
2347 if (argv.size() > 2) {
2348 FontCacheSubSetting *setting = GetFontCacheSubSetting(argfs);
2349 std::string font = setting->font;
2350 uint size = setting->size;
2351 uint8_t arg_index = 2;
2352 /* For <name> we want a string. */
2353
2354 if (!ParseInteger(argv[arg_index]).has_value()) {
2355 font = argv[arg_index++];
2356 }
2357
2358 if (argv.size() > arg_index) {
2359 /* For <size> we want a number. */
2360 auto v = ParseInteger(argv[arg_index]);
2361 if (v.has_value()) {
2362 size = *v;
2363 arg_index++;
2364 }
2365 }
2366
2367 SetFont(argfs, font, size);
2368 }
2369
2370 for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
2371 FontCache *fc = FontCache::Get(fs);
2372 FontCacheSubSetting *setting = GetFontCacheSubSetting(fs);
2373 /* Make sure all non sprite fonts are loaded. */
2374 if (!setting->font.empty() && !fc->HasParent()) {
2375 FontCache::LoadFontCaches(fs);
2376 fc = FontCache::Get(fs);
2377 }
2378 IConsolePrint(CC_DEFAULT, "{} font:", FontSizeToName(fs));
2379 IConsolePrint(CC_DEFAULT, "Currently active: \"{}\", size {}", fc->GetFontName(), fc->GetFontSize());
2380 IConsolePrint(CC_DEFAULT, "Requested: \"{}\", size {}", setting->font, setting->size);
2381 }
2382
2383 return true;
2384}
2385
2386static bool ConSetting(std::span<std::string_view> argv)
2387{
2388 if (argv.empty()) {
2389 IConsolePrint(CC_HELP, "Change setting for all clients. Usage: 'setting <name> [<value>]'.");
2390 IConsolePrint(CC_HELP, "Omitting <value> will print out the current value of the setting.");
2391 return true;
2392 }
2393
2394 if (argv.size() == 1 || argv.size() > 3) return false;
2395
2396 if (argv.size() == 2) {
2397 IConsoleGetSetting(argv[1]);
2398 } else {
2399 IConsoleSetSetting(argv[1], argv[2]);
2400 }
2401
2402 return true;
2403}
2404
2405static bool ConSettingNewgame(std::span<std::string_view> argv)
2406{
2407 if (argv.empty()) {
2408 IConsolePrint(CC_HELP, "Change setting for the next game. Usage: 'setting_newgame <name> [<value>]'.");
2409 IConsolePrint(CC_HELP, "Omitting <value> will print out the current value of the setting.");
2410 return true;
2411 }
2412
2413 if (argv.size() == 1 || argv.size() > 3) return false;
2414
2415 if (argv.size() == 2) {
2416 IConsoleGetSetting(argv[1], true);
2417 } else {
2418 IConsoleSetSetting(argv[1], argv[2], true);
2419 }
2420
2421 return true;
2422}
2423
2424static bool ConListSettings(std::span<std::string_view> argv)
2425{
2426 if (argv.empty()) {
2427 IConsolePrint(CC_HELP, "List settings. Usage: 'list_settings [<pre-filter>]'.");
2428 return true;
2429 }
2430
2431 if (argv.size() > 2) return false;
2432
2433 IConsoleListSettings((argv.size() == 2) ? argv[1] : std::string_view{});
2434 return true;
2435}
2436
2437static bool ConGamelogPrint(std::span<std::string_view> argv)
2438{
2439 if (argv.empty()) {
2440 IConsolePrint(CC_HELP, "Print logged fundamental changes to the game since the start. Usage: 'gamelog'.");
2441 return true;
2442 }
2443
2444 _gamelog.PrintConsole();
2445 return true;
2446}
2447
2448static bool ConNewGRFReload(std::span<std::string_view> argv)
2449{
2450 if (argv.empty()) {
2451 IConsolePrint(CC_HELP, "Reloads all active NewGRFs from disk. Equivalent to reapplying NewGRFs via the settings, but without asking for confirmation. This might crash OpenTTD!");
2452 return true;
2453 }
2454
2455 ReloadNewGRFData();
2456 return true;
2457}
2458
2459 static bool ConListDirs(std::span<std::string_view> argv)
2460{
2461 struct SubdirNameMap {
2462 Subdirectory subdir;
2463 std::string_view name;
2464 bool default_only;
2465 };
2466 static const SubdirNameMap subdir_name_map[] = {
2467 /* Game data directories */
2468 { BASESET_DIR, "baseset", false },
2469 { NEWGRF_DIR, "newgrf", false },
2470 { AI_DIR, "ai", false },
2471 { AI_LIBRARY_DIR, "ailib", false },
2472 { GAME_DIR, "gs", false },
2473 { GAME_LIBRARY_DIR, "gslib", false },
2474 { SCENARIO_DIR, "scenario", false },
2475 { HEIGHTMAP_DIR, "heightmap", false },
2476 /* Default save locations for user data */
2477 { SAVE_DIR, "save", true },
2478 { AUTOSAVE_DIR, "autosave", true },
2479 { SCREENSHOT_DIR, "screenshot", true },
2480 { SOCIAL_INTEGRATION_DIR, "social_integration", true },
2481 };
2482
2483 if (argv.size() != 2) {
2484 IConsolePrint(CC_HELP, "List all search paths or default directories for various categories.");
2485 IConsolePrint(CC_HELP, "Usage: list_dirs <category>");
2486 std::string cats{subdir_name_map[0].name};
2487 bool first = true;
2488 for (const SubdirNameMap &sdn : subdir_name_map) {
2489 if (!first) {
2490 cats += ", ";
2491 cats += sdn.name;
2492 }
2493 first = false;
2494 }
2495 IConsolePrint(CC_HELP, "Valid categories: {}", cats);
2496 return true;
2497 }
2498
2499 std::set<std::string> seen_dirs;
2500 for (const SubdirNameMap &sdn : subdir_name_map) {
2501 if (!StrEqualsIgnoreCase(argv[1], sdn.name)) continue;
2502 bool found = false;
2503 for (Searchpath sp : _valid_searchpaths) {
2504 /* Get the directory */
2505 std::string path = FioGetDirectory(sp, sdn.subdir);
2506 /* Check it hasn't already been listed */
2507 if (seen_dirs.find(path) != seen_dirs.end()) continue;
2508 seen_dirs.insert(path);
2509 /* Check if exists and mark found */
2510 bool exists = FileExists(path);
2511 found |= exists;
2512 /* Print */
2513 if (!sdn.default_only || exists) {
2514 IConsolePrint(exists ? CC_DEFAULT : CC_INFO, "{} {}", path, exists ? "[ok]" : "[not found]");
2515 if (sdn.default_only) break;
2516 }
2517 }
2518 if (!found) {
2519 IConsolePrint(CC_ERROR, "No directories exist for category {}", argv[1]);
2520 }
2521 return true;
2522 }
2523
2524 IConsolePrint(CC_ERROR, "Invalid category name: {}", argv[1]);
2525 return false;
2526}
2527
2528static bool ConNewGRFProfile(std::span<std::string_view> argv)
2529{
2530 if (argv.empty()) {
2531 IConsolePrint(CC_HELP, "Collect performance data about NewGRF sprite requests and callbacks. Sub-commands can be abbreviated.");
2532 IConsolePrint(CC_HELP, "Usage: 'newgrf_profile [list]':");
2533 IConsolePrint(CC_HELP, " List all NewGRFs that can be profiled, and their status.");
2534 IConsolePrint(CC_HELP, "Usage: 'newgrf_profile select <grf-num>...':");
2535 IConsolePrint(CC_HELP, " Select one or more GRFs for profiling.");
2536 IConsolePrint(CC_HELP, "Usage: 'newgrf_profile unselect <grf-num>...':");
2537 IConsolePrint(CC_HELP, " Unselect one or more GRFs from profiling. Use the keyword \"all\" instead of a GRF number to unselect all. Removing an active profiler aborts data collection.");
2538 IConsolePrint(CC_HELP, "Usage: 'newgrf_profile start [<num-ticks>]':");
2539 IConsolePrint(CC_HELP, " Begin profiling all selected GRFs. If a number of ticks is provided, profiling stops after that many game ticks. There are 74 ticks in a calendar day.");
2540 IConsolePrint(CC_HELP, "Usage: 'newgrf_profile stop':");
2541 IConsolePrint(CC_HELP, " End profiling and write the collected data to CSV files.");
2542 IConsolePrint(CC_HELP, "Usage: 'newgrf_profile abort':");
2543 IConsolePrint(CC_HELP, " End profiling and discard all collected data.");
2544 return true;
2545 }
2546
2547 std::span<const GRFFile> files = GetAllGRFFiles();
2548
2549 /* "list" sub-command */
2550 if (argv.size() == 1 || StrStartsWithIgnoreCase(argv[1], "lis")) {
2551 IConsolePrint(CC_INFO, "Loaded GRF files:");
2552 int i = 1;
2553 for (const auto &grf : files) {
2554 auto profiler = std::ranges::find(_newgrf_profilers, &grf, &NewGRFProfiler::grffile);
2555 bool selected = profiler != _newgrf_profilers.end();
2556 bool active = selected && profiler->active;
2557 TextColour tc = active ? TC_LIGHT_BLUE : selected ? TC_GREEN : CC_INFO;
2558 std::string_view statustext = active ? " (active)" : selected ? " (selected)" : "";
2559 IConsolePrint(tc, "{}: [{:08X}] {}{}", i, std::byteswap(grf.grfid), grf.filename, statustext);
2560 i++;
2561 }
2562 return true;
2563 }
2564
2565 /* "select" sub-command */
2566 if (StrStartsWithIgnoreCase(argv[1], "sel") && argv.size() >= 3) {
2567 for (size_t argnum = 2; argnum < argv.size(); ++argnum) {
2568 auto grfnum = ParseInteger(argv[argnum]);
2569 if (!grfnum.has_value() || *grfnum < 1 || static_cast<size_t>(*grfnum) > files.size()) {
2570 IConsolePrint(CC_WARNING, "GRF number {} out of range, not added.", *grfnum);
2571 continue;
2572 }
2573 const GRFFile *grf = &files[*grfnum - 1];
2574 if (std::any_of(_newgrf_profilers.begin(), _newgrf_profilers.end(), [&](NewGRFProfiler &pr) { return pr.grffile == grf; })) {
2575 IConsolePrint(CC_WARNING, "GRF number {} [{:08X}] is already selected for profiling.", *grfnum, std::byteswap(grf->grfid));
2576 continue;
2577 }
2578 _newgrf_profilers.emplace_back(grf);
2579 }
2580 return true;
2581 }
2582
2583 /* "unselect" sub-command */
2584 if (StrStartsWithIgnoreCase(argv[1], "uns") && argv.size() >= 3) {
2585 for (size_t argnum = 2; argnum < argv.size(); ++argnum) {
2586 if (StrEqualsIgnoreCase(argv[argnum], "all")) {
2587 _newgrf_profilers.clear();
2588 break;
2589 }
2590 auto grfnum = ParseInteger(argv[argnum]);
2591 if (!grfnum.has_value() || *grfnum < 1 || static_cast<size_t>(*grfnum) > files.size()) {
2592 IConsolePrint(CC_WARNING, "GRF number {} out of range, not removing.", *grfnum);
2593 continue;
2594 }
2595 const GRFFile *grf = &files[*grfnum - 1];
2596 _newgrf_profilers.erase(std::ranges::find(_newgrf_profilers, grf, &NewGRFProfiler::grffile));
2597 }
2598 return true;
2599 }
2600
2601 /* "start" sub-command */
2602 if (StrStartsWithIgnoreCase(argv[1], "sta")) {
2603 std::string grfids;
2604 size_t started = 0;
2605 for (NewGRFProfiler &pr : _newgrf_profilers) {
2606 if (!pr.active) {
2607 pr.Start();
2608 started++;
2609
2610 if (!grfids.empty()) grfids += ", ";
2611 format_append(grfids, "[{:08X}]", std::byteswap(pr.grffile->grfid));
2612 }
2613 }
2614 if (started > 0) {
2615 IConsolePrint(CC_DEBUG, "Started profiling for GRFID{} {}.", (started > 1) ? "s" : "", grfids);
2616
2617 if (argv.size() >= 3) {
2618 auto ticks = StringConsumer{argv[2]}.TryReadIntegerBase<uint64_t>(0);
2619 if (!ticks.has_value()) {
2620 IConsolePrint(CC_ERROR, "No valid amount of ticks was given, profiling will not stop automatically.");
2621 } else {
2622 NewGRFProfiler::StartTimer(*ticks);
2623 IConsolePrint(CC_DEBUG, "Profiling will automatically stop after {} ticks.", *ticks);
2624 }
2625 }
2626 } else if (_newgrf_profilers.empty()) {
2627 IConsolePrint(CC_ERROR, "No GRFs selected for profiling, did not start.");
2628 } else {
2629 IConsolePrint(CC_ERROR, "Did not start profiling for any GRFs, all selected GRFs are already profiling.");
2630 }
2631 return true;
2632 }
2633
2634 /* "stop" sub-command */
2635 if (StrStartsWithIgnoreCase(argv[1], "sto")) {
2636 NewGRFProfiler::FinishAll();
2637 return true;
2638 }
2639
2640 /* "abort" sub-command */
2641 if (StrStartsWithIgnoreCase(argv[1], "abo")) {
2642 for (NewGRFProfiler &pr : _newgrf_profilers) {
2643 pr.Abort();
2644 }
2645 NewGRFProfiler::AbortTimer();
2646 return true;
2647 }
2648
2649 return false;
2650}
2651
2652#ifdef _DEBUG
2653/******************
2654 * debug commands
2655 ******************/
2656
2657static void IConsoleDebugLibRegister()
2658{
2659 IConsole::CmdRegister("resettile", ConResetTile);
2660 IConsole::AliasRegister("dbg_echo", "echo %A; echo %B");
2661 IConsole::AliasRegister("dbg_echo2", "echo %!");
2662}
2663#endif
2664
2665static bool ConFramerate(std::span<std::string_view> argv)
2666{
2667 if (argv.empty()) {
2668 IConsolePrint(CC_HELP, "Show frame rate and game speed information.");
2669 return true;
2670 }
2671
2672 ConPrintFramerate();
2673 return true;
2674}
2675
2676static bool ConFramerateWindow(std::span<std::string_view> argv)
2677{
2678 if (argv.empty()) {
2679 IConsolePrint(CC_HELP, "Open the frame rate window.");
2680 return true;
2681 }
2682
2683 if (_network_dedicated) {
2684 IConsolePrint(CC_ERROR, "Can not open frame rate window on a dedicated server.");
2685 return false;
2686 }
2687
2688 ShowFramerateWindow();
2689 return true;
2690}
2691
2699 static std::string FormatLabel(uint32_t label)
2700{
2701 if (std::isgraph(GB(label, 24, 8)) && std::isgraph(GB(label, 16, 8)) && std::isgraph(GB(label, 8, 8)) && std::isgraph(GB(label, 0, 8))) {
2702 return fmt::format("{:c}{:c}{:c}{:c}", GB(label, 24, 8), GB(label, 16, 8), GB(label, 8, 8), GB(label, 0, 8));
2703 }
2704
2705 return fmt::format("{:08X}", label);
2706}
2707
2708static void ConDumpRoadTypes()
2709{
2710 IConsolePrint(CC_DEFAULT, " Flags:");
2711 IConsolePrint(CC_DEFAULT, " c = catenary");
2712 IConsolePrint(CC_DEFAULT, " l = no level crossings");
2713 IConsolePrint(CC_DEFAULT, " X = no houses");
2714 IConsolePrint(CC_DEFAULT, " h = hidden");
2715 IConsolePrint(CC_DEFAULT, " T = buildable by towns");
2716
2717 std::map<uint32_t, const GRFFile *> grfs;
2718 for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) {
2719 const RoadTypeInfo *rti = GetRoadTypeInfo(rt);
2720 if (rti->label == 0) continue;
2721 uint32_t grfid = 0;
2722 const GRFFile *grf = rti->grffile[ROTSG_GROUND];
2723 if (grf != nullptr) {
2724 grfid = grf->grfid;
2725 grfs.emplace(grfid, grf);
2726 }
2727 IConsolePrint(CC_DEFAULT, " {:02d} {} {}, Flags: {}{}{}{}{}, GRF: {:08X}, {}",
2728 (uint)rt,
2729 RoadTypeIsTram(rt) ? "Tram" : "Road",
2730 FormatLabel(rti->label),
2731 rti->flags.Test(RoadTypeFlag::Catenary) ? 'c' : '-',
2732 rti->flags.Test(RoadTypeFlag::NoLevelCrossing) ? 'l' : '-',
2733 rti->flags.Test(RoadTypeFlag::NoHouses) ? 'X' : '-',
2734 rti->flags.Test(RoadTypeFlag::Hidden) ? 'h' : '-',
2735 rti->flags.Test(RoadTypeFlag::TownBuild) ? 'T' : '-',
2736 std::byteswap(grfid),
2737 GetStringPtr(rti->strings.name)
2738 );
2739 }
2740 for (const auto &grf : grfs) {
2741 IConsolePrint(CC_DEFAULT, " GRF: {:08X} = {}", std::byteswap(grf.first), grf.second->filename);
2742 }
2743}
2744
2745static void ConDumpRailTypes()
2746{
2747 IConsolePrint(CC_DEFAULT, " Flags:");
2748 IConsolePrint(CC_DEFAULT, " c = catenary");
2749 IConsolePrint(CC_DEFAULT, " l = no level crossings");
2750 IConsolePrint(CC_DEFAULT, " h = hidden");
2751 IConsolePrint(CC_DEFAULT, " s = no sprite combine");
2752 IConsolePrint(CC_DEFAULT, " a = always allow 90 degree turns");
2753 IConsolePrint(CC_DEFAULT, " d = always disallow 90 degree turns");
2754
2755 std::map<uint32_t, const GRFFile *> grfs;
2756 for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) {
2757 const RailTypeInfo *rti = GetRailTypeInfo(rt);
2758 if (rti->label == 0) continue;
2759 uint32_t grfid = 0;
2760 const GRFFile *grf = rti->grffile[RTSG_GROUND];
2761 if (grf != nullptr) {
2762 grfid = grf->grfid;
2763 grfs.emplace(grfid, grf);
2764 }
2765 IConsolePrint(CC_DEFAULT, " {:02d} {}, Flags: {}{}{}{}{}{}, GRF: {:08X}, {}",
2766 (uint)rt,
2767 FormatLabel(rti->label),
2768 rti->flags.Test(RailTypeFlag::Catenary) ? 'c' : '-',
2769 rti->flags.Test(RailTypeFlag::NoLevelCrossing) ? 'l' : '-',
2770 rti->flags.Test(RailTypeFlag::Hidden) ? 'h' : '-',
2771 rti->flags.Test(RailTypeFlag::NoSpriteCombine) ? 's' : '-',
2772 rti->flags.Test(RailTypeFlag::Allow90Deg) ? 'a' : '-',
2773 rti->flags.Test(RailTypeFlag::Disallow90Deg) ? 'd' : '-',
2774 std::byteswap(grfid),
2775 GetStringPtr(rti->strings.name)
2776 );
2777 }
2778 for (const auto &grf : grfs) {
2779 IConsolePrint(CC_DEFAULT, " GRF: {:08X} = {}", std::byteswap(grf.first), grf.second->filename);
2780 }
2781}
2782
2783static void ConDumpCargoTypes()
2784{
2785 IConsolePrint(CC_DEFAULT, " Cargo classes:");
2786 IConsolePrint(CC_DEFAULT, " p = passenger");
2787 IConsolePrint(CC_DEFAULT, " m = mail");
2788 IConsolePrint(CC_DEFAULT, " x = express");
2789 IConsolePrint(CC_DEFAULT, " a = armoured");
2790 IConsolePrint(CC_DEFAULT, " b = bulk");
2791 IConsolePrint(CC_DEFAULT, " g = piece goods");
2792 IConsolePrint(CC_DEFAULT, " l = liquid");
2793 IConsolePrint(CC_DEFAULT, " r = refrigerated");
2794 IConsolePrint(CC_DEFAULT, " h = hazardous");
2795 IConsolePrint(CC_DEFAULT, " c = covered/sheltered");
2796 IConsolePrint(CC_DEFAULT, " o = oversized");
2797 IConsolePrint(CC_DEFAULT, " d = powderized");
2798 IConsolePrint(CC_DEFAULT, " n = not pourable");
2799 IConsolePrint(CC_DEFAULT, " e = potable");
2800 IConsolePrint(CC_DEFAULT, " i = non-potable");
2801 IConsolePrint(CC_DEFAULT, " S = special");
2802
2803 std::map<uint32_t, const GRFFile *> grfs;
2804 for (const CargoSpec *spec : CargoSpec::Iterate()) {
2805 uint32_t grfid = 0;
2806 const GRFFile *grf = spec->grffile;
2807 if (grf != nullptr) {
2808 grfid = grf->grfid;
2809 grfs.emplace(grfid, grf);
2810 }
2811 IConsolePrint(CC_DEFAULT, " {:02d} Bit: {:2d}, Label: {}, Callback mask: 0x{:02X}, Cargo class: {}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}, GRF: {:08X}, {}",
2812 spec->Index(),
2813 spec->bitnum,
2814 FormatLabel(spec->label.base()),
2815 spec->callback_mask.base(),
2816 spec->classes.Test(CargoClass::Passengers) ? 'p' : '-',
2817 spec->classes.Test(CargoClass::Mail) ? 'm' : '-',
2818 spec->classes.Test(CargoClass::Express) ? 'x' : '-',
2819 spec->classes.Test(CargoClass::Armoured) ? 'a' : '-',
2820 spec->classes.Test(CargoClass::Bulk) ? 'b' : '-',
2821 spec->classes.Test(CargoClass::PieceGoods) ? 'g' : '-',
2822 spec->classes.Test(CargoClass::Liquid) ? 'l' : '-',
2823 spec->classes.Test(CargoClass::Refrigerated) ? 'r' : '-',
2824 spec->classes.Test(CargoClass::Hazardous) ? 'h' : '-',
2825 spec->classes.Test(CargoClass::Covered) ? 'c' : '-',
2826 spec->classes.Test(CargoClass::Oversized) ? 'o' : '-',
2827 spec->classes.Test(CargoClass::Powderized) ? 'd' : '-',
2828 spec->classes.Test(CargoClass::NotPourable) ? 'n' : '-',
2829 spec->classes.Test(CargoClass::Potable) ? 'e' : '-',
2830 spec->classes.Test(CargoClass::NonPotable) ? 'i' : '-',
2831 spec->classes.Test(CargoClass::Special) ? 'S' : '-',
2832 std::byteswap(grfid),
2833 GetStringPtr(spec->name)
2834 );
2835 }
2836 for (const auto &grf : grfs) {
2837 IConsolePrint(CC_DEFAULT, " GRF: {:08X} = {}", std::byteswap(grf.first), grf.second->filename);
2838 }
2839}
2840
2841static bool ConDumpInfo(std::span<std::string_view> argv)
2842{
2843 if (argv.size() != 2) {
2844 IConsolePrint(CC_HELP, "Dump debugging information.");
2845 IConsolePrint(CC_HELP, "Usage: 'dump_info roadtypes|railtypes|cargotypes'.");
2846 IConsolePrint(CC_HELP, " Show information about road/tram types, rail types or cargo types.");
2847 return true;
2848 }
2849
2850 if (StrEqualsIgnoreCase(argv[1], "roadtypes")) {
2851 ConDumpRoadTypes();
2852 return true;
2853 }
2854
2855 if (StrEqualsIgnoreCase(argv[1], "railtypes")) {
2856 ConDumpRailTypes();
2857 return true;
2858 }
2859
2860 if (StrEqualsIgnoreCase(argv[1], "cargotypes")) {
2861 ConDumpCargoTypes();
2862 return true;
2863 }
2864
2865 return false;
2866}
2867
2868/*******************************
2869 * console command registration
2870 *******************************/
2871
2872void IConsoleStdLibRegister()
2873{
2874 IConsole::CmdRegister("debug_level", ConDebugLevel);
2875 IConsole::CmdRegister("echo", ConEcho);
2876 IConsole::CmdRegister("echoc", ConEchoC);
2877 IConsole::CmdRegister("exec", ConExec);
2878 IConsole::CmdRegister("schedule", ConSchedule);
2879 IConsole::CmdRegister("exit", ConExit);
2880 IConsole::CmdRegister("part", ConPart);
2881 IConsole::CmdRegister("help", ConHelp);
2882 IConsole::CmdRegister("info_cmd", ConInfoCmd);
2883 IConsole::CmdRegister("list_cmds", ConListCommands);
2884 IConsole::CmdRegister("list_aliases", ConListAliases);
2885 IConsole::CmdRegister("newgame", ConNewGame);
2886 IConsole::CmdRegister("restart", ConRestart);
2887 IConsole::CmdRegister("reload", ConReload);
2888 IConsole::CmdRegister("getseed", ConGetSeed);
2889 IConsole::CmdRegister("getdate", ConGetDate);
2890 IConsole::CmdRegister("getsysdate", ConGetSysDate);
2891 IConsole::CmdRegister("quit", ConExit);
2892 IConsole::CmdRegister("resetengines", ConResetEngines, ConHookNoNetwork);
2893 IConsole::CmdRegister("reset_enginepool", ConResetEnginePool, ConHookNoNetwork);
2894 IConsole::CmdRegister("return", ConReturn);
2895 IConsole::CmdRegister("screenshot", ConScreenShot);
2896 IConsole::CmdRegister("script", ConScript);
2897 IConsole::CmdRegister("zoomto", ConZoomToLevel);
2898 IConsole::CmdRegister("scrollto", ConScrollToTile);
2899 IConsole::CmdRegister("alias", ConAlias);
2900 IConsole::CmdRegister("load", ConLoad);
2901 IConsole::CmdRegister("load_save", ConLoad);
2902 IConsole::CmdRegister("load_scenario", ConLoadScenario);
2903 IConsole::CmdRegister("load_heightmap", ConLoadHeightmap);
2904 IConsole::CmdRegister("rm", ConRemove);
2905 IConsole::CmdRegister("save", ConSave);
2906 IConsole::CmdRegister("saveconfig", ConSaveConfig);
2907 IConsole::CmdRegister("ls", ConListFiles);
2908 IConsole::CmdRegister("list_saves", ConListFiles);
2909 IConsole::CmdRegister("list_scenarios", ConListScenarios);
2910 IConsole::CmdRegister("list_heightmaps", ConListHeightmaps);
2911 IConsole::CmdRegister("cd", ConChangeDirectory);
2912 IConsole::CmdRegister("pwd", ConPrintWorkingDirectory);
2913 IConsole::CmdRegister("clear", ConClearBuffer);
2914 IConsole::CmdRegister("font", ConFont);
2915 IConsole::CmdRegister("setting", ConSetting);
2916 IConsole::CmdRegister("setting_newgame", ConSettingNewgame);
2917 IConsole::CmdRegister("list_settings", ConListSettings);
2918 IConsole::CmdRegister("gamelog", ConGamelogPrint);
2919 IConsole::CmdRegister("rescan_newgrf", ConRescanNewGRF);
2920 IConsole::CmdRegister("list_dirs", ConListDirs);
2921
2922 IConsole::AliasRegister("dir", "ls");
2923 IConsole::AliasRegister("del", "rm %+");
2924 IConsole::AliasRegister("newmap", "newgame");
2925 IConsole::AliasRegister("patch", "setting %+");
2926 IConsole::AliasRegister("set", "setting %+");
2927 IConsole::AliasRegister("set_newgame", "setting_newgame %+");
2928 IConsole::AliasRegister("list_patches", "list_settings %+");
2929 IConsole::AliasRegister("developer", "setting developer %+");
2930
2931 IConsole::CmdRegister("list_ai_libs", ConListAILibs);
2932 IConsole::CmdRegister("list_ai", ConListAI);
2933 IConsole::CmdRegister("reload_ai", ConReloadAI);
2934 IConsole::CmdRegister("rescan_ai", ConRescanAI);
2935 IConsole::CmdRegister("start_ai", ConStartAI);
2936 IConsole::CmdRegister("stop_ai", ConStopAI);
2937
2938 IConsole::CmdRegister("list_game", ConListGame);
2939 IConsole::CmdRegister("list_game_libs", ConListGameLibs);
2940 IConsole::CmdRegister("rescan_game", ConRescanGame);
2941
2942 IConsole::CmdRegister("companies", ConCompanies);
2943 IConsole::AliasRegister("players", "companies");
2944
2945 /* networking functions */
2946
2947/* Content downloading is only available with ZLIB */
2948#if defined(WITH_ZLIB)
2949 IConsole::CmdRegister("content", ConContent);
2950#endif /* defined(WITH_ZLIB) */
2951
2952 /*** Networking commands ***/
2953 IConsole::CmdRegister("say", ConSay, ConHookNeedNetwork);
2954 IConsole::CmdRegister("say_company", ConSayCompany, ConHookNeedNetwork);
2955 IConsole::AliasRegister("say_player", "say_company %+");
2956 IConsole::CmdRegister("say_client", ConSayClient, ConHookNeedNetwork);
2957
2958 IConsole::CmdRegister("connect", ConNetworkConnect, ConHookClientOnly);
2959 IConsole::CmdRegister("clients", ConNetworkClients, ConHookNeedNetwork);
2960 IConsole::CmdRegister("status", ConStatus, ConHookServerOnly);
2961 IConsole::CmdRegister("server_info", ConServerInfo, ConHookServerOnly);
2962 IConsole::AliasRegister("info", "server_info");
2963 IConsole::CmdRegister("reconnect", ConNetworkReconnect, ConHookClientOnly);
2964 IConsole::CmdRegister("rcon", ConRcon, ConHookNeedNetwork);
2965
2966 IConsole::CmdRegister("join", ConJoinCompany, ConHookNeedNonDedicatedNetwork);
2967 IConsole::AliasRegister("spectate", "join 255");
2968 IConsole::CmdRegister("move", ConMoveClient, ConHookServerOnly);
2969 IConsole::CmdRegister("reset_company", ConResetCompany, ConHookServerOnly);
2970 IConsole::AliasRegister("clean_company", "reset_company %A");
2971 IConsole::CmdRegister("client_name", ConClientNickChange, ConHookServerOnly);
2972 IConsole::CmdRegister("kick", ConKick, ConHookServerOnly);
2973 IConsole::CmdRegister("ban", ConBan, ConHookServerOnly);
2974 IConsole::CmdRegister("unban", ConUnBan, ConHookServerOnly);
2975 IConsole::CmdRegister("banlist", ConBanList, ConHookServerOnly);
2976
2977 IConsole::CmdRegister("pause", ConPauseGame, ConHookServerOrNoNetwork);
2978 IConsole::CmdRegister("unpause", ConUnpauseGame, ConHookServerOrNoNetwork);
2979
2980 IConsole::CmdRegister("authorized_key", ConNetworkAuthorizedKey, ConHookServerOnly);
2981 IConsole::AliasRegister("ak", "authorized_key %+");
2982
2983 IConsole::AliasRegister("net_frame_freq", "setting frame_freq %+");
2984 IConsole::AliasRegister("net_sync_freq", "setting sync_freq %+");
2985 IConsole::AliasRegister("server_pw", "setting server_password %+");
2986 IConsole::AliasRegister("server_password", "setting server_password %+");
2987 IConsole::AliasRegister("rcon_pw", "setting rcon_password %+");
2988 IConsole::AliasRegister("rcon_password", "setting rcon_password %+");
2989 IConsole::AliasRegister("name", "setting client_name %+");
2990 IConsole::AliasRegister("server_name", "setting server_name %+");
2991 IConsole::AliasRegister("server_port", "setting server_port %+");
2992 IConsole::AliasRegister("max_clients", "setting max_clients %+");
2993 IConsole::AliasRegister("max_companies", "setting max_companies %+");
2994 IConsole::AliasRegister("max_join_time", "setting max_join_time %+");
2995 IConsole::AliasRegister("pause_on_join", "setting pause_on_join %+");
2996 IConsole::AliasRegister("autoclean_companies", "setting autoclean_companies %+");
2997 IConsole::AliasRegister("autoclean_protected", "setting autoclean_protected %+");
2998 IConsole::AliasRegister("restart_game_year", "setting restart_game_year %+");
2999 IConsole::AliasRegister("min_players", "setting min_active_clients %+");
3000 IConsole::AliasRegister("reload_cfg", "setting reload_cfg %+");
3001
3002 /* debugging stuff */
3003#ifdef _DEBUG
3004 IConsoleDebugLibRegister();
3005#endif
3006 IConsole::CmdRegister("fps", ConFramerate);
3007 IConsole::CmdRegister("fps_wnd", ConFramerateWindow);
3008
3009 /* NewGRF development stuff */
3010 IConsole::CmdRegister("reload_newgrfs", ConNewGRFReload, ConHookNewGRFDeveloperTool);
3011 IConsole::CmdRegister("newgrf_profile", ConNewGRFProfile, ConHookNewGRFDeveloperTool);
3012
3013 IConsole::CmdRegister("dump_info", ConDumpInfo);
3014}
ai.hpp
Base functions for all AIs.
ai_config.hpp
AIConfig stores the configuration settings of every AI.
GB
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
Definition bitmath_func.hpp:32
std::byteswap
constexpr enable_if_t< is_integral_v< T >, T > byteswap(T x) noexcept
Custom implementation of std::byteswap; remove once we build with C++23.
Definition bitmath_func.hpp:330
CargoClass
CargoClass
Cargo classes.
Definition cargotype.h:49
CargoClass::NotPourable
@ NotPourable
Not Pourable (open wagon, but not hopper wagon)
CargoClass::Powderized
@ Powderized
Powderized, moist protected (powder/silo wagon)
CargoClass::Hazardous
@ Hazardous
Hazardous cargo (Nuclear Fuel, Explosives, etc.)
CargoClass::NonPotable
@ NonPotable
Non-potable / non-food / dirty.
CargoClass::Bulk
@ Bulk
Bulk cargo (Coal, Grain etc., Ores, Fruit)
CargoClass::Mail
@ Mail
Mail.
CargoClass::Liquid
@ Liquid
Liquids (Oil, Water, Rubber)
CargoClass::Passengers
@ Passengers
Passengers.
CargoClass::Potable
@ Potable
Potable / food / clean.
CargoClass::Oversized
@ Oversized
Oversized (stake/flatbed wagon)
CargoClass::Armoured
@ Armoured
Armoured cargo (Valuables, Gold, Diamonds)
CargoClass::Refrigerated
@ Refrigerated
Refrigerated cargo (Food, Fruit)
CargoClass::Express
@ Express
Express cargo (Goods, Food, Candy, but also possible for passengers)
CargoClass::Special
@ Special
Special bit used for livery refit tricks instead of normal cargoes.
CargoClass::PieceGoods
@ PieceGoods
Piece goods (Livestock, Wood, Steel, Paper)
CargoClass::Covered
@ Covered
Covered/Sheltered Freight (Transportation in Box Vans, Silo Wagons, etc.)
AIConfig
Definition ai_config.hpp:16
AIConfig::GetConfig
static AIConfig * GetConfig(CompanyID company, ScriptSettingSource source=SSS_DEFAULT)
Get the config of a company.
Definition ai_config.cpp:20
AI::GetConsoleLibraryList
static void GetConsoleLibraryList(std::back_insert_iterator< std::string > &output_iterator)
Wrapper function for AIScanner::GetAIConsoleLibraryList.
Definition ai_core.cpp:293
AI::GetConsoleList
static void GetConsoleList(std::back_insert_iterator< std::string > &output_iterator, bool newest_only)
Wrapper function for AIScanner::GetAIConsoleList.
Definition ai_core.cpp:288
AI::CanStartNew
static bool CanStartNew()
Is it possible to start a new AI company?
Definition ai_core.cpp:30
AI::Rescan
static void Rescan()
Rescans all searchpaths for available AIs.
Definition ai_core.cpp:318
BaseBitSet::Test
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
Definition base_bitset_type.hpp:141
BaseBitSet::Any
constexpr bool Any(const Timpl &other) const
Test if any of the given values are set.
Definition base_bitset_type.hpp:170
ClientNetworkContentSocketHandler::SelectUpgrade
void SelectUpgrade()
Select everything that's an update for something we've got.
Definition network_content.cpp:879
ClientNetworkContentSocketHandler::DownloadSelectedContent
void DownloadSelectedContent(uint &files, uint &bytes, bool fallback=false)
Actually begin downloading the content we selected.
Definition network_content.cpp:292
ClientNetworkContentSocketHandler::Select
void Select(ContentID cid)
Select a specific content id.
Definition network_content.cpp:845
ClientNetworkContentSocketHandler::UnselectAll
void UnselectAll()
Unselect everything that we've not downloaded so far.
Definition network_content.cpp:890
ClientNetworkContentSocketHandler::RequestContentList
void RequestContentList(ContentType type)
Request the content list for the given type.
Definition network_content.cpp:175
ClientNetworkContentSocketHandler::AddCallback
void AddCallback(ContentCallback *cb)
Add a callback to this class.
Definition network_content.h:139
ClientNetworkContentSocketHandler::Unselect
void Unselect(ContentID cid)
Unselect a specific content id.
Definition network_content.cpp:858
ClientNetworkGameSocketHandler::IsConnected
static bool IsConnected()
Check whether the client is actually connected (and in the game).
Definition network_client.cpp:484
ConsoleFileList
File list storage for the console, for caching the last 'ls' command.
Definition console_cmds.cpp:93
ConsoleFileList::ValidateFileList
void ValidateFileList(bool force_reload=false)
(Re-)validate the file storage cache.
Definition console_cmds.cpp:110
ConsoleFileList::file_list_valid
bool file_list_valid
If set, the file list is valid.
Definition console_cmds.cpp:120
ConsoleFileList::abstract_filetype
AbstractFileType abstract_filetype
The abstract file type to list.
Definition console_cmds.cpp:118
ConsoleFileList::InvalidateFileList
void InvalidateFileList()
Declare the file storage cache as being invalid, also clears all stored files.
Definition console_cmds.cpp:100
ConsoleFileList::show_dirs
bool show_dirs
Whether to show directories in the file list.
Definition console_cmds.cpp:119
FileHandle::Open
static std::optional< FileHandle > Open(const std::string &filename, std::string_view mode)
Open an RAII file handle if possible.
Definition fileio.cpp:1171
FileList
List of file information.
Definition fios.h:87
FileList::BuildFileList
void BuildFileList(AbstractFileType abstract_filetype, SaveLoadOperation fop, bool show_dirs)
Construct a file list with the given kind of files, for the stated purpose.
Definition fios.cpp:67
FileList::FindItem
const FiosItem * FindItem(std::string_view file)
Find file information of a file by its name from the file list.
Definition fios.cpp:103
FontCache
Font cache for basic fonts.
Definition fontcache.h:22
FontCache::GetFontName
virtual std::string GetFontName()=0
Get the name of this font.
FontCache::HasParent
bool HasParent()
Check whether the font cache has a parent.
Definition fontcache.h:141
FontCache::GetFontSize
virtual int GetFontSize() const
Get the nominal font size of the font.
Definition fontcache.h:77
FontCache::LoadFontCaches
static void LoadFontCaches(FontSizes fontsizes)
(Re)initialize the font cache related things, i.e.
Definition fontcache.cpp:237
FontCache::Get
static FontCache * Get(FontSize fs)
Get the font cache of a given font size.
Definition fontcache.h:130
Game::GetConsoleList
static void GetConsoleList(std::back_insert_iterator< std::string > &output_iterator, bool newest_only)
Wrapper function for GameScanner::GetConsoleList.
Definition game_core.cpp:203
Game::GetConsoleLibraryList
static void GetConsoleLibraryList(std::back_insert_iterator< std::string > &output_iterator)
Wrapper function for GameScanner::GetConsoleLibraryList.
Definition game_core.cpp:208
Gamelog::PrintConsole
void PrintConsole()
Print the gamelog data to the console.
Definition gamelog.cpp:310
IntervalTimer
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
NetworkAuthorizedKeys
Simple helper to (more easily) manage authorized keys.
Definition network_type.h:137
NetworkAuthorizedKeys::Contains
bool Contains(std::string_view key) const
Check whether the given key is contains in these authorized keys.
Definition network.cpp:179
NetworkAuthorizedKeys::Add
bool Add(std::string_view key)
Add the given key to the authorized keys, when it is not already contained.
Definition network.cpp:189
NetworkAuthorizedKeys::Remove
bool Remove(std::string_view key)
Remove the given key from the authorized keys, when it is exists.
Definition network.cpp:205
RailTypeInfo
This struct contains all the info that is needed to draw and construct tracks.
Definition rail.h:115
RailTypeInfo::label
RailTypeLabel label
Unique 32 bit rail type identifier.
Definition rail.h:225
RailTypeInfo::flags
RailTypeFlags flags
Bit mask of rail type flags.
Definition rail.h:200
RailTypeInfo::grffile
const GRFFile * grffile[RTSG_END]
NewGRF providing the Action3 for the railtype.
Definition rail.h:265
RoadTypeInfo
Definition road.h:52
RoadTypeInfo::label
RoadTypeLabel label
Unique 32 bit road type identifier.
Definition road.h:121
RoadTypeInfo::grffile
const GRFFile * grffile[ROTSG_END]
NewGRF providing the Action3 for the roadtype.
Definition road.h:161
ScriptConfig::HasScript
bool HasScript() const
Is this config attached to an Script? In other words, is there a Script that is assigned to this slot...
Definition script_config.cpp:127
ScriptConfig::Change
void Change(std::optional< std::string_view > name, int version=-1, bool force_exact_match=false)
Set another Script to be loaded in this slot.
Definition script_config.cpp:22
ScriptConfig::StringToSettings
void StringToSettings(std::string_view value)
Convert a string which is stored in the config file or savegames to custom settings of this Script.
Definition script_config.cpp:142
StringConsumer
Parse data from a string / buffer.
Definition string_consumer.hpp:27
StringConsumer::TryReadIntegerBase
std::optional< T > TryReadIntegerBase(int base, bool clamp=false)
Try to read and parse an integer in number 'base', and then advance the reader.
Definition string_consumer.hpp:874
StringConsumer::ReadUntilChar
std::string_view ReadUntilChar(char c, SeparatorUsage sep)
Read data until the first occurrence of 8-bit char 'c', and advance reader.
Definition string_consumer.hpp:765
StringConsumer::SKIP_ONE_SEPARATOR
@ SKIP_ONE_SEPARATOR
Read and discard one separator, do not include it in the result.
Definition string_consumer.hpp:696
StringConsumer::WHITESPACE_NO_NEWLINE
static const std::string_view WHITESPACE_NO_NEWLINE
ASCII whitespace characters, excluding new-line.
Definition string_consumer.hpp:40
TimerGameCalendar::ConvertDateToYMD
static YearMonthDay ConvertDateToYMD(Date date)
Converts a Date to a Year, Month & Day.
Definition timer_game_calendar.cpp:42
TimerGameCalendar::date
static Date date
Current date in days (day counter).
Definition timer_game_calendar.h:33
command_func.h
Functions related to commands.
Commands
Commands
List of commands.
Definition command_type.h:196
CalculateCompanyValue
Money CalculateCompanyValue(const Company *c, bool including_loan=true)
Calculate the value of the company.
Definition economy.cpp:150
_company_colours
TypedIndexContainer< std::array< Colours, MAX_COMPANIES >, CompanyID > _company_colours
NOSAVE: can be determined from company structs.
Definition company_cmd.cpp:57
_local_company
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition company_cmd.cpp:55
_current_company
CompanyID _current_company
Company currently doing an action.
Definition company_cmd.cpp:56
company_cmd.h
Command definitions related to companies.
company_func.h
Functions related to companies.
CCA_NEW_AI
@ CCA_NEW_AI
Create a new AI company.
Definition company_type.h:73
CCA_DELETE
@ CCA_DELETE
Delete a company.
Definition company_type.h:74
COMPANY_SPECTATOR
static constexpr CompanyID COMPANY_SPECTATOR
The client is spectating.
Definition company_type.h:21
CALCA_REMOVE
@ CALCA_REMOVE
Remove a public key.
Definition company_type.h:82
CALCA_ADD
@ CALCA_ADD
Create a public key.
Definition company_type.h:81
COMPANY_NEW_COMPANY
static constexpr CompanyID COMPANY_NEW_COMPANY
The client wants a new company.
Definition company_type.h:20
CRR_NONE
@ CRR_NONE
Dummy reason for actions that don't need one.
Definition company_type.h:67
CRR_MANUAL
@ CRR_MANUAL
The company is manually removed.
Definition company_type.h:61
NETWORK_PUBLIC_KEY_LENGTH
static const uint NETWORK_PUBLIC_KEY_LENGTH
The maximum length of the hexadecimal encoded public keys, in bytes including '\0'.
Definition config.h:101
IConsoleCmdExec
void IConsoleCmdExec(std::string_view command_string, const uint recurse_count)
Execute a given command passed to us.
Definition console.cpp:269
IConsolePrint
void IConsolePrint(TextColour colour_code, const std::string &string)
Handle the printing of text entered into the console or redirected there by any other means.
Definition console.cpp:90
OutputContentState
static void OutputContentState(const ContentInfo &ci)
Outputs content state information to console.
Definition console_cmds.cpp:2223
_console_cmd_authorized_keys
static const std::initializer_list< std::pair< std::string_view, NetworkAuthorizedKeys * > > _console_cmd_authorized_keys
All the known authorized keys with their name.
Definition console_cmds.cpp:2047
_scheduled_monthly_script
static std::string _scheduled_monthly_script
Script scheduled to execute by the 'schedule' console command (empty if no script is scheduled).
Definition console_cmds.cpp:61
ConScrollToTile
static bool ConScrollToTile(std::span< std::string_view > argv)
Scroll to a tile on the map.
Definition console_cmds.cpp:365
ConSaveConfig
static bool ConSaveConfig(std::span< std::string_view > argv)
Explicitly save the configuration.
Definition console_cmds.cpp:446
ShowFramerateWindow
void ShowFramerateWindow()
Open the general framerate window.
Definition framerate_gui.cpp:986
ConResetEngines
static bool ConResetEngines(std::span< std::string_view > argv)
Reset status of all engines.
Definition console_cmds.cpp:246
ParseType
static std::optional< T > ParseType(std::string_view arg)
Parse an integer using ParseInteger and convert it to the requested type.
Definition console_cmds.cpp:85
ConListDirs
static bool ConListDirs(std::span< std::string_view > argv)
Definition console_cmds.cpp:2459
ConResetEnginePool
static bool ConResetEnginePool(std::span< std::string_view > argv)
Reset status of the engine pool.
Definition console_cmds.cpp:262
ConHookServerOrNoNetwork
static ConsoleHookResult ConHookServerOrNoNetwork(bool echo)
Check if are either in singleplayer or a server.
Definition console_cmds.cpp:221
_console_file_list_scenario
static ConsoleFileList _console_file_list_scenario
File storage cache for scenarios.
Definition console_cmds.cpp:124
_console_file_list_heightmap
static ConsoleFileList _console_file_list_heightmap
File storage cache for heightmaps.
Definition console_cmds.cpp:125
ConHookServerOnly
static ConsoleHookResult ConHookServerOnly(bool echo)
Check whether we are a server.
Definition console_cmds.cpp:148
_scheduled_monthly_timer
static const IntervalTimer< TimerGameCalendar > _scheduled_monthly_timer
Timer that runs every month of game time for the 'schedule' console command.
Definition console_cmds.cpp:64
FormatLabel
static std::string FormatLabel(uint32_t label)
Format a label as a string.
Definition console_cmds.cpp:2699
ConSave
static bool ConSave(std::span< std::string_view > argv)
Save the map to a file.
Definition console_cmds.cpp:420
ConPrintFramerate
void ConPrintFramerate()
Print performance statistics to game console.
Definition framerate_gui.cpp:999
ConHookNeedNetwork
static ConsoleHookResult ConHookNeedNetwork(bool echo)
Check whether we are in a multiplayer game.
Definition console_cmds.cpp:178
ConHookClientOnly
static ConsoleHookResult ConHookClientOnly(bool echo)
Check whether we are a client in a network game.
Definition console_cmds.cpp:163
ConZoomToLevel
static bool ConZoomToLevel(std::span< std::string_view > argv)
Zoom map to given level.
Definition console_cmds.cpp:313
StringToContentType
static ContentType StringToContentType(std::string_view str)
Resolve a string to a content type.
Definition console_cmds.cpp:2185
_script_current_depth
static uint _script_current_depth
Depth of scripts running (used to abort execution when ConReturn is encountered).
Definition console_cmds.cpp:58
NetworkAvailable
static bool NetworkAvailable(bool echo)
Check network availability and inform in console about failure of detection.
Definition console_cmds.cpp:135
ConHookNeedNonDedicatedNetwork
static ConsoleHookResult ConHookNeedNonDedicatedNetwork(bool echo)
Check whether we are in a multiplayer game and are playing, i.e.
Definition console_cmds.cpp:193
_console_file_list_savegame
static ConsoleFileList _console_file_list_savegame
File storage cache for savegames.
Definition console_cmds.cpp:123
ConHookNoNetwork
static ConsoleHookResult ConHookNoNetwork(bool echo)
Check whether we are in singleplayer mode.
Definition console_cmds.cpp:208
PrintLineByLine
static void PrintLineByLine(const std::string &full_string)
Print a text buffer line by line to the console.
Definition console_cmds.cpp:1386
console_func.h
Console functions used outside of the console code.
IConsoleClose
void IConsoleClose()
Close the in-game console.
Definition console_gui.cpp:442
console_internal.h
Internally used functions for the console.
ConsoleHookResult
ConsoleHookResult
Return values of console hooks (IConsoleHook).
Definition console_internal.h:18
CHR_HIDE
@ CHR_HIDE
Hide the existence of the command.
Definition console_internal.h:21
CHR_DISALLOW
@ CHR_DISALLOW
Disallow command execution.
Definition console_internal.h:20
CHR_ALLOW
@ CHR_ALLOW
Allow command execution.
Definition console_internal.h:19
ICON_CMDLN_SIZE
static const uint ICON_CMDLN_SIZE
maximum length of a typed in command
Definition console_internal.h:15
CC_HELP
static const TextColour CC_HELP
Colour for help lines.
Definition console_type.h:26
CC_WHITE
static const TextColour CC_WHITE
White console lines for various things such as the welcome.
Definition console_type.h:30
CC_INFO
static const TextColour CC_INFO
Colour for information lines.
Definition console_type.h:27
CC_COMMAND
static const TextColour CC_COMMAND
Colour for the console's commands.
Definition console_type.h:29
CC_WARNING
static const TextColour CC_WARNING
Colour for warning lines.
Definition console_type.h:25
CC_DEBUG
static const TextColour CC_DEBUG
Colour for debug output.
Definition console_type.h:28
CC_DEFAULT
static const TextColour CC_DEFAULT
Default colour of the console.
Definition console_type.h:23
CC_ERROR
static const TextColour CC_ERROR
Colour for error lines.
Definition console_type.h:24
SetDebugString
void SetDebugString(std::string_view s, SetDebugStringErrorFunc error_func)
Set debugging levels by parsing the text in s.
Definition debug.cpp:144
GetDebugString
std::string GetDebugString()
Print out the current debug-level.
Definition debug.cpp:201
debug.h
Functions related to debugging.
StartupEngines
void StartupEngines()
Start/initialise all our engines.
Definition engine.cpp:798
engine_base.h
Base class for engines.
engine_func.h
Functions related to engines.
to_underlying
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
FioRemove
bool FioRemove(const std::string &filename)
Remove a file.
Definition fileio.cpp:327
FioFOpenFile
std::optional< FileHandle > FioFOpenFile(std::string_view filename, std::string_view mode, Subdirectory subdir, size_t *filesize)
Opens a OpenTTD file somewhere in a personal or global directory.
Definition fileio.cpp:242
FileExists
bool FileExists(std::string_view filename)
Test whether the given filename exists.
Definition fileio.cpp:132
FioCheckFileExists
bool FioCheckFileExists(std::string_view filename, Subdirectory subdir)
Check whether the given file exists.
Definition fileio.cpp:121
fileio_func.h
Functions for Standard In/Out file operations.
SLO_SAVE
@ SLO_SAVE
File is being saved.
Definition fileio_type.h:55
SLO_LOAD
@ SLO_LOAD
File is being loaded.
Definition fileio_type.h:54
DFT_FIOS_DRIVE
@ DFT_FIOS_DRIVE
A drive (letter) entry.
Definition fileio_type.h:41
DFT_GAME_FILE
@ DFT_GAME_FILE
Save game or scenario file.
Definition fileio_type.h:31
DFT_FIOS_DIR
@ DFT_FIOS_DIR
A directory entry.
Definition fileio_type.h:43
DFT_FIOS_PARENT
@ DFT_FIOS_PARENT
A parent directory entry.
Definition fileio_type.h:42
Searchpath
Searchpath
Types of searchpaths OpenTTD might use.
Definition fileio_type.h:113
Subdirectory
Subdirectory
The different kinds of subdirectories OpenTTD uses.
Definition fileio_type.h:88
AI_LIBRARY_DIR
@ AI_LIBRARY_DIR
Subdirectory for all AI libraries.
Definition fileio_type.h:100
SCREENSHOT_DIR
@ SCREENSHOT_DIR
Subdirectory for all screenshots.
Definition fileio_type.h:103
SOCIAL_INTEGRATION_DIR
@ SOCIAL_INTEGRATION_DIR
Subdirectory for all social integration plugins.
Definition fileio_type.h:104
GAME_LIBRARY_DIR
@ GAME_LIBRARY_DIR
Subdirectory for all GS libraries.
Definition fileio_type.h:102
AI_DIR
@ AI_DIR
Subdirectory for all AI files.
Definition fileio_type.h:99
SCENARIO_DIR
@ SCENARIO_DIR
Base directory for all scenarios.
Definition fileio_type.h:92
BASE_DIR
@ BASE_DIR
Base directory for all subdirectories.
Definition fileio_type.h:89
SAVE_DIR
@ SAVE_DIR
Base directory for all savegames.
Definition fileio_type.h:90
HEIGHTMAP_DIR
@ HEIGHTMAP_DIR
Subdirectory of scenario for heightmaps.
Definition fileio_type.h:93
NEWGRF_DIR
@ NEWGRF_DIR
Subdirectory for all NewGRFs.
Definition fileio_type.h:97
AUTOSAVE_DIR
@ AUTOSAVE_DIR
Subdirectory of save for autosaves.
Definition fileio_type.h:91
BASESET_DIR
@ BASESET_DIR
Subdirectory for all base data (base sets, intro game)
Definition fileio_type.h:96
GAME_DIR
@ GAME_DIR
Subdirectory for all game scripts.
Definition fileio_type.h:101
AbstractFileType
AbstractFileType
The different abstract types of files that the system knows about.
Definition fileio_type.h:17
FT_SCENARIO
@ FT_SCENARIO
old or new scenario
Definition fileio_type.h:20
FT_HEIGHTMAP
@ FT_HEIGHTMAP
heightmap file
Definition fileio_type.h:21
FT_NONE
@ FT_NONE
nothing to do
Definition fileio_type.h:18
FT_SAVEGAME
@ FT_SAVEGAME
old or new savegame
Definition fileio_type.h:19
FT_INVALID
@ FT_INVALID
Invalid or unknown file type.
Definition fileio_type.h:24
FiosGetCurrentPath
std::string FiosGetCurrentPath()
Get the current path/working directory.
Definition fios.cpp:132
FiosBrowseTo
bool FiosBrowseTo(const FiosItem *item)
Browse to a new path based on the passed item, starting at _fios_path.
Definition fios.cpp:142
fios.h
Declarations for savegames operations.
fontcache.h
Functions to read fonts from files and cache them.
GetFontCacheSubSetting
FontCacheSubSetting * GetFontCacheSubSetting(FontSize fs)
Get the settings of a given font size.
Definition fontcache.h:196
game.hpp
Base functions for all Games.
_gamelog
Gamelog _gamelog
Gamelog instance.
Definition gamelog.cpp:31
gamelog.h
Functions to be called to log fundamental changes to the game.
genworld.h
Functions related to world/map generation.
GENERATE_NEW_SEED
static const uint32_t GENERATE_NEW_SEED
Create a new random seed.
Definition genworld.h:25
StartNewGameWithoutGUI
void StartNewGameWithoutGUI(uint32_t seed)
Start a normal game without the GUI.
Definition genworld_gui.cpp:1062
_pause_mode
PauseModes _pause_mode
The current pause mode.
Definition gfx.cpp:50
_switch_mode
SwitchMode _switch_mode
The next mainloop command.
Definition gfx.cpp:49
FontSize
FontSize
Available font sizes.
Definition gfx_type.h:248
FS_BEGIN
@ FS_BEGIN
First font.
Definition gfx_type.h:255
TextColour
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition gfx_type.h:307
landscape.h
Functions related to OTTD's landscape.
DoZoomInOutWindow
bool DoZoomInOutWindow(ZoomStateChange how, Window *w)
Zooms a viewport in a window in or out.
Definition main_gui.cpp:93
TileXY
static TileIndex TileXY(uint x, uint y)
Returns the TileIndex of a coordinate.
Definition map_func.h:385
IsInsideMM
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
Definition math_func.hpp:267
misc_cmd.h
Miscellaneous command definitions.
_redirect_console_to_client
ClientID _redirect_console_to_client
If not invalid, redirect the console output to a client.
Definition network.cpp:72
_network_available
bool _network_available
is network mode available?
Definition network.cpp:68
_networking
bool _networking
are we in networking mode?
Definition network.cpp:66
_network_ban_list
StringList _network_ban_list
The banned clients.
Definition network.cpp:76
_network_dedicated
bool _network_dedicated
are we a dedicated server?
Definition network.cpp:69
_network_server
bool _network_server
network-server is active
Definition network.cpp:67
NetworkClientConnectGame
bool NetworkClientConnectGame(std::string_view connection_string, CompanyID default_company, const std::string &join_server_password)
Join a client to the server at with the given connection string.
Definition network.cpp:785
_network_own_client_id
ClientID _network_own_client_id
Our client identifier.
Definition network.cpp:71
network.h
Basic functions/variables used all over the place.
_redirect_console_to_admin
AdminID _redirect_console_to_admin
Redirection of the (remote) console to the admin.
Definition network_admin.cpp:34
network_admin.h
Server part of the admin network protocol.
network_base.h
Base core network types and some helper functions to access them.
NetworkClientSendRcon
void NetworkClientSendRcon(std::string_view password, std::string_view command)
Send a remote console command.
Definition network_client.cpp:1205
NetworkClientSendChat
void NetworkClientSendChat(NetworkAction action, DestType type, int dest, std::string_view msg, int64_t data)
Send a chat message.
Definition network_client.cpp:1321
NetworkClientRequestMove
void NetworkClientRequestMove(CompanyID company_id)
Notify the server of this client wanting to be moved to another company.
Definition network_client.cpp:1214
NetworkIsValidClientName
bool NetworkIsValidClientName(std::string_view client_name)
Check whether the given client name is deemed valid for use in network games.
Definition network_client.cpp:1245
network_client.h
Client part of the network protocol.
_network_content_client
ClientNetworkContentSocketHandler _network_content_client
The client we use to connect to the server.
Definition network_content.cpp:47
network_content.h
Part of the network protocol handling content distribution.
_network_server_invite_code
std::string _network_server_invite_code
Our invite code as indicated by the Game Coordinator.
Definition network_coordinator.cpp:32
network_func.h
Network functions used by other parts of OpenTTD.
NetworkServerChangeClientName
bool NetworkServerChangeClientName(ClientID client_id, const std::string &new_name)
Change the client name of the given client.
Definition network_server.cpp:1647
NetworkPrintClients
void NetworkPrintClients()
Print all the clients to the console.
Definition network_server.cpp:2115
NetworkServerDoMove
void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
Handle the tid-bits of moving a client from one company to another.
Definition network_server.cpp:1976
NetworkCompanyHasClients
bool NetworkCompanyHasClients(CompanyID company)
Check whether a particular company has clients.
Definition network_server.cpp:2090
NetworkServerKickClient
void NetworkServerKickClient(ClientID client_id, std::string_view reason)
Kick a single client.
Definition network_server.cpp:2029
NetworkGetPublicKeyOfClient
std::string_view NetworkGetPublicKeyOfClient(ClientID client_id)
Get the public key of the client with the given id.
Definition network_server.cpp:2138
NetworkServerSendChat
void NetworkServerSendChat(NetworkAction action, DestType type, int dest, std::string_view msg, ClientID from_id, int64_t data=0, bool from_admin=false)
Send an actual chat message.
Definition network_server.cpp:1252
NetworkServerShowStatusToConsole
void NetworkServerShowStatusToConsole()
Show the status message of all clients on the console.
Definition network_server.cpp:1925
NetworkServerKickOrBanIP
uint NetworkServerKickOrBanIP(ClientID client_id, bool ban, std::string_view reason)
Ban, or kick, everyone joined from the given client's IP.
Definition network_server.cpp:2041
DESTTYPE_CLIENT
@ DESTTYPE_CLIENT
Send message/notice to only a certain client (Private)
Definition network_type.h:71
DESTTYPE_TEAM
@ DESTTYPE_TEAM
Send message/notice to everyone playing the same company (Team)
Definition network_type.h:70
DESTTYPE_BROADCAST
@ DESTTYPE_BROADCAST
Send message/notice to all clients (All)
Definition network_type.h:69
ClientID
ClientID
'Unique' identifier to be given to clients
Definition network_type.h:43
INVALID_CLIENT_ID
@ INVALID_CLIENT_ID
Client is not part of anything.
Definition network_type.h:44
CLIENT_ID_SERVER
@ CLIENT_ID_SERVER
Servers always have this ID.
Definition network_type.h:45
newgrf.h
Base for the NewGRF implementation.
ReloadNewGRFData
void ReloadNewGRFData()
Reload all NewGRF files during a running game.
Definition afterload.cpp:3442
newgrf_profiling.h
Profiling of NewGRF action 2 handling.
RequestNewGRFScan
bool RequestNewGRFScan(NewGRFScanCallback *callback)
Request a new NewGRF scan.
Definition openttd.cpp:1327
PauseMode::Error
@ Error
A game paused because a (critical) error.
PauseMode::Normal
@ Normal
A game normally paused.
SM_START_HEIGHTMAP
@ SM_START_HEIGHTMAP
Load a heightmap and start a new game from it.
Definition openttd.h:38
SM_MENU
@ SM_MENU
Switch to game intro menu.
Definition openttd.h:33
SM_RESTARTGAME
@ SM_RESTARTGAME
Restart --> 'Random game' with current settings.
Definition openttd.h:29
SM_RELOADGAME
@ SM_RELOADGAME
Reload the savegame / scenario / heightmap you started the game with.
Definition openttd.h:30
SM_LOAD_GAME
@ SM_LOAD_GAME
Load game, Play Scenario.
Definition openttd.h:32
rail.h
Rail specific functions.
GetRailTypeInfo
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition rail.h:300
RailTypeFlag
RailTypeFlag
Railtype flag bit numbers.
Definition rail.h:27
RailTypeFlag::Catenary
@ Catenary
Bit number for drawing a catenary.
RailTypeFlag::Allow90Deg
@ Allow90Deg
Bit number for always allowed 90 degree turns, regardless of setting.
RailTypeFlag::Disallow90Deg
@ Disallow90Deg
Bit number for never allowed 90 degree turns, regardless of setting.
RailTypeFlag::Hidden
@ Hidden
Bit number for hiding from selection.
RailTypeFlag::NoSpriteCombine
@ NoSpriteCombine
Bit number for using non-combined junctions.
RailTypeFlag::NoLevelCrossing
@ NoLevelCrossing
Bit number for disallowing level crossings.
RTSG_GROUND
@ RTSG_GROUND
Main group of ground images.
Definition rail.h:43
RailType
RailType
Enumeration for all possible railtypes.
Definition rail_type.h:25
RAILTYPE_BEGIN
@ RAILTYPE_BEGIN
Used for iterations.
Definition rail_type.h:26
RAILTYPE_END
@ RAILTYPE_END
Used for iterations.
Definition rail_type.h:31
road.h
Road specific functions.
RoadTypeFlag
RoadTypeFlag
Roadtype flag bit numbers.
Definition road.h:24
RoadTypeFlag::NoHouses
@ NoHouses
Bit number for setting this roadtype as not house friendly.
RoadTypeFlag::TownBuild
@ TownBuild
Bit number for allowing towns to build this roadtype.
GetRoadTypeInfo
const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition road.h:215
ROTSG_GROUND
@ ROTSG_GROUND
Required: Main group of ground images.
Definition road.h:39
RoadType
RoadType
The different roadtypes we support.
Definition road_type.h:23
ROADTYPE_END
@ ROADTYPE_END
Used for iterations.
Definition road_type.h:27
ROADTYPE_BEGIN
@ ROADTYPE_BEGIN
Used for iterations.
Definition road_type.h:24
safeguards.h
A number of safeguards to prevent using unsafe methods.
SaveOrLoad
SaveOrLoadResult SaveOrLoad(std::string_view filename, SaveLoadOperation fop, DetailedFileType dft, Subdirectory sb, bool threaded)
Main Save or Load function where the high-level saveload functions are handled.
Definition saveload.cpp:3258
_file_to_saveload
FileToSaveLoad _file_to_saveload
File to save or load in the openttd loop.
Definition saveload.cpp:78
DoExitSave
void DoExitSave()
Do a save when exiting the game (_settings_client.gui.autosave_on_exit)
Definition saveload.cpp:3367
saveload.h
Functions/types related to saving and loading games.
SL_OK
@ SL_OK
completed successfully
Definition saveload.h:421
MakeScreenshot
bool MakeScreenshot(ScreenshotType t, const std::string &name, uint32_t width, uint32_t height)
Schedule making a screenshot.
Definition screenshot.cpp:456
screenshot.h
Functions to make screenshots.
ScreenshotType
ScreenshotType
Type of requested screenshot.
Definition screenshot.h:16
SC_VIEWPORT
@ SC_VIEWPORT
Screenshot of viewport.
Definition screenshot.h:17
SC_ZOOMEDIN
@ SC_ZOOMEDIN
Fully zoomed in screenshot of the visible area.
Definition screenshot.h:19
SC_HEIGHTMAP
@ SC_HEIGHTMAP
Heightmap of the world.
Definition screenshot.h:22
SC_WORLD
@ SC_WORLD
World screenshot.
Definition screenshot.h:21
SC_MINIMAP
@ SC_MINIMAP
Minimap screenshot.
Definition screenshot.h:23
SC_DEFAULTZOOM
@ SC_DEFAULTZOOM
Zoomed to default zoom level screenshot of the visible area.
Definition screenshot.h:20
IConsoleGetSetting
void IConsoleGetSetting(std::string_view name, bool force_newgame)
Output value of a specific setting to the console.
Definition settings.cpp:1970
SaveToConfig
void SaveToConfig()
Save the values to the configuration file.
Definition settings.cpp:1469
_settings_game
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
IConsoleListSettings
void IConsoleListSettings(std::string_view prefilter)
List all settings and their value to the console.
Definition settings.cpp:2008
_settings_client
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
settings_func.h
Functions related to setting/changing the settings.
stdafx.h
Definition of base types and functions in a cross-platform compatible way.
lengthof
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:271
FormatArrayAsHex
std::string FormatArrayAsHex(std::span< const uint8_t > data)
Format a byte array into a continuous hex string.
Definition string.cpp:77
StrEqualsIgnoreCase
bool StrEqualsIgnoreCase(std::string_view str1, std::string_view str2)
Compares two string( view)s for equality, while ignoring the case of the characters.
Definition string.cpp:323
StrStartsWithIgnoreCase
bool StrStartsWithIgnoreCase(std::string_view str, std::string_view prefix)
Check whether the given string starts with the given prefix, ignoring case.
Definition string.cpp:257
StrContainsIgnoreCase
bool StrContainsIgnoreCase(std::string_view str, std::string_view value)
Checks if a string is contained in another string, while ignoring the case of the characters.
Definition string.cpp:336
string_consumer.hpp
Parse strings.
ParseInteger
static std::optional< T > ParseInteger(std::string_view arg, int base=10, bool clamp=false)
Change a string into its number representation.
Definition string_consumer.hpp:917
GetString
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
strings_func.h
Functions related to OTTD's strings.
AISettings::ai_in_multiplayer
bool ai_in_multiplayer
so we allow AIs in multiplayer
Definition settings_type.h:439
AutoRestoreBackup
Class to backup a specific variable and restore it upon destruction of this object to prevent stack v...
Definition backup_type.hpp:150
CargoSpec
Specification of a cargo type.
Definition cargotype.h:74
ClientSettings::network
NetworkSettings network
settings related to the network
Definition settings_type.h:651
ClientSettings::gui
GUISettings gui
settings related to the GUI
Definition settings_type.h:650
CommandHelper
Definition command_func.h:83
CompanyProperties::allow_list
NetworkAuthorizedKeys allow_list
Public keys of clients that are allowed to join this company.
Definition company_base.h:80
Company
Definition company_base.h:127
Company::IsHumanID
static bool IsHumanID(auto index)
Is this company a company not controlled by a NoAI program?
Definition company_base.h:178
ConsoleContentCallback
Asynchronous callback.
Definition console_cmds.cpp:2202
ConsoleContentCallback::OnConnect
void OnConnect(bool success) override
Callback for when the connection has finished.
Definition console_cmds.cpp:2203
ConsoleContentCallback::OnDownloadComplete
void OnDownloadComplete(ContentID cid) override
We have finished downloading a file.
Definition console_cmds.cpp:2213
ConsoleContentCallback::OnDisconnect
void OnDisconnect() override
Callback for when the connection got disconnected.
Definition console_cmds.cpp:2208
ContentCallback
Callbacks for notifying others about incoming data.
Definition network_content.h:25
ContentInfo
Container for all important information about a piece of content.
Definition tcp_content_type.h:56
ContentInfo::unique_id
uint32_t unique_id
Unique ID; either GRF ID or shortname.
Definition tcp_content_type.h:75
ContentInfo::md5sum
MD5Hash md5sum
The MD5 checksum.
Definition tcp_content_type.h:76
ContentInfo::state
State state
Whether the content info is selected (for download)
Definition tcp_content_type.h:79
ContentInfo::name
std::string name
Name of the content.
Definition tcp_content_type.h:71
ContentInfo::id
ContentID id
Unique (server side) ID for the content.
Definition tcp_content_type.h:68
ContentInfo::type
ContentType type
Type of content.
Definition tcp_content_type.h:67
ContentInfo::State::Selected
@ Selected
The content has been manually selected.
ContentInfo::State::Autoselected
@ Autoselected
The content has been selected as dependency.
EngineOverrideManager::ResetToCurrentNewGRFConfig
static bool ResetToCurrentNewGRFConfig()
Tries to reset the engine mapping to match the current NewGRF configuration.
Definition engine.cpp:584
FileToSaveLoad::ftype
FiosType ftype
File type.
Definition saveload.h:429
FileToSaveLoad::Set
void Set(const FiosItem &item)
Set the title of the file.
Definition saveload.cpp:3437
FiosItem
Deals with finding savegames.
Definition fios.h:78
FiosType::detailed
DetailedFileType detailed
Detailed file type.
Definition fileio_type.h:65
FiosType::abstract
AbstractFileType abstract
Abstract file type.
Definition fileio_type.h:64
FontCacheSubSetting
Settings for a single font.
Definition fontcache.h:172
FontCacheSubSetting::font
std::string font
The name of the font, or path to the font.
Definition fontcache.h:173
FontCacheSubSetting::size
uint size
The (requested) size of the font.
Definition fontcache.h:174
GRFFile
Dynamic data of a loaded NewGRF.
Definition newgrf.h:114
GUISettings::autosave_on_exit
bool autosave_on_exit
save an autosave when you quit the game, but do not ask "Do you really want to quit?...
Definition settings_type.h:197
GUISettings::zoom_min
ZoomLevel zoom_min
minimum zoom out level
Definition settings_type.h:191
GUISettings::newgrf_developer_tools
bool newgrf_developer_tools
activate NewGRF developer tools and allow modifying NewGRFs in an existing game
Definition settings_type.h:251
GUISettings::zoom_max
ZoomLevel zoom_max
maximum zoom out level
Definition settings_type.h:192
GameCreationSettings::map_x
uint8_t map_x
X size of map.
Definition settings_type.h:382
GameCreationSettings::map_y
uint8_t map_y
Y size of map.
Definition settings_type.h:383
GameCreationSettings::generation_seed
uint32_t generation_seed
noise seed for world generation
Definition settings_type.h:379
GameSettings::ai
AISettings ai
what may the AI do?
Definition settings_type.h:636
GameSettings::game_creation
GameCreationSettings game_creation
settings used during the creation of a game (map)
Definition settings_type.h:634
IConsoleAlias
–Aliases– Aliases are like shortcuts for complex functions, variable assignments, etc.
Definition console_internal.h:54
IConsoleAlias::cmdline
std::string cmdline
command(s) that is/are being aliased
Definition console_internal.h:58
IConsoleAlias::name
std::string name
name of the alias
Definition console_internal.h:57
IConsoleCmd
Definition console_internal.h:34
IConsoleCmd::proc
IConsoleCmdProc * proc
process executed when command is typed
Definition console_internal.h:38
IConsoleCmd::hook
IConsoleHook * hook
any special trigger action that needs executing
Definition console_internal.h:39
IConsoleCmd::name
std::string name
name of command
Definition console_internal.h:37
IConsole
Definition console_internal.h:62
IConsole::AliasRegister
static void AliasRegister(const std::string &name, std::string_view cmd)
Register a an alias for an already existing command in the console.
Definition console.cpp:159
IConsole::AliasGet
static IConsoleAlias * AliasGet(const std::string &name)
Find the alias pointed to by its string.
Definition console.cpp:170
IConsole::CmdRegister
static void CmdRegister(const std::string &name, IConsoleCmdProc *proc, IConsoleHook *hook=nullptr)
Register a new command to be used in the console.
Definition console.cpp:137
IConsole::CmdGet
static IConsoleCmd * CmdGet(const std::string &name)
Find the command pointed to by its string.
Definition console.cpp:147
Map::SizeX
static uint SizeX()
Get the size of the map along the X.
Definition map_func.h:272
Map::SizeY
static uint SizeY()
Get the size of the map along the Y.
Definition map_func.h:281
Map::LogX
static uint LogX()
Logarithm of the map size along the X side.
Definition map_func.h:253
Map::LogY
static uint LogY()
Logarithm of the map size along the y side.
Definition map_func.h:263
Map::Size
static uint Size()
Get the size of the map.
Definition map_func.h:290
NetworkClientInfo
Container for all information known about a client.
Definition network_base.h:24
NetworkClientInfo::GetByClientID
static NetworkClientInfo * GetByClientID(ClientID client_id)
Return the CI given it's client-identifier.
Definition network.cpp:117
NetworkClientInfo::CanJoinCompany
bool CanJoinCompany(CompanyID company_id) const
Returns whether the given company can be joined by this client.
Definition network.cpp:131
NetworkClientInfo::client_playas
CompanyID client_playas
As which company is this client playing (CompanyID)
Definition network_base.h:28
NetworkClientInfo::client_id
ClientID client_id
Client identifier (same as ClientState->client_id)
Definition network_base.h:25
NetworkServerGameInfo::clients_on
uint8_t clients_on
Current count of clients on server.
Definition network_game_info.h:108
NetworkSettings::max_clients
uint8_t max_clients
maximum amount of clients
Definition settings_type.h:365
NetworkSettings::max_companies
uint8_t max_companies
maximum amount of companies
Definition settings_type.h:364
NetworkSettings::admin_authorized_keys
NetworkAuthorizedKeys admin_authorized_keys
Public keys of clients that are authorized to use the admin network.
Definition settings_type.h:356
NetworkSettings::rcon_authorized_keys
NetworkAuthorizedKeys rcon_authorized_keys
Public keys of clients that are authorized to use the rconsole (server side).
Definition settings_type.h:353
NetworkSettings::last_joined
std::string last_joined
Last joined server.
Definition settings_type.h:370
NetworkSettings::server_authorized_keys
NetworkAuthorizedKeys server_authorized_keys
Public keys of clients that are authorized to connect to the game.
Definition settings_type.h:351
NewGRFProfiler
Callback profiler for NewGRF development.
Definition newgrf_profiling.h:22
NewGRFProfiler::StartTimer
static void StartTimer(uint64_t ticks)
Start the timeout timer that will finish all profiling sessions.
Definition newgrf_profiling.cpp:188
NewGRFProfiler::active
bool active
Is this profiler collecting data.
Definition newgrf_profiling.h:52
NewGRFProfiler::grffile
const GRFFile * grffile
Which GRF is being profiled.
Definition newgrf_profiling.h:51
NewGRFProfiler::AbortTimer
static void AbortTimer()
Abort the timeout timer, so the timer callback is never called.
Definition newgrf_profiling.cpp:196
PoolID< uint8_t, struct CompanyIDTag, 0xF, 0xFF >
Pool::PoolItem<&_company_pool >::GetNumItems
static size_t GetNumItems()
Returns number of valid items in the pool.
Definition pool_type.hpp:417
Pool::PoolItem::index
Tindex index
Index of this pool item.
Definition pool_type.hpp:286
Pool::PoolItem<&_company_pool >::IsValidID
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Definition pool_type.hpp:376
Pool::PoolItem<&_company_pool >::GetIfValid
static Titem * GetIfValid(auto index)
Returns Titem with given index.
Definition pool_type.hpp:398
Pool::MAX_SIZE
static constexpr size_t MAX_SIZE
Make template parameter accessible from outside.
Definition pool_type.hpp:135
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > >
Viewport
Data structure for viewport, display of a part of the world.
Definition viewport_type.h:31
Viewport::zoom
ZoomLevel zoom
The zoom level of the viewport.
Definition viewport_type.h:42
Window
Data structure for an opened window.
Definition window_gui.h:274
Window::viewport
std::unique_ptr< ViewportData > viewport
Pointer to viewport data, if present.
Definition window_gui.h:319
ContentID
uint32_t ContentID
Unique identifier for the content.
Definition tcp_content_type.h:51
ContentType
ContentType
The values in the enum are important; they are used as database 'keys'.
Definition tcp_content_type.h:21
CONTENT_TYPE_AI_LIBRARY
@ CONTENT_TYPE_AI_LIBRARY
The content consists of an AI library.
Definition tcp_content_type.h:26
CONTENT_TYPE_BASE_GRAPHICS
@ CONTENT_TYPE_BASE_GRAPHICS
The content consists of base graphics.
Definition tcp_content_type.h:23
CONTENT_TYPE_AI
@ CONTENT_TYPE_AI
The content consists of an AI.
Definition tcp_content_type.h:25
CONTENT_TYPE_SCENARIO
@ CONTENT_TYPE_SCENARIO
The content consists of a scenario.
Definition tcp_content_type.h:27
CONTENT_TYPE_NEWGRF
@ CONTENT_TYPE_NEWGRF
The content consists of a NewGRF.
Definition tcp_content_type.h:24
CONTENT_TYPE_BEGIN
@ CONTENT_TYPE_BEGIN
Helper to mark the begin of the types.
Definition tcp_content_type.h:22
CONTENT_TYPE_END
@ CONTENT_TYPE_END
Helper to mark the end of the types.
Definition tcp_content_type.h:33
CONTENT_TYPE_HEIGHTMAP
@ CONTENT_TYPE_HEIGHTMAP
The content consists of a heightmap.
Definition tcp_content_type.h:28
IsValidTile
bool IsValidTile(Tile tile)
Checks if a tile is valid.
Definition tile_map.h:161
timer.h
Definition of Interval and OneShot timers.
VEH_ROAD
@ VEH_ROAD
Road vehicle type.
Definition vehicle_type.h:26
VEH_AIRCRAFT
@ VEH_AIRCRAFT
Aircraft vehicle type.
Definition vehicle_type.h:28
VEH_SHIP
@ VEH_SHIP
Ship vehicle type.
Definition vehicle_type.h:27
VEH_TRAIN
@ VEH_TRAIN
Train vehicle type.
Definition vehicle_type.h:25
ScrollMainWindowToTile
bool ScrollMainWindowToTile(TileIndex tile, bool instant)
Scrolls the viewport of the main window to a given location.
Definition viewport.cpp:2592
viewport_func.h
Functions related to (drawing on) viewports.
ZOOM_IN
@ ZOOM_IN
Zoom in (get more detailed view).
Definition viewport_type.h:81
ZOOM_OUT
@ ZOOM_OUT
Zoom out (get helicopter view).
Definition viewport_type.h:82
GetMainWindow
Window * GetMainWindow()
Get the main window, i.e.
Definition window.cpp:1180
SetWindowDirty
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3176
window_func.h
Window functions not directly related to making/drawing windows.
WC_CONSOLE
@ WC_CONSOLE
Console; Window numbers:
Definition window_type.h:660
ZoomLevel
ZoomLevel
All zoom levels we know.
Definition zoom_type.h:20
ZoomLevel::Begin
@ Begin
Begin for iteration.
ZoomLevel::Max
@ Max
Maximum zoom level.
ZoomLevel::Min
@ Min
Minimum zoom level.
ZoomLevel::End
@ End
End for iteration.