diff options
author | fonsinchen <fonsinchen@openttd.org> | 2013-06-09 13:03:48 +0000 |
---|---|---|
committer | fonsinchen <fonsinchen@openttd.org> | 2013-06-09 13:03:48 +0000 |
commit | 04e3eb6fabc0e4aff04c189368356b8af15e9655 (patch) | |
tree | aa9d6a025fb3e343fc8cdc9358a913182445210b /src/economy.cpp | |
parent | a2ff96d6828bd32f7beb461bfb902880bf46ef75 (diff) | |
download | openttd-04e3eb6fabc0e4aff04c189368356b8af15e9655.tar.xz |
(svn r25361) -Feature: distribute cargo according to plan given by linkgraph
Diffstat (limited to 'src/economy.cpp')
-rw-r--r-- | src/economy.cpp | 70 |
1 files changed, 43 insertions, 27 deletions
diff --git a/src/economy.cpp b/src/economy.cpp index 552839192..d22d35e6f 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -42,6 +42,7 @@ #include "economy_base.h" #include "core/pool_func.hpp" #include "core/backup_type.hpp" +#include "cargo_type.h" #include "water.h" #include "game/game.hpp" #include "cargomonitor.h" @@ -1210,33 +1211,42 @@ Money CargoPayment::PayTransfer(const CargoPacket *cp, uint count) /** * Prepare the vehicle to be unloaded. + * @param curr_station the station where the consist is at the moment * @param front_v the vehicle to be unloaded */ void PrepareUnload(Vehicle *front_v) { + Station *curr_station = Station::Get(front_v->last_station_visited); + curr_station->loading_vehicles.push_back(front_v); + /* At this moment loading cannot be finished */ ClrBit(front_v->vehicle_flags, VF_LOADING_FINISHED); - /* Start unloading in at the first possible moment */ + /* Start unloading at the first possible moment */ front_v->load_unload_ticks = 1; - if ((front_v->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) { + assert(front_v->cargo_payment == NULL); + /* One CargoPayment per vehicle and the vehicle limit equals the + * limit in number of CargoPayments. Can't go wrong. */ + assert_compile(CargoPaymentPool::MAX_SIZE == VehiclePool::MAX_SIZE); + assert(CargoPayment::CanAllocateItem()); + front_v->cargo_payment = new CargoPayment(front_v); + + StationID next_station = front_v->GetNextStoppingStation(); + if (front_v->orders.list == NULL || (front_v->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) { + Station *st = Station::Get(front_v->last_station_visited); for (Vehicle *v = front_v; v != NULL; v = v->Next()) { + const GoodsEntry *ge = &st->goods[v->cargo_type]; if (v->cargo_cap > 0 && v->cargo.TotalCount() > 0) { v->cargo.Stage( - HasBit(Station::Get(front_v->last_station_visited)->goods[v->cargo_type].acceptance_pickup, GoodsEntry::GES_ACCEPTANCE), - front_v->last_station_visited, front_v->current_order.GetUnloadType()); + HasBit(ge->acceptance_pickup, GoodsEntry::GES_ACCEPTANCE), + front_v->last_station_visited, next_station, + front_v->current_order.GetUnloadType(), ge, + front_v->cargo_payment); if (v->cargo.UnloadCount() > 0) SetBit(v->vehicle_flags, VF_CARGO_UNLOADING); } } } - - assert(front_v->cargo_payment == NULL); - /* One CargoPayment per vehicle and the vehicle limit equals the - * limit in number of CargoPayments. Can't go wrong. */ - assert_compile(CargoPaymentPool::MAX_SIZE == VehiclePool::MAX_SIZE); - assert(CargoPayment::CanAllocateItem()); - front_v->cargo_payment = new CargoPayment(front_v); } /** @@ -1280,8 +1290,9 @@ static byte GetLoadAmount(Vehicle *v) * @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 the vehicle will stop at next. */ -static void ReserveConsist(Station *st, Vehicle *u, CargoArray *consist_capleft) +static void ReserveConsist(Station *st, Vehicle *u, CargoArray *consist_capleft, StationID next_station) { Vehicle *next_cargo = u; uint32 seen_cargos = 0; @@ -1310,7 +1321,7 @@ static void ReserveConsist(Station *st, Vehicle *u, CargoArray *consist_capleft) /* Nothing to do if the vehicle is full */ if (cap > 0) { - cap -= st->goods[v->cargo_type].cargo.Reserve(cap, &v->cargo, st->xy); + cap -= st->goods[v->cargo_type].cargo.Reserve(cap, &v->cargo, st->xy, next_station); } if (consist_capleft != NULL) { @@ -1347,11 +1358,14 @@ static void LoadUnloadVehicle(Vehicle *front) StationID last_visited = front->last_station_visited; Station *st = Station::Get(last_visited); + StationID 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)) { - ReserveConsist(st, front, (use_autorefit && front->load_unload_ticks != 0) ? &consist_capleft : NULL); + ReserveConsist(st, front, + (use_autorefit && front->load_unload_ticks != 0) ? &consist_capleft : NULL, + next_station); } /* We have not waited enough time till the next round of loading/unloading */ @@ -1408,7 +1422,7 @@ static void LoadUnloadVehicle(Vehicle *front) uint new_remaining = v->cargo.RemainingCount() + v->cargo.ActionCount(VehicleCargoList::MTA_DELIVER); if (v->cargo_cap < new_remaining) { /* Return some of the reserved cargo to not overload the vehicle. */ - v->cargo.Return(new_remaining - v->cargo_cap, &ge->cargo); + v->cargo.Return(new_remaining - v->cargo_cap, &ge->cargo, INVALID_STATION); } /* Keep instead of delivering. This may lead to no cargo being unloaded, so ...*/ @@ -1474,18 +1488,19 @@ static void LoadUnloadVehicle(Vehicle *front) } if (new_cid == CT_AUTO_REFIT) { - /* Get refittable cargo type with the most waiting cargo. */ - int amount = 0; + /* Get a refittable cargo type with waiting cargo for next_station or INVALID_STATION. */ CargoID cid; + new_cid = v_start->cargo_type; FOR_EACH_SET_CARGO_ID(cid, refit_mask) { - /* Consider refitting to this cargo, if other vehicles of the consist cannot - * already take the cargo without refitting */ - if ((int)st->goods[cid].cargo.AvailableCount() > (int)consist_capleft[cid] + amount) { + if (st->goods[cid].cargo.HasCargoFor(next_station) || + st->goods[cid].cargo.HasCargoFor(INVALID_STATION)) { /* Try to find out if auto-refitting would succeed. In case the refit is allowed, * the returned refit capacity will be greater than zero. */ DoCommand(v_start->tile, v_start->index, cid | 1U << 6 | 0xFF << 8 | 1U << 16, DC_QUERY_COST, GetCmdRefitVeh(v_start)); // Auto-refit and only this vehicle including artic parts. - if (_returned_refit_capacity > 0) { - amount = st->goods[cid].cargo.AvailableCount() - consist_capleft[cid]; + /* Try to balance different loadable cargoes between parts of the consist, so that + * all of them can be loaded. Avoid a situation where all vehicles suddenly switch + * to the first loadable cargo for which there is only one packet. */ + if (_returned_refit_capacity > 0 && consist_capleft[cid] < consist_capleft[new_cid]) { new_cid = cid; } } @@ -1493,7 +1508,7 @@ static void LoadUnloadVehicle(Vehicle *front) } /* Refit if given a valid cargo. */ - if (new_cid < NUM_CARGO) { + if (new_cid < NUM_CARGO && new_cid != v_start->cargo_type) { CommandCost cost = DoCommand(v_start->tile, v_start->index, new_cid | 1U << 6 | 0xFF << 8 | 1U << 16, DC_EXEC, GetCmdRefitVeh(v_start)); // Auto-refit and only this vehicle including artic parts. if (cost.Succeeded()) front->profit_this_year -= cost.GetCost() << 8; ge = &st->goods[v->cargo_type]; @@ -1502,7 +1517,7 @@ static void LoadUnloadVehicle(Vehicle *front) /* Add new capacity to consist capacity and reserve cargo */ w = v_start; do { - st->goods[w->cargo_type].cargo.Reserve(w->cargo_cap, &w->cargo, st->xy); + st->goods[w->cargo_type].cargo.Reserve(w->cargo_cap, &w->cargo, st->xy, next_station); consist_capleft[w->cargo_type] += w->cargo_cap - w->cargo.RemainingCount(); w = w->HasArticulatedPart() ? w->GetNextArticulatedPart() : NULL; } while (w != NULL); @@ -1534,14 +1549,15 @@ static void LoadUnloadVehicle(Vehicle *front) ge->last_age = min(_cur_year - front->build_year, 255); ge->time_since_pickup = 0; + assert(v->cargo_cap >= v->cargo.StoredCount()); /* If there's goods waiting at the station, and the vehicle * has capacity for it, load it on the vehicle. */ - int cap_left = v->cargo_cap - v->cargo.StoredCount(); + uint cap_left = v->cargo_cap - v->cargo.StoredCount(); if (cap_left > 0 && (v->cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0 || ge->cargo.AvailableCount() > 0)) { if (_settings_game.order.gradual_loading) cap_left = min(cap_left, load_amount); if (v->cargo.StoredCount() == 0) TriggerVehicle(v, VEHICLE_TRIGGER_NEW_CARGO); - uint loaded = ge->cargo.Load(cap_left, &v->cargo, st->xy); + uint loaded = ge->cargo.Load(cap_left, &v->cargo, st->xy, next_station); if (v->cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0) { /* Remember if there are reservations left so that we don't stop * loading before they're loaded. */ @@ -1549,7 +1565,7 @@ static void LoadUnloadVehicle(Vehicle *front) } /* Store whether the maximum possible load amount was loaded or not.*/ - if (loaded == (uint)cap_left) { + if (loaded == cap_left) { SetBit(full_load_amount, v->cargo_type); } else { ClrBit(full_load_amount, v->cargo_type); |