4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
10 /** @file command.cpp Handling of commands. */
13 #include "landscape.h"
16 #include "command_func.h"
17 #include "network/network_type.h"
18 #include "network/network.h"
20 #include "strings_func.h"
21 #include "texteff.hpp"
23 #include "date_func.h"
24 #include "company_func.h"
25 #include "company_base.h"
26 #include "signalbuffer.h"
27 #include "core/backup_type.hpp"
28 #include "object_base.h"
29 #include "ai/ai_instance.hpp"
30 #include "game/game_instance.hpp"
32 #include "table/strings.h"
34 CommandProc CmdBuildRailroadTrack
;
35 CommandProc CmdRemoveRailroadTrack
;
36 CommandProc CmdBuildSingleRail
;
37 CommandProc CmdRemoveSingleRail
;
39 CommandProc CmdLandscapeClear
;
41 CommandProc CmdBuildBridge
;
43 CommandProc CmdBuildRailStation
;
44 CommandProc CmdRemoveFromRailStation
;
45 CommandProc CmdConvertRail
;
47 CommandProc CmdBuildSingleSignal
;
48 CommandProc CmdRemoveSingleSignal
;
50 CommandProc CmdTerraformLand
;
52 CommandProc CmdBuildObject
;
53 CommandProc CmdSellLandArea
;
55 CommandProc CmdBuildTunnel
;
57 CommandProc CmdBuildTrainDepot
;
58 CommandProc CmdBuildRailWaypoint
;
59 CommandProc CmdRenameWaypoint
;
60 CommandProc CmdRemoveFromRailWaypoint
;
62 CommandProc CmdBuildRoadStop
;
63 CommandProc CmdRemoveRoadStop
;
65 CommandProc CmdBuildLongRoad
;
66 CommandProc CmdRemoveLongRoad
;
67 CommandProc CmdBuildRoad
;
69 CommandProc CmdBuildRoadDepot
;
71 CommandProc CmdBuildAirport
;
73 CommandProc CmdBuildDock
;
75 CommandProc CmdBuildShipDepot
;
77 CommandProc CmdBuildBuoy
;
79 CommandProc CmdPlantTree
;
81 CommandProc CmdMoveRailVehicle
;
83 CommandProc CmdBuildVehicle
;
84 CommandProc CmdSellVehicle
;
85 CommandProc CmdRefitVehicle
;
86 CommandProc CmdSendVehicleToDepot
;
87 CommandProc CmdSetVehicleVisibility
;
89 CommandProc CmdForceTrainProceed
;
90 CommandProc CmdReverseTrainDirection
;
92 CommandProc CmdClearOrderBackup
;
93 CommandProc CmdModifyOrder
;
94 CommandProc CmdSkipToOrder
;
95 CommandProc CmdDeleteOrder
;
96 CommandProc CmdInsertOrder
;
97 CommandProc CmdChangeServiceInt
;
99 CommandProc CmdBuildIndustry
;
101 CommandProc CmdSetCompanyManagerFace
;
102 CommandProc CmdSetCompanyColour
;
104 CommandProc CmdIncreaseLoan
;
105 CommandProc CmdDecreaseLoan
;
107 CommandProc CmdWantEnginePreview
;
109 CommandProc CmdRenameVehicle
;
110 CommandProc CmdRenameEngine
;
112 CommandProc CmdRenameCompany
;
113 CommandProc CmdRenamePresident
;
115 CommandProc CmdRenameStation
;
116 CommandProc CmdRenameDepot
;
118 CommandProc CmdPlaceSign
;
119 CommandProc CmdRenameSign
;
121 CommandProc CmdTurnRoadVeh
;
123 CommandProc CmdPause
;
125 CommandProc CmdBuyShareInCompany
;
126 CommandProc CmdSellShareInCompany
;
127 CommandProc CmdBuyCompany
;
129 CommandProc CmdFoundTown
;
130 CommandProc CmdRenameTown
;
131 CommandProc CmdDoTownAction
;
132 CommandProc CmdTownGrowthRate
;
133 CommandProc CmdTownCargoGoal
;
134 CommandProc CmdTownSetText
;
135 CommandProc CmdExpandTown
;
136 CommandProc CmdDeleteTown
;
138 CommandProc CmdChangeSetting
;
139 CommandProc CmdChangeCompanySetting
;
141 CommandProc CmdOrderRefit
;
142 CommandProc CmdCloneOrder
;
144 CommandProc CmdClearArea
;
146 CommandProc CmdGiveMoney
;
147 CommandProc CmdMoneyCheat
;
148 CommandProc CmdChangeBankBalance
;
149 CommandProc CmdBuildCanal
;
150 CommandProc CmdBuildLock
;
152 CommandProc CmdCreateSubsidy
;
153 CommandProc CmdCompanyCtrl
;
154 CommandProc CmdCustomNewsItem
;
155 CommandProc CmdCreateGoal
;
156 CommandProc CmdRemoveGoal
;
157 CommandProc CmdSetGoalText
;
158 CommandProc CmdSetGoalProgress
;
159 CommandProc CmdSetGoalCompleted
;
160 CommandProc CmdGoalQuestion
;
161 CommandProc CmdGoalQuestionAnswer
;
162 CommandProc CmdCreateStoryPage
;
163 CommandProc CmdCreateStoryPageElement
;
164 CommandProc CmdUpdateStoryPageElement
;
165 CommandProc CmdSetStoryPageTitle
;
166 CommandProc CmdSetStoryPageDate
;
167 CommandProc CmdShowStoryPage
;
168 CommandProc CmdRemoveStoryPage
;
169 CommandProc CmdRemoveStoryPageElement
;
171 CommandProc CmdLevelLand
;
173 CommandProc CmdBuildSignalTrack
;
174 CommandProc CmdRemoveSignalTrack
;
176 CommandProc CmdSetAutoReplace
;
178 CommandProc CmdCloneVehicle
;
179 CommandProc CmdStartStopVehicle
;
180 CommandProc CmdMassStartStopVehicle
;
181 CommandProc CmdAutoreplaceVehicle
;
182 CommandProc CmdDepotSellAllVehicles
;
183 CommandProc CmdDepotMassAutoReplace
;
185 CommandProc CmdCreateGroup
;
186 CommandProc CmdAlterGroup
;
187 CommandProc CmdDeleteGroup
;
188 CommandProc CmdAddVehicleGroup
;
189 CommandProc CmdAddSharedVehicleGroup
;
190 CommandProc CmdRemoveAllVehiclesGroup
;
191 CommandProc CmdSetGroupReplaceProtection
;
193 CommandProc CmdMoveOrder
;
194 CommandProc CmdChangeTimetable
;
195 CommandProc CmdSetVehicleOnTime
;
196 CommandProc CmdAutofillTimetable
;
197 CommandProc CmdSetTimetableStart
;
199 CommandProc CmdOpenCloseAirport
;
201 template <StringID str
>
202 StringID
GetErrConstant (TileIndex tile
, uint32 p1
, uint32 p2
, const char *text
)
207 CommandErrstrF GetErrTerraformLand
;
208 CommandErrstrF GetErrLevelLand
;
209 CommandErrstrF GetErrRenameSign
;
211 CommandErrstrF GetErrBuildSingleRail
;
212 CommandErrstrF GetErrBuildSignals
;
214 CommandErrstrF GetErrBuildRoadStop
;
215 CommandErrstrF GetErrRemoveRoadStop
;
216 CommandErrstrF GetErrBuildRoad
;
217 CommandErrstrF GetErrRemoveRoad
;
218 CommandErrstrF GetErrBuildRoadDepot
;
220 CommandErrstrF GetErrBuildCanal
;
222 CommandErrstrF GetErrBuildBridge
;
223 CommandErrstrF GetErrBuildObject
;
225 CommandErrstrF GetErrRenameEngine
;
227 CommandErrstrF GetErrBuildVehicle
;
228 CommandErrstrF GetErrSellVehicle
;
229 CommandErrstrF GetErrRefitVehicle
;
230 CommandErrstrF GetErrCloneVehicle
;
231 CommandErrstrF GetErrRenameVehicle
;
232 CommandErrstrF GetErrStartStopVehicle
;
233 CommandErrstrF GetErrSendVehicleToDepot
;
234 CommandErrstrF GetErrMoveRailVehicle
;
235 CommandErrstrF GetErrReverseTrain
;
237 CommandErrstrF GetErrCloneOrder
;
238 CommandErrstrF GetErrSkipToOrder
;
240 CommandErrstrF GetErrAlterGroup
;
242 CommandErrstrF GetErrFoundTown
;
244 #define DEF_CMD(proc, flags, type, callback, errorf) {proc, #proc, (CommandFlags)flags, type, callback, errorf}
247 * The master command table
249 * This table contains all possible CommandProc functions with
250 * the flags which belongs to it. The indices are the same
251 * as the value from the CMD_* enums.
253 static const CommandClass _command_proc_table
[] = {
254 DEF_CMD(CmdBuildRailroadTrack
, CMDF_NO_WATER
| CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK
>), // CMD_BUILD_RAILROAD_TRACK
255 DEF_CMD(CmdRemoveRailroadTrack
, CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK
>), // CMD_REMOVE_RAILROAD_TRACK
256 DEF_CMD(CmdBuildSingleRail
, CMDF_NO_WATER
| CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcSingleRail
, GetErrBuildSingleRail
), // CMD_BUILD_SINGLE_RAIL
257 DEF_CMD(CmdRemoveSingleRail
, CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcSingleRail
, GetErrConstant
<STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK
>), // CMD_REMOVE_SINGLE_RAIL
258 DEF_CMD(CmdLandscapeClear
, 0, CMDT_LANDSCAPE_CONSTRUCTION
, NULL
, NULL
), // CMD_LANDSCAPE_CLEAR
259 DEF_CMD(CmdBuildBridge
, CMDF_DEITY
| CMDF_NO_WATER
| CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcBuildBridge
, GetErrBuildBridge
), // CMD_BUILD_BRIDGE
260 DEF_CMD(CmdBuildRailStation
, CMDF_NO_WATER
| CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcStation
, GetErrConstant
<STR_ERROR_CAN_T_BUILD_RAILROAD_STATION
>), // CMD_BUILD_RAIL_STATION
261 DEF_CMD(CmdBuildTrainDepot
, CMDF_NO_WATER
| CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcRailDepot
, GetErrConstant
<STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT
>), // CMD_BUILD_TRAIN_DEPOT
262 DEF_CMD(CmdBuildSingleSignal
, CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcPlaySound_SPLAT_RAIL
, GetErrBuildSignals
), // CMD_BUILD_SIGNALS
263 DEF_CMD(CmdRemoveSingleSignal
, CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcPlaySound_SPLAT_RAIL
, GetErrConstant
<STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM
>), // CMD_REMOVE_SIGNALS
264 DEF_CMD(CmdTerraformLand
, CMDF_ALL_TILES
| CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcTerraformLand
, GetErrTerraformLand
), // CMD_TERRAFORM_LAND
265 DEF_CMD(CmdBuildObject
, CMDF_NO_WATER
| CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcBuildObject
, GetErrBuildObject
), // CMD_BUILD_OBJECT
266 DEF_CMD(CmdBuildTunnel
, CMDF_DEITY
| CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcBuildTunnel
, GetErrConstant
<STR_ERROR_CAN_T_BUILD_TUNNEL_HERE
>), // CMD_BUILD_TUNNEL
267 DEF_CMD(CmdRemoveFromRailStation
, 0, CMDT_LANDSCAPE_CONSTRUCTION
, CcPlaySound_SPLAT_RAIL
, GetErrConstant
<STR_ERROR_CAN_T_REMOVE_PART_OF_STATION
>),// CMD_REMOVE_FROM_RAIL_STATION
268 DEF_CMD(CmdConvertRail
, 0, CMDT_LANDSCAPE_CONSTRUCTION
, CcPlaySound_SPLAT_RAIL
, GetErrConstant
<STR_ERROR_CAN_T_CONVERT_RAIL
>), // CMD_CONVERT_RAIL
269 DEF_CMD(CmdBuildRailWaypoint
, 0, CMDT_LANDSCAPE_CONSTRUCTION
, CcPlaySound_SPLAT_RAIL
, GetErrConstant
<STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT
>), // CMD_BUILD_RAIL_WAYPOINT
270 DEF_CMD(CmdRenameWaypoint
, 0, CMDT_OTHER_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_CHANGE_WAYPOINT_NAME
>), // CMD_RENAME_WAYPOINT
271 DEF_CMD(CmdRemoveFromRailWaypoint
, 0, CMDT_LANDSCAPE_CONSTRUCTION
, CcPlaySound_SPLAT_RAIL
, GetErrConstant
<STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT
>), // CMD_REMOVE_FROM_RAIL_WAYPOINT
273 DEF_CMD(CmdBuildRoadStop
, CMDF_NO_WATER
| CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcRoadStop
, GetErrBuildRoadStop
), // CMD_BUILD_ROAD_STOP
274 DEF_CMD(CmdRemoveRoadStop
, 0, CMDT_LANDSCAPE_CONSTRUCTION
, CcPlaySound_SPLAT_OTHER
, GetErrRemoveRoadStop
), // CMD_REMOVE_ROAD_STOP
275 DEF_CMD(CmdBuildLongRoad
, CMDF_DEITY
| CMDF_NO_WATER
| CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcPlaySound_SPLAT_OTHER
, GetErrBuildRoad
), // CMD_BUILD_LONG_ROAD
276 DEF_CMD(CmdRemoveLongRoad
, CMDF_NO_TEST
| CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcPlaySound_SPLAT_OTHER
, GetErrRemoveRoad
), // 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.
277 DEF_CMD(CmdBuildRoad
, CMDF_DEITY
| CMDF_NO_WATER
| CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, NULL
, NULL
), // CMD_BUILD_ROAD
278 DEF_CMD(CmdBuildRoadDepot
, CMDF_NO_WATER
| CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcRoadDepot
, GetErrBuildRoadDepot
), // CMD_BUILD_ROAD_DEPOT
280 DEF_CMD(CmdBuildAirport
, CMDF_NO_WATER
| CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcBuildAirport
, GetErrConstant
<STR_ERROR_CAN_T_BUILD_AIRPORT_HERE
>), // CMD_BUILD_AIRPORT
281 DEF_CMD(CmdBuildDock
, CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcBuildDocks
, GetErrConstant
<STR_ERROR_CAN_T_BUILD_DOCK_HERE
>), // CMD_BUILD_DOCK
282 DEF_CMD(CmdBuildShipDepot
, CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcBuildDocks
, GetErrConstant
<STR_ERROR_CAN_T_BUILD_SHIP_DEPOT
>), // CMD_BUILD_SHIP_DEPOT
283 DEF_CMD(CmdBuildBuoy
, CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcBuildDocks
, GetErrConstant
<STR_ERROR_CAN_T_POSITION_BUOY_HERE
>), // CMD_BUILD_BUOY
284 DEF_CMD(CmdPlantTree
, CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_PLANT_TREE_HERE
>), // CMD_PLANT_TREE
286 DEF_CMD(CmdBuildVehicle
, CMDF_CLIENT_ID
, CMDT_VEHICLE_CONSTRUCTION
, CcBuildVehicle
, GetErrBuildVehicle
), // CMD_BUILD_VEHICLE
287 DEF_CMD(CmdSellVehicle
, CMDF_CLIENT_ID
, CMDT_VEHICLE_CONSTRUCTION
, NULL
, GetErrSellVehicle
), // CMD_SELL_VEHICLE
288 DEF_CMD(CmdRefitVehicle
, 0, CMDT_VEHICLE_CONSTRUCTION
, NULL
, GetErrRefitVehicle
), // CMD_REFIT_VEHICLE
289 DEF_CMD(CmdSendVehicleToDepot
, 0, CMDT_VEHICLE_MANAGEMENT
, NULL
, GetErrSendVehicleToDepot
), // CMD_SEND_VEHICLE_TO_DEPOT
290 DEF_CMD(CmdSetVehicleVisibility
, 0, CMDT_COMPANY_SETTING
, NULL
, NULL
), // CMD_SET_VEHICLE_VISIBILITY
292 DEF_CMD(CmdMoveRailVehicle
, 0, CMDT_VEHICLE_CONSTRUCTION
, NULL
, GetErrMoveRailVehicle
), // CMD_MOVE_RAIL_VEHICLE
293 DEF_CMD(CmdForceTrainProceed
, 0, CMDT_VEHICLE_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL
>), // CMD_FORCE_TRAIN_PROCEED
294 DEF_CMD(CmdReverseTrainDirection
, 0, CMDT_VEHICLE_MANAGEMENT
, NULL
, GetErrReverseTrain
), // CMD_REVERSE_TRAIN_DIRECTION
296 DEF_CMD(CmdClearOrderBackup
, CMDF_CLIENT_ID
, CMDT_SERVER_SETTING
, NULL
, NULL
), // CMD_CLEAR_ORDER_BACKUP
297 DEF_CMD(CmdModifyOrder
, 0, CMDT_ROUTE_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_MODIFY_THIS_ORDER
>), // CMD_MODIFY_ORDER
298 DEF_CMD(CmdSkipToOrder
, 0, CMDT_ROUTE_MANAGEMENT
, NULL
, GetErrSkipToOrder
), // CMD_SKIP_TO_ORDER
299 DEF_CMD(CmdDeleteOrder
, 0, CMDT_ROUTE_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_DELETE_THIS_ORDER
>), // CMD_DELETE_ORDER
300 DEF_CMD(CmdInsertOrder
, 0, CMDT_ROUTE_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_INSERT_NEW_ORDER
>), // CMD_INSERT_ORDER
302 DEF_CMD(CmdChangeServiceInt
, 0, CMDT_VEHICLE_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_CHANGE_SERVICING
>), // CMD_CHANGE_SERVICE_INT
304 DEF_CMD(CmdBuildIndustry
, CMDF_DEITY
, CMDT_LANDSCAPE_CONSTRUCTION
, CcBuildIndustry
, GetErrConstant
<STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY
>), // CMD_BUILD_INDUSTRY
305 DEF_CMD(CmdSetCompanyManagerFace
, 0, CMDT_OTHER_MANAGEMENT
, NULL
, NULL
), // CMD_SET_COMPANY_MANAGER_FACE
306 DEF_CMD(CmdSetCompanyColour
, 0, CMDT_OTHER_MANAGEMENT
, NULL
, NULL
), // CMD_SET_COMPANY_COLOUR
308 DEF_CMD(CmdIncreaseLoan
, 0, CMDT_MONEY_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY
>), // CMD_INCREASE_LOAN
309 DEF_CMD(CmdDecreaseLoan
, 0, CMDT_MONEY_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_REPAY_LOAN
>), // CMD_DECREASE_LOAN
311 DEF_CMD(CmdWantEnginePreview
, 0, CMDT_VEHICLE_MANAGEMENT
, NULL
, NULL
), // CMD_WANT_ENGINE_PREVIEW
313 DEF_CMD(CmdRenameVehicle
, 0, CMDT_OTHER_MANAGEMENT
, NULL
, GetErrRenameVehicle
), // CMD_RENAME_VEHICLE
314 DEF_CMD(CmdRenameEngine
, CMDF_SERVER
, CMDT_OTHER_MANAGEMENT
, NULL
, GetErrRenameEngine
), // CMD_RENAME_ENGINE
316 DEF_CMD(CmdRenameCompany
, 0, CMDT_OTHER_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_CHANGE_COMPANY_NAME
>), // CMD_RENAME_COMPANY
317 DEF_CMD(CmdRenamePresident
, 0, CMDT_OTHER_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_CHANGE_PRESIDENT
>), // CMD_RENAME_PRESIDENT
319 DEF_CMD(CmdRenameStation
, 0, CMDT_OTHER_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_RENAME_STATION
>), // CMD_RENAME_STATION
320 DEF_CMD(CmdRenameDepot
, 0, CMDT_OTHER_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_RENAME_DEPOT
>), // CMD_RENAME_DEPOT
322 DEF_CMD(CmdPlaceSign
, CMDF_DEITY
, CMDT_OTHER_MANAGEMENT
, CcPlaceSign
, GetErrConstant
<STR_ERROR_CAN_T_PLACE_SIGN_HERE
>), // CMD_PLACE_SIGN
323 DEF_CMD(CmdRenameSign
, CMDF_DEITY
, CMDT_OTHER_MANAGEMENT
, NULL
, GetErrRenameSign
), // CMD_RENAME_SIGN
325 DEF_CMD(CmdTurnRoadVeh
, 0, CMDT_VEHICLE_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_MAKE_ROAD_VEHICLE_TURN
>), // CMD_TURN_ROADVEH
327 DEF_CMD(CmdPause
, CMDF_SERVER
, CMDT_SERVER_SETTING
, NULL
, NULL
), // CMD_PAUSE
329 DEF_CMD(CmdBuyShareInCompany
, 0, CMDT_MONEY_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS
>), // CMD_BUY_SHARE_IN_COMPANY
330 DEF_CMD(CmdSellShareInCompany
, 0, CMDT_MONEY_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_SELL_25_SHARE_IN
>), // CMD_SELL_SHARE_IN_COMPANY
331 DEF_CMD(CmdBuyCompany
, 0, CMDT_MONEY_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_BUY_COMPANY
>), // CMD_BUY_COMPANY
333 DEF_CMD(CmdFoundTown
, CMDF_DEITY
| CMDF_NO_TEST
, CMDT_LANDSCAPE_CONSTRUCTION
, CcFoundTown
, GetErrFoundTown
), // CMD_FOUND_TOWN; founding random town can fail only in exec run
334 DEF_CMD(CmdRenameTown
, CMDF_DEITY
| CMDF_SERVER
, CMDT_OTHER_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_RENAME_TOWN
>), // CMD_RENAME_TOWN
335 DEF_CMD(CmdDoTownAction
, 0, CMDT_LANDSCAPE_CONSTRUCTION
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_DO_THIS
>), // CMD_DO_TOWN_ACTION
336 DEF_CMD(CmdTownCargoGoal
, CMDF_DEITY
, CMDT_OTHER_MANAGEMENT
, NULL
, NULL
/* unused */), // CMD_TOWN_CARGO_GOAL
337 DEF_CMD(CmdTownGrowthRate
, CMDF_DEITY
, CMDT_OTHER_MANAGEMENT
, NULL
, NULL
/* unused */), // CMD_TOWN_GROWTH_RATE
338 DEF_CMD(CmdTownSetText
, CMDF_STR_CTRL
| CMDF_DEITY
, CMDT_OTHER_MANAGEMENT
, NULL
, NULL
/* unused */), // CMD_TOWN_SET_TEXT
339 DEF_CMD(CmdExpandTown
, CMDF_DEITY
, CMDT_LANDSCAPE_CONSTRUCTION
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_EXPAND_TOWN
>), // CMD_EXPAND_TOWN
340 DEF_CMD(CmdDeleteTown
, CMDF_OFFLINE
, CMDT_LANDSCAPE_CONSTRUCTION
, NULL
, GetErrConstant
<STR_ERROR_TOWN_CAN_T_DELETE
>), // CMD_DELETE_TOWN
342 DEF_CMD(CmdOrderRefit
, 0, CMDT_ROUTE_MANAGEMENT
, NULL
, NULL
), // CMD_ORDER_REFIT
343 DEF_CMD(CmdCloneOrder
, 0, CMDT_ROUTE_MANAGEMENT
, NULL
, GetErrCloneOrder
), // CMD_CLONE_ORDER
345 DEF_CMD(CmdClearArea
, CMDF_NO_TEST
, CMDT_LANDSCAPE_CONSTRUCTION
, CcPlaySound_EXPLOSION
, GetErrConstant
<STR_ERROR_CAN_T_CLEAR_THIS_AREA
>), // CMD_CLEAR_AREA; destroying multi-tile houses makes town rating differ between test and execution
347 DEF_CMD(CmdMoneyCheat
, CMDF_OFFLINE
, CMDT_CHEAT
, NULL
, NULL
), // CMD_MONEY_CHEAT
348 DEF_CMD(CmdChangeBankBalance
, CMDF_DEITY
, CMDT_MONEY_MANAGEMENT
, NULL
, NULL
/* unused */), // CMD_CHANGE_BANK_BALANCE
349 DEF_CMD(CmdBuildCanal
, CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcPlaySound_SPLAT_WATER
, GetErrBuildCanal
), // CMD_BUILD_CANAL
350 DEF_CMD(CmdCreateSubsidy
, CMDF_DEITY
, CMDT_OTHER_MANAGEMENT
, NULL
, NULL
/* unused */), // CMD_CREATE_SUBSIDY
351 DEF_CMD(CmdCompanyCtrl
, CMDF_SPECTATOR
| CMDF_CLIENT_ID
, CMDT_SERVER_SETTING
, NULL
, NULL
), // CMD_COMPANY_CTRL
352 DEF_CMD(CmdCustomNewsItem
, CMDF_STR_CTRL
| CMDF_DEITY
, CMDT_OTHER_MANAGEMENT
, NULL
, NULL
/* unused */), // CMD_CUSTOM_NEWS_ITEM
353 DEF_CMD(CmdCreateGoal
, CMDF_STR_CTRL
| CMDF_DEITY
, CMDT_OTHER_MANAGEMENT
, NULL
, NULL
/* unused */), // CMD_CREATE_GOAL
354 DEF_CMD(CmdRemoveGoal
, CMDF_DEITY
, CMDT_OTHER_MANAGEMENT
, NULL
, NULL
/* unused */), // CMD_REMOVE_GOAL
355 DEF_CMD(CmdSetGoalText
, CMDF_STR_CTRL
| CMDF_DEITY
, CMDT_OTHER_MANAGEMENT
, NULL
, NULL
/* unused */), // CMD_SET_GOAL_TEXT
356 DEF_CMD(CmdSetGoalProgress
, CMDF_STR_CTRL
| CMDF_DEITY
, CMDT_OTHER_MANAGEMENT
, NULL
, NULL
/* unused */), // CMD_SET_GOAL_PROGRESS
357 DEF_CMD(CmdSetGoalCompleted
, CMDF_STR_CTRL
| CMDF_DEITY
, CMDT_OTHER_MANAGEMENT
, NULL
, NULL
/* unused */), // CMD_SET_GOAL_COMPLETED
358 DEF_CMD(CmdGoalQuestion
, CMDF_STR_CTRL
| CMDF_DEITY
, CMDT_OTHER_MANAGEMENT
, NULL
, NULL
/* unused */), // CMD_GOAL_QUESTION
359 DEF_CMD(CmdGoalQuestionAnswer
, CMDF_DEITY
, CMDT_OTHER_MANAGEMENT
, NULL
, NULL
), // CMD_GOAL_QUESTION_ANSWER
360 DEF_CMD(CmdCreateStoryPage
, CMDF_STR_CTRL
| CMDF_DEITY
, CMDT_OTHER_MANAGEMENT
, NULL
, NULL
/* unused */), // CMD_CREATE_STORY_PAGE
361 DEF_CMD(CmdCreateStoryPageElement
, CMDF_STR_CTRL
| CMDF_DEITY
, CMDT_OTHER_MANAGEMENT
, NULL
, NULL
/* unused */), // CMD_CREATE_STORY_PAGE_ELEMENT
362 DEF_CMD(CmdUpdateStoryPageElement
, CMDF_STR_CTRL
| CMDF_DEITY
, CMDT_OTHER_MANAGEMENT
, NULL
, NULL
/* unused */), // CMD_UPDATE_STORY_PAGE_ELEMENT
363 DEF_CMD(CmdSetStoryPageTitle
, CMDF_STR_CTRL
| CMDF_DEITY
, CMDT_OTHER_MANAGEMENT
, NULL
, NULL
/* unused */), // CMD_SET_STORY_PAGE_TITLE
364 DEF_CMD(CmdSetStoryPageDate
, CMDF_DEITY
, CMDT_OTHER_MANAGEMENT
, NULL
, NULL
/* unused */), // CMD_SET_STORY_PAGE_DATE
365 DEF_CMD(CmdShowStoryPage
, CMDF_DEITY
, CMDT_OTHER_MANAGEMENT
, NULL
, NULL
/* unused */), // CMD_SHOW_STORY_PAGE
366 DEF_CMD(CmdRemoveStoryPage
, CMDF_DEITY
, CMDT_OTHER_MANAGEMENT
, NULL
, NULL
/* unused */), // CMD_REMOVE_STORY_PAGE
367 DEF_CMD(CmdRemoveStoryPageElement
, CMDF_DEITY
, CMDT_OTHER_MANAGEMENT
, NULL
, NULL
/* unused */), // CMD_REMOVE_STORY_PAGE_ELEMENT
369 DEF_CMD(CmdLevelLand
, CMDF_ALL_TILES
| CMDF_NO_TEST
| CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcTerraform
, GetErrLevelLand
), // CMD_LEVEL_LAND; test run might clear tiles multiple times, in execution that only happens once
371 DEF_CMD(CmdBuildLock
, CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcBuildDocks
, GetErrConstant
<STR_ERROR_CAN_T_BUILD_LOCKS
>), // CMD_BUILD_LOCK
373 DEF_CMD(CmdBuildSignalTrack
, CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcPlaySound_SPLAT_RAIL
, GetErrConstant
<STR_ERROR_CAN_T_BUILD_SIGNALS_HERE
>), // CMD_BUILD_SIGNAL_TRACK
374 DEF_CMD(CmdRemoveSignalTrack
, CMDF_AUTO
, CMDT_LANDSCAPE_CONSTRUCTION
, CcPlaySound_SPLAT_RAIL
, GetErrConstant
<STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM
>), // CMD_REMOVE_SIGNAL_TRACK
376 DEF_CMD(CmdGiveMoney
, 0, CMDT_MONEY_MANAGEMENT
, CcGiveMoney
, GetErrConstant
<STR_ERROR_INSUFFICIENT_FUNDS
>), // CMD_GIVE_MONEY
377 DEF_CMD(CmdChangeSetting
, CMDF_SERVER
, CMDT_SERVER_SETTING
, NULL
, NULL
), // CMD_CHANGE_SETTING
378 DEF_CMD(CmdChangeCompanySetting
, 0, CMDT_COMPANY_SETTING
, NULL
, NULL
), // CMD_CHANGE_COMPANY_SETTING
379 DEF_CMD(CmdSetAutoReplace
, 0, CMDT_VEHICLE_MANAGEMENT
, NULL
, NULL
), // CMD_SET_AUTOREPLACE
380 DEF_CMD(CmdCloneVehicle
, CMDF_NO_TEST
, CMDT_VEHICLE_CONSTRUCTION
, CcCloneVehicle
, GetErrCloneVehicle
), // CMD_CLONE_VEHICLE; NewGRF callbacks influence building and refitting making it impossible to correctly estimate the cost
381 DEF_CMD(CmdStartStopVehicle
, 0, CMDT_VEHICLE_MANAGEMENT
, CcStartStopVehicle
, GetErrStartStopVehicle
), // CMD_START_STOP_VEHICLE
382 DEF_CMD(CmdMassStartStopVehicle
, 0, CMDT_VEHICLE_MANAGEMENT
, NULL
, NULL
), // CMD_MASS_START_STOP
383 DEF_CMD(CmdAutoreplaceVehicle
, 0, CMDT_VEHICLE_MANAGEMENT
, NULL
, NULL
/* unused */), // CMD_AUTOREPLACE_VEHICLE
384 DEF_CMD(CmdDepotSellAllVehicles
, 0, CMDT_VEHICLE_CONSTRUCTION
, NULL
, NULL
), // CMD_DEPOT_SELL_ALL_VEHICLES
385 DEF_CMD(CmdDepotMassAutoReplace
, 0, CMDT_VEHICLE_CONSTRUCTION
, NULL
, NULL
), // CMD_DEPOT_MASS_AUTOREPLACE
386 DEF_CMD(CmdCreateGroup
, 0, CMDT_ROUTE_MANAGEMENT
, CcCreateGroup
, GetErrConstant
<STR_ERROR_GROUP_CAN_T_CREATE
>), // CMD_CREATE_GROUP
387 DEF_CMD(CmdDeleteGroup
, 0, CMDT_ROUTE_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_GROUP_CAN_T_DELETE
>), // CMD_DELETE_GROUP
388 DEF_CMD(CmdAlterGroup
, 0, CMDT_OTHER_MANAGEMENT
, NULL
, GetErrAlterGroup
), // CMD_ALTER_GROUP
389 DEF_CMD(CmdAddVehicleGroup
, 0, CMDT_ROUTE_MANAGEMENT
, CcAddVehicleGroup
, GetErrConstant
<STR_ERROR_GROUP_CAN_T_ADD_VEHICLE
>), // CMD_ADD_VEHICLE_GROUP
390 DEF_CMD(CmdAddSharedVehicleGroup
, 0, CMDT_ROUTE_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE
>), // CMD_ADD_SHARED_VEHICLE_GROUP
391 DEF_CMD(CmdRemoveAllVehiclesGroup
, 0, CMDT_ROUTE_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES
>), // CMD_REMOVE_ALL_VEHICLES_GROUP
392 DEF_CMD(CmdSetGroupReplaceProtection
, 0, CMDT_ROUTE_MANAGEMENT
, NULL
, NULL
), // CMD_SET_GROUP_REPLACE_PROTECTION
393 DEF_CMD(CmdMoveOrder
, 0, CMDT_ROUTE_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_MOVE_THIS_ORDER
>), // CMD_MOVE_ORDER
394 DEF_CMD(CmdChangeTimetable
, 0, CMDT_ROUTE_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_TIMETABLE_VEHICLE
>), // CMD_CHANGE_TIMETABLE
395 DEF_CMD(CmdSetVehicleOnTime
, 0, CMDT_ROUTE_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_TIMETABLE_VEHICLE
>), // CMD_SET_VEHICLE_ON_TIME
396 DEF_CMD(CmdAutofillTimetable
, 0, CMDT_ROUTE_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_TIMETABLE_VEHICLE
>), // CMD_AUTOFILL_TIMETABLE
397 DEF_CMD(CmdSetTimetableStart
, 0, CMDT_ROUTE_MANAGEMENT
, NULL
, GetErrConstant
<STR_ERROR_CAN_T_TIMETABLE_VEHICLE
>), // CMD_SET_TIMETABLE_START
399 DEF_CMD(CmdOpenCloseAirport
, 0, CMDT_ROUTE_MANAGEMENT
, NULL
, NULL
), // CMD_OPEN_CLOSE_AIRPORT
403 * This function range-checks a cmd, and checks if the cmd is not NULL
405 * @param cmd The integer value of a command
406 * @return true if the command is valid (and got a CommandProc function)
408 bool IsValidCommand(CommandID cmd
)
410 return cmd
< lengthof(_command_proc_table
) && _command_proc_table
[cmd
].proc
!= NULL
;
414 * This function returns the flags which belongs to the given command.
416 * @param cmd The integer value of the command
417 * @return The flags for this command
419 CommandFlags
GetCommandFlags(CommandID cmd
)
421 assert(IsValidCommand(cmd
));
423 return _command_proc_table
[cmd
].flags
;
427 * This function returns the name which belongs to the given command.
429 * @param cmd The integer value of the command
430 * @return The name for this command
432 const char *GetCommandName(CommandID cmd
)
434 assert(IsValidCommand(cmd
));
436 return _command_proc_table
[cmd
].name
;
440 * Returns whether the command is allowed while the game is paused.
441 * @param cmd The command to check.
442 * @return True if the command is allowed while paused, false otherwise.
444 bool IsCommandAllowedWhilePaused(CommandID cmd
)
446 /* Lookup table for the command types that are allowed for a given pause level setting. */
447 static const int command_type_lookup
[] = {
448 CMDPL_ALL_ACTIONS
, ///< CMDT_LANDSCAPE_CONSTRUCTION
449 CMDPL_NO_LANDSCAPING
, ///< CMDT_VEHICLE_CONSTRUCTION
450 CMDPL_NO_LANDSCAPING
, ///< CMDT_MONEY_MANAGEMENT
451 CMDPL_NO_CONSTRUCTION
, ///< CMDT_VEHICLE_MANAGEMENT
452 CMDPL_NO_CONSTRUCTION
, ///< CMDT_ROUTE_MANAGEMENT
453 CMDPL_NO_CONSTRUCTION
, ///< CMDT_OTHER_MANAGEMENT
454 CMDPL_NO_CONSTRUCTION
, ///< CMDT_COMPANY_SETTING
455 CMDPL_NO_ACTIONS
, ///< CMDT_SERVER_SETTING
456 CMDPL_NO_ACTIONS
, ///< CMDT_CHEAT
458 assert_compile(lengthof(command_type_lookup
) == CMDT_END
);
460 assert(IsValidCommand(cmd
));
461 return _game_mode
== GM_EDITOR
|| command_type_lookup
[_command_proc_table
[cmd
].type
] <= _settings_game
.construction
.command_pause_level
;
465 static int _docommand_recursive
= 0;
468 * This function executes a given command with the parameters from the #CommandProc parameter list.
469 * Depending on the flags parameter it execute or test a command.
471 * @param flags Flags for the command and how to execute the command
475 CommandCost
Command::exec (DoCommandFlag flags
) const
479 /* Do not even think about executing out-of-bounds tile-commands */
480 if (this->tile
!= 0 && (this->tile
>= MapSize() || (!IsValidTile(this->tile
) && (flags
& DC_ALL_TILES
) == 0))) return CMD_ERROR
;
482 CommandProc
*proc
= _command_proc_table
[this->cmd
].proc
;
484 _docommand_recursive
++;
486 /* only execute the test call if it's toplevel, or we're not execing. */
487 if (_docommand_recursive
== 1 || !(flags
& DC_EXEC
) ) {
488 if (_docommand_recursive
== 1) _cleared_object_areas
.Clear();
489 SetTownRatingTestMode(true);
490 res
= proc(this->tile
, flags
& ~DC_EXEC
, this->p1
, this->p2
, this->text
);
491 SetTownRatingTestMode(false);
496 if (_docommand_recursive
== 1 &&
497 !(flags
& DC_QUERY_COST
) &&
498 !(flags
& DC_BANKRUPT
) &&
499 !CheckCompanyHasMoney(res
)) { // CheckCompanyHasMoney() modifies 'res' to an error if it fails.
503 if (!(flags
& DC_EXEC
)) {
504 _docommand_recursive
--;
509 /* Execute the command here. All cost-relevant functions set the expenses type
510 * themselves to the cost object at some point */
511 if (_docommand_recursive
== 1) _cleared_object_areas
.Clear();
512 res
= proc(this->tile
, flags
, this->p1
, this->p2
, this->text
);
515 _docommand_recursive
--;
519 /* if toplevel, subtract the money. */
520 if (--_docommand_recursive
== 0 && !(flags
& DC_BANKRUPT
)) {
521 SubtractMoneyFromCompany(res
);
528 * This functions returns the money which can be used to execute a command.
529 * This is either the money of the current company or INT64_MAX if there
530 * is no such a company "at the moment" like the server itself.
532 * @return The available money of a company or INT64_MAX
534 Money
GetAvailableMoneyForCommand()
536 CompanyID company
= _current_company
;
537 if (!Company::IsValidID(company
)) return INT64_MAX
;
538 return Company::Get(company
)->money
;
542 * Toplevel network safe docommand function for the current company. Must not be called recursively.
544 * @param cmdsrc Source of the command
545 * @return \c true if the command succeeded, else \c false.
547 bool Command::execp (CommandSource cmdsrc
)
549 /* Cost estimation is generally only done when the
550 * local user presses shift while doing somthing.
551 * However, in case of incoming network commands,
552 * map generation or the pause button we do want
554 bool estimate_only
= _shift_pressed
&& IsLocalCompany() &&
555 !_generating_world
&&
556 cmdsrc_is_local(cmdsrc
) &&
557 this->cmd
!= CMD_PAUSE
;
559 /* We're only sending the command, so don't do
560 * fancy things for 'success'. */
561 bool only_sending
= _networking
&& cmdsrc_is_local(cmdsrc
);
563 /* Where to show the message? */
564 int x
= TileX(this->tile
) * TILE_SIZE
;
565 int y
= TileY(this->tile
) * TILE_SIZE
;
567 if (_pause_mode
!= PM_UNPAUSED
&& !IsCommandAllowedWhilePaused(this->cmd
)) {
568 CommandErrstrF
*errorstrf
= _command_proc_table
[this->cmd
].errorstrf
;
569 StringID errorstr
= (errorstrf
== NULL
) ? 0 : errorstrf (this->tile
, this->p1
, this->p2
, this->text
);
570 ShowErrorMessage (errorstr
, STR_ERROR_NOT_ALLOWED_WHILE_PAUSED
, WL_INFO
, x
, y
);
574 #ifdef ENABLE_NETWORK
575 /* Only set p2 when the command does not come from the network. */
576 if (cmdsrc_is_local(cmdsrc
) && GetCommandFlags(this->cmd
) & CMDF_CLIENT_ID
&& this->p2
== 0) this->p2
= CLIENT_ID_SERVER
;
579 CommandCost res
= this->execp_internal (estimate_only
, cmdsrc
);
581 /* Only show the error when it's for us. */
582 CommandErrstrF
*errorstrf
= _command_proc_table
[this->cmd
].errorstrf
;
583 StringID error_part1
= (errorstrf
== NULL
) ? 0 : errorstrf (this->tile
, this->p1
, this->p2
, this->text
);
584 if (estimate_only
|| (IsLocalCompany() && error_part1
!= 0 && cmdsrc_get_type(cmdsrc
) == CMDSRC_SELF
)) {
585 ShowErrorMessage(error_part1
, res
.GetErrorMessage(), WL_INFO
, x
, y
, res
.GetTextRefStackGRF(), res
.GetTextRefStackSize(), res
.GetTextRefStack());
587 } else if (estimate_only
) {
588 ShowEstimatedCostOrIncome(res
.GetCost(), x
, y
);
589 } else if (!only_sending
&& res
.GetCost() != 0 && this->tile
!= 0 && IsLocalCompany() && _game_mode
!= GM_EDITOR
) {
590 /* Only show the cost animation when we did actually
591 * execute the command, i.e. we're not sending it to
592 * the server, when it has cost the local company
593 * something. Furthermore in the editor there is no
594 * concept of cost, so don't show it there either. */
595 ShowCostOrIncomeAnimation(x
, y
, GetSlopePixelZ(x
, y
), res
.GetCost());
598 if (!estimate_only
&& !only_sending
) {
599 switch (cmdsrc_get_type(cmdsrc
)) {
601 CommandCallback
*callback
= _command_proc_table
[this->cmd
].callback
;
602 if (callback
!= NULL
) {
603 callback(res
, this->tile
, this->p1
, this->p2
);
608 case CMDSRC_AI
: CcAI (res
); break;
609 case CMDSRC_GS
: CcGame(res
); break;
614 return res
.Succeeded();
619 * Helper to deduplicate the code for returning.
620 * @param cmd the command cost to return.
621 * @param clear whether to keep the storage changes or not.
623 #define return_dcpi(cmd) { _docommand_recursive = 0; return cmd; }
626 * Helper function for the toplevel network safe docommand function for the current company.
628 * @param estimate_only whether to give only the estimate or also execute the command
629 * @param cmdsrc Source of the command
630 * @return the command cost of this function.
632 CommandCost
Command::execp_internal (bool estimate_only
, CommandSource cmdsrc
) const
634 assert(!estimate_only
|| cmdsrc_is_local(cmdsrc
));
636 /* Prevent recursion; it gives a mess over the network */
637 assert(_docommand_recursive
== 0);
638 _docommand_recursive
= 1;
640 /* Reset the state. */
641 _additional_cash_required
= 0;
643 /* Get pointer to command handler */
644 assert(this->cmd
< lengthof(_command_proc_table
));
645 CommandProc
*proc
= _command_proc_table
[this->cmd
].proc
;
646 /* Shouldn't happen, but you never know when someone adds
647 * NULLs to the _command_proc_table. */
648 assert(proc
!= NULL
);
650 /* Command flags are used internally */
651 CommandFlags cmd_flags
= GetCommandFlags(this->cmd
);
652 /* Flags get send to the DoCommand */
653 DoCommandFlag flags
= CommandFlagsToDCFlags(cmd_flags
);
655 #ifdef ENABLE_NETWORK
656 /* Make sure p2 is properly set to a ClientID. */
657 assert(!(cmd_flags
& CMDF_CLIENT_ID
) || this->p2
!= 0);
660 /* Do not even think about executing out-of-bounds tile-commands */
661 if (this->tile
!= 0 && (this->tile
>= MapSize() || (!IsValidTile(this->tile
) && (cmd_flags
& CMDF_ALL_TILES
) == 0))) return_dcpi(CMD_ERROR
);
663 /* Always execute server and spectator commands as spectator */
664 bool exec_as_spectator
= (cmd_flags
& (CMDF_SPECTATOR
| CMDF_SERVER
)) != 0;
666 /* If the company isn't valid it may only do server command or start a new company!
667 * The server will ditch any server commands a client sends to it, so effectively
668 * this guards the server from executing functions for an invalid company. */
669 if (_game_mode
== GM_NORMAL
&& !exec_as_spectator
&& !Company::IsValidID(_current_company
) && !(_current_company
== OWNER_DEITY
&& (cmd_flags
& CMDF_DEITY
) != 0)) {
670 return_dcpi(CMD_ERROR
);
673 Backup
<CompanyByte
> cur_company(_current_company
, FILE_LINE
);
674 if (exec_as_spectator
) cur_company
.Change(COMPANY_SPECTATOR
);
676 bool test_and_exec_can_differ
= (cmd_flags
& CMDF_NO_TEST
) != 0;
678 /* Test the command. */
679 _cleared_object_areas
.Clear();
680 SetTownRatingTestMode(true);
681 BasePersistentStorageArray::SwitchMode(PSM_ENTER_TESTMODE
);
682 CommandCost res
= proc(this->tile
, flags
, this->p1
, this->p2
, this->text
);
683 BasePersistentStorageArray::SwitchMode(PSM_LEAVE_TESTMODE
);
684 SetTownRatingTestMode(false);
686 /* Make sure we're not messing things up here. */
687 assert(exec_as_spectator
? _current_company
== COMPANY_SPECTATOR
: cur_company
.Verify());
689 /* If the command fails, we're doing an estimate
690 * or the player does not have enough money
691 * (unless it's a command where the test and
692 * execution phase might return different costs)
693 * we bail out here. */
694 if (res
.Failed() || estimate_only
||
695 (!test_and_exec_can_differ
&& !CheckCompanyHasMoney(res
))) {
696 if (!_networking
|| _generating_world
|| !cmdsrc_is_local(cmdsrc
)) {
697 /* Log the failed command as well. Just to be able to be find
698 * causes of desyncs due to bad command test implementations. */
699 DEBUG (desync
, 1, "cmdf: %08x.%02x %02x %06x %08x %08x %02x \"%s\" (%s)",
700 _date
, _date_fract
, (int)_current_company
,
701 this->tile
, this->p1
, this->p2
, this->cmd
, this->text
, GetCommandName(this->cmd
));
703 cur_company
.Restore();
707 #ifdef ENABLE_NETWORK
709 * If we are in network, and the command is not from the network
710 * send it to the command-queue and abort execution
712 if (_networking
&& !_generating_world
&& cmdsrc_is_local(cmdsrc
)) {
713 NetworkSendCommand(this, _current_company
, cmdsrc
);
714 cur_company
.Restore();
716 /* Don't return anything special here; no error, no costs.
717 * This way it's not handled by DoCommand and only the
718 * actual execution of the command causes messages. Also
719 * reset the storages as we've not executed the command. */
720 return_dcpi(CommandCost());
722 #endif /* ENABLE_NETWORK */
723 DEBUG (desync
, 1, "cmd: %08x.%02x %02x %06x %08x %08x %02x \"%s\" (%s)",
724 _date
, _date_fract
, (int)_current_company
,
725 this->tile
, this->p1
, this->p2
, this->cmd
, this->text
, GetCommandName(this->cmd
));
727 /* Actually try and execute the command. If no cost-type is given
728 * use the construction one */
729 _cleared_object_areas
.Clear();
730 BasePersistentStorageArray::SwitchMode(PSM_ENTER_COMMAND
);
731 CommandCost res2
= proc(this->tile
, flags
| DC_EXEC
, this->p1
, this->p2
, this->text
);
732 BasePersistentStorageArray::SwitchMode(PSM_LEAVE_COMMAND
);
734 if (this->cmd
== CMD_COMPANY_CTRL
) {
736 /* We are a new company -> Switch to new local company.
737 * We were closed down -> Switch to spectator
738 * Some other company opened/closed down -> The outside function will switch back */
739 _current_company
= _local_company
;
741 /* Make sure nothing bad happened, like changing the current company. */
742 assert(exec_as_spectator
? _current_company
== COMPANY_SPECTATOR
: cur_company
.Verify());
743 cur_company
.Restore();
746 /* If the test and execution can differ we have to check the
747 * return of the command. Otherwise we can check whether the
748 * test and execution have yielded the same result,
749 * i.e. cost and error state are the same. */
750 if (!test_and_exec_can_differ
) {
751 assert(res
.GetCost() == res2
.GetCost() && res
.Failed() == res2
.Failed()); // sanity check
752 } else if (res2
.Failed()) {
756 /* If we're needing more money and we haven't done
757 * anything yet, ask for the money! */
758 if (_additional_cash_required
!= 0 && res2
.GetCost() == 0) {
759 /* It could happen we removed rail, thus gained money, and deleted something else.
760 * So make sure the signal buffer is empty even in this case */
761 UpdateSignalsInBuffer();
762 SetDParam(0, _additional_cash_required
);
763 return_dcpi(CommandCost(STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY
));
766 /* update last build coordinate of company. */
767 if (this->tile
!= 0) {
768 Company
*c
= Company::GetIfValid(_current_company
);
769 if (c
!= NULL
) c
->last_build_coordinate
= this->tile
;
772 SubtractMoneyFromCompany(res2
);
774 /* update signals if needed */
775 UpdateSignalsInBuffer();
783 * Adds the cost of the given command return value to this cost.
784 * Also takes a possible error message when it is set.
785 * @param ret The command to add the cost of.
787 void CommandCost::AddCost(const CommandCost
&ret
)
789 this->AddCost(ret
.cost
);
790 if (this->success
&& !ret
.success
) {
791 this->message
= ret
.message
;
792 this->success
= false;
797 * Values to put on the #TextRefStack for the error message.
798 * There is only one static instance of the array, just like there is only one
799 * instance of normal DParams.
801 uint32
CommandCost::textref_stack
[16];
804 * Activate usage of the NewGRF #TextRefStack for the error message.
805 * @param grffile NewGRF that provides the #TextRefStack
806 * @param num_registers number of entries to copy from the temporary NewGRF registers
808 void CommandCost::UseTextRefStack(const GRFFile
*grffile
, uint num_registers
)
810 extern TemporaryStorageArray
<int32
, 0x110> _temp_store
;
812 assert(num_registers
< lengthof(textref_stack
));
813 this->textref_stack_grffile
= grffile
;
814 this->textref_stack_size
= num_registers
;
815 for (uint i
= 0; i
< num_registers
; i
++) {
816 textref_stack
[i
] = _temp_store
.GetValue(0x100 + i
);