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 uint best_rating1 = 0; // rating of st1 uint best_rating2 = 0; // rating of st2 uint best_rating3 = 0; // rating of st3 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 */ if (st1 == NULL || st->goods[type].rating >= best_rating1) { 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) { st3 = st2; best_rating3 = best_rating2; st2 = st; best_rating2 = st->goods[type].rating; } else if (st3 == NULL || st->goods[type].rating >= best_rating3) { st3 = st; best_rating3 = st->goods[type].rating; } } /* 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); } /* 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 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_st3 = amount * best_rating3 / (best_rating1 + best_rating2 + best_rating3); assert(worst_cargo_st3 <= (amount - worst_cargo_st3)); uint remaining_amount = amount - worst_cargo_st3; uint worst_cargo_st2 = remaining_amount * best_rating2 / (best_rating1 + best_rating2); assert(worst_cargo_st2 <= (remaining_amount - worst_cargo_st2)); /* And then send the cargo to the stations! */ uint moved = UpdateStationWaiting(st1, type, remaining_amount - worst_cargo_st2, source_type, source_id); /* HALP - I GOT 3 UpdateStationWaitings now! */ moved += UpdateStationWaiting(st2, type, worst_cargo_st2, source_type, source_id); return moved + UpdateStationWaiting(st3, type, worst_cargo_st3, source_type, source_id); }