diff --git a/src/economy.cpp b/src/economy.cpp index 44dceb1f2d..37a89b3f25 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -1293,53 +1293,6 @@ static uint GetLoadAmount(Vehicle *v) return load_amount; } -/** - * Reserves cargo if the full load order and improved_load is set or if the - * current order allows autorefit. - * @param st Station where the consist is loading at the moment. - * @param u Front of the loading vehicle consist. - * @param consist_capleft If given, save free capacities after reserving there. - * @param next_station Station(s) the vehicle will stop at next. - */ -static void ReserveConsist(Station *st, Vehicle *u, CargoArray *consist_capleft, StationIDStack next_station) -{ - Vehicle *next_cargo = u; - uint32 seen_cargos = 0; - - while (next_cargo != NULL) { - if (next_cargo->cargo_cap == 0) { - /* No need to reserve for vehicles without capacity. */ - next_cargo = next_cargo->Next(); - continue; - } - - CargoID current_cargo = next_cargo->cargo_type; - - Vehicle *v = next_cargo; - SetBit(seen_cargos, current_cargo); - next_cargo = NULL; - for (; v != NULL; v = v->Next()) { - if (v->cargo_type != current_cargo) { - /* Save start point for next cargo type. */ - if (next_cargo == NULL && !HasBit(seen_cargos, v->cargo_type)) next_cargo = v; - continue; - } - - assert(v->cargo_cap >= v->cargo.RemainingCount()); - uint cap = v->cargo_cap - v->cargo.RemainingCount(); - - /* Nothing to do if the vehicle is full */ - if (cap > 0) { - cap -= st->goods[v->cargo_type].cargo.Reserve(cap, &v->cargo, st->xy, next_station); - } - - if (consist_capleft != NULL) { - (*consist_capleft)[current_cargo] += cap; - } - } - } -} - /** * Iterate the articulated parts of a vehicle, also considering the special cases of "normal" * aircraft and double headed trains. Apply an action to each vehicle and immediately return false @@ -1445,15 +1398,17 @@ struct FinalizeRefitAction CargoArray &consist_capleft; ///< Capacities left in the consist. Station *st; ///< Station to reserve cargo from. StationIDStack &next_station; ///< Next hops to reserve cargo for. + bool do_reserve; ///< If the vehicle should reserve. /** * Create a finalizing action. * @param consist_capleft Capacities left in the consist. * @param st Station to reserve cargo from. * @param next_station Next hops to reserve cargo for. + * @param do_reserve If we should reserve cargo or just add up the capacities. */ - FinalizeRefitAction(CargoArray &consist_capleft, Station *st, StationIDStack &next_station) : - consist_capleft(consist_capleft), st(st), next_station(next_station) {} + FinalizeRefitAction(CargoArray &consist_capleft, Station *st, StationIDStack &next_station, bool do_reserve) : + consist_capleft(consist_capleft), st(st), next_station(next_station), do_reserve(do_reserve) {} /** * Reserve cargo from the station and update the remaining consist capacities with the @@ -1463,8 +1418,10 @@ struct FinalizeRefitAction */ bool operator()(Vehicle *v) { - this->st->goods[v->cargo_type].cargo.Reserve(v->cargo_cap - v->cargo.RemainingCount(), - &v->cargo, st->xy, next_station); + if (this->do_reserve) { + this->st->goods[v->cargo_type].cargo.Reserve(v->cargo_cap - v->cargo.RemainingCount(), + &v->cargo, st->xy, this->next_station); + } this->consist_capleft[v->cargo_type] += v->cargo_cap - v->cargo.RemainingCount(); return true; } @@ -1490,7 +1447,8 @@ static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station /* Remove old capacity from consist capacity and collect refit mask. */ IterateVehicleParts(v_start, PrepareRefitAction(consist_capleft, refit_mask)); - if (new_cid == CT_AUTO_REFIT) { + bool is_auto_refit = new_cid == CT_AUTO_REFIT; + if (is_auto_refit) { /* Get a refittable cargo type with waiting cargo for next_station or INVALID_STATION. */ CargoID cid; new_cid = v_start->cargo_type; @@ -1526,11 +1484,62 @@ static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station } /* Add new capacity to consist capacity and reserve cargo */ - IterateVehicleParts(v_start, FinalizeRefitAction(consist_capleft, st, next_station)); + IterateVehicleParts(v_start, FinalizeRefitAction(consist_capleft, st, next_station, + is_auto_refit || (v->First()->current_order.GetLoadType() & OLFB_FULL_LOAD) != 0)); cur_company.Restore(); } +struct ReserveCargoAction { + Station *st; + StationIDStack *next_station; + + ReserveCargoAction(Station *st, StationIDStack *next_station) : + st(st), next_station(next_station) {} + + bool operator()(Vehicle *v) + { + if (v->cargo_cap > v->cargo.RemainingCount()) { + st->goods[v->cargo_type].cargo.Reserve(v->cargo_cap - v->cargo.RemainingCount(), + &v->cargo, st->xy, *next_station); + } + + return true; + } + +}; + +/** + * Reserves cargo if the full load order and improved_load is set or if the + * current order allows autorefit. + * @param st Station where the consist is loading at the moment. + * @param u Front of the loading vehicle consist. + * @param consist_capleft If given, save free capacities after reserving there. + * @param next_station Station(s) the vehicle will stop at next. + */ +static void ReserveConsist(Station *st, Vehicle *u, CargoArray *consist_capleft, StationIDStack *next_station) +{ + /* If there is a cargo payment not all vehicles of the consist have tried to do the refit. + * In that case, only reserve if it's a fixed refit and the equivalent of "articulated chain" + * a vehicle belongs to already has the right cargo. */ + bool must_reserve = !u->current_order.IsRefit() || u->cargo_payment == NULL; + for (Vehicle *v = u; v != NULL; v = v->Next()) { + assert(v->cargo_cap >= v->cargo.RemainingCount()); + + /* Exclude various ways in which the vehicle might not be the head of an equivalent of + * "articulated chain". Also don't do the reservation if the vehicle is going to refit + * to a different cargo and hasn't tried to do so, yet. */ + if (!v->IsArticulatedPart() && + (v->type != VEH_TRAIN || !Train::From(v)->IsRearDualheaded()) && + (v->type != VEH_AIRCRAFT || Aircraft::From(v)->IsNormalAircraft()) && + (must_reserve || u->current_order.GetRefitCargo() == v->cargo_type)) { + IterateVehicleParts(v, ReserveCargoAction(st, next_station)); + } + if (consist_capleft == NULL || v->cargo_cap == 0) continue; + (*consist_capleft)[v->cargo_type] += v->cargo_cap - v->cargo.RemainingCount(); + } +} + /** * Update the vehicle's load_unload_ticks, the time it will wait until it tries to load or unload * again. Adjust for overhang of trains and set it at least to 1. @@ -1566,11 +1575,11 @@ static void LoadUnloadVehicle(Vehicle *front) StationIDStack next_station = front->GetNextStoppingStation(); bool use_autorefit = front->current_order.IsRefit() && front->current_order.GetRefitCargo() == CT_AUTO_REFIT; CargoArray consist_capleft; - if (_settings_game.order.improved_load && - ((front->current_order.GetLoadType() & OLFB_FULL_LOAD) != 0 || use_autorefit)) { + if (_settings_game.order.improved_load && use_autorefit ? + front->cargo_payment == NULL : (front->current_order.GetLoadType() & OLFB_FULL_LOAD) != 0) { ReserveConsist(st, front, (use_autorefit && front->load_unload_ticks != 0) ? &consist_capleft : NULL, - next_station); + &next_station); } /* We have not waited enough time till the next round of loading/unloading */