# command.cpp

Go to the documentation of this file.

    00001 /* $Id: command.cpp 19130 2010-02-14 15:44:21Z alberth $ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * 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.
    00006  * 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.
    00007  * 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/>.
    00008  */
    00009
    00012 #include "stdafx.h"
    00013 #include "openttd.h"
    00014 #include "landscape.h"
    00015 #include "gui.h"
    00016 #include "command_func.h"
    00017 #include "network/network.h"
    00018 #include "genworld.h"
    00019 #include "newgrf_storage.h"
    00020 #include "strings_func.h"
    00021 #include "gfx_func.h"
    00022 #include "functions.h"
    00023 #include "town.h"
    00024 #include "date_func.h"
    00025 #include "debug.h"
    00026 #include "company_func.h"
    00027 #include "company_base.h"
    00028 #include "signal_func.h"
    00029
    00030 #include "table/strings.h"
    00031
    00032 StringID _error_message;
    00033
    00034 CommandProc CmdBuildRailroadTrack;
    00035 CommandProc CmdRemoveRailroadTrack;
    00036 CommandProc CmdBuildSingleRail;
    00037 CommandProc CmdRemoveSingleRail;
    00038
    00039 CommandProc CmdLandscapeClear;
    00040
    00041 CommandProc CmdBuildBridge;
    00042
    00043 CommandProc CmdBuildRailStation;
    00044 CommandProc CmdRemoveFromRailStation;
    00045 CommandProc CmdConvertRail;
    00046
    00047 CommandProc CmdBuildSingleSignal;
    00048 CommandProc CmdRemoveSingleSignal;
    00049
    00050 CommandProc CmdTerraformLand;
    00051
    00052 CommandProc CmdPurchaseLandArea;
    00053 CommandProc CmdSellLandArea;
    00054
    00055 CommandProc CmdBuildTunnel;
    00056
    00057 CommandProc CmdBuildTrainDepot;
    00058 CommandProc CmdBuildRailWaypoint;
    00059 CommandProc CmdRenameWaypoint;
    00060 CommandProc CmdRemoveFromRailWaypoint;
    00061
    00062 CommandProc CmdBuildRoadStop;
    00063 CommandProc CmdRemoveRoadStop;
    00064
    00065 CommandProc CmdBuildLongRoad;
    00066 CommandProc CmdRemoveLongRoad;
    00067 CommandProc CmdBuildRoad;
    00068
    00069 CommandProc CmdBuildRoadDepot;
    00070
    00071 CommandProc CmdBuildAirport;
    00072
    00073 CommandProc CmdBuildDock;
    00074
    00075 CommandProc CmdBuildShipDepot;
    00076
    00077 CommandProc CmdBuildBuoy;
    00078
    00079 CommandProc CmdPlantTree;
    00080
    00081 CommandProc CmdBuildRailVehicle;
    00082 CommandProc CmdMoveRailVehicle;
    00083
    00084 CommandProc CmdSellRailWagon;
    00085
    00086 CommandProc CmdSendTrainToDepot;
    00087 CommandProc CmdForceTrainProceed;
    00088 CommandProc CmdReverseTrainDirection;
    00089
    00090 CommandProc CmdModifyOrder;
    00091 CommandProc CmdSkipToOrder;
    00092 CommandProc CmdDeleteOrder;
    00093 CommandProc CmdInsertOrder;
    00094 CommandProc CmdChangeServiceInt;
    00095 CommandProc CmdRestoreOrderIndex;
    00096
    00097 CommandProc CmdBuildIndustry;
    00098
    00099 CommandProc CmdBuildCompanyHQ;
    00100 CommandProc CmdSetCompanyManagerFace;
    00101 CommandProc CmdSetCompanyColour;
    00102
    00103 CommandProc CmdIncreaseLoan;
    00104 CommandProc CmdDecreaseLoan;
    00105
    00106 CommandProc CmdWantEnginePreview;
    00107
    00108 CommandProc CmdRenameVehicle;
    00109 CommandProc CmdRenameEngine;
    00110
    00111 CommandProc CmdRenameCompany;
    00112 CommandProc CmdRenamePresident;
    00113
    00114 CommandProc CmdRenameStation;
    00115
    00116 CommandProc CmdSellAircraft;
    00117 CommandProc CmdBuildAircraft;
    00118 CommandProc CmdSendAircraftToHangar;
    00119 CommandProc CmdRefitAircraft;
    00120
    00121 CommandProc CmdPlaceSign;
    00122 CommandProc CmdRenameSign;
    00123
    00124 CommandProc CmdBuildRoadVeh;
    00125 CommandProc CmdSellRoadVeh;
    00126 CommandProc CmdSendRoadVehToDepot;
    00127 CommandProc CmdTurnRoadVeh;
    00128 CommandProc CmdRefitRoadVeh;
    00129
    00130 CommandProc CmdPause;
    00131
    00132 CommandProc CmdBuyShareInCompany;
    00133 CommandProc CmdSellShareInCompany;
    00134 CommandProc CmdBuyCompany;
    00135
    00136 CommandProc CmdFoundTown;
    00137
    00138 CommandProc CmdRenameTown;
    00139 CommandProc CmdDoTownAction;
    00140
    00141 CommandProc CmdChangeSetting;
    00142 CommandProc CmdChangeCompanySetting;
    00143
    00144 CommandProc CmdSellShip;
    00145 CommandProc CmdBuildShip;
    00146 CommandProc CmdSendShipToDepot;
    00147 CommandProc CmdRefitShip;
    00148
    00149 CommandProc CmdOrderRefit;
    00150 CommandProc CmdCloneOrder;
    00151
    00152 CommandProc CmdClearArea;
    00153
    00154 CommandProc CmdGiveMoney;
    00155 CommandProc CmdMoneyCheat;
    00156 CommandProc CmdBuildCanal;
    00157 CommandProc CmdBuildLock;
    00158
    00159 CommandProc CmdCompanyCtrl;
    00160
    00161 CommandProc CmdLevelLand;
    00162
    00163 CommandProc CmdRefitRailVehicle;
    00164
    00165 CommandProc CmdBuildSignalTrack;
    00166 CommandProc CmdRemoveSignalTrack;
    00167
    00168 CommandProc CmdSetAutoReplace;
    00169
    00170 CommandProc CmdCloneVehicle;
    00171 CommandProc CmdStartStopVehicle;
    00172 CommandProc CmdMassStartStopVehicle;
    00173 CommandProc CmdAutoreplaceVehicle;
    00174 CommandProc CmdDepotSellAllVehicles;
    00175 CommandProc CmdDepotMassAutoReplace;
    00176
    00177 CommandProc CmdCreateGroup;
    00178 CommandProc CmdRenameGroup;
    00179 CommandProc CmdDeleteGroup;
    00180 CommandProc CmdAddVehicleGroup;
    00181 CommandProc CmdAddSharedVehicleGroup;
    00182 CommandProc CmdRemoveAllVehiclesGroup;
    00183 CommandProc CmdSetGroupReplaceProtection;
    00184
    00185 CommandProc CmdMoveOrder;
    00186 CommandProc CmdChangeTimetable;
    00187 CommandProc CmdSetVehicleOnTime;
    00188 CommandProc CmdAutofillTimetable;
    00189 CommandProc CmdSetTimetableStart;
    00190
    00198 static const Command _command_proc_table[] = {
    00199   {CmdBuildRailroadTrack,   CMD_NO_WATER | CMD_AUTO}, // CMD_BUILD_RAILROAD_TRACK
    00200   {CmdRemoveRailroadTrack,                 CMD_AUTO}, // CMD_REMOVE_RAILROAD_TRACK
    00201   {CmdBuildSingleRail,      CMD_NO_WATER | CMD_AUTO}, // CMD_BUILD_SINGLE_RAIL
    00202   {CmdRemoveSingleRail,                    CMD_AUTO}, // CMD_REMOVE_SINGLE_RAIL
    00203   {CmdLandscapeClear,                             0}, // CMD_LANDSCAPE_CLEAR
    00204   {CmdBuildBridge,                         CMD_AUTO}, // CMD_BUILD_BRIDGE
    00205   {CmdBuildRailStation,     CMD_NO_WATER | CMD_AUTO}, // CMD_BUILD_RAIL_STATION
    00206   {CmdBuildTrainDepot,      CMD_NO_WATER | CMD_AUTO}, // CMD_BUILD_TRAIN_DEPOT
    00207   {CmdBuildSingleSignal,                   CMD_AUTO}, // CMD_BUILD_SIGNALS
    00208   {CmdRemoveSingleSignal,                  CMD_AUTO}, // CMD_REMOVE_SIGNALS
    00209   {CmdTerraformLand,       CMD_ALL_TILES | CMD_AUTO}, // CMD_TERRAFORM_LAND
    00210   {CmdPurchaseLandArea,     CMD_NO_WATER | CMD_AUTO}, // CMD_PURCHASE_LAND_AREA
    00211   {CmdSellLandArea,                               0}, // CMD_SELL_LAND_AREA
    00212   {CmdBuildTunnel,                         CMD_AUTO}, // CMD_BUILD_TUNNEL
    00213   {CmdRemoveFromRailStation,                      0}, // CMD_REMOVE_FROM_RAIL_STATION
    00214   {CmdConvertRail,                                0}, // CMD_CONVERT_RAILD
    00215   {CmdBuildRailWaypoint,                          0}, // CMD_BUILD_RAIL_WAYPOINT
    00216   {CmdRenameWaypoint,                             0}, // CMD_RENAME_WAYPOINT
    00217   {CmdRemoveFromRailWaypoint,                     0}, // CMD_REMOVE_FROM_RAIL_WAYPOINT
    00218
    00219   {CmdBuildRoadStop,        CMD_NO_WATER | CMD_AUTO}, // CMD_BUILD_ROAD_STOP
    00220   {CmdRemoveRoadStop,                             0}, // CMD_REMOVE_ROAD_STOP
    00221   {CmdBuildLongRoad,        CMD_NO_WATER | CMD_AUTO}, // CMD_BUILD_LONG_ROAD
    00222   {CmdRemoveLongRoad,        CMD_NO_TEST | CMD_AUTO}, // CMD_REMOVE_LONG_ROAD; towns may disallow removing road bits (as they are connected) in test, but in exec they're removed and thus removing is allowed.
    00223   {CmdBuildRoad,            CMD_NO_WATER | CMD_AUTO}, // CMD_BUILD_ROAD
    00224   {CmdBuildRoadDepot,       CMD_NO_WATER | CMD_AUTO}, // CMD_BUILD_ROAD_DEPOT
    00225
    00226   {CmdBuildAirport,         CMD_NO_WATER | CMD_AUTO}, // CMD_BUILD_AIRPORT
    00227   {CmdBuildDock,                           CMD_AUTO}, // CMD_BUILD_DOCK
    00228   {CmdBuildShipDepot,                      CMD_AUTO}, // CMD_BUILD_SHIP_DEPOT
    00229   {CmdBuildBuoy,                           CMD_AUTO}, // CMD_BUILD_BUOY
    00230   {CmdPlantTree,                           CMD_AUTO}, // CMD_PLANT_TREE
    00231   {CmdBuildRailVehicle,                           0}, // CMD_BUILD_RAIL_VEHICLE
    00232   {CmdMoveRailVehicle,                            0}, // CMD_MOVE_RAIL_VEHICLE
    00233
    00234   {CmdSellRailWagon,                              0}, // CMD_SELL_RAIL_WAGON
    00235   {CmdSendTrainToDepot,                           0}, // CMD_SEND_TRAIN_TO_DEPOT
    00236   {CmdForceTrainProceed,                          0}, // CMD_FORCE_TRAIN_PROCEED
    00237   {CmdReverseTrainDirection,                      0}, // CMD_REVERSE_TRAIN_DIRECTION
    00238
    00239   {CmdModifyOrder,                                0}, // CMD_MODIFY_ORDER
    00240   {CmdSkipToOrder,                                0}, // CMD_SKIP_TO_ORDER
    00241   {CmdDeleteOrder,                                0}, // CMD_DELETE_ORDER
    00242   {CmdInsertOrder,                                0}, // CMD_INSERT_ORDER
    00243
    00244   {CmdChangeServiceInt,                           0}, // CMD_CHANGE_SERVICE_INT
    00245
    00246   {CmdBuildIndustry,                              0}, // CMD_BUILD_INDUSTRY
    00247   {CmdBuildCompanyHQ,       CMD_NO_WATER | CMD_AUTO}, // CMD_BUILD_COMPANY_HQ
    00248   {CmdSetCompanyManagerFace,                      0}, // CMD_SET_COMPANY_MANAGER_FACE
    00249   {CmdSetCompanyColour,                           0}, // CMD_SET_COMPANY_COLOUR
    00250
    00251   {CmdIncreaseLoan,                               0}, // CMD_INCREASE_LOAN
    00252   {CmdDecreaseLoan,                               0}, // CMD_DECREASE_LOAN
    00253
    00254   {CmdWantEnginePreview,                          0}, // CMD_WANT_ENGINE_PREVIEW
    00255
    00256   {CmdRenameVehicle,                              0}, // CMD_RENAME_VEHICLE
    00257   {CmdRenameEngine,                               0}, // CMD_RENAME_ENGINE
    00258
    00259   {CmdRenameCompany,                              0}, // CMD_RENAME_COMPANY
    00260   {CmdRenamePresident,                            0}, // CMD_RENAME_PRESIDENT
    00261
    00262   {CmdRenameStation,                              0}, // CMD_RENAME_STATION
    00263
    00264   {CmdSellAircraft,                               0}, // CMD_SELL_AIRCRAFT
    00265
    00266   {CmdBuildAircraft,                              0}, // CMD_BUILD_AIRCRAFT
    00267   {CmdSendAircraftToHangar,                       0}, // CMD_SEND_AIRCRAFT_TO_HANGAR
    00268   {CmdRefitAircraft,                              0}, // CMD_REFIT_AIRCRAFT
    00269
    00270   {CmdPlaceSign,                                  0}, // CMD_PLACE_SIGN
    00271   {CmdRenameSign,                                 0}, // CMD_RENAME_SIGN
    00272
    00273   {CmdBuildRoadVeh,                               0}, // CMD_BUILD_ROAD_VEH
    00274   {CmdSellRoadVeh,                                0}, // CMD_SELL_ROAD_VEH
    00275   {CmdSendRoadVehToDepot,                         0}, // CMD_SEND_ROADVEH_TO_DEPOT
    00276   {CmdTurnRoadVeh,                                0}, // CMD_TURN_ROADVEH
    00277   {CmdRefitRoadVeh,                               0}, // CMD_REFIT_ROAD_VEH
    00278
    00279   {CmdPause,                             CMD_SERVER}, // CMD_PAUSE
    00280
    00281   {CmdBuyShareInCompany,                          0}, // CMD_BUY_SHARE_IN_COMPANY
    00282   {CmdSellShareInCompany,                         0}, // CMD_SELL_SHARE_IN_COMPANY
    00283   {CmdBuyCompany,                                 0}, // CMD_BUY_COMANY
    00284
    00285   {CmdFoundTown,                        CMD_NO_TEST}, // CMD_FOUND_TOWN; founding random town can fail only in exec run
    00286   {CmdRenameTown,                        CMD_SERVER}, // CMD_RENAME_TOWN
    00287   {CmdDoTownAction,                               0}, // CMD_DO_TOWN_ACTION
    00288
    00289   {CmdSellShip,                                   0}, // CMD_SELL_SHIP
    00290   {CmdBuildShip,                                  0}, // CMD_BUILD_SHIP
    00291   {CmdSendShipToDepot,                            0}, // CMD_SEND_SHIP_TO_DEPOT
    00292   {CmdRefitShip,                                  0}, // CMD_REFIT_SHIP
    00293
    00294   {CmdOrderRefit,                                 0}, // CMD_ORDER_REFIT
    00295   {CmdCloneOrder,                                 0}, // CMD_CLONE_ORDER
    00296
    00297   {CmdClearArea,                        CMD_NO_TEST}, // CMD_CLEAR_AREA; destroying multi-tile houses makes town rating differ between test and execution
    00298
    00299   {CmdMoneyCheat,                       CMD_OFFLINE}, // CMD_MONEY_CHEAT
    00300   {CmdBuildCanal,                          CMD_AUTO}, // CMD_BUILD_CANAL
    00301   {CmdCompanyCtrl,                    CMD_SPECTATOR}, // CMD_COMPANY_CTRL
    00302
    00303   {CmdLevelLand, CMD_ALL_TILES | CMD_NO_TEST | CMD_AUTO}, // CMD_LEVEL_LAND; test run might clear tiles multiple times, in execution that only happens once
    00304
    00305   {CmdRefitRailVehicle,                           0}, // CMD_REFIT_RAIL_VEHICLE
    00306   {CmdRestoreOrderIndex,                          0}, // CMD_RESTORE_ORDER_INDEX
    00307   {CmdBuildLock,                           CMD_AUTO}, // CMD_BUILD_LOCK
    00308
    00309   {CmdBuildSignalTrack,                    CMD_AUTO}, // CMD_BUILD_SIGNAL_TRACK
    00310   {CmdRemoveSignalTrack,                   CMD_AUTO}, // CMD_REMOVE_SIGNAL_TRACK
    00311
    00312   {CmdGiveMoney,                                  0}, // CMD_GIVE_MONEY
    00313   {CmdChangeSetting,                     CMD_SERVER}, // CMD_CHANGE_SETTING
    00314   {CmdChangeCompanySetting,                       0}, // CMD_CHANGE_COMPANY_SETTING
    00315   {CmdSetAutoReplace,                             0}, // CMD_SET_AUTOREPLACE
    00316   {CmdCloneVehicle,                     CMD_NO_TEST}, // CMD_CLONE_VEHICLE; NewGRF callbacks influence building and refitting making it impossible to correctly estimate the cost
    00317   {CmdStartStopVehicle,                           0}, // CMD_START_STOP_VEHICLE
    00318   {CmdMassStartStopVehicle,                       0}, // CMD_MASS_START_STOP
    00319   {CmdAutoreplaceVehicle,                         0}, // CMD_AUTOREPLACE_VEHICLE
    00320   {CmdDepotSellAllVehicles,                       0}, // CMD_DEPOT_SELL_ALL_VEHICLES
    00321   {CmdDepotMassAutoReplace,                       0}, // CMD_DEPOT_MASS_AUTOREPLACE
    00322   {CmdCreateGroup,                                0}, // CMD_CREATE_GROUP
    00323   {CmdDeleteGroup,                                0}, // CMD_DELETE_GROUP
    00324   {CmdRenameGroup,                                0}, // CMD_RENAME_GROUP
    00325   {CmdAddVehicleGroup,                            0}, // CMD_ADD_VEHICLE_GROUP
    00326   {CmdAddSharedVehicleGroup,                      0}, // CMD_ADD_SHARE_VEHICLE_GROUP
    00327   {CmdRemoveAllVehiclesGroup,                     0}, // CMD_REMOVE_ALL_VEHICLES_GROUP
    00328   {CmdSetGroupReplaceProtection,                  0}, // CMD_SET_GROUP_REPLACE_PROTECTION
    00329   {CmdMoveOrder,                                  0}, // CMD_MOVE_ORDER
    00330   {CmdChangeTimetable,                            0}, // CMD_CHANGE_TIMETABLE
    00331   {CmdSetVehicleOnTime,                           0}, // CMD_SET_VEHICLE_ON_TIME
    00332   {CmdAutofillTimetable,                          0}, // CMD_AUTOFILL_TIMETABLE
    00333   {CmdSetTimetableStart,                          0}, // CMD_SET_TIMETABLE_START
    00334 };
    00335
    00342 bool IsValidCommand(uint32 cmd)
    00343 {
    00344   cmd &= CMD_ID_MASK;
    00345
    00346   return
    00347     cmd < lengthof(_command_proc_table) &&
    00348     _command_proc_table[cmd].proc != NULL;
    00349 }
    00350
    00358 byte GetCommandFlags(uint32 cmd)
    00359 {
    00360   assert(IsValidCommand(cmd));
    00361
    00362   return _command_proc_table[cmd & CMD_ID_MASK].flags;
    00363 }
    00364
    00365 static int _docommand_recursive = 0;
    00366
    00375 CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags)
    00376 {
    00377   return DoCommand(container->tile, container->p1, container->p2, flags, container->cmd & CMD_ID_MASK, container->text);
    00378 }
    00379
    00393 CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag flags, uint32 cmd, const char *text)
    00394 {
    00395   CommandCost res;
    00396
    00397   /* Do not even think about executing out-of-bounds tile-commands */
    00398   if (tile != 0 && (tile >= MapSize() || (!IsValidTile(tile) && (flags & DC_ALL_TILES) == 0))) return CMD_ERROR;
    00399
    00400   /* Chop of any CMD_MSG or other flags; we don't need those here */
    00401   CommandProc *proc = _command_proc_table[cmd & CMD_ID_MASK].proc;
    00402
    00403   if (_docommand_recursive == 0) _error_message = INVALID_STRING_ID;
    00404
    00405   _docommand_recursive++;
    00406
    00407   /* only execute the test call if it's toplevel, or we're not execing. */
    00408   if (_docommand_recursive == 1 || !(flags & DC_EXEC) ) {
    00409     SetTownRatingTestMode(true);
    00410     res = proc(tile, flags & ~DC_EXEC, p1, p2, text);
    00411     SetTownRatingTestMode(false);
    00412     if (res.Failed()) {
    00413       goto error;
    00414     }
    00415
    00416     if (_docommand_recursive == 1 &&
    00417         !(flags & DC_QUERY_COST) &&
    00418         !(flags & DC_BANKRUPT) &&
    00419         !CheckCompanyHasMoney(res)) {
    00420       goto error;
    00421     }
    00422
    00423     if (!(flags & DC_EXEC)) {
    00424       _docommand_recursive--;
    00425       return res;
    00426     }
    00427   }
    00428
    00429   /* Execute the command here. All cost-relevant functions set the expenses type
    00430    * themselves to the cost object at some point */
    00431   res = proc(tile, flags, p1, p2, text);
    00432   if (res.Failed()) {
    00433 error:
    00434     res.SetGlobalErrorMessage();
    00435     _docommand_recursive--;
    00436     return CMD_ERROR;
    00437   }
    00438
    00439   /* if toplevel, subtract the money. */
    00440   if (--_docommand_recursive == 0 && !(flags & DC_BANKRUPT)) {
    00441     SubtractMoneyFromCompany(res);
    00442   }
    00443
    00444   return res;
    00445 }
    00446
    00454 Money GetAvailableMoneyForCommand()
    00455 {
    00456   CompanyID company = _current_company;
    00457   if (!Company::IsValidID(company)) return INT64_MAX;
    00458   return Company::Get(company)->money;
    00459 }
    00460
    00467 bool DoCommandP(const CommandContainer *container, bool my_cmd)
    00468 {
    00469   return DoCommandP(container->tile, container->p1, container->p2, container->cmd, container->callback, container->text, my_cmd);
    00470 }
    00471
    00487 bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd)
    00488 {
    00489   /* Cost estimation is generally only done when the
    00490    * local user presses shift while doing somthing.
    00491    * However, in case of incoming network commands,
    00492    * map generation of the pause button we do want
    00493    * to execute. */
    00494   bool estimate_only = _shift_pressed && IsLocalCompany() &&
    00495       !IsGeneratingWorld() &&
    00496       !(cmd & CMD_NETWORK_COMMAND) &&
    00497       (cmd & CMD_ID_MASK) != CMD_PAUSE;
    00498
    00499   /* We're only sending the command, so don't do
    00500    * fancy things for 'success'. */
    00501   bool only_sending = _networking && !(cmd & CMD_NETWORK_COMMAND);
    00502
    00503   /* Where to show the message? */
    00504   int x = TileX(tile) * TILE_SIZE;
    00505   int y = TileY(tile) * TILE_SIZE;
    00506
    00507   CommandCost res = DoCommandPInternal(tile, p1, p2, cmd, callback, text, my_cmd, estimate_only);
    00508   if (res.Failed()) {
    00509     res.SetGlobalErrorMessage();
    00510
    00511     /* Only show the error when it's for us. */
    00512     StringID error_part1 = GB(cmd, 16, 16);
    00513     if (estimate_only || (IsLocalCompany() && error_part1 != 0 && my_cmd)) {
    00514       ShowErrorMessage(error_part1, _error_message, x, y);
    00515     }
    00516   } else if (estimate_only) {
    00517     ShowEstimatedCostOrIncome(res.GetCost(), x, y);
    00518   } else if (!only_sending && res.GetCost() != 0 && tile != 0 && IsLocalCompany() && _game_mode != GM_EDITOR) {
    00519     /* Only show the cost animation when we did actually
    00520      * execute the command, i.e. we're not sending it to
    00521      * the server, when it has cost the local company
    00522      * something. Furthermore in the editor there is no
    00523      * concept of cost, so don't show it there either. */
    00524     ShowCostOrIncomeAnimation(x, y, GetSlopeZ(x, y), res.GetCost());
    00525   }
    00526
    00527   if (!estimate_only && !only_sending && callback != NULL) {
    00528     callback(res, tile, p1, p2);
    00529   }
    00530
    00531   return res.Succeeded();
    00532 }
    00533
    00534
    00540 #define return_dcpi(cmd, clear) { _docommand_recursive = 0; ClearStorageChanges(clear); return cmd; }
    00541
    00555 CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, bool estimate_only)
    00556 {
    00557   /* Prevent recursion; it gives a mess over the network */
    00558   assert(_docommand_recursive == 0);
    00559   _docommand_recursive = 1;
    00560
    00561   /* Reset the state. */
    00562   _error_message = INVALID_STRING_ID;
    00563   _additional_cash_required = 0;
    00564
    00565   /* Get pointer to command handler */
    00566   byte cmd_id = cmd & CMD_ID_MASK;
    00567   assert(cmd_id < lengthof(_command_proc_table));
    00568
    00569   CommandProc *proc = _command_proc_table[cmd_id].proc;
    00570   /* Shouldn't happen, but you never know when someone adds
    00571    * NULLs to the _command_proc_table. */
    00572   assert(proc != NULL);
    00573
    00574   /* Command flags are used internally */
    00575   uint cmd_flags = GetCommandFlags(cmd);
    00576   /* Flags get send to the DoCommand */
    00577   DoCommandFlag flags = CommandFlagsToDCFlags(cmd_flags);
    00578
    00579   /* Do not even think about executing out-of-bounds tile-commands */
    00580   if (tile != 0 && (tile >= MapSize() || (!IsValidTile(tile) && (cmd_flags & CMD_ALL_TILES) == 0))) return_dcpi(CMD_ERROR, false);
    00581
    00582   /* Always execute server and spectator commands as spectator */
    00583   if (cmd_flags & (CMD_SPECTATOR | CMD_SERVER)) _current_company = COMPANY_SPECTATOR;
    00584
    00585   CompanyID old_company = _current_company;
    00586
    00587   /* If the company isn't valid it may only do server command or start a new company!
    00588    * The server will ditch any server commands a client sends to it, so effectively
    00589    * this guards the server from executing functions for an invalid company. */
    00590   if (_game_mode == GM_NORMAL && (cmd_flags & (CMD_SPECTATOR | CMD_SERVER)) == 0 && !Company::IsValidID(_current_company)) {
    00591     return_dcpi(CMD_ERROR, false);
    00592   }
    00593
    00594   bool test_and_exec_can_differ = (cmd_flags & CMD_NO_TEST) != 0;
    00595   bool skip_test = _networking && (cmd & CMD_NO_TEST_IF_IN_NETWORK) != 0;
    00596
    00597   /* Do we need to do a test run?
    00598    * Basically we need to always do this, except when
    00599    * the no-test-in-network flag is giving and we're
    00600    * in a network game (e.g. restoring orders would
    00601    * fail this test because the first order does not
    00602    * exist yet when inserting the second, giving that
    00603    * a wrong insert location and ignoring the command
    00604    * and thus breaking restoring). However, when we
    00605    * just want to do cost estimation we don't care
    00606    * because it's only done once anyway. */
    00607   CommandCost res;
    00608   if (estimate_only || !skip_test) {
    00609     /* Test the command. */
    00610     SetTownRatingTestMode(true);
    00611     res = proc(tile, flags, p1, p2, text);
    00612     SetTownRatingTestMode(false);
    00613
    00614     /* Make sure we're not messing things up here. */
    00615     assert(cmd_id == CMD_COMPANY_CTRL || old_company == _current_company);
    00616
    00617     /* If the command fails, we're doing an estimate
    00618      * or the player does not have enough money
    00619      * (unless it's a command where the test and
    00620      * execution phase might return different costs)
    00621      * we bail out here. */
    00622     if (res.Failed() || estimate_only ||
    00623         (!test_and_exec_can_differ && !CheckCompanyHasMoney(res))) {
    00624       return_dcpi(res, false);
    00625     }
    00626   }
    00627
    00628 #ifdef ENABLE_NETWORK
    00629   /*
    00630    * If we are in network, and the command is not from the network
    00631    * send it to the command-queue and abort execution
    00632    */
    00633   if (_networking && !(cmd & CMD_NETWORK_COMMAND)) {
    00634     NetworkSend_Command(tile, p1, p2, cmd & ~CMD_FLAGS_MASK, callback, text, _current_company);
    00635
    00636     /* Don't return anything special here; no error, no costs.
    00637      * This way it's not handled by DoCommand and only the
    00638      * actual execution of the command causes messages. Also
    00639      * reset the storages as we've not executed the command. */
    00640     return_dcpi(CommandCost(), false);
    00641   }
    00642 #endif /* ENABLE_NETWORK */
    00643   DEBUG(desync, 1, "cmd: %08x; %08x; %1x; %06x; %08x; %08x; %04x; %s\n", _date, _date_fract, (int)_current_company, tile, p1, p2, cmd & ~CMD_NETWORK_COMMAND, text);
    00644
    00645   /* Actually try and execute the command. If no cost-type is given
    00646    * use the construction one */
    00647   CommandCost res2 = proc(tile, flags | DC_EXEC, p1, p2, text);
    00648
    00649   /* Make sure nothing bad happened, like changing the current company. */
    00650   assert(cmd_id == CMD_COMPANY_CTRL || old_company == _current_company);
    00651
    00652   /* If the test and execution can differ, or we skipped the test
    00653    * we have to check the return of the command. Otherwise we can
    00654    * check whether the test and execution have yielded the same
    00655    * result, i.e. cost and error state are the same. */
    00656   if (!test_and_exec_can_differ && !skip_test) {
    00657     assert(res.GetCost() == res2.GetCost() && res.Failed() == res2.Failed()); // sanity check
    00658   } else if (res2.Failed()) {
    00659     return_dcpi(res2, false);
    00660   }
    00661
    00662   /* If we're needing more money and we haven't done
    00663    * anything yet, ask for the money! */
    00664   if (_additional_cash_required != 0 && res2.GetCost() == 0) {
    00665     SetDParam(0, _additional_cash_required);
    00666     return_dcpi(CommandCost(STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY), false);
    00667   }
    00668
    00669   /* update last build coordinate of company. */
    00670   if (tile != 0) {
    00671     Company *c = Company::GetIfValid(_current_company);
    00672     if (c != NULL) c->last_build_coordinate = tile;
    00673   }
    00674
    00675   SubtractMoneyFromCompany(res2);
    00676
    00677   /* update signals if needed */
    00678   UpdateSignalsInBuffer();
    00679
    00680   return_dcpi(res2, true);
    00681 }
    00682 #undef return_dcpi
    00683
    00684
    00690 void CommandCost::AddCost(const CommandCost &ret)
    00691 {
    00692   this->AddCost(ret.cost);
    00693   if (this->success && !ret.success) {
    00694     this->message = ret.message;
    00695     this->success = false;
    00696   }
    00697 }