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(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); } } }