Initial LinkRefresher support for cargo-specific links.

This commit is contained in:
Jonathan G Rennison
2016-09-04 16:49:27 +01:00
parent a670966acf
commit 3507b51d9e
8 changed files with 188 additions and 94 deletions

View File

@@ -380,14 +380,17 @@ Order *OrderList::GetOrderAt(int index) const
* or refit at a depot or evaluate a non-trivial condition.
* @param next The order to start looking at.
* @param hops The number of orders we have already looked at.
* @param cargo_mask The bit set of cargoes that the we are looking at, this may be reduced to indicate the set of cargoes that the result is valid for.
* @return Either of
* \li a station order
* \li a refitting depot order
* \li a non-trivial conditional order
* \li NULL if the vehicle won't stop anymore.
*/
const Order *OrderList::GetNextDecisionNode(const Order *next, uint hops) const
const Order *OrderList::GetNextDecisionNode(const Order *next, uint hops, uint32 &cargo_mask) const
{
assert(cargo_mask != 0);
if (hops > this->GetNumOrders() || next == NULL) return NULL;
if (next->IsType(OT_CONDITIONAL)) {
@@ -397,7 +400,7 @@ const Order *OrderList::GetNextDecisionNode(const Order *next, uint hops) const
* the same as regular order progression. */
return this->GetNextDecisionNode(
this->GetOrderAt(next->GetConditionSkipToOrder()),
hops + 1);
hops + 1, cargo_mask);
}
if (next->IsType(OT_GOTO_DEPOT)) {
@@ -405,8 +408,30 @@ const Order *OrderList::GetNextDecisionNode(const Order *next, uint hops) const
if (next->IsRefit()) return next;
}
if (!next->CanLoadOrUnload()) {
return this->GetNextDecisionNode(this->GetNext(next), hops + 1);
bool can_load_or_unload = false;
if ((next->IsType(OT_GOTO_STATION) || next->IsType(OT_IMPLICIT)) &&
(next->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) == 0) {
if (next->GetUnloadType() == OUFB_CARGO_TYPE_UNLOAD || next->GetLoadType() == OLFB_CARGO_TYPE_LOAD) {
/* This is a cargo-specific load/unload order.
* If the first cargo is both a no-load and no-unload order, skip it.
* Drop cargoes which don't match the first one. */
CargoID first_cargo_id = FindFirstBit(cargo_mask);
can_load_or_unload = ((next->GetCargoLoadType(first_cargo_id) & OLFB_NO_LOAD) == 0 || (next->GetCargoUnloadType(first_cargo_id) & OUFB_NO_UNLOAD) == 0);
uint32 other_cargo_mask = cargo_mask;
ClrBit(other_cargo_mask, first_cargo_id);
CargoID cargo;
FOR_EACH_SET_BIT(cargo, other_cargo_mask) {
if (can_load_or_unload != ((next->GetCargoLoadType(cargo) & OLFB_NO_LOAD) == 0 || (next->GetCargoUnloadType(cargo) & OUFB_NO_UNLOAD) == 0)) {
ClrBit(cargo_mask, cargo);
}
}
} else if ((next->GetLoadType() & OLFB_NO_LOAD) == 0 || (next->GetUnloadType() & OUFB_NO_UNLOAD) == 0) {
can_load_or_unload = true;
}
}
if (!can_load_or_unload) {
return this->GetNextDecisionNode(this->GetNext(next), hops + 1, cargo_mask);
}
return next;
@@ -425,9 +450,6 @@ const Order *OrderList::GetNextDecisionNode(const Order *next, uint hops) const
CargoMaskedStationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, uint32 cargo_mask, const Order *first, uint hops) const
{
assert(cargo_mask != 0);
CargoID first_cargo_id = FindFirstBit(cargo_mask);
uint32 other_cargo_mask = cargo_mask;
ClrBit(other_cargo_mask, first_cargo_id);
const Order *next = first;
if (first == NULL) {
@@ -445,15 +467,15 @@ CargoMaskedStationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, ui
}
do {
next = this->GetNextDecisionNode(next, ++hops);
next = this->GetNextDecisionNode(next, ++hops, cargo_mask);
/* Resolve possibly nested conditionals by estimation. */
while (next != NULL && next->IsType(OT_CONDITIONAL)) {
/* We return both options of conditional orders. */
const Order *skip_to = this->GetNextDecisionNode(
this->GetOrderAt(next->GetConditionSkipToOrder()), hops);
this->GetOrderAt(next->GetConditionSkipToOrder()), hops, cargo_mask);
const Order *advance = this->GetNextDecisionNode(
this->GetNext(next), hops);
this->GetNext(next), hops, cargo_mask);
if (advance == NULL || advance == first || skip_to == advance) {
next = (skip_to == first) ? NULL : skip_to;
} else if (skip_to == NULL || skip_to == first) {
@@ -471,36 +493,23 @@ CargoMaskedStationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, ui
if (next == NULL) return CargoMaskedStationIDStack(cargo_mask, INVALID_STATION);
if ((next->IsType(OT_GOTO_STATION) || next->IsType(OT_IMPLICIT)) && (next->GetUnloadType() == OUFB_CARGO_TYPE_UNLOAD || next->GetLoadType() == OLFB_CARGO_TYPE_LOAD)) {
/* This is a cargo-specific load/unload order.
* If the first cargo is both a no-load and no-unload order, skip it.
* Drop cargoes which don't match the first one. */
bool should_drop = next->GetCargoLoadType(first_cargo_id) & OLFB_NO_LOAD && next->GetCargoUnloadType(first_cargo_id) & OUFB_NO_UNLOAD;
CargoID cargo;
FOR_EACH_SET_BIT(cargo, other_cargo_mask) {
if (should_drop != (next->GetCargoLoadType(cargo) & OLFB_NO_LOAD && next->GetCargoUnloadType(cargo) & OUFB_NO_UNLOAD)) {
ClrBit(cargo_mask, cargo);
}
}
other_cargo_mask &= cargo_mask;
if (should_drop) continue;
}
/* Don't return a next stop if the vehicle has to unload everything. */
if ((next->IsType(OT_GOTO_STATION) || next->IsType(OT_IMPLICIT)) &&
next->GetDestination() == v->last_station_visited) {
CargoID first_cargo_id = FindFirstBit(cargo_mask);
bool invalid = ((next->GetCargoUnloadType(first_cargo_id) & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0);
if (next->GetUnloadType() == OUFB_CARGO_TYPE_UNLOAD) {
/* This is a cargo-specific load/unload order.
* Don't return a next stop if first cargo has transfer or unload set.
* Drop cargoes which don't match the first one. */
uint32 other_cargo_mask = cargo_mask;
ClrBit(other_cargo_mask, first_cargo_id);
CargoID cargo;
FOR_EACH_SET_BIT(cargo, other_cargo_mask) {
if (invalid != ((next->GetCargoUnloadType(cargo) & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0)) {
ClrBit(cargo_mask, cargo);
}
}
other_cargo_mask &= cargo_mask;
}
if (invalid) return CargoMaskedStationIDStack(cargo_mask, INVALID_STATION);
}
@@ -2339,22 +2348,14 @@ bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
!(this->GetNonStopType() & (is_dest_station ? ONSF_NO_STOP_AT_DESTINATION_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS));
}
bool Order::CanLoadOrUnload() const
{
return (this->IsType(OT_GOTO_STATION) || this->IsType(OT_IMPLICIT)) &&
(this->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) == 0 &&
((this->GetLoadType() & OLFB_NO_LOAD) == 0 ||
(this->GetUnloadType() & OUFB_NO_UNLOAD) == 0);
}
/**
* A vehicle can leave the current station with cargo if:
* 1. it can load cargo here OR
* 2a. it could leave the last station with cargo AND
* 2b. it doesn't have to unload all cargo here.
*/
bool Order::CanLeaveWithCargo(bool has_cargo) const
bool Order::CanLeaveWithCargo(bool has_cargo, CargoID cargo) const
{
return (this->GetLoadType() & OLFB_NO_LOAD) == 0 || (has_cargo &&
(this->GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == 0);
return (this->GetCargoLoadType(cargo) & OLFB_NO_LOAD) == 0 || (has_cargo &&
(this->GetCargoUnloadType(cargo) & (OUFB_UNLOAD | OUFB_TRANSFER)) == 0);
}