console_cmds.cpp

Go to the documentation of this file.
00001 /* $Id: console_cmds.cpp 14828 2009-01-04 15:32:25Z smatz $ */
00002 
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "console_internal.h"
00008 #include "debug.h"
00009 #include "engine_func.h"
00010 #include "landscape.h"
00011 #include "saveload/saveload.h"
00012 #include "variables.h"
00013 #include "network/network.h"
00014 #include "network/network_func.h"
00015 #include "network/network_base.h"
00016 #include "command_func.h"
00017 #include "settings_func.h"
00018 #include "fios.h"
00019 #include "fileio_func.h"
00020 #include "screenshot.h"
00021 #include "genworld.h"
00022 #include "strings_func.h"
00023 #include "viewport_func.h"
00024 #include "window_func.h"
00025 #include "functions.h"
00026 #include "map_func.h"
00027 #include "date_func.h"
00028 #include "vehicle_func.h"
00029 #include "string_func.h"
00030 #include "company_func.h"
00031 #include "company_base.h"
00032 #include "settings_type.h"
00033 #include "gamelog.h"
00034 
00035 #ifdef ENABLE_NETWORK
00036   #include "table/strings.h"
00037 #endif /* ENABLE_NETWORK */
00038 
00039 // ** scriptfile handling ** //
00040 static FILE *_script_file;
00041 static bool _script_running;
00042 
00043 // ** console command / variable defines ** //
00044 #define DEF_CONSOLE_CMD(function) static bool function(byte argc, char *argv[])
00045 #define DEF_CONSOLE_HOOK(function) static bool function()
00046 
00047 
00048 /* **************************** */
00049 /* variable and command hooks   */
00050 /* **************************** */
00051 
00052 #ifdef ENABLE_NETWORK
00053 
00054 static inline bool NetworkAvailable()
00055 {
00056   if (!_network_available) {
00057     IConsoleError("You cannot use this command because there is no network available.");
00058     return false;
00059   }
00060   return true;
00061 }
00062 
00063 DEF_CONSOLE_HOOK(ConHookServerOnly)
00064 {
00065   if (!NetworkAvailable()) return false;
00066 
00067   if (!_network_server) {
00068     IConsoleError("This command/variable is only available to a network server.");
00069     return false;
00070   }
00071   return true;
00072 }
00073 
00074 DEF_CONSOLE_HOOK(ConHookClientOnly)
00075 {
00076   if (!NetworkAvailable()) return false;
00077 
00078   if (_network_server) {
00079     IConsoleError("This command/variable is not available to a network server.");
00080     return false;
00081   }
00082   return true;
00083 }
00084 
00085 DEF_CONSOLE_HOOK(ConHookNeedNetwork)
00086 {
00087   if (!NetworkAvailable()) return false;
00088 
00089   if (!_networking) {
00090     IConsoleError("Not connected. This command/variable is only available in multiplayer.");
00091     return false;
00092   }
00093   return true;
00094 }
00095 
00096 DEF_CONSOLE_HOOK(ConHookNoNetwork)
00097 {
00098   if (_networking) {
00099     IConsoleError("This command/variable is forbidden in multiplayer.");
00100     return false;
00101   }
00102   return true;
00103 }
00104 
00105 #endif /* ENABLE_NETWORK */
00106 
00107 static void IConsoleHelp(const char *str)
00108 {
00109   IConsolePrintF(CC_WARNING, "- %s", str);
00110 }
00111 
00112 DEF_CONSOLE_CMD(ConResetEngines)
00113 {
00114   if (argc == 0) {
00115     IConsoleHelp("Reset status data of all engines. This might solve some issues with 'lost' engines. Usage: 'resetengines'");
00116     return true;
00117   }
00118 
00119   StartupEngines();
00120   return true;
00121 }
00122 
00123 #ifdef _DEBUG
00124 DEF_CONSOLE_CMD(ConResetTile)
00125 {
00126   if (argc == 0) {
00127     IConsoleHelp("Reset a tile to bare land. Usage: 'resettile <tile>'");
00128     IConsoleHelp("Tile can be either decimal (34161) or hexadecimal (0x4a5B)");
00129     return true;
00130   }
00131 
00132   if (argc == 2) {
00133     uint32 result;
00134     if (GetArgumentInteger(&result, argv[1])) {
00135       DoClearSquare((TileIndex)result);
00136       return true;
00137     }
00138   }
00139 
00140   return false;
00141 }
00142 
00143 DEF_CONSOLE_CMD(ConStopAllVehicles)
00144 {
00145   if (argc == 0) {
00146     IConsoleHelp("Stops all vehicles in the game. For debugging only! Use at your own risk... Usage: 'stopall'");
00147     return true;
00148   }
00149 
00150   StopAllVehicles();
00151   return true;
00152 }
00153 #endif /* _DEBUG */
00154 
00155 DEF_CONSOLE_CMD(ConScrollToTile)
00156 {
00157   if (argc == 0) {
00158     IConsoleHelp("Center the screen on a given tile. Usage: 'scrollto <tile>'");
00159     IConsoleHelp("Tile can be either decimal (34161) or hexadecimal (0x4a5B)");
00160     return true;
00161   }
00162 
00163   if (argc == 2) {
00164     uint32 result;
00165     if (GetArgumentInteger(&result, argv[1])) {
00166       if (result >= MapSize()) {
00167         IConsolePrint(CC_ERROR, "Tile does not exist");
00168         return true;
00169       }
00170       ScrollMainWindowToTile((TileIndex)result);
00171       return true;
00172     }
00173   }
00174 
00175   return false;
00176 }
00177 
00178 extern void BuildFileList();
00179 extern void SetFiosType(const byte fiostype);
00180 
00181 /* Save the map to a file */
00182 DEF_CONSOLE_CMD(ConSave)
00183 {
00184   if (argc == 0) {
00185     IConsoleHelp("Save the current game. Usage: 'save <filename>'");
00186     return true;
00187   }
00188 
00189   if (argc == 2) {
00190     char *filename = str_fmt("%s.sav", argv[1]);
00191     IConsolePrint(CC_DEFAULT, "Saving map...");
00192 
00193     if (SaveOrLoad(filename, SL_SAVE, SAVE_DIR) != SL_OK) {
00194       IConsolePrint(CC_ERROR, "Saving map failed");
00195     } else {
00196       IConsolePrintF(CC_DEFAULT, "Map sucessfully saved to %s", filename);
00197     }
00198     free(filename);
00199     return true;
00200   }
00201 
00202   return false;
00203 }
00204 
00205 /* Explicitly save the configuration */
00206 DEF_CONSOLE_CMD(ConSaveConfig)
00207 {
00208   if (argc == 0) {
00209     IConsoleHelp("Saves the current config, typically to 'openttd.cfg'.");
00210     return true;
00211   }
00212 
00213   SaveToConfig();
00214   IConsolePrint(CC_DEFAULT, "Saved config.");
00215   return true;
00216 }
00217 
00218 static const FiosItem* GetFiosItem(const char* file)
00219 {
00220   _saveload_mode = SLD_LOAD_GAME;
00221   BuildFileList();
00222 
00223   for (const FiosItem *item = _fios_items.Begin(); item != _fios_items.End(); item++) {
00224     if (strcmp(file, item->name) == 0) return item;
00225     if (strcmp(file, item->title) == 0) return item;
00226   }
00227 
00228   /* If no name matches, try to parse it as number */
00229   char *endptr;
00230   int i = strtol(file, &endptr, 10);
00231   if (file == endptr || *endptr != '\0') i = -1;
00232 
00233   return IsInsideMM(i, 0, _fios_items.Length()) ? _fios_items.Get(i) : NULL;
00234 }
00235 
00236 
00237 DEF_CONSOLE_CMD(ConLoad)
00238 {
00239   if (argc == 0) {
00240     IConsoleHelp("Load a game by name or index. Usage: 'load <file | number>'");
00241     return true;
00242   }
00243 
00244   if (argc != 2) return false;
00245 
00246   const char *file = argv[1];
00247   const FiosItem *item = GetFiosItem(file);
00248   if (item != NULL) {
00249     switch (item->type) {
00250       case FIOS_TYPE_FILE: case FIOS_TYPE_OLDFILE: {
00251         _switch_mode = SM_LOAD;
00252         SetFiosType(item->type);
00253 
00254         strecpy(_file_to_saveload.name, FiosBrowseTo(item), lastof(_file_to_saveload.name));
00255         strecpy(_file_to_saveload.title, item->title, lastof(_file_to_saveload.title));
00256       } break;
00257       default: IConsolePrintF(CC_ERROR, "%s: Not a savegame.", file);
00258     }
00259   } else {
00260     IConsolePrintF(CC_ERROR, "%s: No such file or directory.", file);
00261   }
00262 
00263   FiosFreeSavegameList();
00264   return true;
00265 }
00266 
00267 
00268 DEF_CONSOLE_CMD(ConRemove)
00269 {
00270   if (argc == 0) {
00271     IConsoleHelp("Remove a savegame by name or index. Usage: 'rm <file | number>'");
00272     return true;
00273   }
00274 
00275   if (argc != 2) return false;
00276 
00277   const char *file = argv[1];
00278   const FiosItem *item = GetFiosItem(file);
00279   if (item != NULL) {
00280     if (!FiosDelete(item->name))
00281       IConsolePrintF(CC_ERROR, "%s: Failed to delete file", file);
00282   } else {
00283     IConsolePrintF(CC_ERROR, "%s: No such file or directory.", file);
00284   }
00285 
00286   FiosFreeSavegameList();
00287   return true;
00288 }
00289 
00290 
00291 /* List all the files in the current dir via console */
00292 DEF_CONSOLE_CMD(ConListFiles)
00293 {
00294   if (argc == 0) {
00295     IConsoleHelp("List all loadable savegames and directories in the current dir via console. Usage: 'ls | dir'");
00296     return true;
00297   }
00298 
00299   BuildFileList();
00300 
00301   for (uint i = 0; i < _fios_items.Length(); i++) {
00302     IConsolePrintF(CC_DEFAULT, "%d) %s", i, _fios_items[i].title);
00303   }
00304 
00305   FiosFreeSavegameList();
00306   return true;
00307 }
00308 
00309 /* Change the dir via console */
00310 DEF_CONSOLE_CMD(ConChangeDirectory)
00311 {
00312   if (argc == 0) {
00313     IConsoleHelp("Change the dir via console. Usage: 'cd <directory | number>'");
00314     return true;
00315   }
00316 
00317   if (argc != 2) return false;
00318 
00319   const char *file = argv[1];
00320   const FiosItem *item = GetFiosItem(file);
00321   if (item != NULL) {
00322     switch (item->type) {
00323       case FIOS_TYPE_DIR: case FIOS_TYPE_DRIVE: case FIOS_TYPE_PARENT:
00324         FiosBrowseTo(item);
00325         break;
00326       default: IConsolePrintF(CC_ERROR, "%s: Not a directory.", file);
00327     }
00328   } else {
00329     IConsolePrintF(CC_ERROR, "%s: No such file or directory.", file);
00330   }
00331 
00332   FiosFreeSavegameList();
00333   return true;
00334 }
00335 
00336 DEF_CONSOLE_CMD(ConPrintWorkingDirectory)
00337 {
00338   const char *path;
00339 
00340   if (argc == 0) {
00341     IConsoleHelp("Print out the current working directory. Usage: 'pwd'");
00342     return true;
00343   }
00344 
00345   // XXX - Workaround for broken file handling
00346   FiosGetSavegameList(SLD_LOAD_GAME);
00347   FiosFreeSavegameList();
00348 
00349   FiosGetDescText(&path, NULL);
00350   IConsolePrint(CC_DEFAULT, path);
00351   return true;
00352 }
00353 
00354 DEF_CONSOLE_CMD(ConClearBuffer)
00355 {
00356   if (argc == 0) {
00357     IConsoleHelp("Clear the console buffer. Usage: 'clear'");
00358     return true;
00359   }
00360 
00361   IConsoleClearBuffer();
00362   InvalidateWindow(WC_CONSOLE, 0);
00363   return true;
00364 }
00365 
00366 
00367 // ********************************* //
00368 // * Network Core Console Commands * //
00369 // ********************************* //
00370 #ifdef ENABLE_NETWORK
00371 
00372 DEF_CONSOLE_CMD(ConBan)
00373 {
00374   NetworkClientInfo *ci;
00375   const char *banip = NULL;
00376   ClientID client_id;
00377 
00378   if (argc == 0) {
00379     IConsoleHelp("Ban a client from a network game. Usage: 'ban <ip | client-id>'");
00380     IConsoleHelp("For client-id's, see the command 'clients'");
00381     IConsoleHelp("If the client is no longer online, you can still ban his/her IP");
00382     return true;
00383   }
00384 
00385   if (argc != 2) return false;
00386 
00387   if (strchr(argv[1], '.') == NULL) { // banning with ID
00388     client_id = (ClientID)atoi(argv[1]);
00389     ci = NetworkFindClientInfoFromClientID(client_id);
00390   } else { // banning IP
00391     ci = NetworkFindClientInfoFromIP(argv[1]);
00392     if (ci == NULL) {
00393       banip = argv[1];
00394       client_id = (ClientID)-1;
00395     } else {
00396       client_id = ci->client_id;
00397     }
00398   }
00399 
00400   if (client_id == CLIENT_ID_SERVER) {
00401     IConsoleError("Silly boy, you can not ban yourself!");
00402     return true;
00403   }
00404 
00405   if (client_id == INVALID_CLIENT_ID || (ci == NULL && client_id != (ClientID)-1)) {
00406     IConsoleError("Invalid client");
00407     return true;
00408   }
00409 
00410   if (ci != NULL) {
00411     IConsolePrint(CC_DEFAULT, "Client banned");
00412     banip = GetClientIP(ci);
00413     NetworkServerSendError(client_id, NETWORK_ERROR_KICKED);
00414   } else {
00415     IConsolePrint(CC_DEFAULT, "Client not online, banned IP");
00416   }
00417 
00418   /* Add user to ban-list */
00419   for (uint index = 0; index < lengthof(_network_ban_list); index++) {
00420     if (_network_ban_list[index] == NULL) {
00421       _network_ban_list[index] = strdup(banip);
00422       break;
00423     }
00424   }
00425 
00426   return true;
00427 }
00428 
00429 DEF_CONSOLE_CMD(ConUnBan)
00430 {
00431   uint i, index;
00432 
00433   if (argc == 0) {
00434     IConsoleHelp("Unban a client from a network game. Usage: 'unban <ip | client-id>'");
00435     IConsoleHelp("For a list of banned IP's, see the command 'banlist'");
00436     return true;
00437   }
00438 
00439   if (argc != 2) return false;
00440 
00441   index = (strchr(argv[1], '.') == NULL) ? atoi(argv[1]) : 0;
00442   index--;
00443 
00444   for (i = 0; i < lengthof(_network_ban_list); i++) {
00445     if (_network_ban_list[i] == NULL) continue;
00446 
00447     if (strcmp(_network_ban_list[i], argv[1]) == 0 || index == i) {
00448       free(_network_ban_list[i]);
00449       _network_ban_list[i] = NULL;
00450       IConsolePrint(CC_DEFAULT, "IP unbanned.");
00451       return true;
00452     }
00453   }
00454 
00455   IConsolePrint(CC_DEFAULT, "IP not in ban-list.");
00456   return true;
00457 }
00458 
00459 DEF_CONSOLE_CMD(ConBanList)
00460 {
00461   uint i;
00462 
00463   if (argc == 0) {
00464     IConsoleHelp("List the IP's of banned clients: Usage 'banlist'");
00465     return true;
00466   }
00467 
00468   IConsolePrint(CC_DEFAULT, "Banlist: ");
00469 
00470   for (i = 0; i < lengthof(_network_ban_list); i++) {
00471     if (_network_ban_list[i] != NULL)
00472       IConsolePrintF(CC_DEFAULT, "  %d) %s", i + 1, _network_ban_list[i]);
00473   }
00474 
00475   return true;
00476 }
00477 
00478 DEF_CONSOLE_CMD(ConPauseGame)
00479 {
00480   if (argc == 0) {
00481     IConsoleHelp("Pause a network game. Usage: 'pause'");
00482     return true;
00483   }
00484 
00485   if (_pause_game == 0) {
00486     DoCommandP(0, 1, 0, CMD_PAUSE);
00487     IConsolePrint(CC_DEFAULT, "Game paused.");
00488   } else {
00489     IConsolePrint(CC_DEFAULT, "Game is already paused.");
00490   }
00491 
00492   return true;
00493 }
00494 
00495 DEF_CONSOLE_CMD(ConUnPauseGame)
00496 {
00497   if (argc == 0) {
00498     IConsoleHelp("Unpause a network game. Usage: 'unpause'");
00499     return true;
00500   }
00501 
00502   if (_pause_game != 0) {
00503     DoCommandP(0, 0, 0, CMD_PAUSE);
00504     IConsolePrint(CC_DEFAULT, "Game unpaused.");
00505   } else {
00506     IConsolePrint(CC_DEFAULT, "Game is already unpaused.");
00507   }
00508 
00509   return true;
00510 }
00511 
00512 DEF_CONSOLE_CMD(ConRcon)
00513 {
00514   if (argc == 0) {
00515     IConsoleHelp("Remote control the server from another client. Usage: 'rcon <password> <command>'");
00516     IConsoleHelp("Remember to enclose the command in quotes, otherwise only the first parameter is sent");
00517     return true;
00518   }
00519 
00520   if (argc < 3) return false;
00521 
00522   if (_network_server) {
00523     IConsoleCmdExec(argv[2]);
00524   } else {
00525     NetworkClientSendRcon(argv[1], argv[2]);
00526   }
00527   return true;
00528 }
00529 
00530 DEF_CONSOLE_CMD(ConStatus)
00531 {
00532   if (argc == 0) {
00533     IConsoleHelp("List the status of all clients connected to the server. Usage 'status'");
00534     return true;
00535   }
00536 
00537   NetworkServerShowStatusToConsole();
00538   return true;
00539 }
00540 
00541 DEF_CONSOLE_CMD(ConServerInfo)
00542 {
00543   if (argc == 0) {
00544     IConsoleHelp("List current and maximum client/company limits. Usage 'server_info'");
00545     IConsoleHelp("You can change these values by setting the variables 'max_clients', 'max_companies' and 'max_spectators'");
00546     return true;
00547   }
00548 
00549   IConsolePrintF(CC_DEFAULT, "Current/maximum clients:    %2d/%2d", _network_game_info.clients_on, _settings_client.network.max_clients);
00550   IConsolePrintF(CC_DEFAULT, "Current/maximum companies:  %2d/%2d", ActiveCompanyCount(), _settings_client.network.max_companies);
00551   IConsolePrintF(CC_DEFAULT, "Current/maximum spectators: %2d/%2d", NetworkSpectatorCount(), _settings_client.network.max_spectators);
00552 
00553   return true;
00554 }
00555 
00556 DEF_CONSOLE_CMD(ConKick)
00557 {
00558   NetworkClientInfo *ci;
00559   ClientID client_id;
00560 
00561   if (argc == 0) {
00562     IConsoleHelp("Kick a client from a network game. Usage: 'kick <ip | client-id>'");
00563     IConsoleHelp("For client-id's, see the command 'clients'");
00564     return true;
00565   }
00566 
00567   if (argc != 2) return false;
00568 
00569   if (strchr(argv[1], '.') == NULL) {
00570     client_id = (ClientID)atoi(argv[1]);
00571     ci = NetworkFindClientInfoFromClientID(client_id);
00572   } else {
00573     ci = NetworkFindClientInfoFromIP(argv[1]);
00574     client_id = (ci == NULL) ? INVALID_CLIENT_ID : ci->client_id;
00575   }
00576 
00577   if (client_id == CLIENT_ID_SERVER) {
00578     IConsoleError("Silly boy, you can not kick yourself!");
00579     return true;
00580   }
00581 
00582   if (client_id == INVALID_CLIENT_ID) {
00583     IConsoleError("Invalid client");
00584     return true;
00585   }
00586 
00587   if (ci != NULL) {
00588     NetworkServerSendError(client_id, NETWORK_ERROR_KICKED);
00589   } else {
00590     IConsoleError("Client not found");
00591   }
00592 
00593   return true;
00594 }
00595 
00596 DEF_CONSOLE_CMD(ConResetCompany)
00597 {
00598   CompanyID index;
00599 
00600   if (argc == 0) {
00601     IConsoleHelp("Remove an idle company from the game. Usage: 'reset_company <company-id>'");
00602     IConsoleHelp("For company-id's, see the list of companies from the dropdown menu. Company 1 is 1, etc.");
00603     return true;
00604   }
00605 
00606   if (argc != 2) return false;
00607 
00608   index = (CompanyID)(atoi(argv[1]) - 1);
00609 
00610   /* Check valid range */
00611   if (!IsValidCompanyID(index)) {
00612     IConsolePrintF(CC_ERROR, "Company does not exist. Company-id must be between 1 and %d.", MAX_COMPANIES);
00613     return true;
00614   }
00615 
00616   const Company *c = GetCompany(index);
00617 
00618   if (c->is_ai) {
00619     IConsoleError("Company is owned by an AI.");
00620     return true;
00621   }
00622 
00623   if (NetworkCompanyHasClients(index)) {
00624     IConsoleError("Cannot remove company: a client is connected to that company.");
00625     return false;
00626   }
00627   const NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(CLIENT_ID_SERVER);
00628   if (ci->client_playas == index) {
00629     IConsoleError("Cannot remove company: the server is connected to that company.");
00630     return true;
00631   }
00632 
00633   /* It is safe to remove this company */
00634   DoCommandP(0, 2, index, CMD_COMPANY_CTRL);
00635   IConsolePrint(CC_DEFAULT, "Company deleted.");
00636 
00637   return true;
00638 }
00639 
00640 DEF_CONSOLE_CMD(ConNetworkClients)
00641 {
00642   if (argc == 0) {
00643     IConsoleHelp("Get a list of connected clients including their ID, name, company-id, and IP. Usage: 'clients'");
00644     return true;
00645   }
00646 
00647   NetworkPrintClients();
00648 
00649   return true;
00650 }
00651 
00652 DEF_CONSOLE_CMD(ConNetworkConnect)
00653 {
00654   char *ip;
00655   const char *port = NULL;
00656   const char *company = NULL;
00657   uint16 rport;
00658 
00659   if (argc == 0) {
00660     IConsoleHelp("Connect to a remote OTTD server and join the game. Usage: 'connect <ip>'");
00661     IConsoleHelp("IP can contain port and company: 'IP[[#Company]:Port]', eg: 'server.ottd.org#2:443'");
00662     IConsoleHelp("Company #255 is spectator all others are a certain company with Company 1 being #1");
00663     return true;
00664   }
00665 
00666   if (argc < 2) return false;
00667   if (_networking) NetworkDisconnect(); // we are in network-mode, first close it!
00668 
00669   ip = argv[1];
00670   /* Default settings: default port and new company */
00671   rport = NETWORK_DEFAULT_PORT;
00672   _network_playas = COMPANY_NEW_COMPANY;
00673 
00674   ParseConnectionString(&company, &port, ip);
00675 
00676   IConsolePrintF(CC_DEFAULT, "Connecting to %s...", ip);
00677   if (company != NULL) {
00678     _network_playas = (CompanyID)atoi(company);
00679     IConsolePrintF(CC_DEFAULT, "    company-no: %d", _network_playas);
00680 
00681     /* From a user pov 0 is a new company, internally it's different and all
00682      * companies are offset by one to ease up on users (eg companies 1-8 not 0-7) */
00683     if (_network_playas != COMPANY_SPECTATOR) {
00684       _network_playas--;
00685       if (!IsValidCompanyID(_network_playas)) return false;
00686     }
00687   }
00688   if (port != NULL) {
00689     rport = atoi(port);
00690     IConsolePrintF(CC_DEFAULT, "    port: %s", port);
00691   }
00692 
00693   NetworkClientConnectGame(ip, rport);
00694 
00695   return true;
00696 }
00697 
00698 #endif /* ENABLE_NETWORK */
00699 
00700 /* ******************************** */
00701 /*   script file console commands   */
00702 /* ******************************** */
00703 
00704 DEF_CONSOLE_CMD(ConExec)
00705 {
00706   char cmdline[ICON_CMDLN_SIZE];
00707   char *cmdptr;
00708 
00709   if (argc == 0) {
00710     IConsoleHelp("Execute a local script file. Usage: 'exec <script> <?>'");
00711     return true;
00712   }
00713 
00714   if (argc < 2) return false;
00715 
00716   _script_file = FioFOpenFile(argv[1], "r", BASE_DIR);
00717 
00718   if (_script_file == NULL) {
00719     if (argc == 2 || atoi(argv[2]) != 0) IConsoleError("script file not found");
00720     return true;
00721   }
00722 
00723   _script_running = true;
00724 
00725   while (_script_running && fgets(cmdline, sizeof(cmdline), _script_file) != NULL) {
00726     /* Remove newline characters from the executing script */
00727     for (cmdptr = cmdline; *cmdptr != '\0'; cmdptr++) {
00728       if (*cmdptr == '\n' || *cmdptr == '\r') {
00729         *cmdptr = '\0';
00730         break;
00731       }
00732     }
00733     IConsoleCmdExec(cmdline);
00734   }
00735 
00736   if (ferror(_script_file))
00737     IConsoleError("Encountered errror while trying to read from script file");
00738 
00739   _script_running = false;
00740   FioFCloseFile(_script_file);
00741   return true;
00742 }
00743 
00744 DEF_CONSOLE_CMD(ConReturn)
00745 {
00746   if (argc == 0) {
00747     IConsoleHelp("Stop executing a running script. Usage: 'return'");
00748     return true;
00749   }
00750 
00751   _script_running = false;
00752   return true;
00753 }
00754 
00755 /* **************************** */
00756 /*   default console commands   */
00757 /* **************************** */
00758 extern bool CloseConsoleLogIfActive();
00759 
00760 DEF_CONSOLE_CMD(ConScript)
00761 {
00762   extern FILE* _iconsole_output_file;
00763 
00764   if (argc == 0) {
00765     IConsoleHelp("Start or stop logging console output to a file. Usage: 'script <filename>'");
00766     IConsoleHelp("If filename is omitted, a running log is stopped if it is active");
00767     return true;
00768   }
00769 
00770   if (!CloseConsoleLogIfActive()) {
00771     if (argc < 2) return false;
00772 
00773     IConsolePrintF(CC_DEFAULT, "file output started to: %s", argv[1]);
00774     _iconsole_output_file = fopen(argv[1], "ab");
00775     if (_iconsole_output_file == NULL) IConsoleError("could not open file");
00776   }
00777 
00778   return true;
00779 }
00780 
00781 
00782 DEF_CONSOLE_CMD(ConEcho)
00783 {
00784   if (argc == 0) {
00785     IConsoleHelp("Print back the first argument to the console. Usage: 'echo <arg>'");
00786     return true;
00787   }
00788 
00789   if (argc < 2) return false;
00790   IConsolePrint(CC_DEFAULT, argv[1]);
00791   return true;
00792 }
00793 
00794 DEF_CONSOLE_CMD(ConEchoC)
00795 {
00796   if (argc == 0) {
00797     IConsoleHelp("Print back the first argument to the console in a given colour. Usage: 'echoc <colour> <arg2>'");
00798     return true;
00799   }
00800 
00801   if (argc < 3) return false;
00802   IConsolePrint((ConsoleColour)atoi(argv[1]), argv[2]);
00803   return true;
00804 }
00805 
00806 DEF_CONSOLE_CMD(ConNewGame)
00807 {
00808   if (argc == 0) {
00809     IConsoleHelp("Start a new game. Usage: 'newgame [seed]'");
00810     IConsoleHelp("The server can force a new game using 'newgame'; any client joined will rejoin after the server is done generating the new game.");
00811     return true;
00812   }
00813 
00814   StartNewGameWithoutGUI((argc == 2) ? (uint)atoi(argv[1]) : GENERATE_NEW_SEED);
00815   return true;
00816 }
00817 
00818 extern void SwitchMode(int new_mode);
00819 
00820 DEF_CONSOLE_CMD(ConRestart)
00821 {
00822   if (argc == 0) {
00823     IConsoleHelp("Restart game. Usage: 'restart'");
00824     IConsoleHelp("Restarts a game. It tries to reproduce the exact same map as the game started with.");
00825     return true;
00826   }
00827 
00828   /* Don't copy the _newgame pointers to the real pointers, so call SwitchMode directly */
00829   _settings_game.game_creation.map_x = MapLogX();
00830   _settings_game.game_creation.map_y = FindFirstBit(MapSizeY());
00831   SwitchMode(SM_NEWGAME);
00832   return true;
00833 }
00834 
00835 DEF_CONSOLE_CMD(ConGetSeed)
00836 {
00837   if (argc == 0) {
00838     IConsoleHelp("Returns the seed used to create this game. Usage: 'getseed'");
00839     IConsoleHelp("The seed can be used to reproduce the exact same map as the game started with.");
00840     return true;
00841   }
00842 
00843   IConsolePrintF(CC_DEFAULT, "Generation Seed: %u", _settings_game.game_creation.generation_seed);
00844   return true;
00845 }
00846 
00847 DEF_CONSOLE_CMD(ConGetDate)
00848 {
00849   if (argc == 0) {
00850     IConsoleHelp("Returns the current date (day-month-year) of the game. Usage: 'getdate'");
00851     return true;
00852   }
00853 
00854   YearMonthDay ymd;
00855   ConvertDateToYMD(_date, &ymd);
00856   IConsolePrintF(CC_DEFAULT, "Date: %d-%d-%d", ymd.day, ymd.month + 1, ymd.year);
00857   return true;
00858 }
00859 
00860 
00861 DEF_CONSOLE_CMD(ConAlias)
00862 {
00863   IConsoleAlias *alias;
00864 
00865   if (argc == 0) {
00866     IConsoleHelp("Add a new alias, or redefine the behaviour of an existing alias . Usage: 'alias <name> <command>'");
00867     return true;
00868   }
00869 
00870   if (argc < 3) return false;
00871 
00872   alias = IConsoleAliasGet(argv[1]);
00873   if (alias == NULL) {
00874     IConsoleAliasRegister(argv[1], argv[2]);
00875   } else {
00876     free(alias->cmdline);
00877     alias->cmdline = strdup(argv[2]);
00878   }
00879   return true;
00880 }
00881 
00882 DEF_CONSOLE_CMD(ConScreenShot)
00883 {
00884   if (argc == 0) {
00885     IConsoleHelp("Create a screenshot of the game. Usage: 'screenshot [big | no_con]'");
00886     IConsoleHelp("'big' makes a screenshot of the whole map, 'no_con' hides the console to create the screenshot");
00887     return true;
00888   }
00889 
00890   if (argc > 3) return false;
00891 
00892   SetScreenshotType(SC_VIEWPORT);
00893   if (argc > 1) {
00894     if (strcmp(argv[1], "big") == 0 || (argc == 3 && strcmp(argv[2], "big") == 0))
00895       SetScreenshotType(SC_WORLD);
00896 
00897     if (strcmp(argv[1], "no_con") == 0 || (argc == 3 && strcmp(argv[2], "no_con") == 0))
00898       IConsoleClose();
00899   }
00900 
00901   return true;
00902 }
00903 
00904 DEF_CONSOLE_CMD(ConInfoVar)
00905 {
00906   static const char *_icon_vartypes[] = {"boolean", "byte", "uint16", "uint32", "int16", "int32", "string"};
00907   const IConsoleVar *var;
00908 
00909   if (argc == 0) {
00910     IConsoleHelp("Print out debugging information about a variable. Usage: 'info_var <var>'");
00911     return true;
00912   }
00913 
00914   if (argc < 2) return false;
00915 
00916   var = IConsoleVarGet(argv[1]);
00917   if (var == NULL) {
00918     IConsoleError("the given variable was not found");
00919     return true;
00920   }
00921 
00922   IConsolePrintF(CC_DEFAULT, "variable name: %s", var->name);
00923   IConsolePrintF(CC_DEFAULT, "variable type: %s", _icon_vartypes[var->type]);
00924   IConsolePrintF(CC_DEFAULT, "variable addr: 0x%X", var->addr);
00925 
00926   if (var->hook.access) IConsoleWarning("variable is access hooked");
00927   if (var->hook.pre) IConsoleWarning("variable is pre hooked");
00928   if (var->hook.post) IConsoleWarning("variable is post hooked");
00929   return true;
00930 }
00931 
00932 
00933 DEF_CONSOLE_CMD(ConInfoCmd)
00934 {
00935   const IConsoleCmd *cmd;
00936 
00937   if (argc == 0) {
00938     IConsoleHelp("Print out debugging information about a command. Usage: 'info_cmd <cmd>'");
00939     return true;
00940   }
00941 
00942   if (argc < 2) return false;
00943 
00944   cmd = IConsoleCmdGet(argv[1]);
00945   if (cmd == NULL) {
00946     IConsoleError("the given command was not found");
00947     return true;
00948   }
00949 
00950   IConsolePrintF(CC_DEFAULT, "command name: %s", cmd->name);
00951   IConsolePrintF(CC_DEFAULT, "command proc: 0x%X", cmd->proc);
00952 
00953   if (cmd->hook.access) IConsoleWarning("command is access hooked");
00954   if (cmd->hook.pre) IConsoleWarning("command is pre hooked");
00955   if (cmd->hook.post) IConsoleWarning("command is post hooked");
00956 
00957   return true;
00958 }
00959 
00960 DEF_CONSOLE_CMD(ConDebugLevel)
00961 {
00962   if (argc == 0) {
00963     IConsoleHelp("Get/set the default debugging level for the game. Usage: 'debug_level [<level>]'");
00964     IConsoleHelp("Level can be any combination of names, levels. Eg 'net=5 ms=4'. Remember to enclose it in \"'s");
00965     return true;
00966   }
00967 
00968   if (argc > 2) return false;
00969 
00970   if (argc == 1) {
00971     IConsolePrintF(CC_DEFAULT, "Current debug-level: '%s'", GetDebugString());
00972   } else {
00973     SetDebugString(argv[1]);
00974   }
00975 
00976   return true;
00977 }
00978 
00979 DEF_CONSOLE_CMD(ConExit)
00980 {
00981   if (argc == 0) {
00982     IConsoleHelp("Exit the game. Usage: 'exit'");
00983     return true;
00984   }
00985 
00986   if (_game_mode == GM_NORMAL && _settings_client.gui.autosave_on_exit) DoExitSave();
00987 
00988   _exit_game = true;
00989   return true;
00990 }
00991 
00992 DEF_CONSOLE_CMD(ConPart)
00993 {
00994   if (argc == 0) {
00995     IConsoleHelp("Leave the currently joined/running game (only ingame). Usage: 'part'");
00996     return true;
00997   }
00998 
00999   if (_game_mode != GM_NORMAL) return false;
01000 
01001   _switch_mode = SM_MENU;
01002   return true;
01003 }
01004 
01005 DEF_CONSOLE_CMD(ConHelp)
01006 {
01007   if (argc == 2) {
01008     const IConsoleCmd *cmd;
01009     const IConsoleVar *var;
01010     const IConsoleAlias *alias;
01011 
01012     cmd = IConsoleCmdGet(argv[1]);
01013     if (cmd != NULL) {
01014       cmd->proc(0, NULL);
01015       return true;
01016     }
01017 
01018     alias = IConsoleAliasGet(argv[1]);
01019     if (alias != NULL) {
01020       cmd = IConsoleCmdGet(alias->cmdline);
01021       if (cmd != NULL) {
01022         cmd->proc(0, NULL);
01023         return true;
01024       }
01025       IConsolePrintF(CC_ERROR, "ERROR: alias is of special type, please see its execution-line: '%s'", alias->cmdline);
01026       return true;
01027     }
01028 
01029     var = IConsoleVarGet(argv[1]);
01030     if (var != NULL && var->help != NULL) {
01031       IConsoleHelp(var->help);
01032       return true;
01033     }
01034 
01035     IConsoleError("command or variable not found");
01036     return true;
01037   }
01038 
01039   IConsolePrint(CC_WARNING, " ---- OpenTTD Console Help ---- ");
01040   IConsolePrint(CC_DEFAULT, " - variables: [command to list all variables: list_vars]");
01041   IConsolePrint(CC_DEFAULT, " set value with '<var> = <value>', use '++/--' to in-or decrement");
01042   IConsolePrint(CC_DEFAULT, " or omit '=' and just '<var> <value>'. get value with typing '<var>'");
01043   IConsolePrint(CC_DEFAULT, " - commands: [command to list all commands: list_cmds]");
01044   IConsolePrint(CC_DEFAULT, " call commands with '<command> <arg2> <arg3>...'");
01045   IConsolePrint(CC_DEFAULT, " - to assign strings, or use them as arguments, enclose it within quotes");
01046   IConsolePrint(CC_DEFAULT, " like this: '<command> \"string argument with spaces\"'");
01047   IConsolePrint(CC_DEFAULT, " - use 'help <command> | <variable>' to get specific information");
01048   IConsolePrint(CC_DEFAULT, " - scroll console output with shift + (up | down) | (pageup | pagedown))");
01049   IConsolePrint(CC_DEFAULT, " - scroll console input history with the up | down arrows");
01050   IConsolePrint(CC_DEFAULT, "");
01051   return true;
01052 }
01053 
01054 DEF_CONSOLE_CMD(ConListCommands)
01055 {
01056   const IConsoleCmd *cmd;
01057   size_t l = 0;
01058 
01059   if (argc == 0) {
01060     IConsoleHelp("List all registered commands. Usage: 'list_cmds [<pre-filter>]'");
01061     return true;
01062   }
01063 
01064   if (argv[1] != NULL) l = strlen(argv[1]);
01065 
01066   for (cmd = _iconsole_cmds; cmd != NULL; cmd = cmd->next) {
01067     if (argv[1] == NULL || strncmp(cmd->name, argv[1], l) == 0) {
01068         IConsolePrintF(CC_DEFAULT, "%s", cmd->name);
01069     }
01070   }
01071 
01072   return true;
01073 }
01074 
01075 DEF_CONSOLE_CMD(ConListVariables)
01076 {
01077   const IConsoleVar *var;
01078   size_t l = 0;
01079 
01080   if (argc == 0) {
01081     IConsoleHelp("List all registered variables. Usage: 'list_vars [<pre-filter>]'");
01082     return true;
01083   }
01084 
01085   if (argv[1] != NULL) l = strlen(argv[1]);
01086 
01087   for (var = _iconsole_vars; var != NULL; var = var->next) {
01088     if (argv[1] == NULL || strncmp(var->name, argv[1], l) == 0)
01089       IConsolePrintF(CC_DEFAULT, "%s", var->name);
01090   }
01091 
01092   return true;
01093 }
01094 
01095 DEF_CONSOLE_CMD(ConListAliases)
01096 {
01097   const IConsoleAlias *alias;
01098   size_t l = 0;
01099 
01100   if (argc == 0) {
01101     IConsoleHelp("List all registered aliases. Usage: 'list_aliases [<pre-filter>]'");
01102     return true;
01103   }
01104 
01105   if (argv[1] != NULL) l = strlen(argv[1]);
01106 
01107   for (alias = _iconsole_aliases; alias != NULL; alias = alias->next) {
01108     if (argv[1] == NULL || strncmp(alias->name, argv[1], l) == 0)
01109       IConsolePrintF(CC_DEFAULT, "%s => %s", alias->name, alias->cmdline);
01110   }
01111 
01112   return true;
01113 }
01114 
01115 #ifdef ENABLE_NETWORK
01116 
01117 DEF_CONSOLE_CMD(ConSay)
01118 {
01119   if (argc == 0) {
01120     IConsoleHelp("Chat to your fellow players in a multiplayer game. Usage: 'say \"<msg>\"'");
01121     return true;
01122   }
01123 
01124   if (argc != 2) return false;
01125 
01126   if (!_network_server) {
01127     NetworkClientSendChat(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0 /* param does not matter */, argv[1]);
01128   } else {
01129     NetworkServerSendChat(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0, argv[1], CLIENT_ID_SERVER);
01130   }
01131 
01132   return true;
01133 }
01134 
01135 DEF_CONSOLE_CMD(ConCompanies)
01136 {
01137   Company *c;
01138 
01139   if (argc == 0) {
01140     IConsoleHelp("List the in-game details of all clients connected to the server. Usage 'companies'");
01141     return true;
01142   }
01143   NetworkCompanyStats company_stats[MAX_COMPANIES];
01144   NetworkPopulateCompanyStats(company_stats);
01145 
01146   FOR_ALL_COMPANIES(c) {
01147     /* Grab the company name */
01148     char company_name[NETWORK_COMPANY_NAME_LENGTH];
01149     SetDParam(0, c->index);
01150     GetString(company_name, STR_COMPANY_NAME, lastof(company_name));
01151 
01152     char buffer[512];
01153     const NetworkCompanyStats *stats = &company_stats[c->index];
01154 
01155     GetString(buffer, STR_00D1_DARK_BLUE + _company_colours[c->index], lastof(buffer));
01156     IConsolePrintF(CC_INFO, "#:%d(%s) Company Name: '%s'  Year Founded: %d  Money: %" OTTD_PRINTF64 "d  Loan: %" OTTD_PRINTF64 "d  Value: %" OTTD_PRINTF64 "d  (T:%d, R:%d, P:%d, S:%d) %sprotected",
01157       c->index + 1, buffer, company_name, c->inaugurated_year, (int64)c->money, (int64)c->current_loan, (int64)CalculateCompanyValue(c),
01158       /* trains      */ stats->num_vehicle[0],
01159       /* lorry + bus */ stats->num_vehicle[1] + stats->num_vehicle[2],
01160       /* planes      */ stats->num_vehicle[3],
01161       /* ships       */ stats->num_vehicle[4],
01162       /* protected   */ StrEmpty(_network_company_states[c->index].password) ? "un" : "");
01163   }
01164 
01165   return true;
01166 }
01167 
01168 DEF_CONSOLE_CMD(ConSayCompany)
01169 {
01170   if (argc == 0) {
01171     IConsoleHelp("Chat to a certain company in a multiplayer game. Usage: 'say_company <company-no> \"<msg>\"'");
01172     IConsoleHelp("CompanyNo is the company that plays as company <companyno>, 1 through max_companies");
01173     return true;
01174   }
01175 
01176   if (argc != 3) return false;
01177 
01178   CompanyID company_id = (CompanyID)(atoi(argv[1]) - 1);
01179   if (!IsValidCompanyID(company_id)) {
01180     IConsolePrintF(CC_DEFAULT, "Unknown company. Company range is between 1 and %d.", MAX_COMPANIES);
01181     return true;
01182   }
01183 
01184   if (!_network_server) {
01185     NetworkClientSendChat(NETWORK_ACTION_CHAT_COMPANY, DESTTYPE_TEAM, company_id, argv[2]);
01186   } else {
01187     NetworkServerSendChat(NETWORK_ACTION_CHAT_COMPANY, DESTTYPE_TEAM, company_id, argv[2], CLIENT_ID_SERVER);
01188   }
01189 
01190   return true;
01191 }
01192 
01193 DEF_CONSOLE_CMD(ConSayClient)
01194 {
01195   if (argc == 0) {
01196     IConsoleHelp("Chat to a certain client in a multiplayer game. Usage: 'say_client <client-no> \"<msg>\"'");
01197     IConsoleHelp("For client-id's, see the command 'clients'");
01198     return true;
01199   }
01200 
01201   if (argc != 3) return false;
01202 
01203   if (!_network_server) {
01204     NetworkClientSendChat(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, atoi(argv[1]), argv[2]);
01205   } else {
01206     NetworkServerSendChat(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, atoi(argv[1]), argv[2], CLIENT_ID_SERVER);
01207   }
01208 
01209   return true;
01210 }
01211 
01212 extern void HashCurrentCompanyPassword(const char *password);
01213 
01214 /* Also use from within company_gui to change the password graphically */
01215 bool NetworkChangeCompanyPassword(byte argc, char *argv[])
01216 {
01217   if (argc == 0) {
01218     IConsoleHelp("Change the password of your company. Usage: 'company_pw \"<password>\"'");
01219     IConsoleHelp("Use \"*\" to disable the password.");
01220     return true;
01221   }
01222 
01223   if (!IsValidCompanyID(_local_company)) {
01224     IConsoleError("You have to own a company to make use of this command.");
01225     return false;
01226   }
01227 
01228   if (argc != 1) return false;
01229 
01230   if (strcmp(argv[0], "*") == 0) argv[0][0] = '\0';
01231 
01232   if (!_network_server) {
01233     NetworkClientSetPassword(argv[0]);
01234   } else {
01235     HashCurrentCompanyPassword(argv[0]);
01236   }
01237 
01238   IConsolePrintF(CC_WARNING, "'company_pw' changed to:  %s", argv[0]);
01239 
01240   return true;
01241 }
01242 
01243 #endif /* ENABLE_NETWORK */
01244 
01245 DEF_CONSOLE_CMD(ConPatch)
01246 {
01247   if (argc == 0) {
01248     IConsoleHelp("Change patch variables for all clients. Usage: 'patch <name> [<value>]'");
01249     IConsoleHelp("Omitting <value> will print out the current value of the patch-setting.");
01250     return true;
01