/** * 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 vehicle will go to next. * @param order_flags OrderUnloadFlags that will apply to the unload operation. * @param ge GoodsEntry for getting the flows. * @param payment Payment object for registering transfers. * return If any cargo will be unloaded. */ bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationID next_station, uint8 order_flags, const GoodsEntry *ge, CargoPayment *payment) { this->AssertCountConsistency(); assert(this->action_counts[MTA_LOAD] == 0); this->action_counts[MTA_TRANSFER] = this->action_counts[MTA_DELIVER] = this->action_counts[MTA_KEEP] = 0; Iterator deliver = this->packets.end(); Iterator it = this->packets.begin(); uint sum = 0; bool force_keep = (order_flags & OUFB_NO_UNLOAD) != 0; bool force_unload = (order_flags & OUFB_UNLOAD) != 0; bool force_transfer = (order_flags & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0; assert(this->count > 0 || it == this->packets.end()); while (sum < this->count) { CargoPacket *cp = *it; this->packets.erase(it++); StationID cargo_next = INVALID_STATION; MoveToAction action = MTA_LOAD; if (force_keep) { action = MTA_KEEP; } else if (force_unload && accepted && cp->source != current_station) { action = MTA_DELIVER; } else if (force_transfer) { action = MTA_TRANSFER; cargo_next = ge->GetVia(cp->source, current_station, next_station); assert((cargo_next != next_station || cargo_next == INVALID_STATION) && cargo_next != current_station); } else { /* Rewrite an invalid source station to some random other one to * avoid keeping the cargo in the vehicle forever. */ if (cp->source == INVALID_STATION && !ge->flows.empty()) { cp->source = ge->flows.begin()->first; } cargo_next = ge->GetVia(cp->source); if (cargo_next == INVALID_STATION) { action = (accepted && cp->source != current_station) ? MTA_DELIVER : MTA_KEEP; } else if (cargo_next == current_station) { action = MTA_DELIVER; } else if (cargo_next == next_station) { action = MTA_KEEP; } else { action = MTA_TRANSFER; } } Money share; switch (action) { case MTA_KEEP: this->packets.push_back(cp); if (deliver == this->packets.end()) --deliver; break; case MTA_DELIVER: this->packets.insert(deliver, cp); break; case MTA_TRANSFER: this->packets.push_front(cp); /* Add feeder share here to allow reusing field for next station. */ share = payment->PayTransfer(cp, cp->count); cp->AddFeederShare(share); this->feeder_share += share; cp->next_station = cargo_next; break; default: NOT_REACHED(); } this->action_counts[action] += cp->count; sum += cp->count; } this->AssertCountConsistency(); return this->action_counts[MTA_DELIVER] > 0 || this->action_counts[MTA_TRANSFER] > 0; }
/** * 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 vehicle will go to next. * @param order_flags OrderUnloadFlags that will apply to the unload operation. * @param ge GoodsEntry for getting the flows. * @param payment Payment object for registering transfers. * return If any cargo will be unloaded. */ bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationIDStack next_station, uint8 order_flags, const GoodsEntry *ge, CargoPayment *payment) { this->AssertCountConsistency(); assert(this->action_counts[MTA_LOAD] == 0); this->action_counts[MTA_TRANSFER] = this->action_counts[MTA_DELIVER] = this->action_counts[MTA_KEEP] = 0; Iterator deliver = this->packets.end(); Iterator it = this->packets.begin(); uint sum = 0; bool force_keep = (order_flags & OUFB_NO_UNLOAD) != 0; bool force_unload = (order_flags & OUFB_UNLOAD) != 0; bool force_transfer = (order_flags & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0; assert(this->count > 0 || it == this->packets.end()); while (sum < this->count) { CargoPacket *cp = *it; this->packets.erase(it++); StationID cargo_next = INVALID_STATION; MoveToAction action = MTA_LOAD; if (force_keep) { action = MTA_KEEP; } else if (force_unload && accepted && cp->source != current_station) { action = MTA_DELIVER; } else if (force_transfer) { action = MTA_TRANSFER; /* We cannot send the cargo to any of the possible next hops and * also not to the current station. */ FlowStatMap::const_iterator flow_it(ge->flows.find(cp->source)); if (flow_it == ge->flows.end()) { cargo_next = INVALID_STATION; } else { FlowStat new_shares = flow_it->second; new_shares.ChangeShare(current_station, INT_MIN); StationIDStack excluded = next_station; while (!excluded.IsEmpty() && !new_shares.GetShares()->empty()) { new_shares.ChangeShare(excluded.Pop(), INT_MIN); } if (new_shares.GetShares()->empty()) { cargo_next = INVALID_STATION; } else { cargo_next = new_shares.GetVia(); } } } else { /* Rewrite an invalid source station to some random other one to * avoid keeping the cargo in the vehicle forever. */ if (cp->source == INVALID_STATION && !ge->flows.empty()) { cp->source = ge->flows.begin()->first; } bool restricted = false; FlowStatMap::const_iterator flow_it(ge->flows.find(cp->source)); if (flow_it == ge->flows.end()) { cargo_next = INVALID_STATION; } else { cargo_next = flow_it->second.GetViaWithRestricted(restricted); } action = VehicleCargoList::ChooseAction(cp, cargo_next, current_station, accepted, next_station); if (restricted && action == MTA_TRANSFER) { /* If the flow is restricted we can't transfer to it. Choose an * unrestricted one instead. */ cargo_next = flow_it->second.GetVia(); action = VehicleCargoList::ChooseAction(cp, cargo_next, current_station, accepted, next_station); } } Money share; switch (action) { case MTA_KEEP: this->packets.push_back(cp); if (deliver == this->packets.end()) --deliver; break; case MTA_DELIVER: this->packets.insert(deliver, cp); break; case MTA_TRANSFER: this->packets.push_front(cp); /* Add feeder share here to allow reusing field for next station. */ share = payment->PayTransfer(cp, cp->count); cp->AddFeederShare(share); this->feeder_share += share; cp->next_station = cargo_next; break; default: NOT_REACHED(); } this->action_counts[action] += cp->count; sum += cp->count; } this->AssertCountConsistency(); return this->action_counts[MTA_DELIVER] > 0 || this->action_counts[MTA_TRANSFER] > 0; }