static int CDECL StationRatingSorter(const Station * const *a, const Station * const *b)
{
// GSortT(used_stations->Begin(), used_stations.Lenght(), );
const Station *sta = *a;
const Station *stb = *b;
return stb->goods[0].rating - sta->goods[0].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;
Station *st1 = NULL; // Station with best rating
Station *st2 = NULL; // Second best station
Station *st3 = NULL; // Third best station
Station *st4 = NULL; // Fourth best station
Station *st5 = NULL; // Fifth best station
Station *st6 = NULL; // Sixth best station
uint best_rating1 = 0; // rating of st1
uint best_rating2 = 0; // rating of st2
uint best_rating3 = 0; // rating of st3
uint best_rating4 = 0; // rating of st4
uint best_rating5 = 0; // rating of st5
uint best_rating6 = 0; // rating of st6
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 st1/st2/st3/st4/st5/st6 */
used_stations.Include(st);
if (st1 == NULL || st->goods[type].rating >= best_rating1) {
st6 = st5; best_rating6 = best_rating5;
st5 = st4; best_rating5 = best_rating4;
st4 = st3; best_rating4 = best_rating3;
st3 = st2; best_rating3 = best_rating2;
st2 = st1; best_rating2 = best_rating1;
st1 = st; best_rating1 = st->goods[type].rating;
} else if (st2 == NULL || st->goods[type].rating >= best_rating2) {
st6 = st5; best_rating6 = best_rating5;
st5 = st4; best_rating5 = best_rating4;
st4 = st3; best_rating4 = best_rating3;
st3 = st2; best_rating3 = best_rating2;
st2 = st; best_rating2 = st->goods[type].rating;
} else if (st3 == NULL || st->goods[type].rating >= best_rating3) {
st6 = st5; best_rating6 = best_rating5;
st5 = st4; best_rating5 = best_rating4;
st4 = st3; best_rating4 = best_rating3;
st3 = st; best_rating3 = st->goods[type].rating;
} else if (st4 == NULL || st->goods[type].rating >= best_rating4) {
st6 = st5; best_rating6 = best_rating5;
st5 = st4; best_rating5 = best_rating4;
st4 = st; best_rating4 = st->goods[type].rating;
} else if (st5 == NULL || st->goods[type].rating >= best_rating5) {
st6 = st5; best_rating6 = best_rating5;
st5 = st; best_rating5 = st->goods[type].rating;
} else if (st6 == NULL || st->goods[type].rating >= best_rating6) {
st6 = st; best_rating6 = st->goods[type].rating;
}
}
uint no_stations = used_stations.Length();
GSortT(used_stations.Begin(), used_stations.Length(), &StationRatingSorter);
if (no_stations > 1) {
Station *st1 = &used_stations.Begin();
Station *st2 = &st1++;
uint offset = 0;
while (no_stations > 1) {
const int diff = st1->goods[type].rating - st2->goods[type].rating;
if (diff <= 0) {
if (offset != 0) {
st1 += offset;
st2 += offset;
offset = 0;
continue;
}
st1++;
st2++;
no_stations--;
} else {
Swap(*st1, *st2);
if (st1 == *used_stations.Begin()) continue;
st1--;
st2--;
offset++;
}
}
// for (Station **st_iter = used_stations.Begin(); st_iter != used_stations.End(); ++st_iter) {
// Station *st1 = *st_iter;
// Station *st2 = *st_iter + 1;
//
// if (st1->goods[type].rating >= st2->goods[type].rating) {
// st2 = st1;
// }
//
// }
}
/* no stations around at all? */
if (st1 == NULL) return 0;
/* From now we'll calculate with fractal cargo amounts.
* First determine how much cargo we really have. */
amount *= best_rating1 + 1;
if (st2 == NULL) {
/* only one station around */
return UpdateStationWaiting(st1, type, amount, source_type, source_id);
}
if (st3 == NULL) {
/* two stations around, the best two (highest rating) are in st1 and st2 */
assert(st1 != NULL);
assert(st2 != NULL);
assert(best_rating1 != 0 || best_rating2 != 0);
/* Then determine the amount the worst station gets. We do it this way as the
* best should get a bonus, which in this case is the rounding difference from
* this calculation. 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 worst_cargo = amount * best_rating2 / (best_rating1 + best_rating2);
assert(worst_cargo <= (amount - worst_cargo));
/* And then send the cargo to the stations! */
uint moved = UpdateStationWaiting(st1, type, amount - worst_cargo, source_type, source_id);
/* 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(st2, type, worst_cargo, source_type, source_id);
}
if (st4 == NULL) {
/* three stations around, the best three (highest rating) are in st1, st2 and st3 */
assert(st1 != NULL);
assert(st2 != NULL);
assert(st3 != NULL);
assert(best_rating1 != 0 || best_rating2 != 0 || best_rating3 != 0);
/* Then determine the amount the worst stations get. We do it this way as the
* best should get a bonus, which in this case is the rounding difference from
* this calculation. 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 cargo_st3 = amount * best_rating3 / (best_rating1 + best_rating2 + best_rating3);
assert(cargo_st3 <= (amount - cargo_st3));
uint remaining = amount - cargo_st3;
uint cargo_st2 = remaining * best_rating2 / (best_rating1 + best_rating2);
assert(cargo_st2 <= (remaining - cargo_st2));
uint cargo_st1 = remaining - cargo_st2;
assert(amount == cargo_st1 + cargo_st2 + cargo_st3);
/* And then send the cargo to the stations! */
uint moved = UpdateStationWaiting(st1, type, cargo_st1, source_type, source_id);
moved += UpdateStationWaiting(st2, type, cargo_st2, source_type, source_id);
return moved + UpdateStationWaiting(st3, type, cargo_st3, source_type, source_id);
}
if (st5 == NULL) {
/* Four stations around, the best four (highest rating) are in st1, st2, st3 and st4 */
assert(st1 != NULL);
assert(st2 != NULL);
assert(st3 != NULL);
assert(st4 != NULL);
assert(best_rating1 != 0 || best_rating2 != 0 || best_rating3 != 0 || best_rating4 != 0);
/* Then determine the amount the worst stations get. We do it this way as the
* best should get a bonus, which in this case is the rounding difference from
* this calculation. 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 cargo_st4 = amount * best_rating4 / (best_rating1 + best_rating2 + best_rating3 + best_rating4);
assert(cargo_st4 <= (amount - cargo_st4));
uint remaining = amount - cargo_st4;
uint cargo_st3 = remaining * best_rating3 / (best_rating1 + best_rating2 + best_rating3);
assert(cargo_st3 <= (remaining - cargo_st3));
remaining -= cargo_st3;
uint cargo_st2 = remaining * best_rating2 / (best_rating1 + best_rating2);
assert(cargo_st2 <= (remaining - cargo_st2));
uint cargo_st1 = remaining - cargo_st2;
assert(amount == cargo_st1 + cargo_st2 + cargo_st3 + cargo_st4);
/* And then send the cargo to the stations! */
uint moved = UpdateStationWaiting(st1, type, cargo_st1, source_type, source_id);
moved += UpdateStationWaiting(st2, type, cargo_st2, source_type, source_id);
moved += UpdateStationWaiting(st3, type, cargo_st3, source_type, source_id);
return moved + UpdateStationWaiting(st4, type, cargo_st4, source_type, source_id);
}
if (st6 == NULL) {
/* Five stations around, the best five (highest rating) are in st1, st2, st3, st4 and st5 */
assert(st1 != NULL);
assert(st2 != NULL);
assert(st3 != NULL);
assert(st4 != NULL);
assert(st5 != NULL);
assert(best_rating1 != 0 || best_rating2 != 0 || best_rating3 != 0 || best_rating4 != 0 || best_rating5 != 0);
/* Then determine the amount the worst stations get. We do it this way as the
* best should get a bonus, which in this case is the rounding difference from
* this calculation. 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 cargo_st5 = amount * best_rating5 / (best_rating1 + best_rating2 + best_rating3 + best_rating4 + best_rating5);
assert(cargo_st5 <= (amount - cargo_st5));
uint remaining = amount - cargo_st5;
uint cargo_st4 = remaining * best_rating4 / (best_rating1 + best_rating2 + best_rating3 + best_rating4);
assert(cargo_st4 <= (remaining - cargo_st4));
remaining -= cargo_st4;
uint cargo_st3 = remaining * best_rating3 / (best_rating1 + best_rating2 + best_rating3);
assert(cargo_st3 <= (remaining - cargo_st3));
remaining -= cargo_st3;
uint cargo_st2 = remaining * best_rating2 / (best_rating1 + best_rating2);
assert(cargo_st2 <= (remaining - cargo_st2));
uint cargo_st1 = remaining - cargo_st2;
assert(amount == cargo_st1 + cargo_st2 + cargo_st3 + cargo_st4 + cargo_st5);
/* And then send the cargo to the stations! */
uint moved = UpdateStationWaiting(st1, type, cargo_st1, source_type, source_id);
moved += UpdateStationWaiting(st2, type, cargo_st2, source_type, source_id);
moved += UpdateStationWaiting(st3, type, cargo_st3, source_type, source_id);
moved += UpdateStationWaiting(st4, type, cargo_st4, source_type, source_id);
return moved + UpdateStationWaiting(st5, type, cargo_st5, source_type, source_id);
}
/* Six stations around, the best six (highest rating) are in st1, st2, st3, st4, st5 and st6 */
assert(st1 != NULL);
assert(st2 != NULL);
assert(st3 != NULL);
assert(st4 != NULL);
assert(st5 != NULL);
assert(st6 != NULL);
assert(best_rating1 != 0 || best_rating2 != 0 || best_rating3 != 0 || best_rating4 != 0 || best_rating5 != 0 || best_rating6 != 0);
/* Then determine the amount the worst stations get. We do it this way as the
* best should get a bonus, which in this case is the rounding difference from
* this calculation. 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 cargo_st6 = amount * best_rating6 / (best_rating1 + best_rating2 + best_rating3 + best_rating4 + best_rating5 + best_rating6);
assert(cargo_st6 <= (amount - cargo_st6));
uint remaining = amount - cargo_st6;
uint cargo_st5 = remaining * best_rating5 / (best_rating1 + best_rating2 + best_rating3 + best_rating4 + best_rating5);
assert(cargo_st5 <= (remaining - cargo_st5));
remaining -= cargo_st5;
uint cargo_st4 = remaining * best_rating4 / (best_rating1 + best_rating2 + best_rating3 + best_rating4);
assert(cargo_st4 <= (remaining - cargo_st4));
remaining -= cargo_st4;
uint cargo_st3 = remaining * best_rating3 / (best_rating1 + best_rating2 + best_rating3);
assert(cargo_st3 <= (remaining - cargo_st3));
remaining -= cargo_st3;
uint cargo_st2 = remaining * best_rating2 / (best_rating1 + best_rating2);
assert(cargo_st2 <= (remaining - cargo_st2));
uint cargo_st1 = remaining - cargo_st2;
assert(amount == cargo_st1 + cargo_st2 + cargo_st3 + cargo_st4 + cargo_st5 + cargo_st6);
/* And then send the cargo to the stations! */
uint moved = UpdateStationWaiting(st1, type, cargo_st1, source_type, source_id);
moved += UpdateStationWaiting(st2, type, cargo_st2, source_type, source_id);
moved += UpdateStationWaiting(st3, type, cargo_st3, source_type, source_id);
moved += UpdateStationWaiting(st4, type, cargo_st4, source_type, source_id);
moved += UpdateStationWaiting(st5, type, cargo_st5, source_type, source_id);
return moved + UpdateStationWaiting(st6, type, cargo_st6, source_type, source_id);
}