OpenTTD
console_cmds.cpp
Go to the documentation of this file.
1 /* $Id: console_cmds.cpp 27653 2016-09-04 16:06:50Z alberth $ */
2 
3 /*
4  * This file is part of OpenTTD.
5  * 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.
6  * 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.
7  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8  */
9 
12 #include "stdafx.h"
13 #include "console_internal.h"
14 #include "debug.h"
15 #include "engine_func.h"
16 #include "landscape.h"
17 #include "saveload/saveload.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 "screenshot.h"
28 #include "genworld.h"
29 #include "strings_func.h"
30 #include "viewport_func.h"
31 #include "window_func.h"
32 #include "date_func.h"
33 #include "company_func.h"
34 #include "gamelog.h"
35 #include "ai/ai.hpp"
36 #include "ai/ai_config.hpp"
37 #include "newgrf.h"
38 #include "console_func.h"
39 #include "engine_base.h"
40 #include "game/game.hpp"
41 #include "table/strings.h"
42 
43 #include "safeguards.h"
44 
45 /* scriptfile handling */
46 static bool _script_running;
47 
49 class ConsoleFileList : public FileList {
50 public:
52  {
53  this->file_list_valid = false;
54  }
55 
58  {
59  this->Clear();
60  this->file_list_valid = false;
61  }
62 
67  void ValidateFileList(bool force_reload = false)
68  {
69  if (force_reload || !this->file_list_valid) {
71  this->file_list_valid = true;
72  }
73  }
74 
76 };
77 
79 
80 /* console command defines */
81 #define DEF_CONSOLE_CMD(function) static bool function(byte argc, char *argv[])
82 #define DEF_CONSOLE_HOOK(function) static ConsoleHookResult function(bool echo)
83 
84 
85 /****************
86  * command hooks
87  ****************/
88 
89 #ifdef ENABLE_NETWORK
90 
95 static inline bool NetworkAvailable(bool echo)
96 {
97  if (!_network_available) {
98  if (echo) IConsoleError("You cannot use this command because there is no network available.");
99  return false;
100  }
101  return true;
102 }
103 
108 DEF_CONSOLE_HOOK(ConHookServerOnly)
109 {
110  if (!NetworkAvailable(echo)) return CHR_DISALLOW;
111 
112  if (!_network_server) {
113  if (echo) IConsoleError("This command is only available to a network server.");
114  return CHR_DISALLOW;
115  }
116  return CHR_ALLOW;
117 }
118 
123 DEF_CONSOLE_HOOK(ConHookClientOnly)
124 {
125  if (!NetworkAvailable(echo)) return CHR_DISALLOW;
126 
127  if (_network_server) {
128  if (echo) IConsoleError("This command is not available to a network server.");
129  return CHR_DISALLOW;
130  }
131  return CHR_ALLOW;
132 }
133 
138 DEF_CONSOLE_HOOK(ConHookNeedNetwork)
139 {
140  if (!NetworkAvailable(echo)) return CHR_DISALLOW;
141 
143  if (echo) IConsoleError("Not connected. This command is only available in multiplayer.");
144  return CHR_DISALLOW;
145  }
146  return CHR_ALLOW;
147 }
148 
153 DEF_CONSOLE_HOOK(ConHookNoNetwork)
154 {
155  if (_networking) {
156  if (echo) IConsoleError("This command is forbidden in multiplayer.");
157  return CHR_DISALLOW;
158  }
159  return CHR_ALLOW;
160 }
161 
162 #else
163 # define ConHookNoNetwork NULL
164 #endif /* ENABLE_NETWORK */
165 
166 DEF_CONSOLE_HOOK(ConHookNewGRFDeveloperTool)
167 {
169  if (_game_mode == GM_MENU) {
170  if (echo) IConsoleError("This command is only available in game and editor.");
171  return CHR_DISALLOW;
172  }
173 #ifdef ENABLE_NETWORK
174  return ConHookNoNetwork(echo);
175 #else
176  return CHR_ALLOW;
177 #endif
178  }
179  return CHR_HIDE;
180 }
181 
186 static void IConsoleHelp(const char *str)
187 {
188  IConsolePrintF(CC_WARNING, "- %s", str);
189 }
190 
195 DEF_CONSOLE_CMD(ConResetEngines)
196 {
197  if (argc == 0) {
198  IConsoleHelp("Reset status data of all engines. This might solve some issues with 'lost' engines. Usage: 'resetengines'");
199  return true;
200  }
201 
202  StartupEngines();
203  return true;
204 }
205 
211 DEF_CONSOLE_CMD(ConResetEnginePool)
212 {
213  if (argc == 0) {
214  IConsoleHelp("Reset NewGRF allocations of engine slots. This will remove invalid engine definitions, and might make default engines available again.");
215  return true;
216  }
217 
218  if (_game_mode == GM_MENU) {
219  IConsoleError("This command is only available in game and editor.");
220  return true;
221  }
222 
224  IConsoleError("This can only be done when there are no vehicles in the game.");
225  return true;
226  }
227 
228  return true;
229 }
230 
231 #ifdef _DEBUG
232 
237 DEF_CONSOLE_CMD(ConResetTile)
238 {
239  if (argc == 0) {
240  IConsoleHelp("Reset a tile to bare land. Usage: 'resettile <tile>'");
241  IConsoleHelp("Tile can be either decimal (34161) or hexadecimal (0x4a5B)");
242  return true;
243  }
244 
245  if (argc == 2) {
246  uint32 result;
247  if (GetArgumentInteger(&result, argv[1])) {
248  DoClearSquare((TileIndex)result);
249  return true;
250  }
251  }
252 
253  return false;
254 }
255 #endif /* _DEBUG */
256 
266 DEF_CONSOLE_CMD(ConScrollToTile)
267 {
268  switch (argc) {
269  case 0:
270  IConsoleHelp("Center the screen on a given tile.");
271  IConsoleHelp("Usage: 'scrollto <tile>' or 'scrollto <x> <y>'");
272  IConsoleHelp("Numbers can be either decimal (34161) or hexadecimal (0x4a5B).");
273  return true;
274 
275  case 2: {
276  uint32 result;
277  if (GetArgumentInteger(&result, argv[1])) {
278  if (result >= MapSize()) {
279  IConsolePrint(CC_ERROR, "Tile does not exist");
280  return true;
281  }
283  return true;
284  }
285  break;
286  }
287 
288  case 3: {
289  uint32 x, y;
290  if (GetArgumentInteger(&x, argv[1]) && GetArgumentInteger(&y, argv[2])) {
291  if (x >= MapSizeX() || y >= MapSizeY()) {
292  IConsolePrint(CC_ERROR, "Tile does not exist");
293  return true;
294  }
296  return true;
297  }
298  break;
299  }
300  }
301 
302  return false;
303 }
304 
310 DEF_CONSOLE_CMD(ConSave)
311 {
312  if (argc == 0) {
313  IConsoleHelp("Save the current game. Usage: 'save <filename>'");
314  return true;
315  }
316 
317  if (argc == 2) {
318  char *filename = str_fmt("%s.sav", argv[1]);
319  IConsolePrint(CC_DEFAULT, "Saving map...");
320 
321  if (SaveOrLoad(filename, SLO_SAVE, DFT_GAME_FILE, SAVE_DIR) != SL_OK) {
322  IConsolePrint(CC_ERROR, "Saving map failed");
323  } else {
324  IConsolePrintF(CC_DEFAULT, "Map successfully saved to %s", filename);
325  }
326  free(filename);
327  return true;
328  }
329 
330  return false;
331 }
332 
337 DEF_CONSOLE_CMD(ConSaveConfig)
338 {
339  if (argc == 0) {
340  IConsoleHelp("Saves the configuration for new games to the configuration file, typically 'openttd.cfg'.");
341  IConsoleHelp("It does not save the configuration of the current game to the configuration file.");
342  return true;
343  }
344 
345  SaveToConfig();
346  IConsolePrint(CC_DEFAULT, "Saved config.");
347  return true;
348 }
349 
350 DEF_CONSOLE_CMD(ConLoad)
351 {
352  if (argc == 0) {
353  IConsoleHelp("Load a game by name or index. Usage: 'load <file | number>'");
354  return true;
355  }
356 
357  if (argc != 2) return false;
358 
359  const char *file = argv[1];
360  _console_file_list.ValidateFileList();
361  const FiosItem *item = _console_file_list.FindItem(file);
362  if (item != NULL) {
363  if (GetAbstractFileType(item->type) == FT_SAVEGAME) {
365  _file_to_saveload.SetMode(item->type);
367  _file_to_saveload.SetTitle(item->title);
368  } else {
369  IConsolePrintF(CC_ERROR, "%s: Not a savegame.", file);
370  }
371  } else {
372  IConsolePrintF(CC_ERROR, "%s: No such file or directory.", file);
373  }
374 
375  return true;
376 }
377 
378 
379 DEF_CONSOLE_CMD(ConRemove)
380 {
381  if (argc == 0) {
382  IConsoleHelp("Remove a savegame by name or index. Usage: 'rm <file | number>'");
383  return true;
384  }
385 
386  if (argc != 2) return false;
387 
388  const char *file = argv[1];
389  _console_file_list.ValidateFileList();
390  const FiosItem *item = _console_file_list.FindItem(file);
391  if (item != NULL) {
392  if (!FiosDelete(item->name)) {
393  IConsolePrintF(CC_ERROR, "%s: Failed to delete file", file);
394  }
395  } else {
396  IConsolePrintF(CC_ERROR, "%s: No such file or directory.", file);
397  }
398 
399  _console_file_list.InvalidateFileList();
400  return true;
401 }
402 
403 
404 /* List all the files in the current dir via console */
405 DEF_CONSOLE_CMD(ConListFiles)
406 {
407  if (argc == 0) {
408  IConsoleHelp("List all loadable savegames and directories in the current dir via console. Usage: 'ls | dir'");
409  return true;
410  }
411 
412  _console_file_list.ValidateFileList(true);
413  for (uint i = 0; i < _console_file_list.Length(); i++) {
414  IConsolePrintF(CC_DEFAULT, "%d) %s", i, _console_file_list[i].title);
415  }
416 
417  return true;
418 }
419 
420 /* Change the dir via console */
421 DEF_CONSOLE_CMD(ConChangeDirectory)
422 {
423  if (argc == 0) {
424  IConsoleHelp("Change the dir via console. Usage: 'cd <directory | number>'");
425  return true;
426  }
427 
428  if (argc != 2) return false;
429 
430  const char *file = argv[1];
431  _console_file_list.ValidateFileList(true);
432  const FiosItem *item = _console_file_list.FindItem(file);
433  if (item != NULL) {
434  switch (item->type) {
435  case FIOS_TYPE_DIR: case FIOS_TYPE_DRIVE: case FIOS_TYPE_PARENT:
436  FiosBrowseTo(item);
437  break;
438  default: IConsolePrintF(CC_ERROR, "%s: Not a directory.", file);
439  }
440  } else {
441  IConsolePrintF(CC_ERROR, "%s: No such file or directory.", file);
442  }
443 
444  _console_file_list.InvalidateFileList();
445  return true;
446 }
447 
448 DEF_CONSOLE_CMD(ConPrintWorkingDirectory)
449 {
450  const char *path;
451 
452  if (argc == 0) {
453  IConsoleHelp("Print out the current working directory. Usage: 'pwd'");
454  return true;
455  }
456 
457  /* XXX - Workaround for broken file handling */
458  _console_file_list.ValidateFileList(true);
459  _console_file_list.InvalidateFileList();
460 
461  FiosGetDescText(&path, NULL);
462  IConsolePrint(CC_DEFAULT, path);
463  return true;
464 }
465 
466 DEF_CONSOLE_CMD(ConClearBuffer)
467 {
468  if (argc == 0) {
469  IConsoleHelp("Clear the console buffer. Usage: 'clear'");
470  return true;
471  }
472 
473  IConsoleClearBuffer();
475  return true;
476 }
477 
478 
479 /**********************************
480  * Network Core Console Commands
481  **********************************/
482 #ifdef ENABLE_NETWORK
483 
484 static bool ConKickOrBan(const char *argv, bool ban)
485 {
486  uint n;
487 
488  if (strchr(argv, '.') == NULL && strchr(argv, ':') == NULL) { // banning with ID
489  ClientID client_id = (ClientID)atoi(argv);
490 
491  /* Don't kill the server, or the client doing the rcon. The latter can't be kicked because
492  * kicking frees closes and subsequently free the connection related instances, which we
493  * would be reading from and writing to after returning. So we would read or write data
494  * from freed memory up till the segfault triggers. */
495  if (client_id == CLIENT_ID_SERVER || client_id == _redirect_console_to_client) {
496  IConsolePrintF(CC_ERROR, "ERROR: Silly boy, you can not %s yourself!", ban ? "ban" : "kick");
497  return true;
498  }
499 
501  if (ci == NULL) {
502  IConsoleError("Invalid client");
503  return true;
504  }
505 
506  if (!ban) {
507  /* Kick only this client, not all clients with that IP */
508  NetworkServerKickClient(client_id);
509  return true;
510  }
511 
512  /* When banning, kick+ban all clients with that IP */
513  n = NetworkServerKickOrBanIP(client_id, ban);
514  } else {
515  n = NetworkServerKickOrBanIP(argv, ban);
516  }
517 
518  if (n == 0) {
519  IConsolePrint(CC_DEFAULT, ban ? "Client not online, address added to banlist" : "Client not found");
520  } else {
521  IConsolePrintF(CC_DEFAULT, "%sed %u client(s)", ban ? "Bann" : "Kick", n);
522  }
523 
524  return true;
525 }
526 
527 DEF_CONSOLE_CMD(ConKick)
528 {
529  if (argc == 0) {
530  IConsoleHelp("Kick a client from a network game. Usage: 'kick <ip | client-id>'");
531  IConsoleHelp("For client-id's, see the command 'clients'");
532  return true;
533  }
534 
535  if (argc != 2) return false;
536 
537  return ConKickOrBan(argv[1], false);
538 }
539 
540 DEF_CONSOLE_CMD(ConBan)
541 {
542  if (argc == 0) {
543  IConsoleHelp("Ban a client from a network game. Usage: 'ban <ip | client-id>'");
544  IConsoleHelp("For client-id's, see the command 'clients'");
545  IConsoleHelp("If the client is no longer online, you can still ban his/her IP");
546  return true;
547  }
548 
549  if (argc != 2) return false;
550 
551  return ConKickOrBan(argv[1], true);
552 }
553 
554 DEF_CONSOLE_CMD(ConUnBan)
555 {
556 
557  if (argc == 0) {
558  IConsoleHelp("Unban a client from a network game. Usage: 'unban <ip | client-id>'");
559  IConsoleHelp("For a list of banned IP's, see the command 'banlist'");
560  return true;
561  }
562 
563  if (argc != 2) return false;
564 
565  uint index = (strchr(argv[1], '.') == NULL) ? atoi(argv[1]) : 0;
566  index--;
567  uint i = 0;
568 
569  for (char **iter = _network_ban_list.Begin(); iter != _network_ban_list.End(); iter++, i++) {
570  if (strcmp(_network_ban_list[i], argv[1]) == 0 || index == i) {
572  _network_ban_list.Erase(iter);
573  IConsolePrint(CC_DEFAULT, "IP unbanned.");
574  return true;
575  }
576  }
577 
578  IConsolePrint(CC_DEFAULT, "IP not in ban-list.");
579  return true;
580 }
581 
582 DEF_CONSOLE_CMD(ConBanList)
583 {
584  if (argc == 0) {
585  IConsoleHelp("List the IP's of banned clients: Usage 'banlist'");
586  return true;
587  }
588 
589  IConsolePrint(CC_DEFAULT, "Banlist: ");
590 
591  uint i = 1;
592  for (char **iter = _network_ban_list.Begin(); iter != _network_ban_list.End(); iter++, i++) {
593  IConsolePrintF(CC_DEFAULT, " %d) %s", i, *iter);
594  }
595 
596  return true;
597 }
598 
599 DEF_CONSOLE_CMD(ConPauseGame)
600 {
601  if (argc == 0) {
602  IConsoleHelp("Pause a network game. Usage: 'pause'");
603  return true;
604  }
605 
607  DoCommandP(0, PM_PAUSED_NORMAL, 1, CMD_PAUSE);
608  if (!_networking) IConsolePrint(CC_DEFAULT, "Game paused.");
609  } else {
610  IConsolePrint(CC_DEFAULT, "Game is already paused.");
611  }
612 
613  return true;
614 }
615 
616 DEF_CONSOLE_CMD(ConUnpauseGame)
617 {
618  if (argc == 0) {
619  IConsoleHelp("Unpause a network game. Usage: 'unpause'");
620  return true;
621  }
622 
623  if ((_pause_mode & PM_PAUSED_NORMAL) != PM_UNPAUSED) {
624  DoCommandP(0, PM_PAUSED_NORMAL, 0, CMD_PAUSE);
625  if (!_networking) IConsolePrint(CC_DEFAULT, "Game unpaused.");
626  } else if ((_pause_mode & PM_PAUSED_ERROR) != PM_UNPAUSED) {
627  IConsolePrint(CC_DEFAULT, "Game is in error state and cannot be unpaused via console.");
628  } else if (_pause_mode != PM_UNPAUSED) {
629  IConsolePrint(CC_DEFAULT, "Game cannot be unpaused manually; disable pause_on_join/min_active_clients.");
630  } else {
631  IConsolePrint(CC_DEFAULT, "Game is already unpaused.");
632  }
633 
634  return true;
635 }
636 
637 DEF_CONSOLE_CMD(ConRcon)
638 {
639  if (argc == 0) {
640  IConsoleHelp("Remote control the server from another client. Usage: 'rcon <password> <command>'");
641  IConsoleHelp("Remember to enclose the command in quotes, otherwise only the first parameter is sent");
642  return true;
643  }
644 
645  if (argc < 3) return false;
646 
647  if (_network_server) {
648  IConsoleCmdExec(argv[2]);
649  } else {
650  NetworkClientSendRcon(argv[1], argv[2]);
651  }
652  return true;
653 }
654 
655 DEF_CONSOLE_CMD(ConStatus)
656 {
657  if (argc == 0) {
658  IConsoleHelp("List the status of all clients connected to the server. Usage 'status'");
659  return true;
660  }
661 
663  return true;
664 }
665 
666 DEF_CONSOLE_CMD(ConServerInfo)
667 {
668  if (argc == 0) {
669  IConsoleHelp("List current and maximum client/company limits. Usage 'server_info'");
670  IConsoleHelp("You can change these values by modifying settings 'network.max_clients', 'network.max_companies' and 'network.max_spectators'");
671  return true;
672  }
673 
675  IConsolePrintF(CC_DEFAULT, "Current/maximum companies: %2d/%2d", (int)Company::GetNumItems(), _settings_client.network.max_companies);
676  IConsolePrintF(CC_DEFAULT, "Current/maximum spectators: %2d/%2d", NetworkSpectatorCount(), _settings_client.network.max_spectators);
677 
678  return true;
679 }
680 
681 DEF_CONSOLE_CMD(ConClientNickChange)
682 {
683  if (argc != 3) {
684  IConsoleHelp("Change the nickname of a connected client. Usage: 'client_name <client-id> <new-name>'");
685  IConsoleHelp("For client-id's, see the command 'clients'");
686  return true;
687  }
688 
689  ClientID client_id = (ClientID)atoi(argv[1]);
690 
691  if (client_id == CLIENT_ID_SERVER) {
692  IConsoleError("Please use the command 'name' to change your own name!");
693  return true;
694  }
695 
696  if (NetworkClientInfo::GetByClientID(client_id) == NULL) {
697  IConsoleError("Invalid client");
698  return true;
699  }
700 
701  if (!NetworkServerChangeClientName(client_id, argv[2])) {
702  IConsoleError("Cannot give a client a duplicate name");
703  }
704 
705  return true;
706 }
707 
708 DEF_CONSOLE_CMD(ConJoinCompany)
709 {
710  if (argc < 2) {
711  IConsoleHelp("Request joining another company. Usage: join <company-id> [<password>]");
712  IConsoleHelp("For valid company-id see company list, use 255 for spectator");
713  return true;
714  }
715 
716  CompanyID company_id = (CompanyID)(atoi(argv[1]) <= MAX_COMPANIES ? atoi(argv[1]) - 1 : atoi(argv[1]));
717 
718  /* Check we have a valid company id! */
719  if (!Company::IsValidID(company_id) && company_id != COMPANY_SPECTATOR) {
720  IConsolePrintF(CC_ERROR, "Company does not exist. Company-id must be between 1 and %d.", MAX_COMPANIES);
721  return true;
722  }
723 
724  if (NetworkClientInfo::GetByClientID(_network_own_client_id)->client_playas == company_id) {
725  IConsoleError("You are already there!");
726  return true;
727  }
728 
729  if (company_id == COMPANY_SPECTATOR && NetworkMaxSpectatorsReached()) {
730  IConsoleError("Cannot join spectators, maximum number of spectators reached.");
731  return true;
732  }
733 
734  if (company_id != COMPANY_SPECTATOR && !Company::IsHumanID(company_id)) {
735  IConsoleError("Cannot join AI company.");
736  return true;
737  }
738 
739  /* Check if the company requires a password */
740  if (NetworkCompanyIsPassworded(company_id) && argc < 3) {
741  IConsolePrintF(CC_ERROR, "Company %d requires a password to join.", company_id + 1);
742  return true;
743  }
744 
745  /* non-dedicated server may just do the move! */
746  if (_network_server) {
748  } else {
749  NetworkClientRequestMove(company_id, NetworkCompanyIsPassworded(company_id) ? argv[2] : "");
750  }
751 
752  return true;
753 }
754 
755 DEF_CONSOLE_CMD(ConMoveClient)
756 {
757  if (argc < 3) {
758  IConsoleHelp("Move a client to another company. Usage: move <client-id> <company-id>");
759  IConsoleHelp("For valid client-id see 'clients', for valid company-id see 'companies', use 255 for moving to spectators");
760  return true;
761  }
762 
763  const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID((ClientID)atoi(argv[1]));
764  CompanyID company_id = (CompanyID)(atoi(argv[2]) <= MAX_COMPANIES ? atoi(argv[2]) - 1 : atoi(argv[2]));
765 
766  /* check the client exists */
767  if (ci == NULL) {
768  IConsoleError("Invalid client-id, check the command 'clients' for valid client-id's.");
769  return true;
770  }
771 
772  if (!Company::IsValidID(company_id) && company_id != COMPANY_SPECTATOR) {
773  IConsolePrintF(CC_ERROR, "Company does not exist. Company-id must be between 1 and %d.", MAX_COMPANIES);
774  return true;
775  }
776 
777  if (company_id != COMPANY_SPECTATOR && !Company::IsHumanID(company_id)) {
778  IConsoleError("You cannot move clients to AI companies.");
779  return true;
780  }
781 
783  IConsoleError("Silly boy, you cannot move the server!");
784  return true;
785  }
786 
787  if (ci->client_playas == company_id) {
788  IConsoleError("You cannot move someone to where he/she already is!");
789  return true;
790  }
791 
792  /* we are the server, so force the update */
793  NetworkServerDoMove(ci->client_id, company_id);
794 
795  return true;
796 }
797 
798 DEF_CONSOLE_CMD(ConResetCompany)
799 {
800  if (argc == 0) {
801  IConsoleHelp("Remove an idle company from the game. Usage: 'reset_company <company-id>'");
802  IConsoleHelp("For company-id's, see the list of companies from the dropdown menu. Company 1 is 1, etc.");
803  return true;
804  }
805 
806  if (argc != 2) return false;
807 
808  CompanyID index = (CompanyID)(atoi(argv[1]) - 1);
809 
810  /* Check valid range */
811  if (!Company::IsValidID(index)) {
812  IConsolePrintF(CC_ERROR, "Company does not exist. Company-id must be between 1 and %d.", MAX_COMPANIES);
813  return true;
814  }
815 
816  if (!Company::IsHumanID(index)) {
817  IConsoleError("Company is owned by an AI.");
818  return true;
819  }
820 
821  if (NetworkCompanyHasClients(index)) {
822  IConsoleError("Cannot remove company: a client is connected to that company.");
823  return false;
824  }
826  if (ci->client_playas == index) {
827  IConsoleError("Cannot remove company: the server is connected to that company.");
828  return true;
829  }
830 
831  /* It is safe to remove this company */
832  DoCommandP(0, 2 | index << 16, CRR_MANUAL, CMD_COMPANY_CTRL);
833  IConsolePrint(CC_DEFAULT, "Company deleted.");
834 
835  return true;
836 }
837 
838 DEF_CONSOLE_CMD(ConNetworkClients)
839 {
840  if (argc == 0) {
841  IConsoleHelp("Get a list of connected clients including their ID, name, company-id, and IP. Usage: 'clients'");
842  return true;
843  }
844 
846 
847  return true;
848 }
849 
850 DEF_CONSOLE_CMD(ConNetworkReconnect)
851 {
852  if (argc == 0) {
853  IConsoleHelp("Reconnect to server to which you were connected last time. Usage: 'reconnect [<company>]'");
854  IConsoleHelp("Company 255 is spectator (default, if not specified), 0 means creating new company.");
855  IConsoleHelp("All others are a certain company with Company 1 being #1");
856  return true;
857  }
858 
859  CompanyID playas = (argc >= 2) ? (CompanyID)atoi(argv[1]) : COMPANY_SPECTATOR;
860  switch (playas) {
861  case 0: playas = COMPANY_NEW_COMPANY; break;
862  case COMPANY_SPECTATOR: /* nothing to do */ break;
863  default:
864  /* From a user pov 0 is a new company, internally it's different and all
865  * companies are offset by one to ease up on users (eg companies 1-8 not 0-7) */
866  playas--;
867  if (playas < COMPANY_FIRST || playas >= MAX_COMPANIES) return false;
868  break;
869  }
870 
872  IConsolePrint(CC_DEFAULT, "No server for reconnecting.");
873  return true;
874  }
875 
876  /* Don't resolve the address first, just print it directly as it comes from the config file. */
878 
880  return true;
881 }
882 
883 DEF_CONSOLE_CMD(ConNetworkConnect)
884 {
885  if (argc == 0) {
886  IConsoleHelp("Connect to a remote OTTD server and join the game. Usage: 'connect <ip>'");
887  IConsoleHelp("IP can contain port and company: 'IP[:Port][#Company]', eg: 'server.ottd.org:443#2'");
888  IConsoleHelp("Company #255 is spectator all others are a certain company with Company 1 being #1");
889  return true;
890  }
891 
892  if (argc < 2) return false;
893  if (_networking) NetworkDisconnect(); // we are in network-mode, first close it!
894 
895  const char *port = NULL;
896  const char *company = NULL;
897  char *ip = argv[1];
898  /* Default settings: default port and new company */
899  uint16 rport = NETWORK_DEFAULT_PORT;
900  CompanyID join_as = COMPANY_NEW_COMPANY;
901 
902  ParseConnectionString(&company, &port, ip);
903 
904  IConsolePrintF(CC_DEFAULT, "Connecting to %s...", ip);
905  if (company != NULL) {
906  join_as = (CompanyID)atoi(company);
907  IConsolePrintF(CC_DEFAULT, " company-no: %d", join_as);
908 
909  /* From a user pov 0 is a new company, internally it's different and all
910  * companies are offset by one to ease up on users (eg companies 1-8 not 0-7) */
911  if (join_as != COMPANY_SPECTATOR) {
912  if (join_as > MAX_COMPANIES) return false;
913  join_as--;
914  }
915  }
916  if (port != NULL) {
917  rport = atoi(port);
918  IConsolePrintF(CC_DEFAULT, " port: %s", port);
919  }
920 
921  NetworkClientConnectGame(NetworkAddress(ip, rport), join_as);
922 
923  return true;
924 }
925 
926 #endif /* ENABLE_NETWORK */
927 
928 /*********************************
929  * script file console commands
930  *********************************/
931 
932 DEF_CONSOLE_CMD(ConExec)
933 {
934  if (argc == 0) {
935  IConsoleHelp("Execute a local script file. Usage: 'exec <script> <?>'");
936  return true;
937  }
938 
939  if (argc < 2) return false;
940 
941  FILE *script_file = FioFOpenFile(argv[1], "r", BASE_DIR);
942 
943  if (script_file == NULL) {
944  if (argc == 2 || atoi(argv[2]) != 0) IConsoleError("script file not found");
945  return true;
946  }
947 
948  _script_running = true;
949 
950  char cmdline[ICON_CMDLN_SIZE];
951  while (_script_running && fgets(cmdline, sizeof(cmdline), script_file) != NULL) {
952  /* Remove newline characters from the executing script */
953  for (char *cmdptr = cmdline; *cmdptr != '\0'; cmdptr++) {
954  if (*cmdptr == '\n' || *cmdptr == '\r') {
955  *cmdptr = '\0';
956  break;
957  }
958  }
959  IConsoleCmdExec(cmdline);
960  }
961 
962  if (ferror(script_file)) {
963  IConsoleError("Encountered error while trying to read from script file");
964  }
965 
966  _script_running = false;
967  FioFCloseFile(script_file);
968  return true;
969 }
970 
971 DEF_CONSOLE_CMD(ConReturn)
972 {
973  if (argc == 0) {
974  IConsoleHelp("Stop executing a running script. Usage: 'return'");
975  return true;
976  }
977 
978  _script_running = false;
979  return true;
980 }
981 
982 /*****************************
983  * default console commands
984  ******************************/
985 extern bool CloseConsoleLogIfActive();
986 
987 DEF_CONSOLE_CMD(ConScript)
988 {
989  extern FILE *_iconsole_output_file;
990 
991  if (argc == 0) {
992  IConsoleHelp("Start or stop logging console output to a file. Usage: 'script <filename>'");
993  IConsoleHelp("If filename is omitted, a running log is stopped if it is active");
994  return true;
995  }
996 
997  if (!CloseConsoleLogIfActive()) {
998  if (argc < 2) return false;
999 
1000  IConsolePrintF(CC_DEFAULT, "file output started to: %s", argv[1]);
1001  _iconsole_output_file = fopen(argv[1], "ab");
1002  if (_iconsole_output_file == NULL) IConsoleError("could not open file");
1003  }
1004 
1005  return true;
1006 }
1007 
1008 
1009 DEF_CONSOLE_CMD(ConEcho)
1010 {
1011  if (argc == 0) {
1012  IConsoleHelp("Print back the first argument to the console. Usage: 'echo <arg>'");
1013  return true;
1014  }
1015 
1016  if (argc < 2) return false;
1017  IConsolePrint(CC_DEFAULT, argv[1]);
1018  return true;
1019 }
1020 
1021 DEF_CONSOLE_CMD(ConEchoC)
1022 {
1023  if (argc == 0) {
1024  IConsoleHelp("Print back the first argument to the console in a given colour. Usage: 'echoc <colour> <arg2>'");
1025  return true;
1026  }
1027 
1028  if (argc < 3) return false;
1029  IConsolePrint((TextColour)Clamp(atoi(argv[1]), TC_BEGIN, TC_END - 1), argv[2]);
1030  return true;
1031 }
1032 
1033 DEF_CONSOLE_CMD(ConNewGame)
1034 {
1035  if (argc == 0) {
1036  IConsoleHelp("Start a new game. Usage: 'newgame [seed]'");
1037  IConsoleHelp("The server can force a new game using 'newgame'; any client joined will rejoin after the server is done generating the new game.");
1038  return true;
1039  }
1040 
1041  StartNewGameWithoutGUI((argc == 2) ? strtoul(argv[1], NULL, 10) : GENERATE_NEW_SEED);
1042  return true;
1043 }
1044 
1045 DEF_CONSOLE_CMD(ConRestart)
1046 {
1047  if (argc == 0) {
1048  IConsoleHelp("Restart game. Usage: 'restart'");
1049  IConsoleHelp("Restarts a game. It tries to reproduce the exact same map as the game started with.");
1050  IConsoleHelp("However:");
1051  IConsoleHelp(" * restarting games started in another version might create another map due to difference in map generation");
1052  IConsoleHelp(" * restarting games based on scenarios, loaded games or heightmaps will start a new game based on the settings stored in the scenario/savegame");
1053  return true;
1054  }
1055 
1056  /* Don't copy the _newgame pointers to the real pointers, so call SwitchToMode directly */
1060  return true;
1061 }
1062 
1068 static void PrintLineByLine(char *buf)
1069 {
1070  char *p = buf;
1071  /* Print output line by line */
1072  for (char *p2 = buf; *p2 != '\0'; p2++) {
1073  if (*p2 == '\n') {
1074  *p2 = '\0';
1075  IConsolePrintF(CC_DEFAULT, "%s", p);
1076  p = p2 + 1;
1077  }
1078  }
1079 }
1080 
1081 DEF_CONSOLE_CMD(ConListAILibs)
1082 {
1083  char buf[4096];
1084  AI::GetConsoleLibraryList(buf, lastof(buf));
1085 
1086  PrintLineByLine(buf);
1087 
1088  return true;
1089 }
1090 
1091 DEF_CONSOLE_CMD(ConListAI)
1092 {
1093  char buf[4096];
1094  AI::GetConsoleList(buf, lastof(buf));
1095 
1096  PrintLineByLine(buf);
1097 
1098  return true;
1099 }
1100 
1101 DEF_CONSOLE_CMD(ConListGameLibs)
1102 {
1103  char buf[4096];
1105 
1106  PrintLineByLine(buf);
1107 
1108  return true;
1109 }
1110 
1111 DEF_CONSOLE_CMD(ConListGame)
1112 {
1113  char buf[4096];
1114  Game::GetConsoleList(buf, lastof(buf));
1115 
1116  PrintLineByLine(buf);
1117 
1118  return true;
1119 }
1120 
1121 DEF_CONSOLE_CMD(ConStartAI)
1122 {
1123  if (argc == 0 || argc > 3) {
1124  IConsoleHelp("Start a new AI. Usage: 'start_ai [<AI>] [<settings>]'");
1125  IConsoleHelp("Start a new AI. If <AI> is given, it starts that specific AI (if found).");
1126  IConsoleHelp("If <settings> is given, it is parsed and the AI settings are set to that.");
1127  return true;
1128  }
1129 
1130  if (_game_mode != GM_NORMAL) {
1131  IConsoleWarning("AIs can only be managed in a game.");
1132  return true;
1133  }
1134 
1136  IConsoleWarning("Can't start a new AI (no more free slots).");
1137  return true;
1138  }
1139  if (_networking && !_network_server) {
1140  IConsoleWarning("Only the server can start a new AI.");
1141  return true;
1142  }
1144  IConsoleWarning("AIs are not allowed in multiplayer by configuration.");
1145  IConsoleWarning("Switch AI -> AI in multiplayer to True.");
1146  return true;
1147  }
1148  if (!AI::CanStartNew()) {
1149  IConsoleWarning("Can't start a new AI.");
1150  return true;
1151  }
1152 
1153  int n = 0;
1154  Company *c;
1155  /* Find the next free slot */
1156  FOR_ALL_COMPANIES(c) {
1157  if (c->index != n) break;
1158  n++;
1159  }
1160 
1161  AIConfig *config = AIConfig::GetConfig((CompanyID)n);
1162  if (argc >= 2) {
1163  config->Change(argv[1], -1, true);
1164  if (!config->HasScript()) {
1165  IConsoleWarning("Failed to load the specified AI");
1166  return true;
1167  }
1168  if (argc == 3) {
1169  config->StringToSettings(argv[2]);
1170  }
1171  }
1172 
1173  /* Start a new AI company */
1174  DoCommandP(0, 1 | INVALID_COMPANY << 16, 0, CMD_COMPANY_CTRL);
1175 
1176  return true;
1177 }
1178 
1179 DEF_CONSOLE_CMD(ConReloadAI)
1180 {
1181  if (argc != 2) {
1182  IConsoleHelp("Reload an AI. Usage: 'reload_ai <company-id>'");
1183  IConsoleHelp("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.");
1184  return true;
1185  }
1186 
1187  if (_game_mode != GM_NORMAL) {
1188  IConsoleWarning("AIs can only be managed in a game.");
1189  return true;
1190  }
1191 
1192  if (_networking && !_network_server) {
1193  IConsoleWarning("Only the server can reload an AI.");
1194  return true;
1195  }
1196 
1197  CompanyID company_id = (CompanyID)(atoi(argv[1]) - 1);
1198  if (!Company::IsValidID(company_id)) {
1199  IConsolePrintF(CC_DEFAULT, "Unknown company. Company range is between 1 and %d.", MAX_COMPANIES);
1200  return true;
1201  }
1202 
1203  if (Company::IsHumanID(company_id)) {
1204  IConsoleWarning("Company is not controlled by an AI.");
1205  return true;
1206  }
1207 
1208  /* First kill the company of the AI, then start a new one. This should start the current AI again */
1209  DoCommandP(0, 2 | company_id << 16, CRR_MANUAL, CMD_COMPANY_CTRL);
1210  DoCommandP(0, 1 | company_id << 16, 0, CMD_COMPANY_CTRL);
1211  IConsolePrint(CC_DEFAULT, "AI reloaded.");
1212 
1213  return true;
1214 }
1215 
1216 DEF_CONSOLE_CMD(ConStopAI)
1217 {
1218  if (argc != 2) {
1219  IConsoleHelp("Stop an AI. Usage: 'stop_ai <company-id>'");
1220  IConsoleHelp("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.");
1221  return true;
1222  }
1223 
1224  if (_game_mode != GM_NORMAL) {
1225  IConsoleWarning("AIs can only be managed in a game.");
1226  return true;
1227  }
1228 
1229  if (_networking && !_network_server) {
1230  IConsoleWarning("Only the server can stop an AI.");
1231  return true;
1232  }
1233 
1234  CompanyID company_id = (CompanyID)(atoi(argv[1]) - 1);
1235  if (!Company::IsValidID(company_id)) {
1236  IConsolePrintF(CC_DEFAULT, "Unknown company. Company range is between 1 and %d.", MAX_COMPANIES);
1237  return true;
1238  }
1239 
1240  if (Company::IsHumanID(company_id) || company_id == _local_company) {
1241  IConsoleWarning("Company is not controlled by an AI.");
1242  return true;
1243  }
1244 
1245  /* Now kill the company of the AI. */
1246  DoCommandP(0, 2 | company_id << 16, CRR_MANUAL, CMD_COMPANY_CTRL);
1247  IConsolePrint(CC_DEFAULT, "AI stopped, company deleted.");
1248 
1249  return true;
1250 }
1251 
1252 DEF_CONSOLE_CMD(ConRescanAI)
1253 {
1254  if (argc == 0) {
1255  IConsoleHelp("Rescan the AI dir for scripts. Usage: 'rescan_ai'");
1256  return true;
1257  }
1258 
1259  if (_networking && !_network_server) {
1260  IConsoleWarning("Only the server can rescan the AI dir for scripts.");
1261  return true;
1262  }
1263 
1264  AI::Rescan();
1265 
1266  return true;
1267 }
1268 
1269 DEF_CONSOLE_CMD(ConRescanGame)
1270 {
1271  if (argc == 0) {
1272  IConsoleHelp("Rescan the Game Script dir for scripts. Usage: 'rescan_game'");
1273  return true;
1274  }
1275 
1276  if (_networking && !_network_server) {
1277  IConsoleWarning("Only the server can rescan the Game Script dir for scripts.");
1278  return true;
1279  }
1280 
1281  Game::Rescan();
1282 
1283  return true;
1284 }
1285 
1286 DEF_CONSOLE_CMD(ConRescanNewGRF)
1287 {
1288  if (argc == 0) {
1289  IConsoleHelp("Rescan the data dir for NewGRFs. Usage: 'rescan_newgrf'");
1290  return true;
1291  }
1292 
1293  ScanNewGRFFiles(NULL);
1294 
1295  return true;
1296 }
1297 
1298 DEF_CONSOLE_CMD(ConGetSeed)
1299 {
1300  if (argc == 0) {
1301  IConsoleHelp("Returns the seed used to create this game. Usage: 'getseed'");
1302  IConsoleHelp("The seed can be used to reproduce the exact same map as the game started with.");
1303  return true;
1304  }
1305 
1307  return true;
1308 }
1309 
1310 DEF_CONSOLE_CMD(ConGetDate)
1311 {
1312  if (argc == 0) {
1313  IConsoleHelp("Returns the current date (day-month-year) of the game. Usage: 'getdate'");
1314  return true;
1315  }
1316 
1317  YearMonthDay ymd;
1318  ConvertDateToYMD(_date, &ymd);
1319  IConsolePrintF(CC_DEFAULT, "Date: %d-%d-%d", ymd.day, ymd.month + 1, ymd.year);
1320  return true;
1321 }
1322 
1323 
1324 DEF_CONSOLE_CMD(ConAlias)
1325 {
1326  IConsoleAlias *alias;
1327 
1328  if (argc == 0) {
1329  IConsoleHelp("Add a new alias, or redefine the behaviour of an existing alias . Usage: 'alias <name> <command>'");
1330  return true;
1331  }
1332 
1333  if (argc < 3) return false;
1334 
1335  alias = IConsoleAliasGet(argv[1]);
1336  if (alias == NULL) {
1337  IConsoleAliasRegister(argv[1], argv[2]);
1338  } else {
1339  free(alias->cmdline);
1340  alias->cmdline = stredup(argv[2]);
1341  }
1342  return true;
1343 }
1344 
1345 DEF_CONSOLE_CMD(ConScreenShot)
1346 {
1347  if (argc == 0) {
1348  IConsoleHelp("Create a screenshot of the game. Usage: 'screenshot [big | giant | no_con] [file name]'");
1349  IConsoleHelp("'big' makes a zoomed-in screenshot of the visible area, 'giant' makes a screenshot of the "
1350  "whole map, 'no_con' hides the console to create the screenshot. 'big' or 'giant' "
1351  "screenshots are always drawn without console");
1352  return true;
1353  }
1354 
1355  if (argc > 3) return false;
1356 
1357  ScreenshotType type = SC_VIEWPORT;
1358  const char *name = NULL;
1359 
1360  if (argc > 1) {
1361  if (strcmp(argv[1], "big") == 0) {
1362  /* screenshot big [filename] */
1363  type = SC_ZOOMEDIN;
1364  if (argc > 2) name = argv[2];
1365  } else if (strcmp(argv[1], "giant") == 0) {
1366  /* screenshot giant [filename] */
1367  type = SC_WORLD;
1368  if (argc > 2) name = argv[2];
1369  } else if (strcmp(argv[1], "no_con") == 0) {
1370  /* screenshot no_con [filename] */
1371  IConsoleClose();
1372  if (argc > 2) name = argv[2];
1373  } else if (argc == 2) {
1374  /* screenshot filename */
1375  name = argv[1];
1376  } else {
1377  /* screenshot argv[1] argv[2] - invalid */
1378  return false;
1379  }
1380  }
1381 
1382  MakeScreenshot(type, name);
1383  return true;
1384 }
1385 
1386 DEF_CONSOLE_CMD(ConInfoCmd)
1387 {
1388  if (argc == 0) {
1389  IConsoleHelp("Print out debugging information about a command. Usage: 'info_cmd <cmd>'");
1390  return true;
1391  }
1392 
1393  if (argc < 2) return false;
1394 
1395  const IConsoleCmd *cmd = IConsoleCmdGet(argv[1]);
1396  if (cmd == NULL) {
1397  IConsoleError("the given command was not found");
1398  return true;
1399  }
1400 
1401  IConsolePrintF(CC_DEFAULT, "command name: %s", cmd->name);
1402  IConsolePrintF(CC_DEFAULT, "command proc: %p", cmd->proc);
1403 
1404  if (cmd->hook != NULL) IConsoleWarning("command is hooked");
1405 
1406  return true;
1407 }
1408 
1409 DEF_CONSOLE_CMD(ConDebugLevel)
1410 {
1411  if (argc == 0) {
1412  IConsoleHelp("Get/set the default debugging level for the game. Usage: 'debug_level [<level>]'");
1413  IConsoleHelp("Level can be any combination of names, levels. Eg 'net=5 ms=4'. Remember to enclose it in \"'s");
1414  return true;
1415  }
1416 
1417  if (argc > 2) return false;
1418 
1419  if (argc == 1) {
1420  IConsolePrintF(CC_DEFAULT, "Current debug-level: '%s'", GetDebugString());
1421  } else {
1422  SetDebugString(argv[1]);
1423  }
1424 
1425  return true;
1426 }
1427 
1428 DEF_CONSOLE_CMD(ConExit)
1429 {
1430  if (argc == 0) {
1431  IConsoleHelp("Exit the game. Usage: 'exit'");
1432  return true;
1433  }
1434 
1435  if (_game_mode == GM_NORMAL && _settings_client.gui.autosave_on_exit) DoExitSave();
1436 
1437  _exit_game = true;
1438  return true;
1439 }
1440 
1441 DEF_CONSOLE_CMD(ConPart)
1442 {
1443  if (argc == 0) {
1444  IConsoleHelp("Leave the currently joined/running game (only ingame). Usage: 'part'");
1445  return true;
1446  }
1447 
1448  if (_game_mode != GM_NORMAL) return false;
1449 
1451  return true;
1452 }
1453 
1454 DEF_CONSOLE_CMD(ConHelp)
1455 {
1456  if (argc == 2) {
1457  const IConsoleCmd *cmd;
1458  const IConsoleAlias *alias;
1459 
1460  RemoveUnderscores(argv[1]);
1461  cmd = IConsoleCmdGet(argv[1]);
1462  if (cmd != NULL) {
1463  cmd->proc(0, NULL);
1464  return true;
1465  }
1466 
1467  alias = IConsoleAliasGet(argv[1]);
1468  if (alias != NULL) {
1469  cmd = IConsoleCmdGet(alias->cmdline);
1470  if (cmd != NULL) {
1471  cmd->proc(0, NULL);
1472  return true;
1473  }
1474  IConsolePrintF(CC_ERROR, "ERROR: alias is of special type, please see its execution-line: '%s'", alias->cmdline);
1475  return true;
1476  }
1477 
1478  IConsoleError("command not found");
1479  return true;
1480  }
1481 
1482  IConsolePrint(CC_WARNING, " ---- OpenTTD Console Help ---- ");
1483  IConsolePrint(CC_DEFAULT, " - commands: [command to list all commands: list_cmds]");
1484  IConsolePrint(CC_DEFAULT, " call commands with '<command> <arg2> <arg3>...'");
1485  IConsolePrint(CC_DEFAULT, " - to assign strings, or use them as arguments, enclose it within quotes");
1486  IConsolePrint(CC_DEFAULT, " like this: '<command> \"string argument with spaces\"'");
1487  IConsolePrint(CC_DEFAULT, " - use 'help <command>' to get specific information");
1488  IConsolePrint(CC_DEFAULT, " - scroll console output with shift + (up | down | pageup | pagedown)");
1489  IConsolePrint(CC_DEFAULT, " - scroll console input history with the up or down arrows");
1491  return true;
1492 }
1493 
1494 DEF_CONSOLE_CMD(ConListCommands)
1495 {
1496  if (argc == 0) {
1497  IConsoleHelp("List all registered commands. Usage: 'list_cmds [<pre-filter>]'");
1498  return true;
1499  }
1500 
1501  for (const IConsoleCmd *cmd = _iconsole_cmds; cmd != NULL; cmd = cmd->next) {
1502  if (argv[1] == NULL || strstr(cmd->name, argv[1]) != NULL) {
1503  if (cmd->hook == NULL || cmd->hook(false) != CHR_HIDE) IConsolePrintF(CC_DEFAULT, "%s", cmd->name);
1504  }
1505  }
1506 
1507  return true;
1508 }
1509 
1510 DEF_CONSOLE_CMD(ConListAliases)
1511 {
1512  if (argc == 0) {
1513  IConsoleHelp("List all registered aliases. Usage: 'list_aliases [<pre-filter>]'");
1514  return true;
1515  }
1516 
1517  for (const IConsoleAlias *alias = _iconsole_aliases; alias != NULL; alias = alias->next) {
1518  if (argv[1] == NULL || strstr(alias->name, argv[1]) != NULL) {
1519  IConsolePrintF(CC_DEFAULT, "%s => %s", alias->name, alias->cmdline);
1520  }
1521  }
1522 
1523  return true;
1524 }
1525 
1526 DEF_CONSOLE_CMD(ConCompanies)
1527 {
1528  if (argc == 0) {
1529  IConsoleHelp("List the details of all companies in the game. Usage 'companies'");
1530  return true;
1531  }
1532 
1533  Company *c;
1534  FOR_ALL_COMPANIES(c) {
1535  /* Grab the company name */
1536  char company_name[512];
1537  SetDParam(0, c->index);
1538  GetString(company_name, STR_COMPANY_NAME, lastof(company_name));
1539 
1540  const char *password_state = "";
1541  if (c->is_ai) {
1542  password_state = "AI";
1543  }
1544 #ifdef ENABLE_NETWORK
1545  else if (_network_server) {
1546  password_state = StrEmpty(_network_company_states[c->index].password) ? "unprotected" : "protected";
1547  }
1548 #endif
1549 
1550  char colour[512];
1551  GetString(colour, STR_COLOUR_DARK_BLUE + _company_colours[c->index], lastof(colour));
1552  IConsolePrintF(CC_INFO, "#:%d(%s) Company Name: '%s' Year Founded: %d Money: " OTTD_PRINTF64 " Loan: " OTTD_PRINTF64 " Value: " OTTD_PRINTF64 " (T:%d, R:%d, P:%d, S:%d) %s",
1553  c->index + 1, colour, company_name,
1554  c->inaugurated_year, (int64)c->money, (int64)c->current_loan, (int64)CalculateCompanyValue(c),
1559  password_state);
1560  }
1561 
1562  return true;
1563 }
1564 
1565 #ifdef ENABLE_NETWORK
1566 
1567 DEF_CONSOLE_CMD(ConSay)
1568 {
1569  if (argc == 0) {
1570  IConsoleHelp("Chat to your fellow players in a multiplayer game. Usage: 'say \"<msg>\"'");
1571  return true;
1572  }
1573 
1574  if (argc != 2) return false;
1575 
1576  if (!_network_server) {
1577  NetworkClientSendChat(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0 /* param does not matter */, argv[1]);
1578  } else {
1579  bool from_admin = (_redirect_console_to_admin < INVALID_ADMIN_ID);
1580  NetworkServerSendChat(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0, argv[1], CLIENT_ID_SERVER, from_admin);
1581  }
1582 
1583  return true;
1584 }
1585 
1586 DEF_CONSOLE_CMD(ConSayCompany)
1587 {
1588  if (argc == 0) {
1589  IConsoleHelp("Chat to a certain company in a multiplayer game. Usage: 'say_company <company-no> \"<msg>\"'");
1590  IConsoleHelp("CompanyNo is the company that plays as company <companyno>, 1 through max_companies");
1591  return true;
1592  }
1593 
1594  if (argc != 3) return false;
1595 
1596  CompanyID company_id = (CompanyID)(atoi(argv[1]) - 1);
1597  if (!Company::IsValidID(company_id)) {
1598  IConsolePrintF(CC_DEFAULT, "Unknown company. Company range is between 1 and %d.", MAX_COMPANIES);
1599  return true;
1600  }
1601 
1602  if (!_network_server) {
1603  NetworkClientSendChat(NETWORK_ACTION_CHAT_COMPANY, DESTTYPE_TEAM, company_id, argv[2]);
1604  } else {
1605  bool from_admin = (_redirect_console_to_admin < INVALID_ADMIN_ID);
1606  NetworkServerSendChat(NETWORK_ACTION_CHAT_COMPANY, DESTTYPE_TEAM, company_id, argv[2], CLIENT_ID_SERVER, from_admin);
1607  }
1608 
1609  return true;
1610 }
1611 
1612 DEF_CONSOLE_CMD(ConSayClient)
1613 {
1614  if (argc == 0) {
1615  IConsoleHelp("Chat to a certain client in a multiplayer game. Usage: 'say_client <client-no> \"<msg>\"'");
1616  IConsoleHelp("For client-id's, see the command 'clients'");
1617  return true;
1618  }
1619 
1620  if (argc != 3) return false;
1621 
1622  if (!_network_server) {
1623  NetworkClientSendChat(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, atoi(argv[1]), argv[2]);
1624  } else {
1625  bool from_admin = (_redirect_console_to_admin < INVALID_ADMIN_ID);
1626  NetworkServerSendChat(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, atoi(argv[1]), argv[2], CLIENT_ID_SERVER, from_admin);
1627  }
1628 
1629  return true;
1630 }
1631 
1632 DEF_CONSOLE_CMD(ConCompanyPassword)
1633 {
1634  if (argc == 0) {
1635  const char *helpmsg;
1636 
1637  if (_network_dedicated) {
1638  helpmsg = "Change the password of a company. Usage: 'company_pw <company-no> \"<password>\"";
1639  } else if (_network_server) {
1640  helpmsg = "Change the password of your or any other company. Usage: 'company_pw [<company-no>] \"<password>\"'";
1641  } else {
1642  helpmsg = "Change the password of your company. Usage: 'company_pw \"<password>\"'";
1643  }
1644 
1645  IConsoleHelp(helpmsg);
1646  IConsoleHelp("Use \"*\" to disable the password.");
1647  return true;
1648  }
1649 
1650  CompanyID company_id;
1651  const char *password;
1652  const char *errormsg;
1653 
1654  if (argc == 2) {
1655  company_id = _local_company;
1656  password = argv[1];
1657  errormsg = "You have to own a company to make use of this command.";
1658  } else if (argc == 3 && _network_server) {
1659  company_id = (CompanyID)(atoi(argv[1]) - 1);
1660  password = argv[2];
1661  errormsg = "You have to specify the ID of a valid human controlled company.";
1662  } else {
1663  return false;
1664  }
1665 
1666  if (!Company::IsValidHumanID(company_id)) {
1667  IConsoleError(errormsg);
1668  return false;
1669  }
1670 
1671  password = NetworkChangeCompanyPassword(company_id, password);
1672 
1673  if (StrEmpty(password)) {
1674  IConsolePrintF(CC_WARNING, "Company password cleared");
1675  } else {
1676  IConsolePrintF(CC_WARNING, "Company password changed to: %s", password);
1677  }
1678 
1679  return true;
1680 }
1681 
1682 /* Content downloading only is available with ZLIB */
1683 #if defined(WITH_ZLIB)
1684 #include "network/network_content.h"
1685 
1687 static ContentType StringToContentType(const char *str)
1688 {
1689  static const char * const inv_lookup[] = { "", "base", "newgrf", "ai", "ailib", "scenario", "heightmap" };
1690  for (uint i = 1 /* there is no type 0 */; i < lengthof(inv_lookup); i++) {
1691  if (strcasecmp(str, inv_lookup[i]) == 0) return (ContentType)i;
1692  }
1693  return CONTENT_TYPE_END;
1694 }
1695 
1698  void OnConnect(bool success)
1699  {
1700  IConsolePrintF(CC_DEFAULT, "Content server connection %s", success ? "established" : "failed");
1701  }
1702 
1704  {
1705  IConsolePrintF(CC_DEFAULT, "Content server connection closed");
1706  }
1707 
1709  {
1710  IConsolePrintF(CC_DEFAULT, "Completed download of %d", cid);
1711  }
1712 };
1713 
1718 static void OutputContentState(const ContentInfo *const ci)
1719 {
1720  static const char * const types[] = { "Base graphics", "NewGRF", "AI", "AI library", "Scenario", "Heightmap", "Base sound", "Base music", "Game script", "GS library" };
1721  assert_compile(lengthof(types) == CONTENT_TYPE_END - CONTENT_TYPE_BEGIN);
1722  static const char * const states[] = { "Not selected", "Selected", "Dep Selected", "Installed", "Unknown" };
1723  static const TextColour state_to_colour[] = { CC_COMMAND, CC_INFO, CC_INFO, CC_WHITE, CC_ERROR };
1724 
1725  char buf[sizeof(ci->md5sum) * 2 + 1];
1726  md5sumToString(buf, lastof(buf), ci->md5sum);
1727  IConsolePrintF(state_to_colour[ci->state], "%d, %s, %s, %s, %08X, %s", ci->id, types[ci->type - 1], states[ci->state], ci->name, ci->unique_id, buf);
1728 }
1729 
1730 DEF_CONSOLE_CMD(ConContent)
1731 {
1732  static ContentCallback *cb = NULL;
1733  if (cb == NULL) {
1734  cb = new ConsoleContentCallback();
1736  }
1737 
1738  if (argc <= 1) {
1739  IConsoleHelp("Query, select and download content. Usage: 'content update|upgrade|select [all|id]|unselect [all|id]|state [filter]|download'");
1740  IConsoleHelp(" update: get a new list of downloadable content; must be run first");
1741  IConsoleHelp(" upgrade: select all items that are upgrades");
1742  IConsoleHelp(" select: select a specific item given by its id or 'all' to select all. If no parameter is given, all selected content will be listed");
1743  IConsoleHelp(" unselect: unselect a specific item given by its id or 'all' to unselect all");
1744  IConsoleHelp(" state: show the download/select state of all downloadable content. Optionally give a filter string");
1745  IConsoleHelp(" download: download all content you've selected");
1746  return true;
1747  }
1748 
1749  if (strcasecmp(argv[1], "update") == 0) {
1751  return true;
1752  }
1753 
1754  if (strcasecmp(argv[1], "upgrade") == 0) {
1756  return true;
1757  }
1758 
1759  if (strcasecmp(argv[1], "select") == 0) {
1760  if (argc <= 2) {
1761  /* List selected content */
1762  IConsolePrintF(CC_WHITE, "id, type, state, name");
1764  if ((*iter)->state != ContentInfo::SELECTED && (*iter)->state != ContentInfo::AUTOSELECTED) continue;
1765  OutputContentState(*iter);
1766  }
1767  } else if (strcasecmp(argv[2], "all") == 0) {
1769  } else {
1770  _network_content_client.Select((ContentID)atoi(argv[2]));
1771  }
1772  return true;
1773  }
1774 
1775  if (strcasecmp(argv[1], "unselect") == 0) {
1776  if (argc <= 2) {
1777  IConsoleError("You must enter the id.");
1778  return false;
1779  }
1780  if (strcasecmp(argv[2], "all") == 0) {
1782  } else {
1783  _network_content_client.Unselect((ContentID)atoi(argv[2]));
1784  }
1785  return true;
1786  }
1787 
1788  if (strcasecmp(argv[1], "state") == 0) {
1789  IConsolePrintF(CC_WHITE, "id, type, state, name");
1791  if (argc > 2 && strcasestr((*iter)->name, argv[2]) == NULL) continue;
1792  OutputContentState(*iter);
1793  }
1794  return true;
1795  }
1796 
1797  if (strcasecmp(argv[1], "download") == 0) {
1798  uint files;
1799  uint bytes;
1801  IConsolePrintF(CC_DEFAULT, "Downloading %d file(s) (%d bytes)", files, bytes);
1802  return true;
1803  }
1804 
1805  return false;
1806 }
1807 #endif /* defined(WITH_ZLIB) */
1808 #endif /* ENABLE_NETWORK */
1809 
1810 DEF_CONSOLE_CMD(ConSetting)
1811 {
1812  if (argc == 0) {
1813  IConsoleHelp("Change setting for all clients. Usage: 'setting <name> [<value>]'");
1814  IConsoleHelp("Omitting <value> will print out the current value of the setting.");
1815  return true;
1816  }
1817 
1818  if (argc == 1 || argc > 3) return false;
1819 
1820  if (argc == 2) {
1821  IConsoleGetSetting(argv[1]);
1822  } else {
1823  IConsoleSetSetting(argv[1], argv[2]);
1824  }
1825 
1826  return true;
1827 }
1828 
1829 DEF_CONSOLE_CMD(ConSettingNewgame)
1830 {
1831  if (argc == 0) {
1832  IConsoleHelp("Change setting for the next game. Usage: 'setting_newgame <name> [<value>]'");
1833  IConsoleHelp("Omitting <value> will print out the current value of the setting.");
1834  return true;
1835  }
1836 
1837  if (argc == 1 || argc > 3) return false;
1838 
1839  if (argc == 2) {
1840  IConsoleGetSetting(argv[1], true);
1841  } else {
1842  IConsoleSetSetting(argv[1], argv[2], true);
1843  }
1844 
1845  return true;
1846 }
1847 
1848 DEF_CONSOLE_CMD(ConListSettings)
1849 {
1850  if (argc == 0) {
1851  IConsoleHelp("List settings. Usage: 'list_settings [<pre-filter>]'");
1852  return true;
1853  }
1854 
1855  if (argc > 2) return false;
1856 
1857  IConsoleListSettings((argc == 2) ? argv[1] : NULL);
1858  return true;
1859 }
1860 
1861 DEF_CONSOLE_CMD(ConGamelogPrint)
1862 {
1864  return true;
1865 }
1866 
1867 DEF_CONSOLE_CMD(ConNewGRFReload)
1868 {
1869  if (argc == 0) {
1870  IConsoleHelp("Reloads all active NewGRFs from disk. Equivalent to reapplying NewGRFs via the settings, but without asking for confirmation. This might crash OpenTTD!");
1871  return true;
1872  }
1873 
1874  ReloadNewGRFData();
1875  return true;
1876 }
1877 
1878 #ifdef _DEBUG
1879 /******************
1880  * debug commands
1881  ******************/
1882 
1883 static void IConsoleDebugLibRegister()
1884 {
1885  IConsoleCmdRegister("resettile", ConResetTile);
1886  IConsoleAliasRegister("dbg_echo", "echo %A; echo %B");
1887  IConsoleAliasRegister("dbg_echo2", "echo %!");
1888 }
1889 #endif
1890 
1891 /*******************************
1892  * console command registration
1893  *******************************/
1894 
1895 void IConsoleStdLibRegister()
1896 {
1897  IConsoleCmdRegister("debug_level", ConDebugLevel);
1898  IConsoleCmdRegister("echo", ConEcho);
1899  IConsoleCmdRegister("echoc", ConEchoC);
1900  IConsoleCmdRegister("exec", ConExec);
1901  IConsoleCmdRegister("exit", ConExit);
1902  IConsoleCmdRegister("part", ConPart);
1903  IConsoleCmdRegister("help", ConHelp);
1904  IConsoleCmdRegister("info_cmd", ConInfoCmd);
1905  IConsoleCmdRegister("list_cmds", ConListCommands);
1906  IConsoleCmdRegister("list_aliases", ConListAliases);
1907  IConsoleCmdRegister("newgame", ConNewGame);
1908  IConsoleCmdRegister("restart", ConRestart);
1909  IConsoleCmdRegister("getseed", ConGetSeed);
1910  IConsoleCmdRegister("getdate", ConGetDate);
1911  IConsoleCmdRegister("quit", ConExit);
1912  IConsoleCmdRegister("resetengines", ConResetEngines, ConHookNoNetwork);
1913  IConsoleCmdRegister("reset_enginepool", ConResetEnginePool, ConHookNoNetwork);
1914  IConsoleCmdRegister("return", ConReturn);
1915  IConsoleCmdRegister("screenshot", ConScreenShot);
1916  IConsoleCmdRegister("script", ConScript);
1917  IConsoleCmdRegister("scrollto", ConScrollToTile);
1918  IConsoleCmdRegister("alias", ConAlias);
1919  IConsoleCmdRegister("load", ConLoad);
1920  IConsoleCmdRegister("rm", ConRemove);
1921  IConsoleCmdRegister("save", ConSave);
1922  IConsoleCmdRegister("saveconfig", ConSaveConfig);
1923  IConsoleCmdRegister("ls", ConListFiles);
1924  IConsoleCmdRegister("cd", ConChangeDirectory);
1925  IConsoleCmdRegister("pwd", ConPrintWorkingDirectory);
1926  IConsoleCmdRegister("clear", ConClearBuffer);
1927  IConsoleCmdRegister("setting", ConSetting);
1928  IConsoleCmdRegister("setting_newgame", ConSettingNewgame);
1929  IConsoleCmdRegister("list_settings",ConListSettings);
1930  IConsoleCmdRegister("gamelog", ConGamelogPrint);
1931  IConsoleCmdRegister("rescan_newgrf", ConRescanNewGRF);
1932 
1933  IConsoleAliasRegister("dir", "ls");
1934  IConsoleAliasRegister("del", "rm %+");
1935  IConsoleAliasRegister("newmap", "newgame");
1936  IConsoleAliasRegister("patch", "setting %+");
1937  IConsoleAliasRegister("set", "setting %+");
1938  IConsoleAliasRegister("set_newgame", "setting_newgame %+");
1939  IConsoleAliasRegister("list_patches", "list_settings %+");
1940  IConsoleAliasRegister("developer", "setting developer %+");
1941 
1942  IConsoleCmdRegister("list_ai_libs", ConListAILibs);
1943  IConsoleCmdRegister("list_ai", ConListAI);
1944  IConsoleCmdRegister("reload_ai", ConReloadAI);
1945  IConsoleCmdRegister("rescan_ai", ConRescanAI);
1946  IConsoleCmdRegister("start_ai", ConStartAI);
1947  IConsoleCmdRegister("stop_ai", ConStopAI);
1948 
1949  IConsoleCmdRegister("list_game", ConListGame);
1950  IConsoleCmdRegister("list_game_libs", ConListGameLibs);
1951  IConsoleCmdRegister("rescan_game", ConRescanGame);
1952 
1953  IConsoleCmdRegister("companies", ConCompanies);
1954  IConsoleAliasRegister("players", "companies");
1955 
1956  /* networking functions */
1957 #ifdef ENABLE_NETWORK
1958 /* Content downloading is only available with ZLIB */
1959 #if defined(WITH_ZLIB)
1960  IConsoleCmdRegister("content", ConContent);
1961 #endif /* defined(WITH_ZLIB) */
1962 
1963  /*** Networking commands ***/
1964  IConsoleCmdRegister("say", ConSay, ConHookNeedNetwork);
1965  IConsoleCmdRegister("say_company", ConSayCompany, ConHookNeedNetwork);
1966  IConsoleAliasRegister("say_player", "say_company %+");
1967  IConsoleCmdRegister("say_client", ConSayClient, ConHookNeedNetwork);
1968 
1969  IConsoleCmdRegister("connect", ConNetworkConnect, ConHookClientOnly);
1970  IConsoleCmdRegister("clients", ConNetworkClients, ConHookNeedNetwork);
1971  IConsoleCmdRegister("status", ConStatus, ConHookServerOnly);
1972  IConsoleCmdRegister("server_info", ConServerInfo, ConHookServerOnly);
1973  IConsoleAliasRegister("info", "server_info");
1974  IConsoleCmdRegister("reconnect", ConNetworkReconnect, ConHookClientOnly);
1975  IConsoleCmdRegister("rcon", ConRcon, ConHookNeedNetwork);
1976 
1977  IConsoleCmdRegister("join", ConJoinCompany, ConHookNeedNetwork);
1978  IConsoleAliasRegister("spectate", "join 255");
1979  IConsoleCmdRegister("move", ConMoveClient, ConHookServerOnly);
1980  IConsoleCmdRegister("reset_company", ConResetCompany, ConHookServerOnly);
1981  IConsoleAliasRegister("clean_company", "reset_company %A");
1982  IConsoleCmdRegister("client_name", ConClientNickChange, ConHookServerOnly);
1983  IConsoleCmdRegister("kick", ConKick, ConHookServerOnly);
1984  IConsoleCmdRegister("ban", ConBan, ConHookServerOnly);
1985  IConsoleCmdRegister("unban", ConUnBan, ConHookServerOnly);
1986  IConsoleCmdRegister("banlist", ConBanList, ConHookServerOnly);
1987 
1988  IConsoleCmdRegister("pause", ConPauseGame, ConHookServerOnly);
1989  IConsoleCmdRegister("unpause", ConUnpauseGame, ConHookServerOnly);
1990 
1991  IConsoleCmdRegister("company_pw", ConCompanyPassword, ConHookNeedNetwork);
1992  IConsoleAliasRegister("company_password", "company_pw %+");
1993 
1994  IConsoleAliasRegister("net_frame_freq", "setting frame_freq %+");
1995  IConsoleAliasRegister("net_sync_freq", "setting sync_freq %+");
1996  IConsoleAliasRegister("server_pw", "setting server_password %+");
1997  IConsoleAliasRegister("server_password", "setting server_password %+");
1998  IConsoleAliasRegister("rcon_pw", "setting rcon_password %+");
1999  IConsoleAliasRegister("rcon_password", "setting rcon_password %+");
2000  IConsoleAliasRegister("name", "setting client_name %+");
2001  IConsoleAliasRegister("server_name", "setting server_name %+");
2002  IConsoleAliasRegister("server_port", "setting server_port %+");
2003  IConsoleAliasRegister("server_advertise", "setting server_advertise %+");
2004  IConsoleAliasRegister("max_clients", "setting max_clients %+");
2005  IConsoleAliasRegister("max_companies", "setting max_companies %+");
2006  IConsoleAliasRegister("max_spectators", "setting max_spectators %+");
2007  IConsoleAliasRegister("max_join_time", "setting max_join_time %+");
2008  IConsoleAliasRegister("pause_on_join", "setting pause_on_join %+");
2009  IConsoleAliasRegister("autoclean_companies", "setting autoclean_companies %+");
2010  IConsoleAliasRegister("autoclean_protected", "setting autoclean_protected %+");
2011  IConsoleAliasRegister("autoclean_unprotected", "setting autoclean_unprotected %+");
2012  IConsoleAliasRegister("restart_game_year", "setting restart_game_year %+");
2013  IConsoleAliasRegister("min_players", "setting min_active_clients %+");
2014  IConsoleAliasRegister("reload_cfg", "setting reload_cfg %+");
2015 #endif /* ENABLE_NETWORK */
2016 
2017  /* debugging stuff */
2018 #ifdef _DEBUG
2019  IConsoleDebugLibRegister();
2020 #endif
2021 
2022  /* NewGRF development stuff */
2023  IConsoleCmdRegister("reload_newgrfs", ConNewGRFReload, ConHookNewGRFDeveloperTool);
2024 }