Add support for multiple scheduled dispatch schedules per order list
This commit is contained in:
@@ -82,6 +82,7 @@ CommandCost CmdScheduledDispatch(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
||||
CommandCost CmdScheduledDispatchAdd(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, uint32 binary_length)
|
||||
{
|
||||
VehicleID veh = GB(p1, 0, 20);
|
||||
uint schedule_index = GB(p1, 20, 12);
|
||||
uint32 offset = GB(p3, 0, 32);
|
||||
uint32 extra_slots = GB(p3, 32, 16);
|
||||
|
||||
@@ -93,14 +94,17 @@ CommandCost CmdScheduledDispatchAdd(TileIndex tile, DoCommandFlag flags, uint32
|
||||
|
||||
if (v->orders.list == nullptr) return CMD_ERROR;
|
||||
|
||||
if (schedule_index >= v->orders.list->GetScheduledDispatchScheduleCount()) return CMD_ERROR;
|
||||
|
||||
if (extra_slots > 512) return_cmd_error(STR_ERROR_SCHDISPATCH_TRIED_TO_ADD_TOO_MANY_SLOTS);
|
||||
if (extra_slots > 0 && offset == 0) return CMD_ERROR;
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
v->orders.list->AddScheduledDispatch(p2);
|
||||
DispatchSchedule &ds = v->orders.list->GetDispatchScheduleByIndex(schedule_index);
|
||||
ds.AddScheduledDispatch(p2);
|
||||
for (uint i = 0; i < extra_slots; i++) {
|
||||
p2 += offset;
|
||||
v->orders.list->AddScheduledDispatch(p2);
|
||||
ds.AddScheduledDispatch(p2);
|
||||
}
|
||||
SetWindowDirty(WC_SCHDISPATCH_SLOTS, v->index);
|
||||
}
|
||||
@@ -120,6 +124,7 @@ CommandCost CmdScheduledDispatchAdd(TileIndex tile, DoCommandFlag flags, uint32
|
||||
CommandCost CmdScheduledDispatchRemove(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
|
||||
{
|
||||
VehicleID veh = GB(p1, 0, 20);
|
||||
uint schedule_index = GB(p1, 20, 12);
|
||||
|
||||
Vehicle *v = Vehicle::GetIfValid(veh);
|
||||
if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
|
||||
@@ -129,8 +134,10 @@ CommandCost CmdScheduledDispatchRemove(TileIndex tile, DoCommandFlag flags, uint
|
||||
|
||||
if (v->orders.list == nullptr) return CMD_ERROR;
|
||||
|
||||
if (schedule_index >= v->orders.list->GetScheduledDispatchScheduleCount()) return CMD_ERROR;
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
v->orders.list->RemoveScheduledDispatch(p2);
|
||||
v->orders.list->GetDispatchScheduleByIndex(schedule_index).RemoveScheduledDispatch(p2);
|
||||
SetWindowDirty(WC_SCHDISPATCH_SLOTS, v->index);
|
||||
}
|
||||
|
||||
@@ -150,6 +157,7 @@ CommandCost CmdScheduledDispatchRemove(TileIndex tile, DoCommandFlag flags, uint
|
||||
CommandCost CmdScheduledDispatchSetDuration(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
|
||||
{
|
||||
VehicleID veh = GB(p1, 0, 20);
|
||||
uint schedule_index = GB(p1, 20, 12);
|
||||
|
||||
Vehicle *v = Vehicle::GetIfValid(veh);
|
||||
if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
|
||||
@@ -159,9 +167,12 @@ CommandCost CmdScheduledDispatchSetDuration(TileIndex tile, DoCommandFlag flags,
|
||||
|
||||
if (v->orders.list == nullptr) return CMD_ERROR;
|
||||
|
||||
if (schedule_index >= v->orders.list->GetScheduledDispatchScheduleCount()) return CMD_ERROR;
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
v->orders.list->SetScheduledDispatchDuration(p2);
|
||||
v->orders.list->UpdateScheduledDispatch();
|
||||
DispatchSchedule &ds = v->orders.list->GetDispatchScheduleByIndex(schedule_index);
|
||||
ds.SetScheduledDispatchDuration(p2);
|
||||
ds.UpdateScheduledDispatch();
|
||||
SetWindowDirty(WC_SCHDISPATCH_SLOTS, v->index);
|
||||
}
|
||||
|
||||
@@ -173,23 +184,22 @@ CommandCost CmdScheduledDispatchSetDuration(TileIndex tile, DoCommandFlag flags,
|
||||
*
|
||||
* The parameter is quite tricky. The default maximum of daylength factor is 125,
|
||||
* and with DAY_TICKS of 74 the result (maximum scaled tick per day) fits in 14 bit.
|
||||
* Vehicle index in p1 takes 20 bit, so we have 12 bit here. The MSB of the fraction is stored here.
|
||||
* The 2-bit LSB is stored in MSB of p2, which is start date. The default date is stored in int32,
|
||||
* which only have topmost bit available. However, if the date reached 31 bits, that means it is over 1,000,000 years,
|
||||
* so I think it is safe to steal another bit here.
|
||||
*
|
||||
* See also the static_assert at the top of the file.
|
||||
*
|
||||
* @param tile Not used.
|
||||
* @param flags Operation to perform.
|
||||
* @param p1 MSB of Start Full Date Fraction || Vehicle index
|
||||
* @param p2 LSB of Start Full Date Fraction || Date to add.
|
||||
* @param p1 Vehicle index
|
||||
* @param p2 Date to add.
|
||||
* @param p3 various bitstuffed elements
|
||||
* - p3 = (bit 0 - 15) - Full date fraction
|
||||
* @param text unused
|
||||
* @return the cost of this operation or an error
|
||||
*/
|
||||
CommandCost CmdScheduledDispatchSetStartDate(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
|
||||
CommandCost CmdScheduledDispatchSetStartDate(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, uint32 binary_length)
|
||||
{
|
||||
VehicleID veh = GB(p1, 0, 20);
|
||||
uint schedule_index = GB(p1, 20, 12);
|
||||
|
||||
Vehicle *v = Vehicle::GetIfValid(veh);
|
||||
if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
|
||||
@@ -199,12 +209,15 @@ CommandCost CmdScheduledDispatchSetStartDate(TileIndex tile, DoCommandFlag flags
|
||||
|
||||
if (v->orders.list == nullptr) return CMD_ERROR;
|
||||
|
||||
int32 date = (int32) GB(p2, 0, 30);
|
||||
uint16 full_date_fract = (GB(p1, 20, 12) << 2) + GB(p2, 30, 2);
|
||||
if (schedule_index >= v->orders.list->GetScheduledDispatchScheduleCount()) return CMD_ERROR;
|
||||
|
||||
int32 date = (int32)p2;
|
||||
uint16 full_date_fract = GB(p3, 0, 16);
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
v->orders.list->SetScheduledDispatchStartDate(date, full_date_fract);
|
||||
v->orders.list->UpdateScheduledDispatch();
|
||||
DispatchSchedule &ds = v->orders.list->GetDispatchScheduleByIndex(schedule_index);
|
||||
ds.SetScheduledDispatchStartDate(date, full_date_fract);
|
||||
ds.UpdateScheduledDispatch();
|
||||
SetWindowDirty(WC_SCHDISPATCH_SLOTS, v->index);
|
||||
}
|
||||
|
||||
@@ -224,6 +237,7 @@ CommandCost CmdScheduledDispatchSetStartDate(TileIndex tile, DoCommandFlag flags
|
||||
CommandCost CmdScheduledDispatchSetDelay(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
|
||||
{
|
||||
VehicleID veh = GB(p1, 0, 20);
|
||||
uint schedule_index = GB(p1, 20, 12);
|
||||
|
||||
Vehicle *v = Vehicle::GetIfValid(veh);
|
||||
if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
|
||||
@@ -233,8 +247,10 @@ CommandCost CmdScheduledDispatchSetDelay(TileIndex tile, DoCommandFlag flags, ui
|
||||
|
||||
if (v->orders.list == nullptr) return CMD_ERROR;
|
||||
|
||||
if (schedule_index >= v->orders.list->GetScheduledDispatchScheduleCount()) return CMD_ERROR;
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
v->orders.list->SetScheduledDispatchDelay(p2);
|
||||
v->orders.list->GetDispatchScheduleByIndex(schedule_index).SetScheduledDispatchDelay(p2);
|
||||
SetWindowDirty(WC_SCHDISPATCH_SLOTS, v->index);
|
||||
}
|
||||
|
||||
@@ -259,6 +275,7 @@ CommandCost CmdScheduledDispatchSetDelay(TileIndex tile, DoCommandFlag flags, ui
|
||||
CommandCost CmdScheduledDispatchResetLastDispatch(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
|
||||
{
|
||||
VehicleID veh = GB(p1, 0, 20);
|
||||
uint schedule_index = GB(p1, 20, 12);
|
||||
|
||||
Vehicle *v = Vehicle::GetIfValid(veh);
|
||||
if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
|
||||
@@ -268,8 +285,10 @@ CommandCost CmdScheduledDispatchResetLastDispatch(TileIndex tile, DoCommandFlag
|
||||
|
||||
if (v->orders.list == nullptr) return CMD_ERROR;
|
||||
|
||||
if (schedule_index >= v->orders.list->GetScheduledDispatchScheduleCount()) return CMD_ERROR;
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
v->orders.list->SetScheduledDispatchLastDispatch(0);
|
||||
v->orders.list->GetDispatchScheduleByIndex(schedule_index).SetScheduledDispatchLastDispatch(0);
|
||||
SetWindowDirty(WC_SCHDISPATCH_SLOTS, v->index);
|
||||
}
|
||||
|
||||
@@ -289,6 +308,7 @@ CommandCost CmdScheduledDispatchResetLastDispatch(TileIndex tile, DoCommandFlag
|
||||
CommandCost CmdScheduledDispatchClear(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
|
||||
{
|
||||
VehicleID veh = GB(p1, 0, 20);
|
||||
uint schedule_index = GB(p1, 20, 12);
|
||||
|
||||
Vehicle *v = Vehicle::GetIfValid(veh);
|
||||
if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
|
||||
@@ -298,19 +318,106 @@ CommandCost CmdScheduledDispatchClear(TileIndex tile, DoCommandFlag flags, uint3
|
||||
|
||||
if (v->orders.list == nullptr) return CMD_ERROR;
|
||||
|
||||
if (schedule_index >= v->orders.list->GetScheduledDispatchScheduleCount()) return CMD_ERROR;
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
v->orders.list->ClearScheduledDispatch();
|
||||
v->orders.list->GetDispatchScheduleByIndex(schedule_index).ClearScheduledDispatch();
|
||||
SetWindowDirty(WC_SCHDISPATCH_SLOTS, v->index);
|
||||
}
|
||||
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new scheduled dispatch schedule
|
||||
*
|
||||
* @param tile Not used.
|
||||
* @param flags Operation to perform.
|
||||
* @param p1 Vehicle index
|
||||
* @param p2 Duration, in scaled tick
|
||||
* @param p3 various bitstuffed elements
|
||||
* - p3 = (bit 0 - 31) - Start date
|
||||
* - p3 = (bit 32 - 47) - Full date fraction
|
||||
* @param text unused
|
||||
* @return the cost of this operation or an error
|
||||
*/
|
||||
CommandCost CmdScheduledDispatchAddNewSchedule(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, uint32 binary_length)
|
||||
{
|
||||
VehicleID veh = GB(p1, 0, 20);
|
||||
|
||||
Vehicle *v = Vehicle::GetIfValid(veh);
|
||||
if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
|
||||
|
||||
CommandCost ret = CheckOwnership(v->owner);
|
||||
if (ret.Failed()) return ret;
|
||||
|
||||
if (v->orders.list == nullptr) return CMD_ERROR;
|
||||
if (v->orders.list->GetScheduledDispatchScheduleCount() >= 4096) return CMD_ERROR;
|
||||
|
||||
int32 date = GB(p3, 0, 32);
|
||||
uint16 full_date_fract = GB(p3, 32, 16);
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
v->orders.list->GetScheduledDispatchScheduleSet().emplace_back();
|
||||
DispatchSchedule &ds = v->orders.list->GetScheduledDispatchScheduleSet().back();
|
||||
ds.SetScheduledDispatchDuration(p2);
|
||||
ds.SetScheduledDispatchStartDate(date, full_date_fract);
|
||||
ds.UpdateScheduledDispatch();
|
||||
SetWindowClassesDirty(WC_VEHICLE_TIMETABLE);
|
||||
SetWindowDirty(WC_SCHDISPATCH_SLOTS, v->index);
|
||||
}
|
||||
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove scheduled dispatch schedule
|
||||
*
|
||||
* @param tile Not used.
|
||||
* @param flags Operation to perform.
|
||||
* @param p1 Vehicle index
|
||||
* @param p2 Not used
|
||||
* @param text unused
|
||||
* @return the cost of this operation or an error
|
||||
*/
|
||||
CommandCost CmdScheduledDispatchRemoveSchedule(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
|
||||
{
|
||||
VehicleID veh = GB(p1, 0, 20);
|
||||
uint schedule_index = GB(p1, 20, 12);
|
||||
|
||||
Vehicle *v = Vehicle::GetIfValid(veh);
|
||||
if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
|
||||
|
||||
CommandCost ret = CheckOwnership(v->owner);
|
||||
if (ret.Failed()) return ret;
|
||||
|
||||
if (v->orders.list == nullptr) return CMD_ERROR;
|
||||
|
||||
if (schedule_index >= v->orders.list->GetScheduledDispatchScheduleCount()) return CMD_ERROR;
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
std::vector<DispatchSchedule> &scheds = v->orders.list->GetScheduledDispatchScheduleSet();
|
||||
scheds.erase(scheds.begin() + schedule_index);
|
||||
for (Order *o = v->GetFirstOrder(); o != nullptr; o = o->next) {
|
||||
int idx = o->GetDispatchScheduleIndex();
|
||||
if (idx == (int)schedule_index) {
|
||||
o->SetDispatchScheduleIndex(-1);
|
||||
} else if (idx > (int)schedule_index) {
|
||||
o->SetDispatchScheduleIndex(idx - 1);
|
||||
}
|
||||
}
|
||||
SetWindowClassesDirty(WC_VEHICLE_TIMETABLE);
|
||||
InvalidateWindowClassesData(WC_SCHDISPATCH_SLOTS, VIWD_MODIFY_ORDERS);
|
||||
}
|
||||
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set scheduled dispatch slot list.
|
||||
* @param dispatch_list The offset time list, must be correctly sorted.
|
||||
*/
|
||||
void OrderList::SetScheduledDispatch(std::vector<uint32> dispatch_list)
|
||||
void DispatchSchedule::SetScheduledDispatch(std::vector<uint32> dispatch_list)
|
||||
{
|
||||
this->scheduled_dispatch = std::move(dispatch_list);
|
||||
assert(std::is_sorted(this->scheduled_dispatch.begin(), this->scheduled_dispatch.end()));
|
||||
@@ -321,7 +428,7 @@ void OrderList::SetScheduledDispatch(std::vector<uint32> dispatch_list)
|
||||
* Add new scheduled dispatch slot at offsets time.
|
||||
* @param offset The offset time to add.
|
||||
*/
|
||||
void OrderList::AddScheduledDispatch(uint32 offset)
|
||||
void DispatchSchedule::AddScheduledDispatch(uint32 offset)
|
||||
{
|
||||
/* Maintain sorted list status */
|
||||
auto insert_position = std::lower_bound(this->scheduled_dispatch.begin(), this->scheduled_dispatch.end(), offset);
|
||||
@@ -336,7 +443,7 @@ void OrderList::AddScheduledDispatch(uint32 offset)
|
||||
* Remove scheduled dispatch slot at offsets time.
|
||||
* @param offset The offset time to remove.
|
||||
*/
|
||||
void OrderList::RemoveScheduledDispatch(uint32 offset)
|
||||
void DispatchSchedule::RemoveScheduledDispatch(uint32 offset)
|
||||
{
|
||||
/* Maintain sorted list status */
|
||||
auto erase_position = std::lower_bound(this->scheduled_dispatch.begin(), this->scheduled_dispatch.end(), offset);
|
||||
@@ -349,7 +456,7 @@ void OrderList::RemoveScheduledDispatch(uint32 offset)
|
||||
/**
|
||||
* Update the scheduled dispatch start time to be the most recent possible.
|
||||
*/
|
||||
void OrderList::UpdateScheduledDispatch()
|
||||
void DispatchSchedule::UpdateScheduledDispatch()
|
||||
{
|
||||
bool update_windows = false;
|
||||
if (this->GetScheduledDispatchStartTick() == 0) {
|
||||
@@ -388,45 +495,3 @@ void OrderList::UpdateScheduledDispatch()
|
||||
}
|
||||
if (update_windows) InvalidateWindowClassesData(WC_SCHDISPATCH_SLOTS, VIWD_MODIFY_ORDERS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the scheduled dispatch schedule.
|
||||
*
|
||||
* This only occurs during initialization of the scheduled dispatch for each shared order. Basically we set
|
||||
* proper default value for start time and duration
|
||||
*/
|
||||
void OrderList::ResetScheduledDispatch()
|
||||
{
|
||||
uint32 windex = this->first_shared->index;
|
||||
|
||||
Date start_date;
|
||||
uint16 start_full_date_fract;
|
||||
uint32 duration;
|
||||
|
||||
if (_settings_time.time_in_minutes) {
|
||||
/* Set to 00:00 of today, and 1 day */
|
||||
|
||||
DateTicksScaled val;
|
||||
val = MINUTES_DATE(MINUTES_DAY(CURRENT_MINUTE), 0, 0);
|
||||
val -= _settings_time.clock_offset;
|
||||
val *= _settings_time.ticks_per_minute;
|
||||
SchdispatchConvertToFullDateFract(val, &start_date, &start_full_date_fract);
|
||||
|
||||
duration = 24 * 60 * _settings_time.ticks_per_minute;
|
||||
} else {
|
||||
/* Set Jan 1st and 365 day */
|
||||
start_date = DAYS_TILL(_cur_year);
|
||||
start_full_date_fract = 0;
|
||||
duration = 365*DAY_TICKS;
|
||||
}
|
||||
|
||||
DoCommandP(0, windex, duration, CMD_SCHEDULED_DISPATCH_SET_DURATION | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE));
|
||||
|
||||
uint32 p1 = 0, p2 = 0;
|
||||
SB(p1, 0, 20, windex);
|
||||
SB(p1, 20, 12, GB(start_full_date_fract, 2, 12));
|
||||
SB(p2, 0, 30, start_date);
|
||||
SB(p2, 30, 2, GB(start_full_date_fract, 0, 2));
|
||||
|
||||
DoCommandP(0, p1, p2, CMD_SCHEDULED_DISPATCH_SET_START_DATE | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE));
|
||||
}
|
||||
|
Reference in New Issue
Block a user