static CargoID cargo_type_comparator;
static int CDECL CompareCargoRatings(Station * const *a, Station * const *b)
{
return (*b)->goods[cargo_type_comparator].rating - (*a)->goods[cargo_type_comparator].rating;
}
uint MoveGoodsToStation(CargoID type, uint amount, SourceType source_type, SourceID source_id, const StationList *all_stations)
{
/* Return if nothing to do. Also the rounding below fails for 0. */
if (amount == 0) return 0;
StationList used_stations;
for (Station * const *st_iter = all_stations->Begin(); st_iter != all_stations->End(); ++st_iter) {
Station *st = *st_iter;
/* Is the station reserved exclusively for somebody else? */
if (st->town->exclusive_counter > 0 && st->town->exclusivity != st->owner) continue;
if (st->goods[type].rating == 0) continue; // Lowest possible rating, better not to give cargo anymore
if (_settings_game.order.selectgoods && !st->goods[type].HasVehicleEverTriedLoading()) continue; // Selectively servicing stations, and not this one
if (IsCargoInClass(type, CC_PASSENGERS)) {
if (st->facilities == FACIL_TRUCK_STOP) continue; // passengers are never served by just a truck stop
} else {
if (st->facilities == FACIL_BUS_STOP) continue; // non-passengers are never served by just a bus stop
}
/* This station can be used, add it to the list */
used_stations.Include(st);
}
const uint no_stations = used_stations.Length(); // total number of stations added
/* no stations around at all? */
if (no_stations == 0) return 0;
/* Sort the stations by cargo rating in descending order. */
cargo_type_comparator = type;
QSortT<Station *>(used_stations.Begin(), no_stations, CompareCargoRatings);
/* From now we'll calculate with fractal cargo amounts.
* First determine how much cargo we really have. */
amount *= ((*used_stations.Begin())->goods[type].rating) + 1;
/* several stations around */
uint ratings_sum = 0;
for (Station * const *st_iter = used_stations.Begin(); st_iter != used_stations.End(); ++st_iter) {
Station *st = *st_iter;
ratings_sum += st->goods[type].rating;
}
uint moved = 0;
for (Station * const *st_iter = used_stations.End(); st_iter != used_stations.Begin(); --st_iter) {
Station *st = *(st_iter - 1);
if (st != *used_stations.Begin()) {
/* Determine the amount the worst station gets, which is the last one from the list.
* Then determine the amount the next worst gets by iterating backwards, until the
* best station remains. We do it this way as the best should get a bonus, which in
* this case is the rounding difference from the last time this calculation is done.
* In reality that will mean the bonus will be pretty low. Nevertheless, the best
* station should always get the most cargo regardless of rounding issues. */
uint cur_worst = amount * st->goods[type].rating / ratings_sum;
/* And then send the cargo to the stations! */
moved += UpdateStationWaiting(st, type, cur_worst, source_type, source_id);
amount -= cur_worst;
ratings_sum -= st->goods[type].rating;
} else {
/* These two UpdateStationWaiting's can't be in the statement as then the order
* of execution would be undefined and that could cause desyncs with callbacks. */
return moved + UpdateStationWaiting(st, type, amount, source_type, source_id);
}
}
}