(svn r25361) -Feature: distribute cargo according to plan given by linkgraph
This commit is contained in:
@@ -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) {
|
||||
for (Vehicle *v = front_v; v != NULL; v = v->Next()) {
|
||||
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());
|
||||
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);
|
||||
|
||||
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(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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);
|
||||
|
Reference in New Issue
Block a user