* Stages cargo for unloading. The cargo is sorted so that packets to be * transferred, delivered or kept are in consecutive chunks in the list. At the * same time the designation_counts are updated to reflect the size of those * chunks. * @param accepted If the cargo will be accepted at the station. * @param current_station ID of the station. * @param next_station ID of the station the vehic
| 433 | * return If any cargo will be unloaded. |
| 434 | */ |
| 435 | bool VehicleCargoList::Stage(bool accepted, StationID current_station, std::span<const StationID> next_station, OrderUnloadType unload_type, const GoodsEntry *ge, CargoType cargo, CargoPayment *payment, TileIndex current_tile) |
| 436 | { |
| 437 | this->AssertCountConsistency(); |
| 438 | assert(this->action_counts[MTA_LOAD] == 0); |
| 439 | this->action_counts[MTA_TRANSFER] = this->action_counts[MTA_DELIVER] = this->action_counts[MTA_KEEP] = 0; |
| 440 | Iterator deliver = this->packets.end(); |
| 441 | Iterator it = this->packets.begin(); |
| 442 | uint sum = 0; |
| 443 | |
| 444 | static const FlowStatMap EMPTY_FLOW_STAT_MAP = {}; |
| 445 | const FlowStatMap &flows = ge->HasData() ? ge->GetData().flows : EMPTY_FLOW_STAT_MAP; |
| 446 | |
| 447 | bool force_keep = unload_type == OrderUnloadType::NoUnload; |
| 448 | bool force_unload = unload_type == OrderUnloadType::Unload; |
| 449 | bool force_transfer = unload_type == OrderUnloadType::Transfer || unload_type == OrderUnloadType::Unload; |
| 450 | assert(this->count > 0 || it == this->packets.end()); |
| 451 | while (sum < this->count) { |
| 452 | CargoPacket *cp = *it; |
| 453 | |
| 454 | this->packets.erase(it++); |
| 455 | StationID cargo_next = StationID::Invalid(); |
| 456 | MoveToAction action = MTA_LOAD; |
| 457 | if (force_keep) { |
| 458 | action = MTA_KEEP; |
| 459 | } else if (force_unload && accepted && cp->first_station != current_station) { |
| 460 | action = MTA_DELIVER; |
| 461 | } else if (force_transfer) { |
| 462 | action = MTA_TRANSFER; |
| 463 | /* We cannot send the cargo to any of the possible next hops and |
| 464 | * also not to the current station. */ |
| 465 | FlowStatMap::const_iterator flow_it(flows.find(cp->first_station)); |
| 466 | if (flow_it == flows.end()) { |
| 467 | cargo_next = StationID::Invalid(); |
| 468 | } else { |
| 469 | FlowStat new_shares = flow_it->second; |
| 470 | new_shares.ChangeShare(current_station, INT_MIN); |
| 471 | for (auto station_it = next_station.rbegin(); station_it != next_station.rend(); ++station_it) { |
| 472 | if (new_shares.GetShares()->empty()) break; |
| 473 | new_shares.ChangeShare(*station_it, INT_MIN); |
| 474 | } |
| 475 | if (new_shares.GetShares()->empty()) { |
| 476 | cargo_next = StationID::Invalid(); |
| 477 | } else { |
| 478 | cargo_next = new_shares.GetVia(); |
| 479 | } |
| 480 | } |
| 481 | } else { |
| 482 | /* Rewrite an invalid source station to some random other one to |
| 483 | * avoid keeping the cargo in the vehicle forever. */ |
| 484 | if (cp->first_station == StationID::Invalid() && !flows.empty()) { |
| 485 | cp->first_station = flows.begin()->first; |
| 486 | } |
| 487 | bool restricted = false; |
| 488 | FlowStatMap::const_iterator flow_it(flows.find(cp->first_station)); |
| 489 | if (flow_it == flows.end()) { |
| 490 | cargo_next = StationID::Invalid(); |
| 491 | } else { |
| 492 | cargo_next = flow_it->second.GetViaWithRestricted(restricted); |
no test coverage detected