mirror of https://github.com/OpenTTD/OpenTTD.git
Codechange: Un-bitstuff commands taking a ClientID (i.e. CMD_CLIENT_ID).
This commit is contained in:
parent
ccefa76a46
commit
4f3ea3907e
|
@ -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:
|
||||
|
|
|
@ -263,11 +263,10 @@ void GetAircraftSpriteSize(EngineID engine, uint &width, uint &height, int &xoff
|
|||
* @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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -345,7 +345,7 @@ static CommandCost BuildReplacementVehicle(Vehicle *old_veh, Vehicle **new_vehic
|
|||
}
|
||||
|
||||
/* 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(Vehicle **single_unit, DoCommandFlag flags, b
|
|||
}
|
||||
|
||||
/* 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 **chain, DoCommandFlag flags, bool wagon
|
|||
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 **chain, DoCommandFlag flags, bool wagon
|
|||
/* 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 **chain, DoCommandFlag flags, bool wagon
|
|||
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 **chain, DoCommandFlag flags, bool wagon
|
|||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -75,15 +75,13 @@ int RecursiveCommandCounter::_counter = 0;
|
|||
* 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_table = MakeCommandsFromTraits(std::make_int
|
|||
|
||||
|
||||
/*!
|
||||
* 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();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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 company_id, CompanyRemoveReason reason)
|
|||
/**
|
||||
* 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 flags, TileIndex tile, uint32 p1, uint3
|
|||
/* 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 flags, TileIndex tile, uint32 p1, uint3
|
|||
}
|
||||
|
||||
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. */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -630,7 +630,7 @@ static void CompanyCheckBankrupt(Company *c)
|
|||
* 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;
|
||||
|
|
|
@ -840,7 +840,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet
|
|||
* 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 */
|
||||
|
|
|
@ -89,15 +89,17 @@ static CommandCallback * const _callback_table[] = {
|
|||
|
||||
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::SendCommand(Packet *p, const CommandPacket *cp)
|
|||
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::SendCommand(Packet *p, const CommandPacket *cp)
|
|||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1396,7 +1396,7 @@ static void AdminCompanyResetCallback(Window *w, bool confirmed)
|
|||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1050,15 +1050,15 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMMAND(Packet
|
|||
* 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 {
|
||||
|
|
|
@ -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(DoCommandFlag flags, TileIndex tile, uint32 p1,
|
|||
/* 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(DoCommandFlag flags, TileIndex tile, uint32 p1,
|
|||
/* 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. */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -254,11 +254,10 @@ void RoadVehUpdateCache(RoadVehicle *v, bool same_length)
|
|||
* @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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<Tcmd, CommandCost(*)(DoCommandFlag, Tar
|
|||
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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -718,11 +718,11 @@ static void AddRearEngineToMultiheadedTrain(Train *v)
|
|||
* @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(DoCommandFlag flags, TileIndex tile, const Engin
|
|||
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(DoCommandFlag flags, TileIndex tile, uint32 p1, u
|
|||
* 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(DoCommandFlag flags, Vehicle *t, uint16 data, uint3
|
|||
/* 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(DoCommandFlag flags, TileIndex tile, uint32 p1, uint
|
|||
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(DoCommandFlag flags, TileIndex tile, uint32 p1, uint
|
|||
|
||||
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(DoCommandFlag flags, TileIndex tile, uint32 p1, uint
|
|||
|
||||
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(DoCommandFlag flags, TileIndex tile, uint32 p1, uint
|
|||
* 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 flags, TileIndex tile, uint32 p1, uint3
|
|||
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(DoCommandFlag flags, TileIndex tile, uint32
|
|||
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(DoCommandFlag flags, TileIndex tile, uint32 p1, uint
|
|||
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(DoCommandFlag flags, TileIndex tile, uint32 p1, uint
|
|||
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(DoCommandFlag flags, TileIndex tile, uint32 p1, uint
|
|||
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(DoCommandFlag flags, TileIndex tile, uint32 p1, uint
|
|||
* 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue