Changeset - r26107:59139eb8d51a
[Not reviewed]
src/ai/ai_gui.cpp
Show inline comments
 
@@ -1292,8 +1292,8 @@ struct AIDebugWindow : public Window {
 
			case WID_AID_RELOAD_TOGGLE:
 
				if (ai_debug_company == OWNER_DEITY) break;
 
				/* First kill the company of the AI, then start a new one. This should start the current AI again */
 
				Command<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | ai_debug_company << 16 | CRR_MANUAL << 24, 0, {});
 
				Command<CMD_COMPANY_CTRL>::Post(0, CCA_NEW_AI | ai_debug_company << 16, 0, {});
 
				Command<CMD_COMPANY_CTRL>::Post(CCA_DELETE, ai_debug_company, CRR_MANUAL, INVALID_CLIENT_ID);
 
				Command<CMD_COMPANY_CTRL>::Post(CCA_NEW_AI, ai_debug_company, CRR_NONE, INVALID_CLIENT_ID);
 
				break;
 

	
 
			case WID_AID_SETTINGS:
src/aircraft_cmd.cpp
Show inline comments
 
@@ -263,11 +263,10 @@ void GetAircraftSpriteSize(EngineID engi
 
 * @param flags    type of operation.
 
 * @param tile     tile of the depot where aircraft is built.
 
 * @param e        the engine to build.
 
 * @param data     unused.
 
 * @param[out] ret the vehicle that has been built.
 
 * @return the cost of this operation or an error.
 
 */
 
CommandCost CmdBuildAircraft(DoCommandFlag flags, TileIndex tile, const Engine *e, uint16 data, Vehicle **ret)
 
CommandCost CmdBuildAircraft(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **ret)
 
{
 
	const AircraftVehicleInfo *avi = &e->u.air;
 
	const Station *st = Station::GetByTile(tile);
src/aircraft_cmd.h
Show inline comments
 
@@ -14,6 +14,6 @@
 
#include "engine_type.h"
 
#include "vehicle_type.h"
 

	
 
CommandCost CmdBuildAircraft(DoCommandFlag flags, TileIndex tile, const Engine *e, uint16 data, Vehicle **v);
 
CommandCost CmdBuildAircraft(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **v);
 

	
 
#endif /* AIRCRAFT_CMD_H */
src/autoreplace_cmd.cpp
Show inline comments
 
@@ -345,7 +345,7 @@ static CommandCost BuildReplacementVehic
 
	}
 

	
 
	/* Build the new vehicle */
 
	cost = Command<CMD_BUILD_VEHICLE>::Do(DC_EXEC | DC_AUTOREPLACE, old_veh->tile, e | (CT_INVALID << 24), 0, {});
 
	cost = Command<CMD_BUILD_VEHICLE>::Do(DC_EXEC | DC_AUTOREPLACE, old_veh->tile, e, true, CT_INVALID, INVALID_CLIENT_ID);
 
	if (cost.Failed()) return cost;
 

	
 
	Vehicle *new_veh = Vehicle::Get(_new_vehicle_id);
 
@@ -471,11 +471,11 @@ static CommandCost ReplaceFreeUnit(Vehic
 
		}
 

	
 
		/* Sell the old vehicle */
 
		cost.AddCost(Command<CMD_SELL_VEHICLE>::Do(flags, 0, old_v->index, 0, {}));
 
		cost.AddCost(Command<CMD_SELL_VEHICLE>::Do(flags, 0, old_v->index, false, false, INVALID_CLIENT_ID));
 

	
 
		/* If we are not in DC_EXEC undo everything */
 
		if ((flags & DC_EXEC) == 0) {
 
			Command<CMD_SELL_VEHICLE>::Do(DC_EXEC, 0, new_v->index, 0, {});
 
			Command<CMD_SELL_VEHICLE>::Do(DC_EXEC, 0, new_v->index, false, false, INVALID_CLIENT_ID);
 
		}
 
	}
 

	
 
@@ -602,7 +602,7 @@ static CommandCost ReplaceChain(Vehicle 
 
					assert(RailVehInfo(wagon->engine_type)->railveh_type == RAILVEH_WAGON);
 

	
 
					/* Sell wagon */
 
					[[maybe_unused]] CommandCost ret = Command<CMD_SELL_VEHICLE>::Do(DC_EXEC, 0, wagon->index, 0, {});
 
					[[maybe_unused]] CommandCost ret = Command<CMD_SELL_VEHICLE>::Do(DC_EXEC, 0, wagon->index, false, false, INVALID_CLIENT_ID);
 
					assert(ret.Succeeded());
 
					new_vehs[i] = nullptr;
 

	
 
@@ -634,7 +634,7 @@ static CommandCost ReplaceChain(Vehicle 
 
					/* Sell the vehicle.
 
					 * Note: This might temporarily construct new trains, so use DC_AUTOREPLACE to prevent
 
					 *       it from failing due to engine limits. */
 
					cost.AddCost(Command<CMD_SELL_VEHICLE>::Do(flags | DC_AUTOREPLACE, 0, w->index, 0, {}));
 
					cost.AddCost(Command<CMD_SELL_VEHICLE>::Do(flags | DC_AUTOREPLACE, 0, w->index, false, false, INVALID_CLIENT_ID));
 
					if ((flags & DC_EXEC) != 0) {
 
						old_vehs[i] = nullptr;
 
						if (i == 0) old_head = nullptr;
 
@@ -665,7 +665,7 @@ static CommandCost ReplaceChain(Vehicle 
 
		if ((flags & DC_EXEC) == 0) {
 
			for (int i = num_units - 1; i >= 0; i--) {
 
				if (new_vehs[i] != nullptr) {
 
					Command<CMD_SELL_VEHICLE>::Do(DC_EXEC, 0, new_vehs[i]->index, 0, {});
 
					Command<CMD_SELL_VEHICLE>::Do(DC_EXEC, 0, new_vehs[i]->index, false, false, INVALID_CLIENT_ID);
 
					new_vehs[i] = nullptr;
 
				}
 
			}
 
@@ -696,12 +696,12 @@ static CommandCost ReplaceChain(Vehicle 
 
				}
 

	
 
				/* Sell the old vehicle */
 
				cost.AddCost(Command<CMD_SELL_VEHICLE>::Do(flags, 0, old_head->index, 0, {}));
 
				cost.AddCost(Command<CMD_SELL_VEHICLE>::Do(flags, 0, old_head->index, false, false, INVALID_CLIENT_ID));
 
			}
 

	
 
			/* If we are not in DC_EXEC undo everything */
 
			if ((flags & DC_EXEC) == 0) {
 
				Command<CMD_SELL_VEHICLE>::Do(DC_EXEC, 0, new_head->index, 0, {});
 
				Command<CMD_SELL_VEHICLE>::Do(DC_EXEC, 0, new_head->index, false, false, INVALID_CLIENT_ID);
 
			}
 
		}
 
	}
src/build_vehicle_gui.cpp
Show inline comments
 
@@ -1229,7 +1229,7 @@ struct BuildVehicleWindow : Window {
 

	
 
		if (!this->listview_mode) {
 
			/* Query for cost and refitted capacity */
 
			CommandCost ret = Command<CMD_BUILD_VEHICLE>::Do(DC_QUERY_COST, this->window_number, this->sel_engine | (cargo << 24), 0, {});
 
			CommandCost ret = Command<CMD_BUILD_VEHICLE>::Do(DC_QUERY_COST, this->window_number, this->sel_engine, true, cargo, INVALID_CLIENT_ID);
 
			if (ret.Succeeded()) {
 
				this->te.cost          = ret.GetCost() - e->GetCost();
 
				this->te.capacity      = _returned_refit_capacity;
 
@@ -1472,7 +1472,7 @@ struct BuildVehicleWindow : Window {
 
					CommandCallback *callback = (this->vehicle_type == VEH_TRAIN && RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildPrimaryVehicle;
 
					CargoID cargo = this->cargo_filter[this->cargo_filter_criteria];
 
					if (cargo == CF_ANY || cargo == CF_ENGINES) cargo = CF_NONE;
 
					Command<CMD_BUILD_VEHICLE>::Post(GetCmdBuildVehMsg(this->vehicle_type), callback, this->window_number, sel_eng | (cargo << 24), 0, {});
 
					Command<CMD_BUILD_VEHICLE>::Post(GetCmdBuildVehMsg(this->vehicle_type), callback, this->window_number, sel_eng, true, cargo, INVALID_CLIENT_ID);
 
				}
 
				break;
 
			}
src/command.cpp
Show inline comments
 
@@ -75,15 +75,13 @@ int RecursiveCommandCounter::_counter = 
 
 * the #CMD_AUTO, #CMD_OFFLINE and #CMD_SERVER values.
 
 */
 
struct CommandInfo {
 
	CommandProc *proc;  ///< The procedure to actually executing
 
	const char *name;   ///< A human readable name for the procedure
 
	CommandFlags flags; ///< The (command) flags to that apply to this command
 
	CommandType type;   ///< The type of command.
 
};
 
/* Helpers to generate the master command table from the command traits. */
 

	
 
template <typename T>
 
inline constexpr CommandInfo CommandFromTrait() noexcept { return { T::proc, T::name, T::flags, T::type }; };
 
inline constexpr CommandInfo CommandFromTrait() noexcept { return { T::name, T::flags, T::type }; };
 

	
 
template<typename T, T... i>
 
inline constexpr auto MakeCommandsFromTraits(std::integer_sequence<T, i...>) noexcept {
 
@@ -101,14 +99,14 @@ static constexpr auto _command_proc_tabl
 

	
 

	
 
/*!
 
 * This function range-checks a cmd, and checks if the cmd is not nullptr
 
 * This function range-checks a cmd.
 
 *
 
 * @param cmd The integer value of a command
 
 * @return true if the command is valid (and got a CommandProc function)
 
 */
 
bool IsValidCommand(Commands cmd)
 
{
 
	return cmd < _command_proc_table.size() && _command_proc_table[cmd].proc != nullptr;
 
	return cmd < _command_proc_table.size();
 
}
 

	
 
/*!
src/command_func.h
Show inline comments
 
@@ -11,6 +11,7 @@
 
#define COMMAND_FUNC_H
 

	
 
#include "command_type.h"
 
#include "network/network_type.h"
 
#include "company_type.h"
 
#include "company_func.h"
 
#include "core/backup_type.hpp"
 
@@ -225,6 +226,22 @@ public:
 
	}
 

	
 
protected:
 
	/** Helper to process a single ClientID argument. */
 
	template <class T>
 
	static inline void SetClientIdHelper(T &data)
 
	{
 
		if constexpr (std::is_same_v<ClientID, T>) {
 
			if (data == INVALID_CLIENT_ID) data = CLIENT_ID_SERVER;
 
		}
 
	}
 

	
 
	/** Set all invalid ClientID's to the proper value. */
 
	template<class Ttuple, size_t... Tindices>
 
	static inline void SetClientIds(Ttuple &values, std::index_sequence<Tindices...>)
 
	{
 
		((SetClientIdHelper(std::get<Tindices>(values))), ...);
 
	}
 

	
 
	static bool InternalPost(StringID err_message, CommandCallback *callback, bool my_cmd, bool network_command, std::tuple<Targs...> args)
 
	{
 
		/* Where to show the message? */
 
@@ -241,8 +258,8 @@ protected:
 
		auto [err, estimate_only, only_sending] = InternalPostBefore(Tcmd, GetCommandFlags<Tcmd>(), tile, err_message, network_command);
 
		if (err) return false;
 

	
 
		/* Only set p2 when the command does not come from the network. */
 
		if (!network_command && GetCommandFlags<Tcmd>() & CMD_CLIENT_ID && std::get<2>(args) == 0) std::get<2>(args) = CLIENT_ID_SERVER;
 
		/* Only set client IDs when the command does not come from the network. */
 
		if (!network_command && GetCommandFlags<Tcmd>() & CMD_CLIENT_ID) SetClientIds(args, std::index_sequence_for<Targs...>{});
 

	
 
		CommandCost res = Execute(err_message, callback, my_cmd, estimate_only, network_command, tile, args);
 
		InternalPostResult(res, tile, estimate_only, only_sending, err_message, my_cmd);
 
@@ -254,6 +271,24 @@ protected:
 
		return res.Succeeded();
 
	}
 

	
 
	/** Helper to process a single ClientID argument. */
 
	template <class T>
 
	static inline bool ClientIdIsSet(T &data)
 
	{
 
		if constexpr (std::is_same_v<ClientID, T>) {
 
			return data != INVALID_CLIENT_ID;
 
		} else {
 
			return true;
 
		}
 
	}
 

	
 
	/** Check if all ClientID arguments are set to valid values. */
 
	template<class Ttuple, size_t... Tindices>
 
	static inline bool AllClientIdsSet(Ttuple &values, std::index_sequence<Tindices...>)
 
	{
 
		return (ClientIdIsSet(std::get<Tindices>(values)) && ...);
 
	}
 

	
 
	static CommandCost Execute(StringID err_message, CommandCallback *callback, bool my_cmd, bool estimate_only, bool network_command, TileIndex tile, std::tuple<Targs...> args)
 
	{
 
		/* Prevent recursion; it gives a mess over the network */
 
@@ -261,10 +296,12 @@ protected:
 
		assert(counter.IsTopLevel());
 

	
 
		/* Command flags are used internally */
 
		CommandFlags cmd_flags = GetCommandFlags<Tcmd>();
 
		constexpr CommandFlags cmd_flags = GetCommandFlags<Tcmd>();
 

	
 
		/* Make sure p2 is properly set to a ClientID also when processing external commands. */
 
		assert(!(cmd_flags & CMD_CLIENT_ID) || std::get<2>(args) != 0);
 
		if constexpr ((cmd_flags & CMD_CLIENT_ID) != 0) {
 
			/* Make sure arguments are properly set to a ClientID also when processing external commands. */
 
			assert(AllClientIdsSet(args, std::index_sequence_for<Targs...>{}));
 
		}
 

	
 
		Backup<CompanyID> cur_company(_current_company, FILE_LINE);
 
		if (!InternalExecutePrepTest(cmd_flags, tile, cur_company)) {
src/company_cmd.cpp
Show inline comments
 
@@ -604,7 +604,7 @@ static bool MaybeStartNewCompany()
 
	if (n < (uint)_settings_game.difficulty.max_no_competitors) {
 
		/* Send a command to all clients to start up a new AI.
 
		 * Works fine for Multiplayer and Singleplayer */
 
		return Command<CMD_COMPANY_CTRL>::Post(0, CCA_NEW_AI | INVALID_COMPANY << 16, 0, {});
 
		return Command<CMD_COMPANY_CTRL>::Post(CCA_NEW_AI, INVALID_COMPANY, CRR_NONE, INVALID_CLIENT_ID );
 
	}
 

	
 
	return false;
 
@@ -796,21 +796,16 @@ void CompanyAdminRemove(CompanyID compan
 
/**
 
 * Control the companies: add, delete, etc.
 
 * @param flags operation to perform
 
 * @param tile unused
 
 * @param p1 various functionality
 
 * - bits 0..15: CompanyCtrlAction
 
 * - bits 16..23: CompanyID
 
 * - bits 24..31: CompanyRemoveReason (with CCA_DELETE)
 
 * @param p2 ClientID
 
 * @param text unused
 
 * @param cca action to perform
 
 * @param company_id company to perform the action on
 
 * @param client_id ClientID
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdCompanyCtrl(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
CommandCost CmdCompanyCtrl(DoCommandFlag flags, CompanyCtrlAction cca, CompanyID company_id, CompanyRemoveReason reason, ClientID client_id)
 
{
 
	InvalidateWindowData(WC_COMPANY_LEAGUE, 0, 0);
 
	CompanyID company_id = (CompanyID)GB(p1, 16, 8);
 

	
 
	switch ((CompanyCtrlAction)GB(p1, 0, 16)) {
 
	switch (cca) {
 
		case CCA_NEW: { // Create a new company
 
			/* This command is only executed in a multiplayer game */
 
			if (!_networking) return CMD_ERROR;
 
@@ -818,7 +813,6 @@ CommandCost CmdCompanyCtrl(DoCommandFlag
 
			/* Has the network client a correct ClientIndex? */
 
			if (!(flags & DC_EXEC)) return CommandCost();
 

	
 
			ClientID client_id = (ClientID)p2;
 
			NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
 

	
 
			/* Delete multiplayer progress bar */
 
@@ -873,7 +867,6 @@ CommandCost CmdCompanyCtrl(DoCommandFlag
 
		}
 

	
 
		case CCA_DELETE: { // Delete a company
 
			CompanyRemoveReason reason = (CompanyRemoveReason)GB(p1, 24, 8);
 
			if (reason >= CRR_END) return CMD_ERROR;
 

	
 
			/* We can't delete the last existing company in singleplayer mode. */
src/company_cmd.h
Show inline comments
 
@@ -12,7 +12,9 @@
 

	
 
#include "command_type.h"
 

	
 
CommandProc CmdCompanyCtrl;
 
enum ClientID : uint32;
 

	
 
CommandCost CmdCompanyCtrl(DoCommandFlag flags, CompanyCtrlAction cca, CompanyID company_id, CompanyRemoveReason reason, ClientID client_id);
 
CommandProc CmdGiveMoney;
 
CommandProc CmdRenameCompany;
 
CommandProc CmdRenamePresident;
src/company_type.h
Show inline comments
 
@@ -52,16 +52,18 @@ struct Company;
 
typedef uint32 CompanyManagerFace; ///< Company manager face bits, info see in company_manager_face.h
 

	
 
/** The reason why the company was removed. */
 
enum CompanyRemoveReason {
 
enum CompanyRemoveReason : uint8 {
 
	CRR_MANUAL,    ///< The company is manually removed.
 
	CRR_AUTOCLEAN, ///< The company is removed due to autoclean.
 
	CRR_BANKRUPT,  ///< The company went belly-up.
 

	
 
	CRR_END,       ///< Sentinel for end.
 

	
 
	CRR_NONE = CRR_MANUAL, ///< Dummy reason for actions that don't need one.
 
};
 

	
 
/** The action to do with CMD_COMPANY_CTRL. */
 
enum CompanyCtrlAction {
 
enum CompanyCtrlAction : uint8 {
 
	CCA_NEW,    ///< Create a new company.
 
	CCA_NEW_AI, ///< Create a new AI company.
 
	CCA_DELETE, ///< Delete a company.
src/console_cmds.cpp
Show inline comments
 
@@ -865,7 +865,7 @@ DEF_CONSOLE_CMD(ConResetCompany)
 
	}
 

	
 
	/* It is safe to remove this company */
 
	Command<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | index << 16 | CRR_MANUAL << 24, 0, {});
 
	Command<CMD_COMPANY_CTRL>::Post(CCA_DELETE, index, CRR_MANUAL, INVALID_CLIENT_ID);
 
	IConsolePrint(CC_DEFAULT, "Company deleted.");
 

	
 
	return true;
 
@@ -1222,7 +1222,7 @@ DEF_CONSOLE_CMD(ConStartAI)
 
	}
 

	
 
	/* Start a new AI company */
 
	Command<CMD_COMPANY_CTRL>::Post(0, CCA_NEW_AI | INVALID_COMPANY << 16, 0, {});
 
	Command<CMD_COMPANY_CTRL>::Post(CCA_NEW_AI, INVALID_COMPANY, CRR_NONE, INVALID_CLIENT_ID);
 

	
 
	return true;
 
}
 
@@ -1258,8 +1258,8 @@ DEF_CONSOLE_CMD(ConReloadAI)
 
	}
 

	
 
	/* First kill the company of the AI, then start a new one. This should start the current AI again */
 
	Command<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | company_id << 16 | CRR_MANUAL << 24, 0, {});
 
	Command<CMD_COMPANY_CTRL>::Post(0, CCA_NEW_AI | company_id << 16, 0, {});
 
	Command<CMD_COMPANY_CTRL>::Post(CCA_DELETE, company_id, CRR_MANUAL, INVALID_CLIENT_ID);
 
	Command<CMD_COMPANY_CTRL>::Post(CCA_NEW_AI, company_id, CRR_NONE, INVALID_CLIENT_ID);
 
	IConsolePrint(CC_DEFAULT, "AI reloaded.");
 

	
 
	return true;
 
@@ -1296,7 +1296,7 @@ DEF_CONSOLE_CMD(ConStopAI)
 
	}
 

	
 
	/* Now kill the company of the AI. */
 
	Command<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | company_id << 16 | CRR_MANUAL << 24, 0, {});
 
	Command<CMD_COMPANY_CTRL>::Post(CCA_DELETE, company_id, CRR_MANUAL, INVALID_CLIENT_ID);
 
	IConsolePrint(CC_DEFAULT, "AI stopped, company deleted.");
 

	
 
	return true;
src/depot_gui.cpp
Show inline comments
 
@@ -1026,8 +1026,8 @@ struct DepotWindow : Window {
 
				this->sel = INVALID_VEHICLE;
 
				this->SetDirty();
 

	
 
				int sell_cmd = (v->type == VEH_TRAIN && (widget == WID_D_SELL_CHAIN || _ctrl_pressed)) ? 1 : 0;
 
				Command<CMD_SELL_VEHICLE>::Post(GetCmdSellVehMsg(v->type), v->tile, v->index | sell_cmd << 20 | MAKE_ORDER_BACKUP_FLAG, 0, {});
 
				bool sell_cmd = (v->type == VEH_TRAIN && (widget == WID_D_SELL_CHAIN || _ctrl_pressed));
 
				Command<CMD_SELL_VEHICLE>::Post(GetCmdSellVehMsg(v->type), v->tile, v->index, sell_cmd, true, INVALID_CLIENT_ID);
 
				break;
 
			}
 

	
src/economy.cpp
Show inline comments
 
@@ -630,7 +630,7 @@ static void CompanyCheckBankrupt(Company
 
			 * player we are sure (the above check) that we are not the local
 
			 * company and thus we won't be moved. */
 
			if (!_networking || _network_server) {
 
				Command<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | (c->index << 16) | (CRR_BANKRUPT << 24), 0, {});
 
				Command<CMD_COMPANY_CTRL>::Post(CCA_DELETE, c->index, CRR_BANKRUPT, INVALID_CLIENT_ID);
 
				return;
 
			}
 
			break;
src/network/network_client.cpp
Show inline comments
 
@@ -840,7 +840,7 @@ NetworkRecvStatus ClientNetworkGameSocke
 
			 * the server will give us a client-id and let us in */
 
			_network_join_status = NETWORK_JOIN_STATUS_REGISTERING;
 
			ShowJoinStatusWindow();
 
			Command<CMD_COMPANY_CTRL>::SendNet(STR_NULL, nullptr, _local_company, 0, CCA_NEW, 0, {});
 
			Command<CMD_COMPANY_CTRL>::SendNet(STR_NULL, nullptr, _local_company, CCA_NEW, INVALID_COMPANY, CRR_NONE, INVALID_CLIENT_ID);
 
		}
 
	} else {
 
		/* take control over an existing company */
src/network/network_command.cpp
Show inline comments
 
@@ -89,15 +89,17 @@ static CommandCallback * const _callback
 

	
 
template <Commands Tcmd> static CommandDataBuffer SanitizeCmdStrings(const CommandDataBuffer &data);
 
template <Commands Tcmd> static void UnpackNetworkCommand(const CommandPacket *cp);
 
template <Commands Tcmd> static void NetworkReplaceCommandClientId(CommandPacket &cp, ClientID client_id);
 
struct CommandDispatch {
 
	CommandDataBuffer(*Sanitize)(const CommandDataBuffer &);
 
	void (*ReplaceClientId)(CommandPacket &, ClientID);
 
	void (*Unpack)(const CommandPacket *);
 
};
 

	
 
template<typename T, T... i>
 
inline constexpr auto MakeDispatchTable(std::integer_sequence<T, i...>) noexcept
 
{
 
	return std::array<CommandDispatch, sizeof...(i)>{{ { &SanitizeCmdStrings<static_cast<Commands>(i)>, &UnpackNetworkCommand<static_cast<Commands>(i)> }... }};
 
	return std::array<CommandDispatch, sizeof...(i)>{{ { &SanitizeCmdStrings<static_cast<Commands>(i)>, &NetworkReplaceCommandClientId<static_cast<Commands>(i)>, &UnpackNetworkCommand<static_cast<Commands>(i)> }... }};
 
}
 
static constexpr auto _cmd_dispatch = MakeDispatchTable(std::make_integer_sequence<std::underlying_type_t<Commands>, CMD_END>{});
 

	
 
@@ -383,6 +385,35 @@ void NetworkGameSocketHandler::SendComma
 
	p->Send_uint8 (callback);
 
}
 

	
 
/** Helper to process a single ClientID argument. */
 
template <class T>
 
static inline void SetClientIdHelper(T &data, [[maybe_unused]] ClientID client_id)
 
{
 
	if constexpr (std::is_same_v<ClientID, T>) {
 
		data = client_id;
 
	}
 
}
 

	
 
/** Set all invalid ClientID's to the proper value. */
 
template<class Ttuple, size_t... Tindices>
 
static inline void SetClientIds(Ttuple &values, ClientID client_id, std::index_sequence<Tindices...>)
 
{
 
	((SetClientIdHelper(std::get<Tindices>(values), client_id)), ...);
 
}
 

	
 
template <Commands Tcmd>
 
static void NetworkReplaceCommandClientId(CommandPacket &cp, ClientID client_id)
 
{
 
	/* Unpack command parameters. */
 
	auto params = EndianBufferReader::ToValue<typename CommandTraits<Tcmd>::Args>(cp.data);
 

	
 
	/* Insert client id. */
 
	SetClientIds(params, client_id, std::make_index_sequence<std::tuple_size_v<decltype(params)>>{});
 

	
 
	/* Repack command parameters. */
 
	cp.data = EndianBufferWriter<CommandDataBuffer>::FromValue(params);
 
}
 

	
 
/**
 
 * Insert a client ID into the command data in a command packet.
 
 * @param cp Command packet to modify.
 
@@ -390,14 +421,7 @@ void NetworkGameSocketHandler::SendComma
 
 */
 
void NetworkReplaceCommandClientId(CommandPacket &cp, ClientID client_id)
 
{
 
	/* Unpack command parameters. */
 
	auto params = EndianBufferReader::ToValue<std::tuple<TileIndex, uint32, uint32, std::string>>(cp.data);
 

	
 
	/* Insert client id. */
 
	std::get<2>(params) = client_id;
 

	
 
	/* Repack command parameters. */
 
	cp.data = EndianBufferWriter<CommandDataBuffer>::FromValue(params);
 
	_cmd_dispatch[cp.cmd].ReplaceClientId(cp, client_id);
 
}
 

	
 

	
src/network/network_gui.cpp
Show inline comments
 
@@ -1396,7 +1396,7 @@ static void AdminCompanyResetCallback(Wi
 
{
 
	if (confirmed) {
 
		if (NetworkCompanyHasClients(_admin_company_id)) return;
 
		Command<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | _admin_company_id << 16 | CRR_MANUAL << 24, 0, {});
 
		Command<CMD_COMPANY_CTRL>::Post(CCA_DELETE, _admin_company_id, CRR_MANUAL, INVALID_CLIENT_ID);
 
	}
 
}
 

	
 
@@ -1536,9 +1536,9 @@ private:
 
	static void OnClickCompanyNew(NetworkClientListWindow *w, Point pt, CompanyID company_id)
 
	{
 
		if (_network_server) {
 
			Command<CMD_COMPANY_CTRL>::Post(0, CCA_NEW, _network_own_client_id, {});
 
			Command<CMD_COMPANY_CTRL>::Post(CCA_NEW, INVALID_COMPANY, CRR_NONE, _network_own_client_id);
 
		} else {
 
			Command<CMD_COMPANY_CTRL>::SendNet(STR_NULL, nullptr, _local_company, 0, CCA_NEW, 0, {});
 
			Command<CMD_COMPANY_CTRL>::SendNet(STR_NULL, nullptr, _local_company, CCA_NEW, INVALID_COMPANY, CRR_NONE, INVALID_CLIENT_ID);
 
		}
 
	}
 

	
src/network/network_server.cpp
Show inline comments
 
@@ -1050,15 +1050,15 @@ NetworkRecvStatus ServerNetworkGameSocke
 
	 * to match the company in the packet. If it doesn't, the client has done
 
	 * something pretty naughty (or a bug), and will be kicked
 
	 */
 
	uint32 company_p1 = cp.cmd == CMD_COMPANY_CTRL ? std::get<1>(EndianBufferReader::ToValue<CommandTraits<CMD_COMPANY_CTRL>::Args>(cp.data)) : 0;
 
	if (!(cp.cmd == CMD_COMPANY_CTRL && company_p1 == 0 && ci->client_playas == COMPANY_NEW_COMPANY) && ci->client_playas != cp.company) {
 
	CompanyCtrlAction cca = cp.cmd == CMD_COMPANY_CTRL ? std::get<0>(EndianBufferReader::ToValue<CommandTraits<CMD_COMPANY_CTRL>::Args>(cp.data)) : CCA_NEW;
 
	if (!(cp.cmd == CMD_COMPANY_CTRL && cca == CCA_NEW && ci->client_playas == COMPANY_NEW_COMPANY) && ci->client_playas != cp.company) {
 
		IConsolePrint(CC_WARNING, "Kicking client #{} (IP: {}) due to calling a command as another company {}.",
 
		               ci->client_playas + 1, this->GetClientIP(), cp.company + 1);
 
		return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH);
 
	}
 

	
 
	if (cp.cmd == CMD_COMPANY_CTRL) {
 
		if (company_p1 != 0 || cp.company != COMPANY_SPECTATOR) {
 
		if (cca != CCA_NEW || cp.company != COMPANY_SPECTATOR) {
 
			return this->SendError(NETWORK_ERROR_CHEATER);
 
		}
 

	
 
@@ -1556,7 +1556,7 @@ static void NetworkAutoCleanCompanies()
 
			/* Is the company empty for autoclean_unprotected-months, and is there no protection? */
 
			if (_settings_client.network.autoclean_unprotected != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_unprotected && _network_company_states[c->index].password.empty()) {
 
				/* Shut the company down */
 
				Command<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | c->index << 16 | CRR_AUTOCLEAN << 24, 0, {});
 
				Command<CMD_COMPANY_CTRL>::Post(CCA_DELETE, c->index, CRR_AUTOCLEAN, INVALID_CLIENT_ID);
 
				IConsolePrint(CC_INFO, "Auto-cleaned company #{} with no password.", c->index + 1);
 
			}
 
			/* Is the company empty for autoclean_protected-months, and there is a protection? */
 
@@ -1570,7 +1570,7 @@ static void NetworkAutoCleanCompanies()
 
			/* Is the company empty for autoclean_novehicles-months, and has no vehicles? */
 
			if (_settings_client.network.autoclean_novehicles != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_novehicles && vehicles_in_company[c->index] == 0) {
 
				/* Shut the company down */
 
				Command<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | c->index << 16 | CRR_AUTOCLEAN << 24, 0, {});
 
				Command<CMD_COMPANY_CTRL>::Post(CCA_DELETE, c->index, CRR_AUTOCLEAN, INVALID_CLIENT_ID);
 
				IConsolePrint(CC_INFO, "Auto-cleaned company #{} with no vehicles.", c->index + 1);
 
			}
 
		} else {
src/order_backup.cpp
Show inline comments
 
@@ -144,15 +144,13 @@ void OrderBackup::DoRestore(Vehicle *v)
 
 * Clear an OrderBackup
 
 * @param flags For command.
 
 * @param tile  Tile related to the to-be-cleared OrderBackup.
 
 * @param p1    Unused.
 
 * @param p2    User that had the OrderBackup.
 
 * @param text  Unused.
 
 * @param user_id User that had the OrderBackup.
 
 * @return The cost of this operation or an error.
 
 */
 
CommandCost CmdClearOrderBackup(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
CommandCost CmdClearOrderBackup(DoCommandFlag flags, TileIndex tile, ClientID user_id)
 
{
 
	/* No need to check anything. If the tile or user don't exist we just ignore it. */
 
	if (flags & DC_EXEC) OrderBackup::ResetOfUser(tile == 0 ? INVALID_TILE : tile, p2);
 
	if (flags & DC_EXEC) OrderBackup::ResetOfUser(tile == 0 ? INVALID_TILE : tile, user_id);
 

	
 
	return CommandCost();
 
}
 
@@ -171,7 +169,7 @@ CommandCost CmdClearOrderBackup(DoComman
 
		/* If it's not a backup of us, ignore it. */
 
		if (ob->user != user) continue;
 

	
 
		Command<CMD_CLEAR_ORDER_BACKUP>::Post(0, 0, user, {});
 
		Command<CMD_CLEAR_ORDER_BACKUP>::Post(0, static_cast<ClientID>(user));
 
		return;
 
	}
 
}
 
@@ -200,7 +198,7 @@ CommandCost CmdClearOrderBackup(DoComman
 
			/* We need to circumvent the "prevention" from this command being executed
 
			 * while the game is paused, so use the internal method. Nor do we want
 
			 * this command to get its cost estimated when shift is pressed. */
 
			Command<CMD_CLEAR_ORDER_BACKUP>::Unsafe(STR_NULL, nullptr, true, false, ob->tile, CommandTraits<CMD_CLEAR_ORDER_BACKUP>::Args{ ob->tile, 0, user, {} });
 
			Command<CMD_CLEAR_ORDER_BACKUP>::Unsafe(STR_NULL, nullptr, true, false, ob->tile, CommandTraits<CMD_CLEAR_ORDER_BACKUP>::Args{ ob->tile, static_cast<ClientID>(user) });
 
		} else {
 
			/* The command came from the game logic, i.e. the clearing of a tile.
 
			 * In that case we have no need to actually sync this, just do it. */
src/order_cmd.h
Show inline comments
 
@@ -19,7 +19,7 @@ CommandProc CmdInsertOrder;
 
CommandProc CmdOrderRefit;
 
CommandProc CmdCloneOrder;
 
CommandProc CmdMoveOrder;
 
CommandProc CmdClearOrderBackup;
 
CommandCost CmdClearOrderBackup(DoCommandFlag flags, TileIndex tile, ClientID user_id);
 

	
 
DEF_CMD_TRAIT(CMD_MODIFY_ORDER,       CmdModifyOrder,       0,             CMDT_ROUTE_MANAGEMENT)
 
DEF_CMD_TRAIT(CMD_SKIP_TO_ORDER,      CmdSkipToOrder,       0,             CMDT_ROUTE_MANAGEMENT)
src/roadveh_cmd.cpp
Show inline comments
 
@@ -254,11 +254,10 @@ void RoadVehUpdateCache(RoadVehicle *v, 
 
 * @param flags    type of operation.
 
 * @param tile     tile of the depot where road vehicle is built.
 
 * @param e        the engine to build.
 
 * @param data     unused.
 
 * @param[out] ret the vehicle that has been built.
 
 * @return the cost of this operation or an error.
 
 */
 
CommandCost CmdBuildRoadVehicle(DoCommandFlag flags, TileIndex tile, const Engine *e, uint16 data, Vehicle **ret)
 
CommandCost CmdBuildRoadVehicle(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **ret)
 
{
 
	/* Check that the vehicle can drive on the road in question */
 
	RoadType rt = e->u.road.roadtype;
src/roadveh_cmd.h
Show inline comments
 
@@ -14,7 +14,7 @@
 
#include "engine_type.h"
 
#include "vehicle_type.h"
 

	
 
CommandCost CmdBuildRoadVehicle(DoCommandFlag flags, TileIndex tile, const Engine *e, uint16 data, Vehicle **v);
 
CommandCost CmdBuildRoadVehicle(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **v);
 

	
 
CommandProc CmdTurnRoadVeh;
 

	
src/script/api/script_object.hpp
Show inline comments
 
@@ -347,6 +347,22 @@ namespace ScriptObjectInternal {
 
	{
 
		((SanitizeSingleStringHelper(std::get<Tindices>(values))), ...);
 
	}
 

	
 
	/** Helper to process a single ClientID argument. */
 
	template <class T>
 
	static inline void SetClientIdHelper(T &data)
 
	{
 
		if constexpr (std::is_same_v<ClientID, T>) {
 
			if (data == INVALID_CLIENT_ID) data = (ClientID)UINT32_MAX;
 
		}
 
	}
 

	
 
	/** Set all invalid ClientID's to the proper value. */
 
	template<class Ttuple, size_t... Tindices>
 
	static inline void SetClientIds(Ttuple &values, std::index_sequence<Tindices...>)
 
	{
 
		((SetClientIdHelper(std::get<Tindices>(values))), ...);
 
	}
 
}
 

	
 
template <Commands Tcmd, typename... Targs>
 
@@ -364,8 +380,8 @@ bool ScriptObject::ScriptDoCommandHelper
 
		tile = std::get<0>(args);
 
	}
 

	
 
	/* Only set p2 when the command does not come from the network. */
 
	if ((::GetCommandFlags<Tcmd>() & CMD_CLIENT_ID) != 0 && std::get<2>(args) == 0) std::get<2>(args) = UINT32_MAX;
 
	/* Only set ClientID parameters when the command does not come from the network. */
 
	if constexpr ((::GetCommandFlags<Tcmd>() & CMD_CLIENT_ID) != 0) ScriptObjectInternal::SetClientIds(args, std::index_sequence_for<Targs...>{});
 

	
 
	/* Store the command for command callback validation. */
 
	if (!estimate_only && networking) ScriptObject::SetLastCommand(tile, EndianBufferWriter<CommandDataBuffer>::FromValue(args), Tcmd);
src/script/api/script_vehicle.cpp
Show inline comments
 
@@ -72,7 +72,7 @@
 

	
 
	EnforcePreconditionCustomError(VEHICLE_INVALID, !ScriptGameSettings::IsDisabledVehicleType((ScriptVehicle::VehicleType)type), ScriptVehicle::ERR_VEHICLE_BUILD_DISABLED);
 

	
 
	if (!ScriptObject::Command<CMD_BUILD_VEHICLE>::Do(&ScriptInstance::DoCommandReturnVehicleID, depot, engine_id | (cargo << 24), 0, {})) return VEHICLE_INVALID;
 
	if (!ScriptObject::Command<CMD_BUILD_VEHICLE>::Do(&ScriptInstance::DoCommandReturnVehicleID, depot, engine_id, true, cargo, INVALID_CLIENT_ID)) return VEHICLE_INVALID;
 

	
 
	/* In case of test-mode, we return VehicleID 0 */
 
	return 0;
 
@@ -94,7 +94,7 @@
 
	if (!ScriptEngine::IsBuildable(engine_id)) return -1;
 
	if (!ScriptCargo::IsValidCargo(cargo)) return -1;
 

	
 
	CommandCost res = ::Command<CMD_BUILD_VEHICLE>::Do(DC_QUERY_COST, depot, engine_id | (cargo << 24), 0, {});
 
	CommandCost res = ::Command<CMD_BUILD_VEHICLE>::Do(DC_QUERY_COST, depot, engine_id, true, cargo, INVALID_CLIENT_ID);
 
	return res.Succeeded() ? _returned_refit_capacity : -1;
 
}
 

	
 
@@ -162,7 +162,7 @@
 
	EnforcePrecondition(false, IsValidVehicle(vehicle_id));
 

	
 
	const Vehicle *v = ::Vehicle::Get(vehicle_id);
 
	return ScriptObject::Command<CMD_SELL_VEHICLE>::Do(0, vehicle_id | (v->type == VEH_TRAIN ? 1 : 0) << 20, 0, {});
 
	return ScriptObject::Command<CMD_SELL_VEHICLE>::Do(0, vehicle_id, v->type == VEH_TRAIN, false, INVALID_CLIENT_ID);
 
}
 

	
 
/* static */ bool ScriptVehicle::_SellWagonInternal(VehicleID vehicle_id, int wagon, bool sell_attached_wagons)
 
@@ -174,7 +174,7 @@
 
	const Train *v = ::Train::Get(vehicle_id);
 
	while (wagon-- > 0) v = v->GetNextUnit();
 

	
 
	return ScriptObject::Command<CMD_SELL_VEHICLE>::Do(0, v->index | (sell_attached_wagons ? 1 : 0) << 20, 0, {});
 
	return ScriptObject::Command<CMD_SELL_VEHICLE>::Do(0, v->index, sell_attached_wagons, false, INVALID_CLIENT_ID);
 
}
 

	
 
/* static */ bool ScriptVehicle::SellWagon(VehicleID vehicle_id, int wagon)
src/ship_cmd.cpp
Show inline comments
 
@@ -841,11 +841,10 @@ void Ship::SetDestTile(TileIndex tile)
 
 * @param flags    type of operation.
 
 * @param tile     tile of the depot where ship is built.
 
 * @param e        the engine to build.
 
 * @param data     unused.
 
 * @param[out] ret the vehicle that has been built.
 
 * @return the cost of this operation or an error.
 
 */
 
CommandCost CmdBuildShip(DoCommandFlag flags, TileIndex tile, const Engine *e, uint16 data, Vehicle **ret)
 
CommandCost CmdBuildShip(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **ret)
 
{
 
	tile = GetShipDepotNorthTile(tile);
 
	if (flags & DC_EXEC) {
src/ship_cmd.h
Show inline comments
 
@@ -14,6 +14,6 @@
 
#include "engine_type.h"
 
#include "vehicle_type.h"
 

	
 
CommandCost CmdBuildShip(DoCommandFlag flags, TileIndex tile, const Engine *e, uint16 data, Vehicle **v);
 
CommandCost CmdBuildShip(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **v);
 

	
 
#endif /* SHIP_CMD_H */
src/train_cmd.cpp
Show inline comments
 
@@ -718,11 +718,11 @@ static void AddRearEngineToMultiheadedTr
 
 * @param flags    type of operation.
 
 * @param tile     tile of the depot where rail-vehicle is built.
 
 * @param e        the engine to build.
 
 * @param data     bit 0 prevents any free cars from being added to the train.
 
 * @param free_cars add any free cars to the train.
 
 * @param[out] ret the vehicle that has been built.
 
 * @return the cost of this operation or an error.
 
 */
 
CommandCost CmdBuildRailVehicle(DoCommandFlag flags, TileIndex tile, const Engine *e, uint16 data, Vehicle **ret)
 
CommandCost CmdBuildRailVehicle(DoCommandFlag flags, TileIndex tile, const Engine *e, bool free_cars, Vehicle **ret)
 
{
 
	const RailVehicleInfo *rvi = &e->u.rail;
 

	
 
@@ -789,7 +789,7 @@ CommandCost CmdBuildRailVehicle(DoComman
 
		v->ConsistChanged(CCF_ARRANGE);
 
		UpdateTrainGroupID(v);
 

	
 
		if (!HasBit(data, 0) && !(flags & DC_AUTOREPLACE)) { // check if the cars should be added to the new vehicle
 
		if (free_cars && !(flags & DC_AUTOREPLACE)) { // check if the cars should be added to the new vehicle
 
			NormalizeTrainVehInDepot(v);
 
		}
 

	
 
@@ -1357,18 +1357,16 @@ CommandCost CmdMoveRailVehicle(DoCommand
 
 * Sell a (single) train wagon/engine.
 
 * @param flags type of operation
 
 * @param t     the train wagon to sell
 
 * @param data  the selling mode
 
 * - data = 0: only sell the single dragged wagon/engine (and any belonging rear-engines)
 
 * - data = 1: sell the vehicle and all vehicles following it in the chain
 
 *             if the wagon is dragged, don't delete the possibly belonging rear-engine to some front
 
 * @param sell_chain  the selling mode
 
 * - sell_chain = false: only sell the single dragged wagon/engine (and any belonging rear-engines)
 
 * - sell_chain = true:  sell the vehicle and all vehicles following it in the chain
 
 *                       if the wagon is dragged, don't delete the possibly belonging rear-engine to some front
 
 * @param backup_order make order backup?
 
 * @param user  the user for the order backup.
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, uint16 data, uint32 user)
 
CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, bool sell_chain, bool backup_order, ClientID user)
 
{
 
	/* Sell a chain of vehicles or not? */
 
	bool sell_chain = HasBit(data, 0);
 

	
 
	Train *v = Train::From(t)->GetFirstEnginePart();
 
	Train *first = v->First();
 

	
 
@@ -1418,7 +1416,7 @@ CommandCost CmdSellRailWagon(DoCommandFl
 
			/* Copy other important data from the front engine */
 
			new_head->CopyVehicleConfigAndStatistics(first);
 
			GroupStatistics::CountVehicle(new_head, 1); // after copying over the profit
 
		} else if (v->IsPrimaryVehicle() && data & (MAKE_ORDER_BACKUP_FLAG >> 20)) {
 
		} else if (v->IsPrimaryVehicle() && backup_order) {
 
			OrderBackup::Backup(v, user);
 
		}
 

	
src/train_cmd.h
Show inline comments
 
@@ -14,8 +14,8 @@
 
#include "engine_type.h"
 
#include "vehicle_type.h"
 

	
 
CommandCost CmdBuildRailVehicle(DoCommandFlag flags, TileIndex tile, const Engine *e, uint16 data, Vehicle **v);
 
CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *v, uint16 data, uint32 user);
 
CommandCost CmdBuildRailVehicle(DoCommandFlag flags, TileIndex tile, const Engine *e, bool free_cars, Vehicle **ret);
 
CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, bool sell_chain, bool backup_order, ClientID user);
 

	
 
CommandProc CmdMoveRailVehicle;
 
CommandProc CmdForceTrainProceed;
src/vehicle_cmd.cpp
Show inline comments
 
@@ -79,15 +79,13 @@ const StringID _send_to_depot_msg_table[
 
 * Build a vehicle.
 
 * @param flags for command
 
 * @param tile tile of depot where the vehicle is built
 
 * @param p1 various bitstuffed data
 
 *  bits  0-15: vehicle type being built.
 
 *  bits 16-23: vehicle type specific bits passed on to the vehicle build functions.
 
 *  bits 24-31: refit cargo type.
 
 * @param p2 User
 
 * @param text unused
 
 * @param eid vehicle type being built.
 
 * @param use_free_vehicles use free vehicles when building the vehicle.
 
 * @param cargo refit cargo type.
 
 * @param client_id User
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdBuildVehicle(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
CommandCost CmdBuildVehicle(DoCommandFlag flags, TileIndex tile, EngineID eid, bool use_free_vehicles, CargoID cargo, ClientID client_id)
 
{
 
	/* Elementary check for valid location. */
 
	if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_company)) return CMD_ERROR;
 
@@ -95,11 +93,9 @@ CommandCost CmdBuildVehicle(DoCommandFla
 
	VehicleType type = GetDepotVehicleType(tile);
 

	
 
	/* Validate the engine type. */
 
	EngineID eid = GB(p1, 0, 16);
 
	if (!IsEngineBuildable(eid, type, _current_company)) return_cmd_error(STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE + type);
 

	
 
	/* Validate the cargo type. */
 
	CargoID cargo = GB(p1, 24, 8);
 
	if (cargo >= NUM_CARGO && cargo != CT_INVALID) return CMD_ERROR;
 

	
 
	const Engine *e = Engine::Get(eid);
 
@@ -140,10 +136,10 @@ CommandCost CmdBuildVehicle(DoCommandFla
 

	
 
	Vehicle *v = nullptr;
 
	switch (type) {
 
		case VEH_TRAIN:    value.AddCost(CmdBuildRailVehicle(subflags, tile, e, GB(p1, 16, 8), &v)); break;
 
		case VEH_ROAD:     value.AddCost(CmdBuildRoadVehicle(subflags, tile, e, GB(p1, 16, 8), &v)); break;
 
		case VEH_SHIP:     value.AddCost(CmdBuildShip       (subflags, tile, e, GB(p1, 16, 8), &v)); break;
 
		case VEH_AIRCRAFT: value.AddCost(CmdBuildAircraft   (subflags, tile, e, GB(p1, 16, 8), &v)); break;
 
		case VEH_TRAIN:    value.AddCost(CmdBuildRailVehicle(subflags, tile, e, use_free_vehicles, &v)); break;
 
		case VEH_ROAD:     value.AddCost(CmdBuildRoadVehicle(subflags, tile, e, &v)); break;
 
		case VEH_SHIP:     value.AddCost(CmdBuildShip       (subflags, tile, e, &v)); break;
 
		case VEH_AIRCRAFT: value.AddCost(CmdBuildAircraft   (subflags, tile, e, &v)); break;
 
		default: NOT_REACHED(); // Safe due to IsDepotTile()
 
	}
 

	
 
@@ -176,14 +172,14 @@ CommandCost CmdBuildVehicle(DoCommandFla
 

	
 
			if (v->IsPrimaryVehicle()) {
 
				GroupStatistics::CountVehicle(v, 1);
 
				if (!(subflags & DC_AUTOREPLACE)) OrderBackup::Restore(v, p2);
 
				if (!(subflags & DC_AUTOREPLACE)) OrderBackup::Restore(v, client_id);
 
			}
 
		}
 

	
 

	
 
		/* If we are not in DC_EXEC undo everything */
 
		if (flags != subflags) {
 
			Command<CMD_SELL_VEHICLE>::Do(DC_EXEC, 0, v->index, 0, {});
 
			Command<CMD_SELL_VEHICLE>::Do(DC_EXEC, 0, v->index, false, false, INVALID_CLIENT_ID);
 
		}
 
	}
 

	
 
@@ -197,17 +193,16 @@ CommandCost CmdBuildVehicle(DoCommandFla
 
 * Sell a vehicle.
 
 * @param tile unused.
 
 * @param flags for command.
 
 * @param p1 various bitstuffed data.
 
 *  bits  0-19: vehicle ID being sold.
 
 *  bits 20-30: vehicle type specific bits passed on to the vehicle build functions.
 
 *  bit     31: make a backup of the vehicle's order (if an engine).
 
 * @param p2 User.
 
 * @aram v_id vehicle ID being sold.
 
 * @param sell_chain sell the vehicle and all vehicles following it in the chain.
 
 * @param backup_order make a backup of the vehicle's order (if an engine).
 
 * @param client_id User.
 
 * @param text unused.
 
 * @return the cost of this operation or an error.
 
 */
 
CommandCost CmdSellVehicle(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
CommandCost CmdSellVehicle(DoCommandFlag flags, TileIndex tile, VehicleID v_id, bool sell_chain, bool backup_order, ClientID client_id)
 
{
 
	Vehicle *v = Vehicle::GetIfValid(GB(p1, 0, 20));
 
	Vehicle *v = Vehicle::GetIfValid(v_id);
 
	if (v == nullptr) return CMD_ERROR;
 

	
 
	Vehicle *front = v->First();
 
@@ -220,22 +215,22 @@ CommandCost CmdSellVehicle(DoCommandFlag
 
	if (!front->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT + front->type);
 

	
 
	/* Can we actually make the order backup, i.e. are there enough orders? */
 
	if (p1 & MAKE_ORDER_BACKUP_FLAG &&
 
	if (backup_order &&
 
			front->orders.list != nullptr &&
 
			!front->orders.list->IsShared() &&
 
			!Order::CanAllocateItem(front->orders.list->GetNumOrders())) {
 
		/* Only happens in exceptional cases when there aren't enough orders anyhow.
 
		 * Thus it should be safe to just drop the orders in that case. */
 
		p1 &= ~MAKE_ORDER_BACKUP_FLAG;
 
		backup_order = false;
 
	}
 

	
 
	if (v->type == VEH_TRAIN) {
 
		ret = CmdSellRailWagon(flags, v, GB(p1, 20, 12), p2);
 
		ret = CmdSellRailWagon(flags, v, sell_chain, backup_order, client_id);
 
	} else {
 
		ret = CommandCost(EXPENSES_NEW_VEHICLES, -front->value);
 

	
 
		if (flags & DC_EXEC) {
 
			if (front->IsPrimaryVehicle() && p1 & MAKE_ORDER_BACKUP_FLAG) OrderBackup::Backup(front, p2);
 
			if (front->IsPrimaryVehicle() && backup_order) OrderBackup::Backup(front, client_id);
 
			delete front;
 
		}
 
	}
 
@@ -694,7 +689,7 @@ CommandCost CmdDepotSellAllVehicles(DoCo
 
	CommandCost last_error = CMD_ERROR;
 
	bool had_success = false;
 
	for (uint i = 0; i < list.size(); i++) {
 
		CommandCost ret = Command<CMD_SELL_VEHICLE>::Do(flags, tile, list[i]->index | (1 << 20), 0, {});
 
		CommandCost ret = Command<CMD_SELL_VEHICLE>::Do(flags, tile, list[i]->index, true, false, INVALID_CLIENT_ID);
 
		if (ret.Succeeded()) {
 
			cost.AddCost(ret);
 
			had_success = true;
 
@@ -872,11 +867,11 @@ CommandCost CmdCloneVehicle(DoCommandFla
 
		DoCommandFlag build_flags = flags;
 
		if ((flags & DC_EXEC) && !v->IsPrimaryVehicle()) build_flags |= DC_AUTOREPLACE;
 

	
 
		CommandCost cost = Command<CMD_BUILD_VEHICLE>::Do(build_flags, tile, v->engine_type | (1 << 16) | (CT_INVALID << 24), 0, {});
 
		CommandCost cost = Command<CMD_BUILD_VEHICLE>::Do(build_flags, tile, v->engine_type, false, CT_INVALID, INVALID_CLIENT_ID);
 

	
 
		if (cost.Failed()) {
 
			/* Can't build a part, then sell the stuff we already made; clear up the mess */
 
			if (w_front != nullptr) Command<CMD_SELL_VEHICLE>::Do(flags, w_front->tile, w_front->index | (1 << 20), 0, {});
 
			if (w_front != nullptr) Command<CMD_SELL_VEHICLE>::Do(flags, w_front->tile, w_front->index, true, false, INVALID_CLIENT_ID);
 
			return cost;
 
		}
 

	
 
@@ -896,8 +891,8 @@ CommandCost CmdCloneVehicle(DoCommandFla
 
				if (result.Failed()) {
 
					/* The train can't be joined to make the same consist as the original.
 
					 * Sell what we already made (clean up) and return an error.           */
 
					Command<CMD_SELL_VEHICLE>::Do(flags, w_front->tile, w_front->index | 1 << 20, 0, {});
 
					Command<CMD_SELL_VEHICLE>::Do(flags, w_front->tile, w->index       | 1 << 20, 0, {});
 
					Command<CMD_SELL_VEHICLE>::Do(flags, w_front->tile, w_front->index, true, false, INVALID_CLIENT_ID);
 
					Command<CMD_SELL_VEHICLE>::Do(flags, w_front->tile, w->index,       true, false, INVALID_CLIENT_ID);
 
					return result; // return error and the message returned from CMD_MOVE_RAIL_VEHICLE
 
				}
 
			} else {
 
@@ -978,7 +973,7 @@ CommandCost CmdCloneVehicle(DoCommandFla
 
		CommandCost result = Command<CMD_CLONE_ORDER>::Do(flags, 0, w_front->index | (p2 & 1 ? CO_SHARE : CO_COPY) << 30, v_front->index, {});
 
		if (result.Failed()) {
 
			/* The vehicle has already been bought, so now it must be sold again. */
 
			Command<CMD_SELL_VEHICLE>::Do(flags, w_front->tile, w_front->index | 1 << 20, 0, {});
 
			Command<CMD_SELL_VEHICLE>::Do(flags, w_front->tile, w_front->index, true, false, INVALID_CLIENT_ID);
 
			return result;
 
		}
 

	
 
@@ -989,7 +984,7 @@ CommandCost CmdCloneVehicle(DoCommandFla
 
		 * check whether the company has enough money manually. */
 
		if (!CheckCompanyHasMoney(total_cost)) {
 
			/* The vehicle has already been bought, so now it must be sold again. */
 
			Command<CMD_SELL_VEHICLE>::Do(flags, w_front->tile, w_front->index | 1 << 20, 0, {});
 
			Command<CMD_SELL_VEHICLE>::Do(flags, w_front->tile, w_front->index, true, false, INVALID_CLIENT_ID);
 
			return total_cost;
 
		}
 
	}
src/vehicle_cmd.h
Show inline comments
 
@@ -12,8 +12,8 @@
 

	
 
#include "command_type.h"
 

	
 
CommandProc CmdBuildVehicle;
 
CommandProc CmdSellVehicle;
 
CommandCost CmdBuildVehicle(DoCommandFlag flags, TileIndex tile, EngineID eid, bool use_free_vehicles, CargoID cargo, ClientID client_id);
 
CommandCost CmdSellVehicle(DoCommandFlag flags, TileIndex tile, VehicleID v_id, bool sell_chain, bool backup_order, ClientID client_id);
 
CommandProc CmdRefitVehicle;
 
CommandProc CmdSendVehicleToDepot;
 
CommandProc CmdChangeServiceInt;
0 comments (0 inline, 0 general)