command.cpp

Go to the documentation of this file.
00001 /* $Id: command.cpp 19665 2010-04-17 22:27:49Z rubidium $ */
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 
00191 #define DEF_CMD(proc, flags) {proc, #proc, flags}
00192 
00200 static const Command _command_proc_table[] = {
00201   DEF_CMD(CmdBuildRailroadTrack,       CMD_NO_WATER | CMD_AUTO), // CMD_BUILD_RAILROAD_TRACK
00202   DEF_CMD(CmdRemoveRailroadTrack,                     CMD_AUTO), // CMD_REMOVE_RAILROAD_TRACK
00203   DEF_CMD(CmdBuildSingleRail,          CMD_NO_WATER | CMD_AUTO), // CMD_BUILD_SINGLE_RAIL
00204   DEF_CMD(CmdRemoveSingleRail,                        CMD_AUTO), // CMD_REMOVE_SINGLE_RAIL
00205   DEF_CMD(CmdLandscapeClear,                                 0), // CMD_LANDSCAPE_CLEAR
00206   DEF_CMD(CmdBuildBridge,                             CMD_AUTO), // CMD_BUILD_BRIDGE
00207   DEF_CMD(CmdBuildRailStation,         CMD_NO_WATER | CMD_AUTO), // CMD_BUILD_RAIL_STATION
00208   DEF_CMD(CmdBuildTrainDepot,          CMD_NO_WATER | CMD_AUTO), // CMD_BUILD_TRAIN_DEPOT
00209   DEF_CMD(CmdBuildSingleSignal,                       CMD_AUTO), // CMD_BUILD_SIGNALS
00210   DEF_CMD(CmdRemoveSingleSignal,                      CMD_AUTO), // CMD_REMOVE_SIGNALS
00211   DEF_CMD(CmdTerraformLand,           CMD_ALL_TILES | CMD_AUTO), // CMD_TERRAFORM_LAND
00212   DEF_CMD(CmdPurchaseLandArea,         CMD_NO_WATER | CMD_AUTO), // CMD_PURCHASE_LAND_AREA
00213   DEF_CMD(CmdSellLandArea,                                   0), // CMD_SELL_LAND_AREA
00214   DEF_CMD(CmdBuildTunnel,                             CMD_AUTO), // CMD_BUILD_TUNNEL
00215   DEF_CMD(CmdRemoveFromRailStation,                          0), // CMD_REMOVE_FROM_RAIL_STATION
00216   DEF_CMD(CmdConvertRail,                                    0), // CMD_CONVERT_RAILD
00217   DEF_CMD(CmdBuildRailWaypoint,                              0), // CMD_BUILD_RAIL_WAYPOINT
00218   DEF_CMD(CmdRenameWaypoint,                                 0), // CMD_RENAME_WAYPOINT
00219   DEF_CMD(CmdRemoveFromRailWaypoint,                         0), // CMD_REMOVE_FROM_RAIL_WAYPOINT
00220 
00221   DEF_CMD(CmdBuildRoadStop,            CMD_NO_WATER | CMD_AUTO), // CMD_BUILD_ROAD_STOP
00222   DEF_CMD(CmdRemoveRoadStop,                                 0), // CMD_REMOVE_ROAD_STOP
00223   DEF_CMD(CmdBuildLongRoad,            CMD_NO_WATER | CMD_AUTO), // CMD_BUILD_LONG_ROAD
00224   DEF_CMD(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.
00225   DEF_CMD(CmdBuildRoad,                CMD_NO_WATER | CMD_AUTO), // CMD_BUILD_ROAD
00226   DEF_CMD(CmdBuildRoadDepot,           CMD_NO_WATER | CMD_AUTO), // CMD_BUILD_ROAD_DEPOT
00227 
00228   DEF_CMD(CmdBuildAirport,             CMD_NO_WATER | CMD_AUTO), // CMD_BUILD_AIRPORT
00229   DEF_CMD(CmdBuildDock,                               CMD_AUTO), // CMD_BUILD_DOCK
00230   DEF_CMD(CmdBuildShipDepot,                          CMD_AUTO), // CMD_BUILD_SHIP_DEPOT
00231   DEF_CMD(CmdBuildBuoy,                               CMD_AUTO), // CMD_BUILD_BUOY
00232   DEF_CMD(CmdPlantTree,                               CMD_AUTO), // CMD_PLANT_TREE
00233   DEF_CMD(CmdBuildRailVehicle,                               0), // CMD_BUILD_RAIL_VEHICLE
00234   DEF_CMD(CmdMoveRailVehicle,                                0), // CMD_MOVE_RAIL_VEHICLE
00235 
00236   DEF_CMD(CmdSellRailWagon,                                  0), // CMD_SELL_RAIL_WAGON
00237   DEF_CMD(CmdSendTrainToDepot,                               0), // CMD_SEND_TRAIN_TO_DEPOT
00238   DEF_CMD(CmdForceTrainProceed,                              0), // CMD_FORCE_TRAIN_PROCEED
00239   DEF_CMD(CmdReverseTrainDirection,                          0), // CMD_REVERSE_TRAIN_DIRECTION
00240 
00241   DEF_CMD(CmdModifyOrder,                                    0), // CMD_MODIFY_ORDER
00242   DEF_CMD(CmdSkipToOrder,                                    0), // CMD_SKIP_TO_ORDER
00243   DEF_CMD(CmdDeleteOrder,                                    0), // CMD_DELETE_ORDER
00244   DEF_CMD(CmdInsertOrder,                                    0), // CMD_INSERT_ORDER
00245 
00246   DEF_CMD(CmdChangeServiceInt,                               0), // CMD_CHANGE_SERVICE_INT
00247 
00248   DEF_CMD(CmdBuildIndustry,                                  0), // CMD_BUILD_INDUSTRY
00249   DEF_CMD(CmdBuildCompanyHQ,           CMD_NO_WATER | CMD_AUTO), // CMD_BUILD_COMPANY_HQ
00250   DEF_CMD(CmdSetCompanyManagerFace,                          0), // CMD_SET_COMPANY_MANAGER_FACE
00251   DEF_CMD(CmdSetCompanyColour,                               0), // CMD_SET_COMPANY_COLOUR
00252 
00253   DEF_CMD(CmdIncreaseLoan,                                   0), // CMD_INCREASE_LOAN
00254   DEF_CMD(CmdDecreaseLoan,                                   0), // CMD_DECREASE_LOAN
00255 
00256   DEF_CMD(CmdWantEnginePreview,                              0), // CMD_WANT_ENGINE_PREVIEW
00257 
00258   DEF_CMD(CmdRenameVehicle,                                  0), // CMD_RENAME_VEHICLE
00259   DEF_CMD(CmdRenameEngine,                                   0), // CMD_RENAME_ENGINE
00260 
00261   DEF_CMD(CmdRenameCompany,                                  0), // CMD_RENAME_COMPANY
00262   DEF_CMD(CmdRenamePresident,                                0), // CMD_RENAME_PRESIDENT
00263 
00264   DEF_CMD(CmdRenameStation,                                  0), // CMD_RENAME_STATION
00265 
00266   DEF_CMD(CmdSellAircraft,                                   0), // CMD_SELL_AIRCRAFT
00267 
00268   DEF_CMD(CmdBuildAircraft,                                  0), // CMD_BUILD_AIRCRAFT
00269   DEF_CMD(CmdSendAircraftToHangar,                           0), // CMD_SEND_AIRCRAFT_TO_HANGAR
00270   DEF_CMD(CmdRefitAircraft,                                  0), // CMD_REFIT_AIRCRAFT
00271 
00272   DEF_CMD(CmdPlaceSign,                                      0), // CMD_PLACE_SIGN
00273   DEF_CMD(CmdRenameSign,                                     0), // CMD_RENAME_SIGN
00274 
00275   DEF_CMD(CmdBuildRoadVeh,                                   0), // CMD_BUILD_ROAD_VEH
00276   DEF_CMD(CmdSellRoadVeh,                                    0), // CMD_SELL_ROAD_VEH
00277   DEF_CMD(CmdSendRoadVehToDepot,                             0), // CMD_SEND_ROADVEH_TO_DEPOT
00278   DEF_CMD(CmdTurnRoadVeh,                                    0), // CMD_TURN_ROADVEH
00279   DEF_CMD(CmdRefitRoadVeh,                                   0), // CMD_REFIT_ROAD_VEH
00280 
00281   DEF_CMD(CmdPause,                                 CMD_SERVER), // CMD_PAUSE
00282 
00283   DEF_CMD(CmdBuyShareInCompany,                              0), // CMD_BUY_SHARE_IN_COMPANY
00284   DEF_CMD(CmdSellShareInCompany,                             0), // CMD_SELL_SHARE_IN_COMPANY
00285   DEF_CMD(CmdBuyCompany,                                     0), // CMD_BUY_COMANY
00286 
00287   DEF_CMD(CmdFoundTown,                            CMD_NO_TEST), // CMD_FOUND_TOWN; founding random town can fail only in exec run
00288   DEF_CMD(CmdRenameTown,                            CMD_SERVER), // CMD_RENAME_TOWN
00289   DEF_CMD(CmdDoTownAction,                                   0), // CMD_DO_TOWN_ACTION
00290 
00291   DEF_CMD(CmdSellShip,                                       0), // CMD_SELL_SHIP
00292   DEF_CMD(CmdBuildShip,                                      0), // CMD_BUILD_SHIP
00293   DEF_CMD(CmdSendShipToDepot,                                0), // CMD_SEND_SHIP_TO_DEPOT
00294   DEF_CMD(CmdRefitShip,                                      0), // CMD_REFIT_SHIP
00295 
00296   DEF_CMD(CmdOrderRefit,                                     0), // CMD_ORDER_REFIT
00297   DEF_CMD(CmdCloneOrder,                                     0), // CMD_CLONE_ORDER
00298 
00299   DEF_CMD(CmdClearArea,                            CMD_NO_TEST), // CMD_CLEAR_AREA; destroying multi-tile houses makes town rating differ between test and execution
00300 
00301   DEF_CMD(CmdMoneyCheat,                           CMD_OFFLINE), // CMD_MONEY_CHEAT
00302   DEF_CMD(CmdBuildCanal,                              CMD_AUTO), // CMD_BUILD_CANAL
00303   DEF_CMD(CmdCompanyCtrl,                        CMD_SPECTATOR), // CMD_COMPANY_CTRL
00304 
00305   DEF_CMD(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
00306 
00307   DEF_CMD(CmdRefitRailVehicle,                               0), // CMD_REFIT_RAIL_VEHICLE
00308   DEF_CMD(CmdRestoreOrderIndex,                              0), // CMD_RESTORE_ORDER_INDEX
00309   DEF_CMD(CmdBuildLock,                               CMD_AUTO), // CMD_BUILD_LOCK
00310 
00311   DEF_CMD(CmdBuildSignalTrack,                        CMD_AUTO), // CMD_BUILD_SIGNAL_TRACK
00312   DEF_CMD(CmdRemoveSignalTrack,                       CMD_AUTO), // CMD_REMOVE_SIGNAL_TRACK
00313 
00314   DEF_CMD(CmdGiveMoney,                                      0), // CMD_GIVE_MONEY
00315   DEF_CMD(CmdChangeSetting,                         CMD_SERVER), // CMD_CHANGE_SETTING
00316   DEF_CMD(CmdChangeCompanySetting,                           0), // CMD_CHANGE_COMPANY_SETTING
00317   DEF_CMD(CmdSetAutoReplace,                                 0), // CMD_SET_AUTOREPLACE
00318   DEF_CMD(CmdCloneVehicle,                         CMD_NO_TEST), // CMD_CLONE_VEHICLE; NewGRF callbacks influence building and refitting making it impossible to correctly estimate the cost
00319   DEF_CMD(CmdStartStopVehicle,                               0), // CMD_START_STOP_VEHICLE
00320   DEF_CMD(CmdMassStartStopVehicle,                           0), // CMD_MASS_START_STOP
00321   DEF_CMD(CmdAutoreplaceVehicle,                             0), // CMD_AUTOREPLACE_VEHICLE
00322   DEF_CMD(CmdDepotSellAllVehicles,                           0), // CMD_DEPOT_SELL_ALL_VEHICLES
00323   DEF_CMD(CmdDepotMassAutoReplace,                           0), // CMD_DEPOT_MASS_AUTOREPLACE
00324   DEF_CMD(CmdCreateGroup,                                    0), // CMD_CREATE_GROUP
00325   DEF_CMD(CmdDeleteGroup,                                    0), // CMD_DELETE_GROUP
00326   DEF_CMD(CmdRenameGroup,                                    0), // CMD_RENAME_GROUP
00327   DEF_CMD(CmdAddVehicleGroup,                                0), // CMD_ADD_VEHICLE_GROUP
00328   DEF_CMD(CmdAddSharedVehicleGroup,                          0), // CMD_ADD_SHARE_VEHICLE_GROUP
00329   DEF_CMD(CmdRemoveAllVehiclesGroup,                         0), // CMD_REMOVE_ALL_VEHICLES_GROUP
00330   DEF_CMD(CmdSetGroupReplaceProtection,                      0), // CMD_SET_GROUP_REPLACE_PROTECTION
00331   DEF_CMD(CmdMoveOrder,                                      0), // CMD_MOVE_ORDER
00332   DEF_CMD(CmdChangeTimetable,                                0), // CMD_CHANGE_TIMETABLE
00333   DEF_CMD(CmdSetVehicleOnTime,                               0), // CMD_SET_VEHICLE_ON_TIME
00334   DEF_CMD(CmdAutofillTimetable,                              0), // CMD_AUTOFILL_TIMETABLE
00335   DEF_CMD(CmdSetTimetableStart,                              0), // CMD_SET_TIMETABLE_START
00336 };
00337 
00344 bool IsValidCommand(uint32 cmd)
00345 {
00346   cmd &= CMD_ID_MASK;
00347 
00348   return
00349     cmd < lengthof(_command_proc_table) &&
00350     _command_proc_table[cmd].proc != NULL;
00351 }
00352 
00360 byte GetCommandFlags(uint32 cmd)
00361 {
00362   assert(IsValidCommand(cmd));
00363 
00364   return _command_proc_table[cmd & CMD_ID_MASK].flags;
00365 }
00366 
00374 const char *GetCommandName(uint32 cmd)
00375 {
00376   assert(IsValidCommand(cmd));
00377 
00378   return _command_proc_table[cmd & CMD_ID_MASK].name;
00379 }
00380 
00381 static int _docommand_recursive = 0;
00382 
00391 CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags)
00392 {
00393   return DoCommand(container->tile, container->p1, container->p2, flags, container->cmd & CMD_ID_MASK, container->text);
00394 }
00395 
00409 CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag flags, uint32 cmd, const char *text)
00410 {
00411   CommandCost res;
00412 
00413   /* Do not even think about executing out-of-bounds tile-commands */
00414   if (tile != 0 && (tile >= MapSize() || (!IsValidTile(tile) && (flags & DC_ALL_TILES) == 0))) return CMD_ERROR;
00415 
00416   /* Chop of any CMD_MSG or other flags; we don't need those here */
00417   CommandProc *proc = _command_proc_table[cmd & CMD_ID_MASK].proc;
00418 
00419   if (_docommand_recursive == 0) _error_message = INVALID_STRING_ID;
00420 
00421   _docommand_recursive++;
00422 
00423   /* only execute the test call if it's toplevel, or we're not execing. */
00424   if (_docommand_recursive == 1 || !(flags & DC_EXEC) ) {
00425     SetTownRatingTestMode(true);
00426     res = proc(tile, flags & ~DC_EXEC, p1, p2, text);
00427     SetTownRatingTestMode(false);
00428     if (res.Failed()) {
00429       goto error;
00430     }
00431 
00432     if (_docommand_recursive == 1 &&
00433         !(flags & DC_QUERY_COST) &&
00434         !(flags & DC_BANKRUPT) &&
00435         !CheckCompanyHasMoney(res)) {
00436       goto error;
00437     }
00438 
00439     if (!(flags & DC_EXEC)) {
00440       _docommand_recursive--;
00441       return res;
00442     }
00443   }
00444 
00445   /* Execute the command here. All cost-relevant functions set the expenses type
00446    * themselves to the cost object at some point */
00447   res = proc(tile, flags, p1, p2, text);
00448   if (res.Failed()) {
00449 error:
00450     res.SetGlobalErrorMessage();
00451     _docommand_recursive--;
00452     return CMD_ERROR;
00453   }
00454 
00455   /* if toplevel, subtract the money. */
00456   if (--_docommand_recursive == 0 && !(flags & DC_BANKRUPT)) {
00457     SubtractMoneyFromCompany(res);
00458   }
00459 
00460   return res;
00461 }
00462 
00470 Money GetAvailableMoneyForCommand()
00471 {
00472   CompanyID company = _current_company;
00473   if (!Company::IsValidID(company)) return INT64_MAX;
00474   return Company::Get(company)->money;
00475 }
00476 
00483 bool DoCommandP(const CommandContainer *container, bool my_cmd)
00484 {
00485   return DoCommandP(container->tile, container->p1, container->p2, container->cmd, container->callback, container->text, my_cmd);
00486 }
00487 
00503 bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd)
00504 {
00505   /* Cost estimation is generally only done when the
00506    * local user presses shift while doing somthing.
00507    * However, in case of incoming network commands,
00508    * map generation of the pause button we do want
00509    * to execute. */
00510   bool estimate_only = _shift_pressed && IsLocalCompany() &&
00511       !IsGeneratingWorld() &&
00512       !(cmd & CMD_NETWORK_COMMAND) &&
00513       (cmd & CMD_ID_MASK) != CMD_PAUSE;
00514 
00515   /* We're only sending the command, so don't do
00516    * fancy things for 'success'. */
00517   bool only_sending = _networking && !(cmd & CMD_NETWORK_COMMAND);
00518 
00519   /* Where to show the message? */
00520   int x = TileX(tile) * TILE_SIZE;
00521   int y = TileY(tile) * TILE_SIZE;
00522 
00523   CommandCost res = DoCommandPInternal(tile, p1, p2, cmd, callback, text, my_cmd, estimate_only);
00524   if (res.Failed()) {
00525     res.SetGlobalErrorMessage();
00526 
00527     /* Only show the error when it's for us. */
00528     StringID error_part1 = GB(cmd, 16, 16);
00529     if (estimate_only || (IsLocalCompany() && error_part1 != 0 && my_cmd)) {
00530       ShowErrorMessage(error_part1, _error_message, x, y);
00531     }
00532   } else if (estimate_only) {
00533     ShowEstimatedCostOrIncome(res.GetCost(), x, y);
00534   } else if (!only_sending && res.GetCost() != 0 && tile != 0 && IsLocalCompany() && _game_mode != GM_EDITOR) {
00535     /* Only show the cost animation when we did actually
00536      * execute the command, i.e. we're not sending it to
00537      * the server, when it has cost the local company
00538      * something. Furthermore in the editor there is no
00539      * concept of cost, so don't show it there either. */
00540     ShowCostOrIncomeAnimation(x, y, GetSlopeZ(x, y), res.GetCost());
00541   }
00542 
00543   if (!estimate_only && !only_sending && callback != NULL) {
00544     callback(res, tile, p1, p2);
00545   }
00546 
00547   return res.Succeeded();
00548 }
00549 
00550 
00556 #define return_dcpi(cmd, clear) { _docommand_recursive = 0; ClearStorageChanges(clear); return cmd; }
00557 
00571 CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, bool estimate_only)
00572 {
00573   /* Prevent recursion; it gives a mess over the network */
00574   assert(_docommand_recursive == 0);
00575   _docommand_recursive = 1;
00576 
00577   /* Reset the state. */
00578   _error_message = INVALID_STRING_ID;
00579   _additional_cash_required = 0;
00580 
00581   /* Get pointer to command handler */
00582   byte cmd_id = cmd & CMD_ID_MASK;
00583   assert(cmd_id < lengthof(_command_proc_table));
00584 
00585   CommandProc *proc = _command_proc_table[cmd_id].proc;
00586   /* Shouldn't happen, but you never know when someone adds
00587    * NULLs to the _command_proc_table. */
00588   assert(proc != NULL);
00589 
00590   /* Command flags are used internally */
00591   uint cmd_flags = GetCommandFlags(cmd);
00592   /* Flags get send to the DoCommand */
00593   DoCommandFlag flags = CommandFlagsToDCFlags(cmd_flags);
00594 
00595   /* Do not even think about executing out-of-bounds tile-commands */
00596   if (tile != 0 && (tile >= MapSize() || (!IsValidTile(tile) && (cmd_flags & CMD_ALL_TILES) == 0))) return_dcpi(CMD_ERROR, false);
00597 
00598   /* Always execute server and spectator commands as spectator */
00599   if (cmd_flags & (CMD_SPECTATOR | CMD_SERVER)) _current_company = COMPANY_SPECTATOR;
00600 
00601   CompanyID old_company = _current_company;
00602 
00603   /* If the company isn't valid it may only do server command or start a new company!
00604    * The server will ditch any server commands a client sends to it, so effectively
00605    * this guards the server from executing functions for an invalid company. */
00606   if (_game_mode == GM_NORMAL && (cmd_flags & (CMD_SPECTATOR | CMD_SERVER)) == 0 && !Company::IsValidID(_current_company)) {
00607     return_dcpi(CMD_ERROR, false);
00608   }
00609 
00610   bool test_and_exec_can_differ = (cmd_flags & CMD_NO_TEST) != 0;
00611   bool skip_test = _networking && (cmd & CMD_NO_TEST_IF_IN_NETWORK) != 0;
00612 
00613   /* Do we need to do a test run?
00614    * Basically we need to always do this, except when
00615    * the no-test-in-network flag is giving and we're
00616    * in a network game (e.g. restoring orders would
00617    * fail this test because the first order does not
00618    * exist yet when inserting the second, giving that
00619    * a wrong insert location and ignoring the command
00620    * and thus breaking restoring). However, when we
00621    * just want to do cost estimation we don't care
00622    * because it's only done once anyway. */
00623   CommandCost res;
00624   if (estimate_only || !skip_test) {
00625     /* Test the command. */
00626     SetTownRatingTestMode(true);
00627     res = proc(tile, flags, p1, p2, text);
00628     SetTownRatingTestMode(false);
00629 
00630     /* Make sure we're not messing things up here. */
00631     assert(cmd_id == CMD_COMPANY_CTRL || old_company == _current_company);
00632 
00633     /* If the command fails, we're doing an estimate
00634      * or the player does not have enough money
00635      * (unless it's a command where the test and
00636      * execution phase might return different costs)
00637      * we bail out here. */
00638     if (res.Failed() || estimate_only ||
00639         (!test_and_exec_can_differ && !CheckCompanyHasMoney(res))) {
00640       return_dcpi(res, false);
00641     }
00642   }
00643 
00644 #ifdef ENABLE_NETWORK
00645   /*
00646    * If we are in network, and the command is not from the network
00647    * send it to the command-queue and abort execution
00648    */
00649   if (_networking && !(cmd & CMD_NETWORK_COMMAND)) {
00650     NetworkSend_Command(tile, p1, p2, cmd & ~CMD_FLAGS_MASK, callback, text, _current_company);
00651 
00652     /* Don't return anything special here; no error, no costs.
00653      * This way it's not handled by DoCommand and only the
00654      * actual execution of the command causes messages. Also
00655      * reset the storages as we've not executed the command. */
00656     return_dcpi(CommandCost(), false);
00657   }
00658 #endif /* ENABLE_NETWORK */
00659   DEBUG(desync, 1, "cmd: %08x; %02x; %02x; %06x; %08x; %08x; %08x; \"%s\" (%s)", _date, _date_fract, (int)_current_company, tile, p1, p2, cmd & ~CMD_NETWORK_COMMAND, text, GetCommandName(cmd));
00660 
00661   /* Actually try and execute the command. If no cost-type is given
00662    * use the construction one */
00663   CommandCost res2 = proc(tile, flags | DC_EXEC, p1, p2, text);
00664 
00665   /* Make sure nothing bad happened, like changing the current company. */
00666   assert(cmd_id == CMD_COMPANY_CTRL || old_company == _current_company);
00667 
00668   /* If the test and execution can differ, or we skipped the test
00669    * we have to check the return of the command. Otherwise we can
00670    * check whether the test and execution have yielded the same
00671    * result, i.e. cost and error state are the same. */
00672   if (!test_and_exec_can_differ && !skip_test) {
00673     assert(res.GetCost() == res2.GetCost() && res.Failed() == res2.Failed()); // sanity check
00674   } else if (res2.Failed()) {
00675     return_dcpi(res2, false);
00676   }
00677 
00678   /* If we're needing more money and we haven't done
00679    * anything yet, ask for the money! */
00680   if (_additional_cash_required != 0 && res2.GetCost() == 0) {
00681     /* It could happen we removed rail, thus gained money, and deleted something else.
00682      * So make sure the signal buffer is empty even in this case */
00683     UpdateSignalsInBuffer();
00684     SetDParam(0, _additional_cash_required);
00685     return_dcpi(CommandCost(STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY), false);
00686   }
00687 
00688   /* update last build coordinate of company. */
00689   if (tile != 0) {
00690     Company *c = Company::GetIfValid(_current_company);
00691     if (c != NULL) c->last_build_coordinate = tile;
00692   }
00693 
00694   SubtractMoneyFromCompany(res2);
00695 
00696   /* update signals if needed */
00697   UpdateSignalsInBuffer();
00698 
00699   return_dcpi(res2, true);
00700 }
00701 #undef return_dcpi
00702 
00703 
00709 void CommandCost::AddCost(const CommandCost &ret)
00710 {
00711   this->AddCost(ret.cost);
00712   if (this->success && !ret.success) {
00713     this->message = ret.message;
00714     this->success = false;
00715   }
00716 }

Generated on Fri Apr 30 21:55:19 2010 for OpenTTD by  doxygen 1.6.1