* Recursively determine the next deterministic station to stop at. * @param v The vehicle we're looking at. * @param first Order to start searching at or INVALID_VEH_ORDER_ID to start at cur_implicit_order_index + 1. * @param hops Number of orders we have already looked at. * @return Next stopping station or StationID::Invalid(). * @pre The vehicle is currently loading and v->last_station_vis
| 361 | * @note This function may draw a random number. Don't use it from the GUI. |
| 362 | */ |
| 363 | void OrderList::GetNextStoppingStation(std::vector<StationID> &next_station, const Vehicle *v, VehicleOrderID first, uint hops) const |
| 364 | { |
| 365 | VehicleOrderID next = first; |
| 366 | if (first == INVALID_VEH_ORDER_ID) { |
| 367 | next = v->cur_implicit_order_index; |
| 368 | if (next >= this->GetNumOrders()) { |
| 369 | next = this->GetFirstOrder(); |
| 370 | if (next == INVALID_VEH_ORDER_ID) return; |
| 371 | } else { |
| 372 | /* GetNext never returns INVALID_VEH_ORDER_ID if there is a valid station in the list. |
| 373 | * As the given "next" is already valid and a station in the list, we |
| 374 | * don't have to check for INVALID_VEH_ORDER_ID here. */ |
| 375 | next = this->GetNext(next); |
| 376 | assert(next != INVALID_VEH_ORDER_ID); |
| 377 | } |
| 378 | } |
| 379 | |
| 380 | auto orders = v->Orders(); |
| 381 | do { |
| 382 | next = this->GetNextDecisionNode(next, ++hops); |
| 383 | |
| 384 | /* Resolve possibly nested conditionals by estimation. */ |
| 385 | while (next != INVALID_VEH_ORDER_ID && orders[next].IsType(OT_CONDITIONAL)) { |
| 386 | /* We return both options of conditional orders. */ |
| 387 | VehicleOrderID skip_to = this->GetNextDecisionNode(orders[next].GetConditionSkipToOrder(), hops); |
| 388 | VehicleOrderID advance = this->GetNextDecisionNode(this->GetNext(next), hops); |
| 389 | if (advance == INVALID_VEH_ORDER_ID || advance == first || skip_to == advance) { |
| 390 | next = (skip_to == first) ? INVALID_VEH_ORDER_ID : skip_to; |
| 391 | } else if (skip_to == INVALID_VEH_ORDER_ID || skip_to == first) { |
| 392 | next = (advance == first) ? INVALID_VEH_ORDER_ID : advance; |
| 393 | } else { |
| 394 | this->GetNextStoppingStation(next_station, v, skip_to, hops); |
| 395 | this->GetNextStoppingStation(next_station, v, advance, hops); |
| 396 | return; |
| 397 | } |
| 398 | ++hops; |
| 399 | } |
| 400 | |
| 401 | /* Don't return a next stop if the vehicle has to unload everything. */ |
| 402 | if (next == INVALID_VEH_ORDER_ID || ((orders[next].IsType(OT_GOTO_STATION) || orders[next].IsType(OT_IMPLICIT)) && |
| 403 | orders[next].GetDestination() == v->last_station_visited && |
| 404 | (orders[next].GetUnloadType() == OrderUnloadType::Transfer || orders[next].GetUnloadType() == OrderUnloadType::Unload))) { |
| 405 | return; |
| 406 | } |
| 407 | } while (orders[next].IsType(OT_GOTO_DEPOT) || orders[next].GetDestination() == v->last_station_visited); |
| 408 | |
| 409 | next_station.push_back(orders[next].GetDestination().ToStationID()); |
| 410 | } |
| 411 | |
| 412 | /** |
| 413 | * Insert a new order into the order chain. |
no test coverage detected