tron@2186: /* $Id$ */ tron@2186: truelight@0: #include "stdafx.h" Darkvater@1891: #include "openttd.h" tron@507: #include "table/strings.h" tron@2163: #include "functions.h" tron@679: #include "map.h" truelight@0: #include "gui.h" truelight@0: #include "command.h" truelight@0: #include "player.h" truelight@543: #include "network.h" tron@2159: #include "variables.h" truelight@4300: #include "genworld.h" truelight@0: tron@1820: const char* _cmd_text = NULL; tron@1820: tron@3491: #define DEF_COMMAND(yyyy) int32 yyyy(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) truelight@0: truelight@0: DEF_COMMAND(CmdBuildRailroadTrack); truelight@0: DEF_COMMAND(CmdRemoveRailroadTrack); truelight@0: DEF_COMMAND(CmdBuildSingleRail); truelight@0: DEF_COMMAND(CmdRemoveSingleRail); truelight@0: truelight@0: DEF_COMMAND(CmdLandscapeClear); truelight@0: truelight@0: DEF_COMMAND(CmdBuildBridge); truelight@0: truelight@0: DEF_COMMAND(CmdBuildRailroadStation); truelight@0: DEF_COMMAND(CmdRemoveFromRailroadStation); truelight@0: DEF_COMMAND(CmdConvertRail); truelight@0: darkvater@1227: DEF_COMMAND(CmdBuildSingleSignal); darkvater@1227: DEF_COMMAND(CmdRemoveSingleSignal); truelight@0: truelight@0: DEF_COMMAND(CmdTerraformLand); truelight@0: truelight@0: DEF_COMMAND(CmdPurchaseLandArea); truelight@0: DEF_COMMAND(CmdSellLandArea); truelight@0: truelight@0: DEF_COMMAND(CmdBuildTunnel); truelight@0: truelight@0: DEF_COMMAND(CmdBuildTrainDepot); darkvater@395: DEF_COMMAND(CmdBuildTrainWaypoint); darkvater@395: DEF_COMMAND(CmdRenameWaypoint); darkvater@395: DEF_COMMAND(CmdRemoveTrainWaypoint); truelight@0: celestar@1217: DEF_COMMAND(CmdBuildRoadStop); truelight@0: truelight@0: DEF_COMMAND(CmdBuildLongRoad); truelight@0: DEF_COMMAND(CmdRemoveLongRoad); truelight@0: DEF_COMMAND(CmdBuildRoad); truelight@0: DEF_COMMAND(CmdRemoveRoad); truelight@0: truelight@0: DEF_COMMAND(CmdBuildRoadDepot); truelight@0: truelight@0: DEF_COMMAND(CmdBuildAirport); truelight@0: truelight@0: DEF_COMMAND(CmdBuildDock); truelight@0: truelight@0: DEF_COMMAND(CmdBuildShipDepot); truelight@0: truelight@0: DEF_COMMAND(CmdBuildBuoy); truelight@0: truelight@0: DEF_COMMAND(CmdPlantTree); truelight@0: truelight@0: DEF_COMMAND(CmdBuildRailVehicle); truelight@0: DEF_COMMAND(CmdMoveRailVehicle); truelight@0: truelight@0: DEF_COMMAND(CmdStartStopTrain); truelight@0: truelight@0: DEF_COMMAND(CmdSellRailWagon); truelight@0: Darkvater@1794: DEF_COMMAND(CmdSendTrainToDepot); truelight@0: DEF_COMMAND(CmdForceTrainProceed); truelight@0: DEF_COMMAND(CmdReverseTrainDirection); truelight@0: truelight@0: DEF_COMMAND(CmdModifyOrder); truelight@0: DEF_COMMAND(CmdSkipOrder); truelight@0: DEF_COMMAND(CmdDeleteOrder); truelight@0: DEF_COMMAND(CmdInsertOrder); tron@2819: DEF_COMMAND(CmdChangeServiceInt); truelight@0: DEF_COMMAND(CmdRestoreOrderIndex); truelight@0: truelight@0: DEF_COMMAND(CmdBuildIndustry); truelight@0: truelight@0: DEF_COMMAND(CmdBuildCompanyHQ); truelight@0: DEF_COMMAND(CmdSetPlayerFace); truelight@0: DEF_COMMAND(CmdSetPlayerColor); truelight@0: truelight@0: DEF_COMMAND(CmdIncreaseLoan); truelight@0: DEF_COMMAND(CmdDecreaseLoan); truelight@0: truelight@0: DEF_COMMAND(CmdWantEnginePreview); truelight@0: truelight@0: DEF_COMMAND(CmdNameVehicle); truelight@0: DEF_COMMAND(CmdRenameEngine); truelight@0: truelight@0: DEF_COMMAND(CmdChangeCompanyName); truelight@0: DEF_COMMAND(CmdChangePresidentName); truelight@0: truelight@0: DEF_COMMAND(CmdRenameStation); truelight@0: truelight@0: DEF_COMMAND(CmdSellAircraft); truelight@0: DEF_COMMAND(CmdStartStopAircraft); truelight@0: DEF_COMMAND(CmdBuildAircraft); truelight@0: DEF_COMMAND(CmdSendAircraftToHangar); truelight@0: DEF_COMMAND(CmdRefitAircraft); truelight@0: truelight@0: DEF_COMMAND(CmdPlaceSign); truelight@0: DEF_COMMAND(CmdRenameSign); truelight@0: truelight@0: DEF_COMMAND(CmdBuildRoadVeh); truelight@0: DEF_COMMAND(CmdStartStopRoadVeh); truelight@0: DEF_COMMAND(CmdSellRoadVeh); truelight@0: DEF_COMMAND(CmdSendRoadVehToDepot); truelight@0: DEF_COMMAND(CmdTurnRoadVeh); peter1138@3990: DEF_COMMAND(CmdRefitRoadVeh); truelight@0: truelight@0: DEF_COMMAND(CmdPause); truelight@0: truelight@0: DEF_COMMAND(CmdBuyShareInCompany); truelight@0: DEF_COMMAND(CmdSellShareInCompany); truelight@0: DEF_COMMAND(CmdBuyCompany); truelight@0: truelight@0: DEF_COMMAND(CmdBuildTown); truelight@0: truelight@0: DEF_COMMAND(CmdRenameTown); truelight@0: DEF_COMMAND(CmdDoTownAction); truelight@0: truelight@0: DEF_COMMAND(CmdSetRoadDriveSide); truelight@0: truelight@0: DEF_COMMAND(CmdChangeDifficultyLevel); truelight@543: DEF_COMMAND(CmdChangePatchSetting); truelight@0: truelight@0: DEF_COMMAND(CmdStartStopShip); truelight@0: DEF_COMMAND(CmdSellShip); truelight@0: DEF_COMMAND(CmdBuildShip); truelight@0: DEF_COMMAND(CmdSendShipToDepot); truelight@0: DEF_COMMAND(CmdRefitShip); truelight@0: bjarni@4712: DEF_COMMAND(CmdOrderRefit); truelight@0: DEF_COMMAND(CmdCloneOrder); truelight@0: truelight@0: DEF_COMMAND(CmdClearArea); truelight@0: truelight@543: DEF_COMMAND(CmdGiveMoney); truelight@0: DEF_COMMAND(CmdMoneyCheat); truelight@0: DEF_COMMAND(CmdBuildCanal); darkvater@147: DEF_COMMAND(CmdBuildLock); truelight@0: truelight@0: DEF_COMMAND(CmdPlayerCtrl); truelight@0: truelight@0: DEF_COMMAND(CmdLevelLand); truelight@0: truelight@0: DEF_COMMAND(CmdRefitRailVehicle); truelight@0: darkvater@1227: DEF_COMMAND(CmdBuildSignalTrack); darkvater@1227: DEF_COMMAND(CmdRemoveSignalTrack); darkvater@58: peter1138@4661: DEF_COMMAND(CmdSetAutoReplace); truelight@812: bjarni@2244: DEF_COMMAND(CmdCloneVehicle); bjarni@4640: DEF_COMMAND(CmdMassStartStopVehicle); bjarni@4659: DEF_COMMAND(CmdDepotSellAllVehicles); bjarni@4662: DEF_COMMAND(CmdDepotMassAutoReplace); bjarni@2244: truelight@0: /* The master command table */ Darkvater@1804: static const Command _command_proc_table[] = { Darkvater@1804: {CmdBuildRailroadTrack, 0}, /* 0 */ Darkvater@1804: {CmdRemoveRailroadTrack, 0}, /* 1 */ Darkvater@1804: {CmdBuildSingleRail, 0}, /* 2 */ Darkvater@1804: {CmdRemoveSingleRail, 0}, /* 3 */ Darkvater@1804: {CmdLandscapeClear, 0}, /* 4 */ Darkvater@1804: {CmdBuildBridge, 0}, /* 5 */ Darkvater@1804: {CmdBuildRailroadStation, 0}, /* 6 */ Darkvater@1804: {CmdBuildTrainDepot, 0}, /* 7 */ Darkvater@1804: {CmdBuildSingleSignal, 0}, /* 8 */ Darkvater@1804: {CmdRemoveSingleSignal, 0}, /* 9 */ Darkvater@1804: {CmdTerraformLand, 0}, /* 10 */ Darkvater@1804: {CmdPurchaseLandArea, 0}, /* 11 */ Darkvater@1804: {CmdSellLandArea, 0}, /* 12 */ Darkvater@1804: {CmdBuildTunnel, 0}, /* 13 */ Darkvater@1804: {CmdRemoveFromRailroadStation, 0}, /* 14 */ Darkvater@1804: {CmdConvertRail, 0}, /* 15 */ Darkvater@1804: {CmdBuildTrainWaypoint, 0}, /* 16 */ Darkvater@1804: {CmdRenameWaypoint, 0}, /* 17 */ Darkvater@1804: {CmdRemoveTrainWaypoint, 0}, /* 18 */ Darkvater@1804: {NULL, 0}, /* 19 */ Darkvater@1804: {NULL, 0}, /* 20 */ Darkvater@1804: {CmdBuildRoadStop, 0}, /* 21 */ Darkvater@1804: {NULL, 0}, /* 22 */ Darkvater@1804: {CmdBuildLongRoad, 0}, /* 23 */ Darkvater@1804: {CmdRemoveLongRoad, 0}, /* 24 */ Darkvater@1804: {CmdBuildRoad, 0}, /* 25 */ Darkvater@1804: {CmdRemoveRoad, 0}, /* 26 */ Darkvater@1804: {CmdBuildRoadDepot, 0}, /* 27 */ Darkvater@1804: {NULL, 0}, /* 28 */ Darkvater@1804: {CmdBuildAirport, 0}, /* 29 */ Darkvater@1804: {CmdBuildDock, 0}, /* 30 */ Darkvater@1804: {CmdBuildShipDepot, 0}, /* 31 */ Darkvater@1804: {CmdBuildBuoy, 0}, /* 32 */ Darkvater@1804: {CmdPlantTree, 0}, /* 33 */ Darkvater@1804: {CmdBuildRailVehicle, 0}, /* 34 */ Darkvater@1804: {CmdMoveRailVehicle, 0}, /* 35 */ Darkvater@1804: {CmdStartStopTrain, 0}, /* 36 */ Darkvater@1804: {NULL, 0}, /* 37 */ Darkvater@1804: {CmdSellRailWagon, 0}, /* 38 */ Darkvater@1804: {CmdSendTrainToDepot, 0}, /* 39 */ Darkvater@1804: {CmdForceTrainProceed, 0}, /* 40 */ Darkvater@1804: {CmdReverseTrainDirection, 0}, /* 41 */ darkvater@147: Darkvater@1804: {CmdModifyOrder, 0}, /* 42 */ Darkvater@1804: {CmdSkipOrder, 0}, /* 43 */ Darkvater@1804: {CmdDeleteOrder, 0}, /* 44 */ Darkvater@1804: {CmdInsertOrder, 0}, /* 45 */ truelight@0: tron@2819: {CmdChangeServiceInt, 0}, /* 46 */ darkvater@147: Darkvater@1804: {CmdBuildIndustry, 0}, /* 47 */ Darkvater@1804: {CmdBuildCompanyHQ, 0}, /* 48 */ Darkvater@1804: {CmdSetPlayerFace, 0}, /* 49 */ Darkvater@1804: {CmdSetPlayerColor, 0}, /* 50 */ Darkvater@1796: Darkvater@1804: {CmdIncreaseLoan, 0}, /* 51 */ Darkvater@1804: {CmdDecreaseLoan, 0}, /* 52 */ Darkvater@1804: Darkvater@1804: {CmdWantEnginePreview, 0}, /* 53 */ Darkvater@1804: Darkvater@1804: {CmdNameVehicle, 0}, /* 54 */ Darkvater@1804: {CmdRenameEngine, 0}, /* 55 */ Darkvater@1804: Darkvater@1804: {CmdChangeCompanyName, 0}, /* 56 */ Darkvater@1804: {CmdChangePresidentName, 0}, /* 57 */ Darkvater@1804: Darkvater@1804: {CmdRenameStation, 0}, /* 58 */ Darkvater@1804: Darkvater@1804: {CmdSellAircraft, 0}, /* 59 */ Darkvater@1804: {CmdStartStopAircraft, 0}, /* 60 */ Darkvater@1804: Darkvater@1804: {CmdBuildAircraft, 0}, /* 61 */ Darkvater@1804: {CmdSendAircraftToHangar, 0}, /* 62 */ tron@2819: {NULL, 0}, /* 63 */ Darkvater@1804: {CmdRefitAircraft, 0}, /* 64 */ Darkvater@1804: Darkvater@1804: {CmdPlaceSign, 0}, /* 65 */ Darkvater@1804: {CmdRenameSign, 0}, /* 66 */ Darkvater@1804: Darkvater@1804: {CmdBuildRoadVeh, 0}, /* 67 */ Darkvater@1804: {CmdStartStopRoadVeh, 0}, /* 68 */ Darkvater@1804: {CmdSellRoadVeh, 0}, /* 69 */ Darkvater@1804: {CmdSendRoadVehToDepot, 0}, /* 70 */ Darkvater@1804: {CmdTurnRoadVeh, 0}, /* 71 */ peter1138@3990: {CmdRefitRoadVeh, 0}, /* 72 */ Darkvater@1804: Darkvater@1804: {CmdPause, CMD_SERVER}, /* 73 */ Darkvater@1804: Darkvater@1804: {CmdBuyShareInCompany, 0}, /* 74 */ Darkvater@1804: {CmdSellShareInCompany, 0}, /* 75 */ Darkvater@1804: {CmdBuyCompany, 0}, /* 76 */ Darkvater@1804: Darkvater@1804: {CmdBuildTown, CMD_OFFLINE}, /* 77 */ Darkvater@1804: {NULL, 0}, /* 78 */ Darkvater@1804: {NULL, 0}, /* 79 */ Darkvater@1804: {CmdRenameTown, CMD_SERVER}, /* 80 */ Darkvater@1804: {CmdDoTownAction, 0}, /* 81 */ Darkvater@1804: Darkvater@1804: {CmdSetRoadDriveSide, CMD_SERVER}, /* 82 */ Darkvater@1804: {NULL, 0}, /* 83 */ Darkvater@1804: {NULL, 0}, /* 84 */ Darkvater@1804: {CmdChangeDifficultyLevel, CMD_SERVER}, /* 85 */ Darkvater@1804: Darkvater@1804: {CmdStartStopShip, 0}, /* 86 */ Darkvater@1804: {CmdSellShip, 0}, /* 87 */ Darkvater@1804: {CmdBuildShip, 0}, /* 88 */ Darkvater@1804: {CmdSendShipToDepot, 0}, /* 89 */ tron@2819: {NULL, 0}, /* 90 */ Darkvater@1804: {CmdRefitShip, 0}, /* 91 */ Darkvater@1804: Darkvater@1804: {NULL, 0}, /* 92 */ Darkvater@1804: {NULL, 0}, /* 93 */ Darkvater@1804: {NULL, 0}, /* 94 */ Darkvater@1804: {NULL, 0}, /* 95 */ Darkvater@1804: {NULL, 0}, /* 96 */ Darkvater@1804: {NULL, 0}, /* 97 */ Darkvater@1804: bjarni@4712: {CmdOrderRefit, 0}, /* 98 */ Darkvater@1804: {CmdCloneOrder, 0}, /* 99 */ Darkvater@1804: Darkvater@1804: {CmdClearArea, 0}, /* 100 */ Darkvater@1804: {NULL, 0}, /* 101 */ Darkvater@1804: Darkvater@1804: {CmdMoneyCheat, CMD_OFFLINE}, /* 102 */ Darkvater@1804: {CmdBuildCanal, 0}, /* 103 */ Darkvater@1804: {CmdPlayerCtrl, 0}, /* 104 */ Darkvater@1804: Darkvater@1804: {CmdLevelLand, 0}, /* 105 */ Darkvater@1804: Darkvater@1804: {CmdRefitRailVehicle, 0}, /* 106 */ Darkvater@1804: {CmdRestoreOrderIndex, 0}, /* 107 */ Darkvater@1804: {CmdBuildLock, 0}, /* 108 */ Darkvater@1804: {NULL, 0}, /* 109 */ Darkvater@1804: {CmdBuildSignalTrack, 0}, /* 110 */ Darkvater@1804: {CmdRemoveSignalTrack, 0}, /* 111 */ Darkvater@1804: {NULL, 0}, /* 112 */ Darkvater@1804: {CmdGiveMoney, 0}, /* 113 */ Darkvater@1804: {CmdChangePatchSetting, CMD_SERVER}, /* 114 */ peter1138@4661: {CmdSetAutoReplace, 0}, /* 115 */ peter1138@3991: {CmdCloneVehicle, 0}, /* 116 */ bjarni@4640: {CmdMassStartStopVehicle, 0}, /* 117 */ bjarni@4659: {CmdDepotSellAllVehicles, 0}, /* 118 */ bjarni@4662: {CmdDepotMassAutoReplace, 0}, /* 119 */ truelight@0: }; truelight@0: truelight@903: /* This function range-checks a cmd, and checks if the cmd is not NULL */ tron@959: bool IsValidCommand(uint cmd) truelight@903: { tron@2645: cmd &= 0xFF; truelight@903: tron@2645: return tron@2645: cmd < lengthof(_command_proc_table) && tron@2645: _command_proc_table[cmd].proc != NULL; truelight@903: } truelight@903: tron@4000: byte GetCommandFlags(uint cmd) tron@4000: { tron@4000: return _command_proc_table[cmd & 0xFF].flags; tron@4000: } Darkvater@1804: truelight@0: tron@2304: static int _docommand_recursive; tron@2304: tron@3491: int32 DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc) truelight@0: { truelight@0: int32 res; truelight@0: CommandProc *proc; truelight@193: Darkvater@1776: /* Do not even think about executing out-of-bounds tile-commands */ tron@3491: if (tile >= MapSize()) { tron@1820: _cmd_text = NULL; tron@1820: return CMD_ERROR; tron@1820: } Darkvater@1776: Darkvater@1804: proc = _command_proc_table[procc].proc; truelight@0: Darkvater@2749: if (_docommand_recursive == 0) _error_message = INVALID_STRING_ID; truelight@0: truelight@0: _docommand_recursive++; truelight@0: truelight@0: // only execute the test call if it's toplevel, or we're not execing. truelight@0: if (_docommand_recursive == 1 || !(flags & DC_EXEC) || (flags & DC_FORCETEST) ) { tron@3491: res = proc(tile, flags & ~DC_EXEC, p1, p2); tron@1691: if (CmdFailed(res)) { truelight@0: if (res & 0xFFFF) _error_message = res & 0xFFFF; truelight@0: goto error; truelight@0: } truelight@0: tron@4000: if (_docommand_recursive == 1 && tron@4000: !(flags & DC_QUERY_COST) && tron@4000: res != 0 && tron@4000: !CheckPlayerHasMoney(res)) { tron@4000: goto error; truelight@0: } truelight@0: truelight@0: if (!(flags & DC_EXEC)) { truelight@0: _docommand_recursive--; tron@1820: _cmd_text = NULL; truelight@0: return res; truelight@0: } truelight@0: } truelight@0: darkvater@889: /* Execute the command here. All cost-relevant functions set the expenses type darkvater@889: * themselves with "SET_EXPENSES_TYPE(...);" at the beginning of the function */ tron@3491: res = proc(tile, flags, p1, p2); tron@1691: if (CmdFailed(res)) { truelight@0: if (res & 0xFFFF) _error_message = res & 0xFFFF; truelight@0: error: truelight@0: _docommand_recursive--; tron@1820: _cmd_text = NULL; truelight@0: return CMD_ERROR; truelight@0: } truelight@0: truelight@0: // if toplevel, subtract the money. truelight@0: if (--_docommand_recursive == 0) { truelight@0: SubtractMoneyFromPlayer(res); Darkvater@2772: // XXX - Old AI hack which doesn't use DoCommandDP; update last build coord of player Darkvater@4850: if (tile != 0 && IsValidPlayer(_current_player)) { tron@3491: GetPlayer(_current_player)->last_build_coordinate = tile; Darkvater@2772: } truelight@0: } truelight@0: tron@1820: _cmd_text = NULL; truelight@0: return res; truelight@0: } truelight@0: tron@1093: int32 GetAvailableMoneyForCommand(void) truelight@0: { Darkvater@1794: PlayerID pid = _current_player; Darkvater@4850: if (!IsValidPlayer(pid)) return 0x7FFFFFFF; // max int celestar@1962: return GetPlayer(pid)->player_money; truelight@0: } truelight@0: truelight@0: // toplevel network safe docommand function for the current player. must not be called recursively. truelight@0: // the callback is called when the command succeeded or failed. truelight@0: bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback, uint32 cmd) truelight@0: { truelight@0: int32 res = 0,res2; truelight@0: CommandProc *proc; truelight@0: uint32 flags; truelight@0: bool notest; tron@3182: StringID error_part1; truelight@0: celestar@3421: int x = TileX(tile) * TILE_SIZE; celestar@3421: int y = TileY(tile) * TILE_SIZE; truelight@0: Darkvater@1776: /* Do not even think about executing out-of-bounds tile-commands */ tron@2820: if (tile >= MapSize()) { tron@1820: _cmd_text = NULL; tron@1820: return false; tron@1820: } Darkvater@1776: truelight@193: assert(_docommand_recursive == 0); truelight@0: truelight@0: _error_message = INVALID_STRING_ID; tron@3182: error_part1 = GB(cmd, 16, 16); truelight@0: _additional_cash_required = 0; truelight@0: Darkvater@5067: /** Spectator has no rights except for the (dedicated) server which Darkvater@5067: * is/can be a spectator but as the server it can do anything */ Darkvater@5067: if (_current_player == PLAYER_SPECTATOR && !_network_server) { tron@3182: ShowErrorMessage(_error_message, error_part1, x, y); tron@1820: _cmd_text = NULL; truelight@0: return false; truelight@0: } truelight@0: truelight@0: flags = 0; truelight@0: if (cmd & CMD_AUTO) flags |= DC_AUTO; truelight@0: if (cmd & CMD_NO_WATER) flags |= DC_NO_WATER; truelight@0: truelight@0: // get pointer to command handler truelight@0: assert((cmd & 0xFF) < lengthof(_command_proc_table)); Darkvater@1804: proc = _command_proc_table[cmd & 0xFF].proc; Darkvater@1877: if (proc == NULL) { Darkvater@1877: _cmd_text = NULL; Darkvater@1877: return false; Darkvater@1877: } truelight@0: miham@826: // Some commands have a different output in dryrun than the realrun truelight@543: // e.g.: if you demolish a whole town, the dryrun would say okay. truelight@543: // but by really destroying, your rating drops and at a certain point truelight@543: // it will fail. so res and res2 are different pasky@467: // CMD_REMOVE_ROAD: This command has special local authority pasky@467: // restrictions which may cause the test run to fail (the previous pasky@467: // road fragments still stay there and the town won't let you pasky@467: // disconnect the road system), but the exec will succeed and this pasky@467: // fact will trigger an assertion failure. --pasky truelight@193: notest = truelight@193: (cmd & 0xFF) == CMD_CLEAR_AREA || truelight@193: (cmd & 0xFF) == CMD_CONVERT_RAIL || truelight@0: (cmd & 0xFF) == CMD_LEVEL_LAND || Darkvater@1701: (cmd & 0xFF) == CMD_REMOVE_ROAD || Darkvater@1696: (cmd & 0xFF) == CMD_REMOVE_LONG_ROAD; truelight@0: truelight@0: _docommand_recursive = 1; truelight@0: truelight@0: // cost estimation only? truelight@4300: if (!IsGeneratingWorld() && _shift_pressed && IsLocalPlayer() && !(cmd & (CMD_NETWORK_COMMAND | CMD_SHOW_NO_ERROR))) { truelight@0: // estimate the cost. tron@3491: res = proc(tile, flags, p1, p2); tron@1691: if (CmdFailed(res)) { truelight@0: if (res & 0xFFFF) _error_message = res & 0xFFFF; tron@3182: ShowErrorMessage(_error_message, error_part1, x, y); truelight@0: } else { truelight@0: ShowEstimatedCostOrIncome(res, x, y); truelight@0: } truelight@0: truelight@0: _docommand_recursive = 0; tron@1820: _cmd_text = NULL; truelight@0: return false; truelight@0: } truelight@0: truelight@193: truelight@543: if (!((cmd & CMD_NO_TEST_IF_IN_NETWORK) && _networking)) { truelight@0: // first test if the command can be executed. tron@3491: res = proc(tile, flags, p1, p2); tron@1691: if (CmdFailed(res)) { truelight@0: if (res & 0xFFFF) _error_message = res & 0xFFFF; truelight@0: goto show_error; truelight@0: } truelight@543: // no money? Only check if notest is off tron@2767: if (!notest && res != 0 && !CheckPlayerHasMoney(res)) goto show_error; truelight@0: } truelight@0: truelight@543: #ifdef ENABLE_NETWORK Darkvater@1838: /** If we are in network, and the command is not from the network Darkvater@1838: * send it to the command-queue and abort execution Darkvater@1838: * If we are a dedicated server temporarily switch local player, otherwise Darkvater@1838: * the other parties won't be able to execute our command and will desync. Darkvater@5067: * We also need to do this if the server's company has gone bankrupt Darkvater@5067: * @todo Rewrite (dedicated) server to something more than a dirty hack! Darkvater@1838: */ truelight@543: if (_networking && !(cmd & CMD_NETWORK_COMMAND)) { Darkvater@5067: PlayerID pbck = _local_player; Darkvater@5067: if (_network_dedicated || (_network_server && pbck == PLAYER_SPECTATOR)) _local_player = 0; truelight@543: NetworkSend_Command(tile, p1, p2, cmd, callback); Darkvater@5067: if (_network_dedicated || (_network_server && pbck == PLAYER_SPECTATOR)) _local_player = pbck; truelight@543: _docommand_recursive = 0; tron@1820: _cmd_text = NULL; truelight@543: return true; truelight@0: } truelight@543: #endif /* ENABLE_NETWORK */ truelight@0: truelight@0: // update last build coordinate of player. Darkvater@4850: if (tile != 0 && IsValidPlayer(_current_player)) { tron@4000: GetPlayer(_current_player)->last_build_coordinate = tile; tron@4000: } truelight@0: darkvater@889: /* Actually try and execute the command. If no cost-type is given darkvater@889: * use the construction one */ darkvater@889: _yearly_expenses_type = EXPENSES_CONSTRUCTION; tron@4000: res2 = proc(tile, flags | DC_EXEC, p1, p2); truelight@193: miham@826: // If notest is on, it means the result of the test can be different than truelight@543: // the real command.. so ignore the test truelight@652: if (!notest && !((cmd & CMD_NO_TEST_IF_IN_NETWORK) && _networking)) { truelight@0: assert(res == res2); // sanity check truelight@0: } else { Darkvater@1702: if (CmdFailed(res2)) { truelight@0: if (res2 & 0xFFFF) _error_message = res2 & 0xFFFF; truelight@0: goto show_error; truelight@0: } truelight@0: } truelight@0: truelight@0: SubtractMoneyFromPlayer(res2); truelight@0: Darkvater@2425: if (IsLocalPlayer() && _game_mode != GM_EDITOR) { tron@4000: if (res2 != 0) ShowCostOrIncomeAnimation(x, y, GetSlopeZ(x, y), res2); truelight@0: if (_additional_cash_required) { tron@534: SetDParam(0, _additional_cash_required); tron@3182: ShowErrorMessage(STR_0003_NOT_ENOUGH_CASH_REQUIRES, error_part1, x,y); truelight@0: if (res2 == 0) goto callb_err; truelight@0: } truelight@0: } truelight@0: truelight@0: _docommand_recursive = 0; truelight@193: truelight@0: if (callback) callback(true, tile, p1, p2); tron@1820: _cmd_text = NULL; truelight@0: return true; truelight@0: truelight@0: show_error: truelight@0: // show error message if the command fails? tron@3182: if (IsLocalPlayer() && error_part1 != 0) { tron@3182: ShowErrorMessage(_error_message, error_part1, x,y); tron@3182: } truelight@0: truelight@0: callb_err: truelight@0: _docommand_recursive = 0; truelight@193: truelight@0: if (callback) callback(false, tile, p1, p2); tron@1820: _cmd_text = NULL; truelight@0: return false; truelight@0: }