Codechange: Un-bitstuff timetable commands.

This commit is contained in:
Michael Lutz 2021-11-04 00:10:13 +01:00
parent 211c630cbe
commit 2637c06f88
6 changed files with 50 additions and 76 deletions

View File

@ -24,6 +24,7 @@
/** Window to select a date graphically by using dropdowns */ /** Window to select a date graphically by using dropdowns */
struct SetDateWindow : Window { struct SetDateWindow : Window {
SetDateCallback *callback; ///< Callback to call when a date has been selected SetDateCallback *callback; ///< Callback to call when a date has been selected
void *callback_data; ///< Callback data pointer.
YearMonthDay date; ///< The currently selected date YearMonthDay date; ///< The currently selected date
Year min_year; ///< The minimum year in the year dropdown Year min_year; ///< The minimum year in the year dropdown
Year max_year; ///< The maximum year (inclusive) in the year dropdown Year max_year; ///< The maximum year (inclusive) in the year dropdown
@ -38,9 +39,10 @@ struct SetDateWindow : Window {
* @param max_year the maximum year (inclusive) to show in the year dropdown * @param max_year the maximum year (inclusive) to show in the year dropdown
* @param callback the callback to call once a date has been selected * @param callback the callback to call once a date has been selected
*/ */
SetDateWindow(WindowDesc *desc, WindowNumber window_number, Window *parent, Date initial_date, Year min_year, Year max_year, SetDateCallback *callback) : SetDateWindow(WindowDesc *desc, WindowNumber window_number, Window *parent, Date initial_date, Year min_year, Year max_year, SetDateCallback *callback, void *callback_data) :
Window(desc), Window(desc),
callback(callback), callback(callback),
callback_data(callback_data),
min_year(std::max(MIN_YEAR, min_year)), min_year(std::max(MIN_YEAR, min_year)),
max_year(std::min(MAX_YEAR, max_year)) max_year(std::min(MAX_YEAR, max_year))
{ {
@ -146,7 +148,7 @@ struct SetDateWindow : Window {
break; break;
case WID_SD_SET_DATE: case WID_SD_SET_DATE:
if (this->callback != nullptr) this->callback(this, ConvertYMDToDate(this->date.year, this->date.month, this->date.day)); if (this->callback != nullptr) this->callback(this, ConvertYMDToDate(this->date.year, this->date.month, this->date.day), this->callback_data);
this->Close(); this->Close();
break; break;
} }
@ -209,9 +211,10 @@ static WindowDesc _set_date_desc(
* @param min_year the minimum year to show in the year dropdown * @param min_year the minimum year to show in the year dropdown
* @param max_year the maximum year (inclusive) to show in the year dropdown * @param max_year the maximum year (inclusive) to show in the year dropdown
* @param callback the callback to call once a date has been selected * @param callback the callback to call once a date has been selected
* @param callback_data extra callback data
*/ */
void ShowSetDateWindow(Window *parent, int window_number, Date initial_date, Year min_year, Year max_year, SetDateCallback *callback) void ShowSetDateWindow(Window *parent, int window_number, Date initial_date, Year min_year, Year max_year, SetDateCallback *callback, void *callback_data)
{ {
CloseWindowByClass(WC_SET_DATE); CloseWindowByClass(WC_SET_DATE);
new SetDateWindow(&_set_date_desc, window_number, parent, initial_date, min_year, max_year, callback); new SetDateWindow(&_set_date_desc, window_number, parent, initial_date, min_year, max_year, callback, callback_data);
} }

View File

@ -18,8 +18,8 @@
* @param w the window that sends the callback * @param w the window that sends the callback
* @param date the date that has been chosen * @param date the date that has been chosen
*/ */
typedef void SetDateCallback(const Window *w, Date date); typedef void SetDateCallback(const Window *w, Date date, void *data);
void ShowSetDateWindow(Window *parent, int window_number, Date initial_date, Year min_year, Year max_year, SetDateCallback *callback); void ShowSetDateWindow(Window *parent, int window_number, Date initial_date, Year min_year, Year max_year, SetDateCallback *callback, void *callback_data);
#endif /* DATE_GUI_H */ #endif /* DATE_GUI_H */

View File

@ -167,7 +167,7 @@ enum OrderDepotAction {
/** /**
* Enumeration for the data to set in #CmdChangeTimetable. * Enumeration for the data to set in #CmdChangeTimetable.
*/ */
enum ModifyTimetableFlags { enum ModifyTimetableFlags : byte {
MTF_WAIT_TIME, ///< Set wait time. MTF_WAIT_TIME, ///< Set wait time.
MTF_TRAVEL_TIME, ///< Set travel time. MTF_TRAVEL_TIME, ///< Set travel time.
MTF_TRAVEL_SPEED, ///< Set max travel speed. MTF_TRAVEL_SPEED, ///< Set max travel speed.

View File

@ -87,32 +87,24 @@ static void ChangeTimetable(Vehicle *v, VehicleOrderID order_number, uint16 val,
/** /**
* Change timetable data of an order. * Change timetable data of an order.
* @param flags Operation to perform. * @param flags Operation to perform.
* @param tile Not used. * @param veh Vehicle with the orders to change.
* @param p1 Various bitstuffed elements * @param order_number Order index to modify.
* - p1 = (bit 0-19) - Vehicle with the orders to change. * @param mtf Timetable data to change (@see ModifyTimetableFlags)
* - p1 = (bit 20-27) - Order index to modify. * @param data The data to modify as specified by \c mtf.
* - p1 = (bit 28-29) - Timetable data to change (@see ModifyTimetableFlags) * 0 to clear times, UINT16_MAX to clear speed limit.
* @param p2 The amount of time to wait.
* - p2 = (bit 0-15) - The data to modify as specified by p1 bits 28-29.
* 0 to clear times, UINT16_MAX to clear speed limit.
* @param text unused
* @return the cost of this operation or an error * @return the cost of this operation or an error
*/ */
CommandCost CmdChangeTimetable(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text) CommandCost CmdChangeTimetable(DoCommandFlag flags, VehicleID veh, VehicleOrderID order_number, ModifyTimetableFlags mtf, uint16 data)
{ {
VehicleID veh = GB(p1, 0, 20);
Vehicle *v = Vehicle::GetIfValid(veh); Vehicle *v = Vehicle::GetIfValid(veh);
if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR; if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
CommandCost ret = CheckOwnership(v->owner); CommandCost ret = CheckOwnership(v->owner);
if (ret.Failed()) return ret; if (ret.Failed()) return ret;
VehicleOrderID order_number = GB(p1, 20, 8);
Order *order = v->GetOrder(order_number); Order *order = v->GetOrder(order_number);
if (order == nullptr || order->IsType(OT_IMPLICIT)) return CMD_ERROR; if (order == nullptr || order->IsType(OT_IMPLICIT)) return CMD_ERROR;
ModifyTimetableFlags mtf = Extract<ModifyTimetableFlags, 28, 2>(p1);
if (mtf >= MTF_END) return CMD_ERROR; if (mtf >= MTF_END) return CMD_ERROR;
int wait_time = order->GetWaitTime(); int wait_time = order->GetWaitTime();
@ -120,15 +112,15 @@ CommandCost CmdChangeTimetable(DoCommandFlag flags, TileIndex tile, uint32 p1, u
int max_speed = order->GetMaxSpeed(); int max_speed = order->GetMaxSpeed();
switch (mtf) { switch (mtf) {
case MTF_WAIT_TIME: case MTF_WAIT_TIME:
wait_time = GB(p2, 0, 16); wait_time = data;
break; break;
case MTF_TRAVEL_TIME: case MTF_TRAVEL_TIME:
travel_time = GB(p2, 0, 16); travel_time = data;
break; break;
case MTF_TRAVEL_SPEED: case MTF_TRAVEL_SPEED:
max_speed = GB(p2, 0, 16); max_speed = data;
if (max_speed == 0) max_speed = UINT16_MAX; // Disable speed limit. if (max_speed == 0) max_speed = UINT16_MAX; // Disable speed limit.
break; break;
@ -185,17 +177,11 @@ CommandCost CmdChangeTimetable(DoCommandFlag flags, TileIndex tile, uint32 p1, u
/** /**
* Clear the lateness counter to make the vehicle on time. * Clear the lateness counter to make the vehicle on time.
* @param flags Operation to perform. * @param flags Operation to perform.
* @param tile Not used. * @param veh Vehicle with the orders to change.
* @param p1 Various bitstuffed elements
* - p1 = (bit 0-19) - Vehicle with the orders to change.
* @param p2 unused
* @param text unused
* @return the cost of this operation or an error * @return the cost of this operation or an error
*/ */
CommandCost CmdSetVehicleOnTime(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text) CommandCost CmdSetVehicleOnTime(DoCommandFlag flags, VehicleID veh)
{ {
VehicleID veh = GB(p1, 0, 20);
Vehicle *v = Vehicle::GetIfValid(veh); Vehicle *v = Vehicle::GetIfValid(veh);
if (v == nullptr || !v->IsPrimaryVehicle() || v->orders.list == nullptr) return CMD_ERROR; if (v == nullptr || !v->IsPrimaryVehicle() || v->orders.list == nullptr) return CMD_ERROR;
@ -251,25 +237,20 @@ static bool VehicleTimetableSorter(Vehicle * const &a, Vehicle * const &b)
/** /**
* Set the start date of the timetable. * Set the start date of the timetable.
* @param flags Operation to perform. * @param flags Operation to perform.
* @param tile Not used. * @param veh_id Vehicle ID.
* @param p2 Various bitstuffed elements * @param timetable_all Set to set timetable start for all vehicles sharing this order
* - p2 = (bit 0-19) - Vehicle ID. * @param start_date The timetable start date.
* - p2 = (bit 20) - Set to 1 to set timetable start for all vehicles sharing this order
* @param p2 The timetable start date.
* @param text Not used.
* @return The error or cost of the operation. * @return The error or cost of the operation.
*/ */
CommandCost CmdSetTimetableStart(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text) CommandCost CmdSetTimetableStart(DoCommandFlag flags, VehicleID veh_id, bool timetable_all, Date start_date)
{ {
bool timetable_all = HasBit(p1, 20); Vehicle *v = Vehicle::GetIfValid(veh_id);
Vehicle *v = Vehicle::GetIfValid(GB(p1, 0, 20));
if (v == nullptr || !v->IsPrimaryVehicle() || v->orders.list == nullptr) return CMD_ERROR; if (v == nullptr || !v->IsPrimaryVehicle() || v->orders.list == nullptr) return CMD_ERROR;
CommandCost ret = CheckOwnership(v->owner); CommandCost ret = CheckOwnership(v->owner);
if (ret.Failed()) return ret; if (ret.Failed()) return ret;
/* Don't let a timetable start more than 15 years into the future or 1 year in the past. */ /* Don't let a timetable start more than 15 years into the future or 1 year in the past. */
Date start_date = (Date)p2;
if (start_date < 0 || start_date > MAX_DAY) return CMD_ERROR; if (start_date < 0 || start_date > MAX_DAY) return CMD_ERROR;
if (start_date - _date > 15 * DAYS_IN_LEAP_YEAR) return CMD_ERROR; if (start_date - _date > 15 * DAYS_IN_LEAP_YEAR) return CMD_ERROR;
if (_date - start_date > DAYS_IN_LEAP_YEAR) return CMD_ERROR; if (_date - start_date > DAYS_IN_LEAP_YEAR) return CMD_ERROR;
@ -316,18 +297,13 @@ CommandCost CmdSetTimetableStart(DoCommandFlag flags, TileIndex tile, uint32 p1,
* actually takes to complete it. When starting to autofill the current times * actually takes to complete it. When starting to autofill the current times
* are cleared and the timetable will start again from scratch. * are cleared and the timetable will start again from scratch.
* @param flags Operation to perform. * @param flags Operation to perform.
* @param tile Not used. * @param veh Vehicle index.
* @param p1 Vehicle index. * @param autofill Enable or disable autofill
* @param p2 Various bitstuffed elements * @param preserve_wait_time Set to preserve waiting times in non-destructive mode
* - p2 = (bit 0) - Set to 1 to enable, 0 to disable autofill.
* - p2 = (bit 1) - Set to 1 to preserve waiting times in non-destructive mode
* @param text unused
* @return the cost of this operation or an error * @return the cost of this operation or an error
*/ */
CommandCost CmdAutofillTimetable(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text) CommandCost CmdAutofillTimetable(DoCommandFlag flags, VehicleID veh, bool autofill, bool preserve_wait_time)
{ {
VehicleID veh = GB(p1, 0, 20);
Vehicle *v = Vehicle::GetIfValid(veh); Vehicle *v = Vehicle::GetIfValid(veh);
if (v == nullptr || !v->IsPrimaryVehicle() || v->orders.list == nullptr) return CMD_ERROR; if (v == nullptr || !v->IsPrimaryVehicle() || v->orders.list == nullptr) return CMD_ERROR;
@ -335,7 +311,7 @@ CommandCost CmdAutofillTimetable(DoCommandFlag flags, TileIndex tile, uint32 p1,
if (ret.Failed()) return ret; if (ret.Failed()) return ret;
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
if (HasBit(p2, 0)) { if (autofill) {
/* Start autofilling the timetable, which clears the /* Start autofilling the timetable, which clears the
* "timetable has started" bit. Times are not cleared anymore, but are * "timetable has started" bit. Times are not cleared anymore, but are
* overwritten when the order is reached now. */ * overwritten when the order is reached now. */
@ -343,7 +319,7 @@ CommandCost CmdAutofillTimetable(DoCommandFlag flags, TileIndex tile, uint32 p1,
ClrBit(v->vehicle_flags, VF_TIMETABLE_STARTED); ClrBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
/* Overwrite waiting times only if they got longer */ /* Overwrite waiting times only if they got longer */
if (HasBit(p2, 1)) SetBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME); if (preserve_wait_time) SetBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
v->timetable_start = 0; v->timetable_start = 0;
v->lateness_counter = 0; v->lateness_counter = 0;

View File

@ -12,10 +12,10 @@
#include "command_type.h" #include "command_type.h"
CommandProc CmdChangeTimetable; CommandCost CmdChangeTimetable(DoCommandFlag flags, VehicleID veh, VehicleOrderID order_number, ModifyTimetableFlags mtf, uint16 data);
CommandProc CmdSetVehicleOnTime; CommandCost CmdSetVehicleOnTime(DoCommandFlag flags, VehicleID veh);
CommandProc CmdAutofillTimetable; CommandCost CmdAutofillTimetable(DoCommandFlag flags, VehicleID veh, bool autofill, bool preserve_wait_time);
CommandProc CmdSetTimetableStart; CommandCost CmdSetTimetableStart(DoCommandFlag flags, VehicleID veh_id, bool timetable_all, Date start_date);
DEF_CMD_TRAIT(CMD_CHANGE_TIMETABLE, CmdChangeTimetable, 0, CMDT_ROUTE_MANAGEMENT) DEF_CMD_TRAIT(CMD_CHANGE_TIMETABLE, CmdChangeTimetable, 0, CMDT_ROUTE_MANAGEMENT)
DEF_CMD_TRAIT(CMD_SET_VEHICLE_ON_TIME, CmdSetVehicleOnTime, 0, CMDT_ROUTE_MANAGEMENT) DEF_CMD_TRAIT(CMD_SET_VEHICLE_ON_TIME, CmdSetVehicleOnTime, 0, CMDT_ROUTE_MANAGEMENT)

View File

@ -23,6 +23,7 @@
#include "vehicle_gui.h" #include "vehicle_gui.h"
#include "settings_type.h" #include "settings_type.h"
#include "timetable_cmd.h" #include "timetable_cmd.h"
#include <cstdint>
#include "widgets/timetable_widget.h" #include "widgets/timetable_widget.h"
@ -141,9 +142,9 @@ static void FillTimetableArrivalDepartureTable(const Vehicle *v, VehicleOrderID
* @param w the window related to the setting of the date * @param w the window related to the setting of the date
* @param date the actually chosen date * @param date the actually chosen date
*/ */
static void ChangeTimetableStartCallback(const Window *w, Date date) static void ChangeTimetableStartCallback(const Window *w, Date date, void *data)
{ {
Command<CMD_SET_TIMETABLE_START>::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, 0, w->window_number, date, {}); Command<CMD_SET_TIMETABLE_START>::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, (VehicleID)w->window_number, reinterpret_cast<std::uintptr_t>(data) != 0, date);
} }
@ -502,14 +503,14 @@ struct TimetableWindow : Window {
} }
} }
static inline uint32 PackTimetableArgs(const Vehicle *v, uint selected, bool speed) static inline std::tuple<VehicleOrderID, ModifyTimetableFlags> PackTimetableArgs(const Vehicle *v, uint selected, bool speed)
{ {
uint order_number = (selected + 1) / 2; uint order_number = (selected + 1) / 2;
ModifyTimetableFlags mtf = (selected % 2 == 1) ? (speed ? MTF_TRAVEL_SPEED : MTF_TRAVEL_TIME) : MTF_WAIT_TIME; ModifyTimetableFlags mtf = (selected % 2 == 1) ? (speed ? MTF_TRAVEL_SPEED : MTF_TRAVEL_TIME) : MTF_WAIT_TIME;
if (order_number >= v->GetNumOrders()) order_number = 0; if (order_number >= v->GetNumOrders()) order_number = 0;
return v->index | (order_number << 20) | (mtf << 28); return { order_number, mtf };
} }
void OnClick(Point pt, int widget, int click_count) override void OnClick(Point pt, int widget, int click_count) override
@ -530,7 +531,7 @@ struct TimetableWindow : Window {
} }
case WID_VT_START_DATE: // Change the date that the timetable starts. case WID_VT_START_DATE: // Change the date that the timetable starts.
ShowSetDateWindow(this, v->index | (v->orders.list->IsCompleteTimetable() && _ctrl_pressed ? 1U << 20 : 0), _date, _cur_year, _cur_year + 15, ChangeTimetableStartCallback); ShowSetDateWindow(this, v->index, _date, _cur_year, _cur_year + 15, ChangeTimetableStartCallback, reinterpret_cast<void *>(static_cast<uintptr_t>(v->orders.list->IsCompleteTimetable() && _ctrl_pressed)));
break; break;
case WID_VT_CHANGE_TIME: { // "Wait For" button. case WID_VT_CHANGE_TIME: { // "Wait For" button.
@ -578,26 +579,23 @@ struct TimetableWindow : Window {
} }
case WID_VT_CLEAR_TIME: { // Clear waiting time. case WID_VT_CLEAR_TIME: { // Clear waiting time.
uint32 p1 = PackTimetableArgs(v, this->sel_index, false); auto [order_id, mtf] = PackTimetableArgs(v, this->sel_index, false);
Command<CMD_CHANGE_TIMETABLE>::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, 0, p1, 0, {}); Command<CMD_CHANGE_TIMETABLE>::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, v->index, order_id, mtf, 0);
break; break;
} }
case WID_VT_CLEAR_SPEED: { // Clear max speed button. case WID_VT_CLEAR_SPEED: { // Clear max speed button.
uint32 p1 = PackTimetableArgs(v, this->sel_index, true); auto [order_id, mtf] = PackTimetableArgs(v, this->sel_index, true);
Command<CMD_CHANGE_TIMETABLE>::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, 0, p1, UINT16_MAX, {}); Command<CMD_CHANGE_TIMETABLE>::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, v->index, order_id, mtf, UINT16_MAX);
break; break;
} }
case WID_VT_RESET_LATENESS: // Reset the vehicle's late counter. case WID_VT_RESET_LATENESS: // Reset the vehicle's late counter.
Command<CMD_SET_VEHICLE_ON_TIME>::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, 0, v->index, 0, {}); Command<CMD_SET_VEHICLE_ON_TIME>::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, v->index);
break; break;
case WID_VT_AUTOFILL: { // Autofill the timetable. case WID_VT_AUTOFILL: { // Autofill the timetable.
uint32 p2 = 0; Command<CMD_AUTOFILL_TIMETABLE>::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, v->index, !HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE), _ctrl_pressed);
if (!HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE)) SetBit(p2, 0);
if (_ctrl_pressed) SetBit(p2, 1);
Command<CMD_AUTOFILL_TIMETABLE>::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, 0, v->index, p2, {});
break; break;
} }
@ -619,8 +617,6 @@ struct TimetableWindow : Window {
const Vehicle *v = this->vehicle; const Vehicle *v = this->vehicle;
uint32 p1 = PackTimetableArgs(v, this->sel_index, this->query_is_speed_query);
uint64 val = StrEmpty(str) ? 0 : strtoul(str, nullptr, 10); uint64 val = StrEmpty(str) ? 0 : strtoul(str, nullptr, 10);
if (this->query_is_speed_query) { if (this->query_is_speed_query) {
val = ConvertDisplaySpeedToKmhishSpeed(val); val = ConvertDisplaySpeedToKmhishSpeed(val);
@ -628,9 +624,8 @@ struct TimetableWindow : Window {
if (!_settings_client.gui.timetable_in_ticks) val *= DAY_TICKS; if (!_settings_client.gui.timetable_in_ticks) val *= DAY_TICKS;
} }
uint32 p2 = std::min<uint32>(val, UINT16_MAX); auto [order_id, mtf] = PackTimetableArgs(v, this->sel_index, this->query_is_speed_query);
Command<CMD_CHANGE_TIMETABLE>::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, v->index, order_id, mtf, std::min<uint32>(val, UINT16_MAX));
Command<CMD_CHANGE_TIMETABLE>::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, 0, p1, p2, {});
} }
void OnResize() override void OnResize() override