mirror of
https://github.com/JGRennison/OpenTTD-patches.git
synced 2024-11-11 13:10:45 +00:00
Departures: Enable showing calling times for arrivals
This commit is contained in:
parent
d61e6ee488
commit
27f8cfba22
@ -39,10 +39,17 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
static constexpr Ticks INVALID_DEPARTURE_TICKS = INT32_MIN;
|
||||
|
||||
/* A cache of used departure time for scheduled dispatch in departure time calculation */
|
||||
using ScheduledDispatchCache = btree::btree_map<const DispatchSchedule *, btree::btree_set<StateTicks>>;
|
||||
using ScheduledDispatchVehicleRecords = btree::btree_map<std::pair<uint, VehicleID>, LastDispatchRecord>;
|
||||
|
||||
struct ArrivalHistoryEntry {
|
||||
const Order *order;
|
||||
Ticks offset;
|
||||
};
|
||||
|
||||
/** A scheduled order. */
|
||||
struct OrderDate {
|
||||
const Order *order; ///< The order
|
||||
@ -54,7 +61,7 @@ struct OrderDate {
|
||||
bool arrivals_complete; ///< arrival history is complete
|
||||
Ticks scheduled_waiting_time; ///< Scheduled waiting time if scheduled dispatch is used
|
||||
ScheduledDispatchVehicleRecords dispatch_records; ///< Dispatch records for this vehicle
|
||||
std::vector<const Order *> arrival_history;
|
||||
std::vector<ArrivalHistoryEntry> arrival_history;
|
||||
|
||||
inline Ticks EffectiveWaitingTime() const
|
||||
{
|
||||
@ -420,7 +427,7 @@ static void GetDepartureCandidateOrderDatesFromVehicle(std::vector<OrderDate> &n
|
||||
if (!IsVehicleUsableForDepartures(v, calling_settings)) return;
|
||||
|
||||
ScheduledDispatchVehicleRecords dispatch_records;
|
||||
std::vector<const Order *> arrival_history;
|
||||
std::vector<ArrivalHistoryEntry> arrival_history;
|
||||
|
||||
const StateTicks state_ticks_base = _state_ticks;
|
||||
|
||||
@ -551,7 +558,7 @@ static void GetDepartureCandidateOrderDatesFromVehicle(std::vector<OrderDate> &n
|
||||
break;
|
||||
} else {
|
||||
if (type == D_ARRIVAL) {
|
||||
arrival_history.push_back(order);
|
||||
arrival_history.push_back({ order, start_ticks });
|
||||
}
|
||||
|
||||
/* Go to the next order in the list. */
|
||||
@ -667,13 +674,23 @@ bool DepartureViaTerminusState::HandleCallingPoint(Departure *d, const Order *or
|
||||
|
||||
/**
|
||||
* Process arrival history, returns true if a valid arrival was found.
|
||||
* @param d Departure.
|
||||
* @param arrival_history Arrival history up to but not including the source order, offset field has arbitrary base, and refers to order departure time.
|
||||
* @param arrival_tick Arrival time at the source order, in the same arbitrary base as arrival_history.
|
||||
* @param source Source order detector.
|
||||
* @param calling_settings Calling at settings.
|
||||
* @return true is an arrival was found.
|
||||
*/
|
||||
static bool ProcessArrivalHistory(Departure *d, std::span<const Order *> arrival_history, DepartureOrderDestinationDetector source, DepartureCallingSettings calling_settings)
|
||||
static bool ProcessArrivalHistory(Departure *d, std::span<ArrivalHistoryEntry> arrival_history, Ticks arrival_tick, DepartureOrderDestinationDetector source, DepartureCallingSettings calling_settings)
|
||||
{
|
||||
/* Not that d->scheduled_tick is an arrival time, not a departure time as in arrival_history.
|
||||
* arrival_offset is thus usable to transform either arrival or departure times in the arrival_history timebase to StateTicks. */
|
||||
const StateTicks arrival_offset = d->scheduled_tick - arrival_tick;
|
||||
|
||||
std::vector<std::pair<StationID, uint>> possible_origins;
|
||||
|
||||
for (uint i = 0; i < (uint)arrival_history.size(); i++) {
|
||||
const Order *o = arrival_history[i];
|
||||
const Order *o = arrival_history[i].order;
|
||||
|
||||
if (IsStationIDCallingPointOrder(o)) {
|
||||
if (source.StationMatches(o->GetDestination())) {
|
||||
@ -699,7 +716,7 @@ static bool ProcessArrivalHistory(Departure *d, std::span<const Order *> arrival
|
||||
}
|
||||
}
|
||||
|
||||
const Order *origin = nullptr;
|
||||
ArrivalHistoryEntry origin = { nullptr, 0 };
|
||||
uint origin_arrival_history_index = 0;
|
||||
for (const auto &item : possible_origins) {
|
||||
if (item.first != INVALID_STATION) {
|
||||
@ -709,7 +726,7 @@ static bool ProcessArrivalHistory(Departure *d, std::span<const Order *> arrival
|
||||
}
|
||||
}
|
||||
possible_origins.clear();
|
||||
if (origin != nullptr) {
|
||||
if (origin.order != nullptr) {
|
||||
bool check_no_load_mode = false;
|
||||
if (calling_settings.ShowAllStops() && d->show_as == DSA_NORMAL) {
|
||||
check_no_load_mode = true;
|
||||
@ -721,21 +738,29 @@ static bool ProcessArrivalHistory(Departure *d, std::span<const Order *> arrival
|
||||
check_no_load_mode = false;
|
||||
}
|
||||
};
|
||||
check_order(origin);
|
||||
check_order(origin.order);
|
||||
|
||||
auto make_call_at = [&](const ArrivalHistoryEntry &entry) -> CallAt {
|
||||
if (entry.offset == INVALID_DEPARTURE_TICKS) {
|
||||
return CallAt((StationID)entry.order->GetDestination());
|
||||
} else {
|
||||
return CallAt((StationID)entry.order->GetDestination(), entry.offset + arrival_offset);
|
||||
}
|
||||
};
|
||||
|
||||
for (uint i = origin_arrival_history_index + 1; i < (uint)arrival_history.size(); i++) {
|
||||
const Order *o = arrival_history[i];
|
||||
const Order *o = arrival_history[i].order;
|
||||
if (IsStationIDCallingPointOrder(o)) {
|
||||
check_order(o);
|
||||
if (o->IsType(OT_GOTO_STATION) && (o->GetLoadType() != OLFB_NO_LOAD || calling_settings.ShowAllStops())) {
|
||||
d->calling_at.push_back(CallAt((StationID)o->GetDestination()));
|
||||
d->calling_at.push_back(make_call_at(arrival_history[i]));
|
||||
} else if (o->IsType(OT_GOTO_WAYPOINT) && calling_settings.ShowAllStops()) {
|
||||
d->calling_at.push_back(CallAt((StationID)o->GetDestination()));
|
||||
d->calling_at.push_back(make_call_at(arrival_history[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
d->terminus = CallAt((StationID)origin->GetDestination());
|
||||
d->terminus = make_call_at(origin);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -948,12 +973,12 @@ static DepartureList MakeDepartureListLiveMode(DepartureOrderDestinationDetector
|
||||
|
||||
/* Project back the arrival history if the vehicle is already part way along the route, this stops at conditional jumps or jump targets */
|
||||
if (!lod.arrivals_complete) {
|
||||
const Order *existing_history_start = lod.arrival_history.empty() ? lod.order : lod.arrival_history.front();
|
||||
ArrivalHistoryEntry existing_history_start = lod.arrival_history.empty() ? ArrivalHistoryEntry{ lod.order, lod.expected_tick } : lod.arrival_history.front();
|
||||
OrderID existing_history_start_idx = 0;
|
||||
OrderID arrival_idx = 0;
|
||||
for (OrderID i = 0; i < lod.v->GetNumOrders(); i++) {
|
||||
const Order *o = lod.v->GetOrder(i);
|
||||
if (o == existing_history_start) existing_history_start_idx = i;
|
||||
if (o == existing_history_start.order) existing_history_start_idx = i;
|
||||
if (o == lod.order) arrival_idx = i;
|
||||
}
|
||||
|
||||
@ -979,15 +1004,46 @@ static DepartureList MakeDepartureListLiveMode(DepartureOrderDestinationDetector
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<const Order *> new_history;
|
||||
for (const Order *o = lod.v->GetOrder(predict_history_starting_from); o != existing_history_start; o = lod.v->orders->GetNext(o)) {
|
||||
if (o->GetType() == OT_GOTO_STATION || o->GetType() == OT_IMPLICIT || (o->IsType(OT_GOTO_WAYPOINT) && o->IsWaitTimetabled())) new_history.push_back(o);
|
||||
std::vector<ArrivalHistoryEntry> new_history;
|
||||
Ticks cumul = 0;
|
||||
for (const Order *o = lod.v->GetOrder(predict_history_starting_from); o != existing_history_start.order; o = lod.v->orders->GetNext(o)) {
|
||||
if ((o->GetTravelTime() == 0 && !o->IsTravelTimetabled()) || o->IsScheduledDispatchOrder(true)) {
|
||||
if (!new_history.empty()) new_history.back().offset = INVALID_DEPARTURE_TICKS; // Signal to not use times for orders before this in the history
|
||||
}
|
||||
|
||||
cumul += o->GetTravelTime() + o->GetWaitTime();
|
||||
|
||||
if (o->GetType() == OT_GOTO_STATION || o->GetType() == OT_IMPLICIT || (o->IsType(OT_GOTO_WAYPOINT) && o->IsWaitTimetabled())) {
|
||||
new_history.push_back({ o, cumul });
|
||||
}
|
||||
}
|
||||
cumul += existing_history_start.order->GetTravelTime();
|
||||
if (existing_history_start.order == lod.order) {
|
||||
cumul += d->EffectiveWaitingTime();
|
||||
} else {
|
||||
cumul += existing_history_start.order->GetWaitTime();
|
||||
}
|
||||
|
||||
/* Iterate in reverse order, to fill in times properly */
|
||||
size_t idx = new_history.size();
|
||||
while (idx > 0) {
|
||||
ArrivalHistoryEntry &entry = new_history[idx - 1];
|
||||
if (entry.offset == INVALID_DEPARTURE_TICKS) break;
|
||||
|
||||
entry.offset = existing_history_start.offset - (cumul - entry.offset);
|
||||
|
||||
idx--;
|
||||
}
|
||||
while (idx > 0) {
|
||||
new_history[idx - 1].offset = INVALID_DEPARTURE_TICKS;
|
||||
idx--;
|
||||
}
|
||||
|
||||
new_history.insert(new_history.end(), lod.arrival_history.begin(), lod.arrival_history.end());
|
||||
lod.arrival_history = std::move(new_history);
|
||||
}
|
||||
|
||||
if (ProcessArrivalHistory(d, lod.arrival_history, source, calling_settings)) {
|
||||
if (ProcessArrivalHistory(d, lod.arrival_history, lod.expected_tick - d->EffectiveWaitingTime(), source, calling_settings)) {
|
||||
bool duplicate = false;
|
||||
|
||||
if (_settings_client.gui.departure_merge_identical) {
|
||||
@ -1083,7 +1139,7 @@ static DepartureList MakeDepartureListLiveMode(DepartureOrderDestinationDetector
|
||||
break;
|
||||
} else {
|
||||
if (type == D_ARRIVAL) {
|
||||
lod.arrival_history.push_back(order);
|
||||
lod.arrival_history.push_back({ order, lod.expected_tick });
|
||||
}
|
||||
}
|
||||
|
||||
@ -1144,7 +1200,7 @@ struct DepartureListScheduleModeSlotEvaluator {
|
||||
const DepartureOrderDestinationDetector &source;
|
||||
DepartureType type;
|
||||
DepartureCallingSettings calling_settings;
|
||||
std::vector<const Order *> &arrival_history;
|
||||
std::vector<ArrivalHistoryEntry> &arrival_history;
|
||||
|
||||
StateTicks slot{};
|
||||
uint slot_index{};
|
||||
@ -1283,7 +1339,7 @@ void DepartureListScheduleModeSlotEvaluator::EvaluateFromSourceOrder(const Order
|
||||
} else {
|
||||
/* Computing arrivals: */
|
||||
|
||||
if (ProcessArrivalHistory(&d, this->arrival_history, this->source, this->calling_settings)) {
|
||||
if (ProcessArrivalHistory(&d, this->arrival_history, (departure_tick - this->slot).AsTicks(), this->source, this->calling_settings)) {
|
||||
this->result.push_back(std::make_unique<Departure>(std::move(d)));
|
||||
}
|
||||
}
|
||||
@ -1307,7 +1363,7 @@ void DepartureListScheduleModeSlotEvaluator::EvaluateSlotIndex(uint slot_index)
|
||||
return;
|
||||
}
|
||||
if (type == D_ARRIVAL) {
|
||||
this->arrival_history.push_back(this->start_order);
|
||||
this->arrival_history.push_back({ this->start_order, (departure_tick - this->slot).AsTicks() });
|
||||
}
|
||||
|
||||
const Order *order = this->v->orders->GetNext(this->start_order);
|
||||
@ -1373,7 +1429,7 @@ void DepartureListScheduleModeSlotEvaluator::EvaluateSlotIndex(uint slot_index)
|
||||
}
|
||||
|
||||
if (type == D_ARRIVAL) {
|
||||
this->arrival_history.push_back(order);
|
||||
this->arrival_history.push_back({ order, (departure_tick - this->slot).AsTicks() });
|
||||
}
|
||||
|
||||
order = this->v->orders->GetNext(order);
|
||||
@ -1434,7 +1490,7 @@ static DepartureList MakeDepartureListScheduleMode(DepartureOrderDestinationDete
|
||||
const Ticks tick_duration = (end_tick - start_tick).AsTicks();
|
||||
|
||||
std::vector<std::unique_ptr<Departure>> result;
|
||||
std::vector<const Order *> arrival_history;
|
||||
std::vector<ArrivalHistoryEntry> arrival_history;
|
||||
|
||||
for (const Vehicle *veh : vehicles) {
|
||||
if (!HasBit(veh->vehicle_flags, VF_SCHEDULED_DISPATCH)) continue;
|
||||
|
@ -582,8 +582,6 @@ public:
|
||||
if (this->source_type == DST_STATION) {
|
||||
_settings_client.gui.departure_default_mode = this->mode;
|
||||
}
|
||||
this->SetWidgetDisabledState(WID_DB_SHOW_TIMES, this->mode == DM_ARRIVALS || !_settings_time.time_in_minutes);
|
||||
this->SetWidgetDirty(WID_DB_SHOW_TIMES);
|
||||
this->SetWidgetDirty(widget);
|
||||
break;
|
||||
}
|
||||
@ -716,7 +714,7 @@ public:
|
||||
this->show_arrival_times = false;
|
||||
this->RaiseWidget(WID_DB_SHOW_TIMES);
|
||||
}
|
||||
this->SetWidgetDisabledState(WID_DB_SHOW_TIMES, this->mode == DM_ARRIVALS || !_settings_time.time_in_minutes);
|
||||
this->SetWidgetDisabledState(WID_DB_SHOW_TIMES, !_settings_time.time_in_minutes);
|
||||
this->SetupValues();
|
||||
this->ReInit();
|
||||
if (_pause_mode != PM_UNPAUSED) this->OnGameTick();
|
||||
@ -810,7 +808,7 @@ uint DeparturesWindow::GetMinWidth() const
|
||||
/* Time */
|
||||
result = (this->mode == DM_COMBINED) ? cached_date_combined_width : cached_date_width;
|
||||
|
||||
if (this->show_arrival_times && _settings_time.time_in_minutes && this->mode != DM_ARRIVALS) {
|
||||
if (this->show_arrival_times && _settings_time.time_in_minutes) {
|
||||
result += PadWidth(cached_date_width);
|
||||
}
|
||||
|
||||
@ -883,7 +881,7 @@ void DeparturesWindow::DrawDeparturesListItems(const Rect &r) const
|
||||
int time_width = (this->mode == DM_COMBINED) ? cached_date_combined_width : cached_date_width;
|
||||
|
||||
int arrival_time_width = 0;
|
||||
if (this->show_arrival_times && _settings_time.time_in_minutes && this->mode != DM_ARRIVALS) {
|
||||
if (this->show_arrival_times && _settings_time.time_in_minutes) {
|
||||
arrival_time_width = cached_date_width;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user