diff --git a/src/cargopacket.cpp b/src/cargopacket.cpp --- a/src/cargopacket.cpp +++ b/src/cargopacket.cpp @@ -544,17 +544,54 @@ void VehicleCargoList::InvalidateCache() /** * Moves some cargo from one designation to another. You can only move - * between adjacent designations. E.g. you can keep cargo that was - * previously reserved (MTA_LOAD) or you can mark cargo to be transferred - * that was previously marked as to be delivered, but you can't reserve - * cargo that's marked as to be delivered. + * between adjacent designations. E.g. you can keep cargo that was previously + * reserved (MTA_LOAD), but you can't reserve cargo that's marked as to be + * delivered. Furthermore, as this method doesn't change the actual packets, + * you cannot move cargo from or to MTA_TRANSFER. You need a specialized + * template method for that. + * @tparam from Previous designation of cargo. + * @tparam to New designation of cargo. + * @param max_move Maximum amount of cargo to reassign. + * @return Amount of cargo actually reassigned. */ -uint VehicleCargoList::Reassign(uint max_move, MoveToAction from, MoveToAction to) +template +uint VehicleCargoList::Reassign(uint max_move, TileOrStationID) { - max_move = min(this->action_counts[from], max_move); - assert(Delta((int)from, (int)to) == 1); - this->action_counts[from] -= max_move; - this->action_counts[to] += max_move; + assert_compile(Tfrom != MTA_TRANSFER && Tto != MTA_TRANSFER); + assert_compile(Tfrom - Tto == 1 || Tto - Tfrom == 1); + max_move = min(this->action_counts[Tfrom], max_move); + this->action_counts[Tfrom] -= max_move; + this->action_counts[Tto] += max_move; + return max_move; +} + +/** + * Reassign cargo from MTA_DELIVER to MTA_TRANSFER and take care of the next + * station the cargo wants to visit. + * @param max_move Maximum amount of cargo to reassign. + * @param next_station Station to record as next hop in the reassigned packets. + * @return Amount of cargo actually reassigned. + */ +template<> +uint VehicleCargoList::Reassign(uint max_move, TileOrStationID next_station) +{ + max_move = min(this->action_counts[MTA_DELIVER], max_move); + + uint sum = 0; + for (Iterator it(this->packets.begin()); sum < this->action_counts[MTA_TRANSFER] + max_move;) { + CargoPacket *cp = *it++; + sum += cp->Count(); + if (sum <= this->action_counts[MTA_TRANSFER]) continue; + if (sum > this->action_counts[MTA_TRANSFER] + max_move) { + CargoPacket *cp_split = cp->Split(sum - this->action_counts[MTA_TRANSFER] + max_move); + sum -= cp_split->Count(); + this->packets.insert(it, cp_split); + } + cp->next_station = next_station; + } + + this->action_counts[MTA_DELIVER] -= max_move; + this->action_counts[MTA_TRANSFER] += max_move; return max_move; } @@ -806,7 +843,7 @@ uint StationCargoList::Load(uint max_mov uint move = min(dest->ActionCount(VehicleCargoList::MTA_LOAD), max_move); if (move > 0) { this->reserved_count -= move; - dest->Reassign(move, VehicleCargoList::MTA_LOAD, VehicleCargoList::MTA_KEEP); + dest->Reassign(move); return move; } else { return this->ShiftCargo(CargoLoad(this, dest, max_move, load_place), next_station, true); @@ -831,3 +868,5 @@ uint StationCargoList::Reroute(uint max_ */ template class CargoList; template class CargoList; +template uint VehicleCargoList::Reassign(uint max_move, TileOrStationID); +template uint VehicleCargoList::Reassign(uint max_move, TileOrStationID next_station); diff --git a/src/cargopacket.h b/src/cargopacket.h --- a/src/cargopacket.h +++ b/src/cargopacket.h @@ -429,7 +429,8 @@ public: * amount of cargo to be moved. Second parameter is destination (if * applicable), return value is amount of cargo actually moved. */ - uint Reassign(uint max_move, MoveToAction from, MoveToAction to); + template + uint Reassign(uint max_move, TileOrStationID update = INVALID_TILE); uint Return(uint max_move, StationCargoList *dest, StationID next_station); uint Unload(uint max_move, StationCargoList *dest, CargoPayment *payment); uint Shift(uint max_move, VehicleCargoList *dest); diff --git a/src/economy.cpp b/src/economy.cpp --- a/src/economy.cpp +++ b/src/economy.cpp @@ -1509,8 +1509,8 @@ static void LoadUnloadVehicle(Vehicle *f /* The station does not accept our goods anymore. */ if (front->current_order.GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) { /* Transfer instead of delivering. */ - v->cargo.Reassign(v->cargo.ActionCount(VehicleCargoList::MTA_DELIVER), - VehicleCargoList::MTA_DELIVER, VehicleCargoList::MTA_TRANSFER); + v->cargo.Reassign( + v->cargo.ActionCount(VehicleCargoList::MTA_DELIVER), INVALID_STATION); } else { uint new_remaining = v->cargo.RemainingCount() + v->cargo.ActionCount(VehicleCargoList::MTA_DELIVER); if (v->cargo_cap < new_remaining) { @@ -1519,8 +1519,8 @@ static void LoadUnloadVehicle(Vehicle *f } /* Keep instead of delivering. This may lead to no cargo being unloaded, so ...*/ - v->cargo.Reassign(v->cargo.ActionCount(VehicleCargoList::MTA_DELIVER), - VehicleCargoList::MTA_DELIVER, VehicleCargoList::MTA_KEEP); + v->cargo.Reassign( + v->cargo.ActionCount(VehicleCargoList::MTA_DELIVER)); /* ... say we unloaded something, otherwise we'll think we didn't unload * something and we didn't load something, so we must be finished