|
@@ -20,6 +20,7 @@
|
|
|
#include "vehicle_func.h"
|
|
|
#include "depot_base.h"
|
|
|
#include "core/pool_func.hpp"
|
|
|
#include "core/random_func.hpp"
|
|
|
#include "aircraft.h"
|
|
|
#include "roadveh.h"
|
|
|
#include "station_base.h"
|
|
@@ -350,6 +351,87 @@ Order *OrderList::GetOrderAt(int index)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Get the next order which will make the given vehicle stop at a station
|
|
|
* or refit at a depot if its state doesn't change.
|
|
|
* @param v The vehicle in question.
|
|
|
* @param next The order to start looking at.
|
|
|
* @param hops The number of orders we have already looked at.
|
|
|
* @return Either an order or NULL if the vehicle won't stop anymore.
|
|
|
*/
|
|
|
const Order *OrderList::GetNextStoppingOrder(const Vehicle *v, const Order *next, uint hops) const
|
|
|
{
|
|
|
if (hops > this->GetNumOrders() || next == NULL) return NULL;
|
|
|
|
|
|
if (next->IsType(OT_CONDITIONAL)) {
|
|
|
if (next->GetConditionVariable() == OCV_LOAD_PERCENTAGE) {
|
|
|
/* If the condition is based on load percentage we can't
|
|
|
* tell what it will do. So we choose randomly. */
|
|
|
const Order *skip_to = this->GetNextStoppingOrder(v,
|
|
|
this->GetOrderAt(next->GetConditionSkipToOrder()),
|
|
|
hops + 1);
|
|
|
const Order *advance = this->GetNextStoppingOrder(v,
|
|
|
this->GetNext(next), hops + 1);
|
|
|
if (advance == NULL) return skip_to;
|
|
|
if (skip_to == NULL) return advance;
|
|
|
return RandomRange(2) == 0 ? skip_to : advance;
|
|
|
}
|
|
|
/* Otherwise we're optimistic and expect that the
|
|
|
* condition value won't change until it's evaluated. */
|
|
|
VehicleOrderID skip_to = ProcessConditionalOrder(next, v);
|
|
|
if (skip_to != INVALID_VEH_ORDER_ID) {
|
|
|
return this->GetNextStoppingOrder(v, this->GetOrderAt(skip_to),
|
|
|
hops + 1);
|
|
|
}
|
|
|
return this->GetNextStoppingOrder(v, this->GetNext(next), hops + 1);
|
|
|
}
|
|
|
|
|
|
if (next->IsType(OT_GOTO_DEPOT)) {
|
|
|
if (next->GetDepotActionType() == ODATFB_HALT) return NULL;
|
|
|
if (next->IsRefit()) return next;
|
|
|
}
|
|
|
|
|
|
if (!next->CanLoadOrUnload()) {
|
|
|
return this->GetNextStoppingOrder(v, this->GetNext(next), hops + 1);
|
|
|
}
|
|
|
|
|
|
return next;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Recursively determine the next deterministic station to stop at.
|
|
|
* @param v The vehicle we're looking at.
|
|
|
* @return Next stoppping station or INVALID_STATION.
|
|
|
*/
|
|
|
StationID OrderList::GetNextStoppingStation(const Vehicle *v) const
|
|
|
{
|
|
|
|
|
|
const Order *next = this->GetOrderAt(v->cur_implicit_order_index);
|
|
|
if (next == NULL) {
|
|
|
next = this->GetFirstOrder();
|
|
|
if (next == NULL) return INVALID_STATION;
|
|
|
} else {
|
|
|
/* GetNext never returns NULL if there is a valid station in the list.
|
|
|
* As the given "next" is already valid and a station in the list, we
|
|
|
* don't have to check for NULL here.
|
|
|
*/
|
|
|
next = this->GetNext(next);
|
|
|
assert(next != NULL);
|
|
|
}
|
|
|
|
|
|
uint hops = 0;
|
|
|
do {
|
|
|
next = this->GetNextStoppingOrder(v, next, ++hops);
|
|
|
/* Don't return a next stop if the vehicle has to unload everything. */
|
|
|
if (next == NULL || (next->GetDestination() == v->last_station_visited &&
|
|
|
(next->GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) == 0)) {
|
|
|
return INVALID_STATION;
|
|
|
}
|
|
|
} while (next->IsType(OT_GOTO_DEPOT) || next->GetDestination() == v->last_station_visited);
|
|
|
|
|
|
return next->GetDestination();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Insert a new order into the order chain.
|
|
|
* @param new_order is the order to insert into the chain.
|
|
|
* @param index is the position where the order is supposed to be inserted.
|
|
@@ -1044,11 +1126,11 @@ CommandCost CmdSkipToOrder(TileIndex til
|
|
|
if (ret.Failed()) return ret;
|
|
|
|
|
|
if (flags & DC_EXEC) {
|
|
|
if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
|
|
|
|
|
|
v->cur_implicit_order_index = v->cur_real_order_index = sel_ord;
|
|
|
v->UpdateRealOrderIndex();
|
|
|
|
|
|
if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
|
|
|
|
|
|
InvalidateVehicleOrder(v, VIWD_MODIFY_ORDERS);
|
|
|
}
|
|
|
|
|
@@ -2122,3 +2204,23 @@ bool Order::ShouldStopAtStation(const Ve
|
|
|
/* Finally do stop when there is no non-stop flag set for this type of station. */
|
|
|
!(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
|
|
|
{
|
|
|
return (this->GetLoadType() & OLFB_NO_LOAD) == 0 || (has_cargo &&
|
|
|
(this->GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == 0);
|
|
|
}
|