From b4f6201e940d3cee219e944664b8505638dbad81 Mon Sep 17 00:00:00 2001 From: rubidium Date: Tue, 28 Sep 2010 22:00:24 +0000 Subject: [PATCH] (svn r20857) -Fix [FS#3637]: The station with the second highest rating was doubly penalised when distributing cargo. Now the penalty is completely removed and the granularity/precision of the distribution in increased by using fractional cargo. This should make competing stations less "all-or-nothing". --- src/saveload/saveload.cpp | 3 ++- src/saveload/station_sl.cpp | 1 + src/station_base.h | 1 + src/station_cmd.cpp | 49 ++++++++++++++++++++----------------- 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 101cc412e8..fdf3b16ad5 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -212,8 +212,9 @@ * 147 20621 * 148 20659 * 149 20832 + * 150 20857 */ -extern const uint16 SAVEGAME_VERSION = 149; ///< current savegame version of OpenTTD +extern const uint16 SAVEGAME_VERSION = 150; ///< current savegame version of OpenTTD SavegameType _savegame_type; ///< type of savegame we are loading diff --git a/src/saveload/station_sl.cpp b/src/saveload/station_sl.cpp index 72d7c7ecf6..1be9b417ef 100644 --- a/src/saveload/station_sl.cpp +++ b/src/saveload/station_sl.cpp @@ -238,6 +238,7 @@ const SaveLoad *GetGoodsDesc() SLE_VAR(GoodsEntry, last_age, SLE_UINT8), SLEG_CONDVAR( _cargo_feeder_share, SLE_FILE_U32 | SLE_VAR_I64, 14, 64), SLEG_CONDVAR( _cargo_feeder_share, SLE_INT64, 65, 67), + SLE_CONDVAR(GoodsEntry, amount_fract, SLE_UINT8, 150, SL_MAX_VERSION), SLE_CONDLST(GoodsEntry, cargo.packets, REF_CARGO_PACKET, 68, SL_MAX_VERSION), SLE_END() diff --git a/src/station_base.h b/src/station_base.h index ca0e598f9f..d595379e97 100644 --- a/src/station_base.h +++ b/src/station_base.h @@ -42,6 +42,7 @@ struct GoodsEntry { byte rating; byte last_speed; byte last_age; + byte amount_fract; ///< Fractional part of the amount in the cargo list StationCargoList cargo; ///< The cargo packets of cargo waiting in this station }; diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 74b4f484b6..c8251258f9 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -3188,8 +3188,15 @@ void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint rad } } -static void UpdateStationWaiting(Station *st, CargoID type, uint amount, SourceType source_type, SourceID source_id) +static uint UpdateStationWaiting(Station *st, CargoID type, uint amount, SourceType source_type, SourceID source_id) { + amount += st->goods[type].amount_fract; + st->goods[type].amount_fract = GB(amount, 0, 8); + + amount >>= 8; + /* No new "real" cargo item yet. */ + if (amount == 0) return 0; + st->goods[type].cargo.Append(new CargoPacket(st->index, st->xy, amount, source_type, source_id)); SetBit(st->goods[type].acceptance_pickup, GoodsEntry::PICKUP); @@ -3198,6 +3205,7 @@ static void UpdateStationWaiting(Station *st, CargoID type, uint amount, SourceT SetWindowDirty(WC_STATION_VIEW, st->index); st->MarkTilesDirty(true); + return amount; } static bool IsUniqueStationName(const char *name) @@ -3328,11 +3336,13 @@ uint MoveGoodsToStation(CargoID type, uint amount, SourceType source_type, Sourc /* 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 */ - uint moved = amount * best_rating1 / 256 + 1; - UpdateStationWaiting(st1, type, moved, source_type, source_id); - return moved; + return UpdateStationWaiting(st1, type, amount, source_type, source_id); } /* several stations around, the best two (highest rating) are in st1 and st2 */ @@ -3340,26 +3350,19 @@ uint MoveGoodsToStation(CargoID type, uint amount, SourceType source_type, Sourc assert(st2 != NULL); assert(best_rating1 != 0 || best_rating2 != 0); - /* the 2nd highest one gets a penalty */ - best_rating2 >>= 1; + /* 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)); - /* amount given to station 1 */ - uint t = (best_rating1 * (amount + 1)) / (best_rating1 + best_rating2); - - uint moved = 0; - if (t != 0) { - moved = t * best_rating1 / 256 + 1; - amount -= t; - UpdateStationWaiting(st1, type, moved, source_type, source_id); - } - - if (amount != 0) { - amount = amount * best_rating2 / 256 + 1; - moved += amount; - UpdateStationWaiting(st2, type, amount, source_type, source_id); - } - - return moved; + /* 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); } void BuildOilRig(TileIndex tile)