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 }

Generated on Wed Feb 17 23:06:45 2010 for OpenTTD by  doxygen 1.6.1