(svn r14705) -Fix [FS#2460]: First transfer the whole load of a vehicle chain to industries before triggering any processing.

This reduces callback usage and resolves critical rounding errors when using input-cargo-multipliers instead of production callbacks.
This commit is contained in:
frosch 2008-12-20 17:21:22 +00:00
parent dca37f1cb0
commit 98a865370d

View File

@ -47,6 +47,7 @@
#include "autoreplace_func.h" #include "autoreplace_func.h"
#include "company_gui.h" #include "company_gui.h"
#include "signs_base.h" #include "signs_base.h"
#include "core/smallvec_type.hpp"
#include "table/strings.h" #include "table/strings.h"
#include "table/sprites.h" #include "table/sprites.h"
@ -83,6 +84,8 @@ static inline uint32 BigMulSU(const uint32 a, const uint32 b, const uint8 shift)
return (uint32)((uint64)a * (uint64)b >> shift); return (uint32)((uint64)a * (uint64)b >> shift);
} }
typedef SmallVector<Industry *, 16> SmallIndustryList;
/* Score info */ /* Score info */
const ScoreInfo _score_info[] = { const ScoreInfo _score_info[] = {
{ SCORE_VEHICLES, 120, 100 }, { SCORE_VEHICLES, 120, 100 },
@ -1284,8 +1287,9 @@ static bool FindIndustryToDeliver(TileIndex ind_tile, void *user_data)
* @param st The station that accepted the cargo * @param st The station that accepted the cargo
* @param cargo_type Type of cargo delivered * @param cargo_type Type of cargo delivered
* @param nun_pieces Amount of cargo delivered * @param nun_pieces Amount of cargo delivered
* @param industry_set The destination industry will be inserted into this set
*/ */
static void DeliverGoodsToIndustry(const Station *st, CargoID cargo_type, int num_pieces) static void DeliverGoodsToIndustry(const Station *st, CargoID cargo_type, int num_pieces, SmallIndustryList *industry_set)
{ {
if (st->rect.IsEmpty()) return; if (st->rect.IsEmpty()) return;
@ -1320,28 +1324,13 @@ static void DeliverGoodsToIndustry(const Station *st, CargoID cargo_type, int nu
*/ */
if (CircularTileSearch(&start_tile, 2 * max_radius + 1, FindIndustryToDeliver, &callback_data)) { if (CircularTileSearch(&start_tile, 2 * max_radius + 1, FindIndustryToDeliver, &callback_data)) {
Industry *best = callback_data.ind; Industry *best = callback_data.ind;
const IndustrySpec *indspec = callback_data.indspec;
uint accepted_cargo_index = callback_data.cargo_index; uint accepted_cargo_index = callback_data.cargo_index;
assert(best != NULL && indspec != NULL); assert(best != NULL);
uint16 callback = indspec->callback_flags;
best->was_cargo_delivered = true; /* Insert the industry into industry_set, if not yet contained */
best->last_cargo_accepted_at = _date; if (industry_set != NULL) industry_set->Include(best);
if (HasBit(callback, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(callback, CBM_IND_PRODUCTION_256_TICKS)) { best->incoming_cargo_waiting[accepted_cargo_index] = min(num_pieces + best->incoming_cargo_waiting[accepted_cargo_index], 0xFFFF);
best->incoming_cargo_waiting[accepted_cargo_index] = min(num_pieces + best->incoming_cargo_waiting[accepted_cargo_index], 0xFFFF);
if (HasBit(callback, CBM_IND_PRODUCTION_CARGO_ARRIVAL)) {
IndustryProductionCallback(best, 0);
} else {
InvalidateWindow(WC_INDUSTRY_VIEW, best->index);
}
} else {
best->produced_cargo_waiting[0] = min(best->produced_cargo_waiting[0] + (num_pieces * indspec->input_cargo_multiplier[accepted_cargo_index][0] / 256), 0xFFFF);
best->produced_cargo_waiting[1] = min(best->produced_cargo_waiting[1] + (num_pieces * indspec->input_cargo_multiplier[accepted_cargo_index][1] / 256), 0xFFFF);
}
TriggerIndustry(best, INDUSTRY_TRIGGER_RECEIVED_CARGO);
StartStopIndustryTileAnimation(best, IAT_INDUSTRY_RECEIVED_CARGO);
} }
} }
@ -1411,7 +1400,17 @@ static bool CheckSubsidised(Station *from, Station *to, CargoID cargo_type)
return false; return false;
} }
static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID source, StationID dest, TileIndex source_tile, byte days_in_transit) /**
* Delivers goods to industries/towns and calculates the payment
* @param num_pieces amount of cargo delivered
* @param source Originstation of the cargo
* @param dest Station the cargo has been unloaded
* @param source_tile The origin of the cargo for distance calculation
* @param days_in_transit Travel time
* @param industry_set The delivered industry will be inserted into this set, if not yet contained
* The cargo is just added to the stockpile of the industry. It is due to the caller to trigger the industry's production machinery
*/
static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID source, StationID dest, TileIndex source_tile, byte days_in_transit, SmallIndustryList *industry_set)
{ {
bool subsidised; bool subsidised;
Station *s_from, *s_to; Station *s_from, *s_to;
@ -1439,7 +1438,7 @@ static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID source,
if (cs->town_effect == TE_WATER) s_to->town->new_act_water += num_pieces; if (cs->town_effect == TE_WATER) s_to->town->new_act_water += num_pieces;
/* Give the goods to the industry. */ /* Give the goods to the industry. */
DeliverGoodsToIndustry(s_to, cargo_type, num_pieces); DeliverGoodsToIndustry(s_to, cargo_type, num_pieces, industry_set);
/* Determine profit */ /* Determine profit */
profit = GetTransportedGoodsIncome(num_pieces, DistanceManhattan(source_tile, s_to->xy), days_in_transit, cargo_type); profit = GetTransportedGoodsIncome(num_pieces, DistanceManhattan(source_tile, s_to->xy), days_in_transit, cargo_type);
@ -1457,6 +1456,41 @@ static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID source,
return profit; return profit;
} }
/**
* Inform the industry about just delivered cargo
* DeliverGoodsToIndustry() silently incremented incoming_cargo_waiting, now it is time to do something with the new cargo.
* @param i The industry to process
*/
static void TriggerIndustryProduction(Industry *i)
{
const IndustrySpec *indspec = GetIndustrySpec(i->type);
uint16 callback = indspec->callback_flags;
i->was_cargo_delivered = true;
i->last_cargo_accepted_at = _date;
if (HasBit(callback, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(callback, CBM_IND_PRODUCTION_256_TICKS)) {
if (HasBit(callback, CBM_IND_PRODUCTION_CARGO_ARRIVAL)) {
IndustryProductionCallback(i, 0);
} else {
InvalidateWindow(WC_INDUSTRY_VIEW, i->index);
}
} else {
for (uint cargo_index = 0; cargo_index < lengthof(i->incoming_cargo_waiting); cargo_index++) {
uint cargo_waiting = i->incoming_cargo_waiting[cargo_index];
if (cargo_waiting == 0) continue;
i->produced_cargo_waiting[0] = min(i->produced_cargo_waiting[0] + (cargo_waiting * indspec->input_cargo_multiplier[cargo_index][0] / 256), 0xFFFF);
i->produced_cargo_waiting[1] = min(i->produced_cargo_waiting[1] + (cargo_waiting * indspec->input_cargo_multiplier[cargo_index][1] / 256), 0xFFFF);
i->incoming_cargo_waiting[cargo_index] = 0;
}
}
TriggerIndustry(i, INDUSTRY_TRIGGER_RECEIVED_CARGO);
StartStopIndustryTileAnimation(i, IAT_INDUSTRY_RECEIVED_CARGO);
}
/** /**
* Performs the vehicle payment _and_ marks the vehicle to be unloaded. * Performs the vehicle payment _and_ marks the vehicle to be unloaded.
* @param front_v the vehicle to be unloaded * @param front_v the vehicle to be unloaded
@ -1482,6 +1516,10 @@ void VehiclePayment(Vehicle *front_v)
/* Start unloading in at the first possible moment */ /* Start unloading in at the first possible moment */
front_v->load_unload_time_rem = 1; front_v->load_unload_time_rem = 1;
/* Collect delivered industries */
static SmallIndustryList industry_set;
industry_set.Clear();
for (Vehicle *v = front_v; v != NULL; v = v->Next()) { for (Vehicle *v = front_v; v != NULL; v = v->Next()) {
/* No cargo to unload */ /* No cargo to unload */
if (v->cargo_cap == 0 || v->cargo.Empty() || front_v->current_order.GetUnloadType() & OUFB_NO_UNLOAD) continue; if (v->cargo_cap == 0 || v->cargo.Empty() || front_v->current_order.GetUnloadType() & OUFB_NO_UNLOAD) continue;
@ -1505,7 +1543,7 @@ void VehiclePayment(Vehicle *front_v)
st->time_since_unload = 0; st->time_since_unload = 0;
/* handle end of route payment */ /* handle end of route payment */
Money profit = DeliverGoods(cp->count, v->cargo_type, cp->source, last_visited, cp->source_xy, cp->days_in_transit); Money profit = DeliverGoods(cp->count, v->cargo_type, cp->source, last_visited, cp->source_xy, cp->days_in_transit, &industry_set);
cp->paid_for = true; cp->paid_for = true;
route_profit += profit; // display amount paid for final route delivery, A-D of a chain A-B-C-D route_profit += profit; // display amount paid for final route delivery, A-D of a chain A-B-C-D
vehicle_profit += profit - cp->feeder_share; // whole vehicle is not payed for transfers picked up earlier vehicle_profit += profit - cp->feeder_share; // whole vehicle is not payed for transfers picked up earlier
@ -1535,6 +1573,12 @@ void VehiclePayment(Vehicle *front_v)
v->cargo.InvalidateCache(); v->cargo.InvalidateCache();
} }
/* Call the production machinery of industries only once for every vehicle chain */
const Industry *const *isend = industry_set.End();
for (Industry **iid = industry_set.Begin(); iid != isend; iid++) {
TriggerIndustryProduction(*iid);
}
if (virtual_profit > 0) { if (virtual_profit > 0) {
ShowFeederIncomeAnimation(front_v->x_pos, front_v->y_pos, front_v->z_pos, virtual_profit); ShowFeederIncomeAnimation(front_v->x_pos, front_v->y_pos, front_v->z_pos, virtual_profit);
} }