diff --git a/src/aircraft_gui.cpp b/src/aircraft_gui.cpp index 98e72460f0..d5e7726007 100644 --- a/src/aircraft_gui.cpp +++ b/src/aircraft_gui.cpp @@ -106,7 +106,13 @@ static void AircraftDetailsWndProc(Window *w, WindowEvent *e) { SetDParam(0, v->service_interval); SetDParam(1, v->date_of_last_service); - DrawString(13, 103, _patches.servint_ispercent?STR_SERVICING_INTERVAL_PERCENT:STR_883C_SERVICING_INTERVAL_DAYS, 0); + DrawString(13, 115, _patches.servint_ispercent?STR_SERVICING_INTERVAL_PERCENT:STR_883C_SERVICING_INTERVAL_DAYS, 0); + } + + /* Draw Transfer credits text */ + { + SetDParam(0, v->cargo_feeder_share); + DrawString(60, 101, STR_FEEDER_CARGO_VALUE, 0); } DrawAircraftImage(v, 3, 57, INVALID_VEHICLE); @@ -187,15 +193,15 @@ static const Widget _aircraft_details_widgets[] = { { WWT_CAPTION, RESIZE_NONE, 14, 11, 349, 0, 13, STR_A00C_DETAILS, STR_018C_WINDOW_TITLE_DRAG_THIS }, { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 350, 389, 0, 13, STR_01AA_NAME, STR_A032_NAME_AIRCRAFT }, { WWT_PANEL, RESIZE_NONE, 14, 0, 389, 14, 55, 0x0, STR_NULL }, -{ WWT_PANEL, RESIZE_NONE, 14, 0, 389, 56, 101, 0x0, STR_NULL }, -{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 0, 10, 102, 107, STR_0188, STR_884D_INCREASE_SERVICING_INTERVAL }, -{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 0, 10, 108, 113, STR_0189, STR_884E_DECREASE_SERVICING_INTERVAL }, -{ WWT_PANEL, RESIZE_NONE, 14, 11, 389, 102, 113, 0x0, STR_NULL }, +{ WWT_PANEL, RESIZE_NONE, 14, 0, 389, 56, 113, 0x0, STR_NULL }, +{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 0, 10, 114, 119, STR_0188, STR_884D_INCREASE_SERVICING_INTERVAL }, +{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 0, 10, 120, 125, STR_0189, STR_884E_DECREASE_SERVICING_INTERVAL }, +{ WWT_PANEL, RESIZE_NONE, 14, 11, 389, 114, 125, 0x0, STR_NULL }, { WIDGETS_END}, }; static const WindowDesc _aircraft_details_desc = { - WDP_AUTO, WDP_AUTO, 390, 114, + WDP_AUTO, WDP_AUTO, 390, 126, WC_VEHICLE_DETAILS, WC_VEHICLE_VIEW, WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS, _aircraft_details_widgets, diff --git a/src/economy.cpp b/src/economy.cpp index 02895243de..6298582eb1 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -1331,13 +1331,15 @@ static bool LoadWait(const Vehicle* v, const Vehicle* u) int LoadUnloadVehicle(Vehicle *v, bool just_arrived) { int profit = 0; - int v_profit = 0; //virtual profit for feeder systems - int v_profit_total = 0; + int total_veh_profit = 0; // accumulates the profit across the vehicle chain (used by trains) + int32 route_profit = 0; // the grand total amount for the route. A-D of transfer chain A-B-C-D + int virtual_profit = 0; // virtual profit of one vehicle element for feeder systems + int virtual_profit_total = 0; // virtual profit for entire vehicle chain + int total_cargo_feeder_share = 0; // the feeder cash amount for the goods being loaded/unloaded in this load step + int unloading_time = 20; Vehicle *u = v; int result = 0; - StationID last_visited; - Station *st; int t; uint count, cap; PlayerID old_player; @@ -1358,8 +1360,10 @@ int LoadUnloadVehicle(Vehicle *v, bool just_arrived) old_player = _current_player; _current_player = v->owner; - last_visited = v->last_station_visited; - st = GetStation(last_visited); + StationID last_visited = v->last_station_visited; + Station *st = GetStation(last_visited); + + int all_vehicles_cargo_feeder_share = v->cargo_feeder_share; // used to hold transfer value of complete vehicle chain - used by trains for (; v != NULL; v = v->next) { GoodsEntry* ge; @@ -1388,26 +1392,44 @@ int LoadUnloadVehicle(Vehicle *v, bool just_arrived) st->time_since_unload = 0; unloading_time += v->cargo_count; // TTDBUG: bug in original TTD + + /* handle end of route payment */ if (just_arrived && v->cargo_paid_for < v->cargo_count) { profit += DeliverGoods(v->cargo_count - v->cargo_paid_for, v->cargo_type, v->cargo_source, last_visited, v->cargo_source_xy, v->cargo_days); v->cargo_paid_for = v->cargo_count; + route_profit = profit; // display amount paid for final route delivery, A-D of a chain A-B-C-D + total_veh_profit = profit - all_vehicles_cargo_feeder_share; // whole vehicle is not payed for transfers picked up earlier + total_cargo_feeder_share = -all_vehicles_cargo_feeder_share; // total of transfer fees in vehicle chain needs to be zero at end of unload + v->cargo_feeder_share = 0; // clear transfer cost per vehicle } result |= 1; v->cargo_count -= amount_unloaded; v->cargo_paid_for -= min(amount_unloaded, v->cargo_paid_for); if (_patches.gradual_loading) continue; + } else if (u->current_order.flags & (OF_UNLOAD | OF_TRANSFER)) { + /* unload goods and let it wait at the station */ st->time_since_unload = 0; - if (just_arrived && (u->current_order.flags & OF_TRANSFER) && v->cargo_paid_for < v->cargo_count) { - v_profit = GetTransportedGoodsIncome( - v->cargo_count - v->cargo_paid_for, - DistanceManhattan(v->cargo_source_xy, GetStation(last_visited)->xy), - v->cargo_days, - v->cargo_type) * 3 / 2; - v_profit_total += v_profit; - v->cargo_paid_for = v->cargo_count; + /* handle transfer */ + if (just_arrived && (u->current_order.flags & OF_TRANSFER) && v->cargo_paid_for < v->cargo_count) { + virtual_profit = GetTransportedGoodsIncome( + v->cargo_count - v->cargo_paid_for, + /* pay transfer vehicle for only the part of transfer it has done: ie. cargo_loaded_at_xy to here */ + DistanceManhattan(v->cargo_loaded_at_xy, GetStation(last_visited)->xy), + v->cargo_days, + v->cargo_type); + + ge->feeder_profit += v->cargo_feeder_share; // transfer cargo transfer fees to station + total_cargo_feeder_share -= v->cargo_feeder_share; // accumulate deduction of feeder shares + v->cargo_feeder_share = 0; // clear transfer cost + + /* keep total of cargo unloaded (pending) for accurate cargoshare calculation on load */ + SB(ge->unload_pending, 0, 12, GB(ge->unload_pending, 0, 12) + v->cargo_count); + + virtual_profit_total += virtual_profit; // accumulate transfer profits for whole vehicle + v->cargo_paid_for = v->cargo_count; // record how much of the cargo has been paid for to eliminate double counting } unloading_time += v->cargo_count; @@ -1429,9 +1451,13 @@ int LoadUnloadVehicle(Vehicle *v, bool just_arrived) /* Update amount of waiting cargo */ SB(ge->waiting_acceptance, 0, 12, min(amount_unloaded + t, 0xFFF)); + /* if there is not enough to unload from pending, ensure it does not go -ve + * else deduct amount actually unloaded from unload_pending */ + SB(ge->unload_pending, 0, 12, max(GB(ge->unload_pending, 0, 12) - amount_unloaded, 0)); + if (u->current_order.flags & OF_TRANSFER) { - ge->feeder_profit += v_profit; - u->profit_this_year += v_profit; + ge->feeder_profit += virtual_profit; + u->profit_this_year += virtual_profit; } result |= 2; v->cargo_count -= amount_unloaded; @@ -1468,8 +1494,6 @@ int LoadUnloadVehicle(Vehicle *v, bool just_arrived) * has capacity for it, load it on the vehicle. */ if (count != 0 && (cap = v->cargo_cap - v->cargo_count) != 0) { - int cargoshare; - int feeder_profit_share; if (v->cargo_count == 0) TriggerVehicle(v, VEHICLE_TRIGGER_NEW_CARGO); @@ -1490,11 +1514,20 @@ int LoadUnloadVehicle(Vehicle *v, bool just_arrived) if (cap > count) cap = count; if (_patches.gradual_loading) cap = min(cap, load_amount); if (cap < count) CLRBIT(u->vehicle_flags, VF_LOADING_FINISHED); - cargoshare = cap * 10000 / ge->waiting_acceptance; - feeder_profit_share = ge->feeder_profit * cargoshare / 10000; + + /* cargoshare is proportioned by the amount due to unload + * Otherwise, with gradual loading, 100% of credits would be taken immediately, + * even if the cargo volume represents a tiny percent of the whole. + * ge->unload_pending holds the amount that has been credited, but has not yet been unloaded. + */ + int cargoshare = cap * 10000 / (ge->waiting_acceptance + ge->unload_pending); + int feeder_profit_share = ge->feeder_profit * cargoshare / 10000; v->cargo_count += cap; ge->waiting_acceptance -= cap; - u->profit_this_year -= feeder_profit_share; + + total_cargo_feeder_share += feeder_profit_share; // store cost for later payment when cargo unloaded + v->cargo_loaded_at_xy = st->xy; // retains location of where the cargo was picked up for intermediate payments + ge->feeder_profit -= feeder_profit_share; unloading_time += cap; st->time_since_load = 0; @@ -1510,6 +1543,10 @@ int LoadUnloadVehicle(Vehicle *v, bool just_arrived) v = u; + /* Ensure a negative total is only applied to the vehicle if there is value to reduce. */ + if (!((v->cargo_feeder_share == 0) && (total_cargo_feeder_share < 0))) + v->cargo_feeder_share += total_cargo_feeder_share; + if (_patches.gradual_loading) { /* The time it takes to load one 'slice' of cargo or passengers depends * on the vehicle type - the values here are those found in TTDPatch */ @@ -1525,8 +1562,8 @@ int LoadUnloadVehicle(Vehicle *v, bool just_arrived) } } - if (v_profit_total > 0) { - ShowFeederIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, v_profit_total); + if (virtual_profit_total > 0) { + ShowFeederIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, virtual_profit_total); } if (v->type == VEH_Train) { @@ -1550,15 +1587,15 @@ int LoadUnloadVehicle(Vehicle *v, bool just_arrived) if (result & 2) InvalidateWindow(WC_STATION_VIEW, last_visited); - if (profit != 0) { - v->profit_this_year += profit; - SubtractMoneyFromPlayer(-profit); + if (route_profit != 0) { + v->profit_this_year += total_veh_profit; + SubtractMoneyFromPlayer(-route_profit); if (IsLocalPlayer() && !PlayVehicleSound(v, VSE_LOAD_UNLOAD)) { SndPlayVehicleFx(SND_14_CASHTILL, v); } - ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, -profit); + ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, -total_veh_profit); } } diff --git a/src/lang/english.txt b/src/lang/english.txt index b540d8a50a..90109bcac6 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -3143,3 +3143,5 @@ STR_DATE_SHORT :{STRING} {NUM} STR_DATE_LONG :{STRING} {STRING} {NUM} ######## + +STR_FEEDER_CARGO_VALUE :{BLACK}Transfer Credits: {LTBLUE}{CURRENCY} diff --git a/src/roadveh_gui.cpp b/src/roadveh_gui.cpp index d9dd3bc98f..5f32c3c50f 100644 --- a/src/roadveh_gui.cpp +++ b/src/roadveh_gui.cpp @@ -78,7 +78,7 @@ static void RoadVehDetailsWndProc(Window *w, WindowEvent *e) { SetDParam(0, v->service_interval); SetDParam(1, v->date_of_last_service); - DrawString(13, 90, _patches.servint_ispercent?STR_SERVICING_INTERVAL_PERCENT:STR_883C_SERVICING_INTERVAL_DAYS, 0); + DrawString(13, 102, _patches.servint_ispercent?STR_SERVICING_INTERVAL_PERCENT:STR_883C_SERVICING_INTERVAL_DAYS, 0); } DrawRoadVehImage(v, 3, 57, INVALID_VEHICLE); @@ -100,6 +100,11 @@ static void RoadVehDetailsWndProc(Window *w, WindowEvent *e) str = STR_8813_FROM; } DrawString(34, 78, str, 0); + + /* Draw Transfer credits text */ + SetDParam(0, v->cargo_feeder_share); + DrawString(34, 89, STR_FEEDER_CARGO_VALUE, 0); + } break; case WE_CLICK: { @@ -144,15 +149,15 @@ static const Widget _roadveh_details_widgets[] = { { WWT_CAPTION, RESIZE_NONE, 14, 11, 339, 0, 13, STR_900C_DETAILS, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 340, 379, 0, 13, STR_01AA_NAME, STR_902E_NAME_ROAD_VEHICLE}, { WWT_PANEL, RESIZE_NONE, 14, 0, 379, 14, 55, 0x0, STR_NULL}, -{ WWT_PANEL, RESIZE_NONE, 14, 0, 379, 56, 88, 0x0, STR_NULL}, -{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 0, 10, 89, 94, STR_0188, STR_884D_INCREASE_SERVICING_INTERVAL}, -{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 0, 10, 95, 100, STR_0189, STR_884E_DECREASE_SERVICING_INTERVAL}, -{ WWT_PANEL, RESIZE_NONE, 14, 11, 379, 89, 100, 0x0, STR_NULL}, +{ WWT_PANEL, RESIZE_NONE, 14, 0, 379, 56, 100, 0x0, STR_NULL}, +{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 0, 10, 101, 106, STR_0188, STR_884D_INCREASE_SERVICING_INTERVAL}, +{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 0, 10, 107, 112, STR_0189, STR_884E_DECREASE_SERVICING_INTERVAL}, +{ WWT_PANEL, RESIZE_NONE, 14, 11, 379, 101, 112, 0x0, STR_NULL}, { WIDGETS_END}, }; static const WindowDesc _roadveh_details_desc = { - WDP_AUTO, WDP_AUTO, 380, 101, + WDP_AUTO, WDP_AUTO, 380, 113, WC_VEHICLE_DETAILS,WC_VEHICLE_VIEW, WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS, _roadveh_details_widgets, diff --git a/src/saveload.cpp b/src/saveload.cpp index ccb96d0692..509fe6f46a 100644 --- a/src/saveload.cpp +++ b/src/saveload.cpp @@ -28,7 +28,7 @@ #include "variables.h" #include -extern const uint16 SAVEGAME_VERSION = 50; +extern const uint16 SAVEGAME_VERSION = 51; uint16 _sl_version; ///< the major savegame version identifier byte _sl_minor_version; ///< the minor savegame version, DO NOT USE! diff --git a/src/ship_gui.cpp b/src/ship_gui.cpp index 0215ec3275..6d656630f5 100644 --- a/src/ship_gui.cpp +++ b/src/ship_gui.cpp @@ -76,7 +76,7 @@ static void ShipDetailsWndProc(Window *w, WindowEvent *e) { SetDParam(0, v->service_interval); SetDParam(1, v->date_of_last_service); - DrawString(13, 90, _patches.servint_ispercent?STR_SERVICING_INTERVAL_PERCENT:STR_883C_SERVICING_INTERVAL_DAYS, 0); + DrawString(13, 102, _patches.servint_ispercent?STR_SERVICING_INTERVAL_PERCENT:STR_883C_SERVICING_INTERVAL_DAYS, 0); } DrawShipImage(v, 3, 57, INVALID_VEHICLE); @@ -98,6 +98,11 @@ static void ShipDetailsWndProc(Window *w, WindowEvent *e) str = STR_8813_FROM; } DrawString(74, 78, str, 0); + + /* Draw Transfer credits text */ + SetDParam(0, v->cargo_feeder_share); + DrawString(74, 89, STR_FEEDER_CARGO_VALUE, 0); + } break; case WE_CLICK: { @@ -141,15 +146,15 @@ static const Widget _ship_details_widgets[] = { { WWT_CAPTION, RESIZE_NONE, 14, 11, 364, 0, 13, STR_9811_DETAILS, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 365, 404, 0, 13, STR_01AA_NAME, STR_982F_NAME_SHIP}, { WWT_PANEL, RESIZE_NONE, 14, 0, 404, 14, 55, 0x0, STR_NULL}, -{ WWT_PANEL, RESIZE_NONE, 14, 0, 404, 56, 88, 0x0, STR_NULL}, -{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 0, 10, 89, 94, STR_0188, STR_884D_INCREASE_SERVICING_INTERVAL}, -{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 0, 10, 95, 100, STR_0189, STR_884E_DECREASE_SERVICING_INTERVAL}, -{ WWT_PANEL, RESIZE_NONE, 14, 11, 404, 89, 100, 0x0, STR_NULL}, +{ WWT_PANEL, RESIZE_NONE, 14, 0, 404, 56, 100, 0x0, STR_NULL}, +{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 0, 10, 101, 106, STR_0188, STR_884D_INCREASE_SERVICING_INTERVAL}, +{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 0, 10, 107, 112, STR_0189, STR_884E_DECREASE_SERVICING_INTERVAL}, +{ WWT_PANEL, RESIZE_NONE, 14, 11, 404, 101, 112, 0x0, STR_NULL}, { WIDGETS_END}, }; static const WindowDesc _ship_details_desc = { - WDP_AUTO, WDP_AUTO, 405, 101, + WDP_AUTO, WDP_AUTO, 405, 113, WC_VEHICLE_DETAILS,WC_VEHICLE_VIEW, WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS, _ship_details_widgets, diff --git a/src/station.h b/src/station.h index d800c24ab0..4cadcd89dd 100644 --- a/src/station.h +++ b/src/station.h @@ -15,6 +15,7 @@ static const StationID INVALID_STATION = 0xFFFF; typedef struct GoodsEntry { GoodsEntry() : waiting_acceptance(0), + unload_pending(0), days_since_pickup(0), rating(175), enroute_from(INVALID_STATION), @@ -25,6 +26,7 @@ typedef struct GoodsEntry { {} uint16 waiting_acceptance; + uint16 unload_pending; ///< records how much cargo is awaiting transfer during gradual loading to allow correct fee calc byte days_since_pickup; byte rating; StationID enroute_from; diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 7bf37354c2..80879e7356 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -2764,6 +2764,7 @@ static const SaveLoad _station_desc[] = { static const SaveLoad _goods_desc[] = { SLE_VAR(GoodsEntry, waiting_acceptance, SLE_UINT16), + SLE_CONDVAR(GoodsEntry, unload_pending, SLE_UINT16, 51, SL_MAX_VERSION), SLE_VAR(GoodsEntry, days_since_pickup, SLE_UINT8), SLE_VAR(GoodsEntry, rating, SLE_UINT8), SLE_CONDVAR(GoodsEntry, enroute_from, SLE_FILE_U8 | SLE_VAR_U16, 0, 6), diff --git a/src/train_gui.cpp b/src/train_gui.cpp index 8fbe33bc48..fcdc35bfe0 100644 --- a/src/train_gui.cpp +++ b/src/train_gui.cpp @@ -503,6 +503,8 @@ static void DrawTrainDetailsWindow(Window *w) DrawString(x, y + 2, FreightWagonMult(i) > 1 ? STR_TOTAL_CAPACITY_MULT : STR_013F_TOTAL_CAPACITY, 0); } } + SetDParam(0, v->cargo_feeder_share); + DrawString(x, y + 15, STR_FEEDER_CARGO_VALUE, 0); } } diff --git a/src/vehicle.cpp b/src/vehicle.cpp index bcca91fe35..04a153a95e 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -3053,6 +3053,8 @@ extern const SaveLoad _common_veh_desc[] = { SLE_VAR(Vehicle, profit_this_year, SLE_INT32), SLE_VAR(Vehicle, profit_last_year, SLE_INT32), + SLE_CONDVAR(Vehicle, cargo_feeder_share, SLE_INT32, 51, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, cargo_loaded_at_xy, SLE_UINT32, 51, SL_MAX_VERSION), SLE_VAR(Vehicle, value, SLE_UINT32), SLE_VAR(Vehicle, random_bits, SLE_UINT8), diff --git a/src/vehicle.h b/src/vehicle.h index 7ae508e0b5..7ae41eb6a3 100644 --- a/src/vehicle.h +++ b/src/vehicle.h @@ -298,6 +298,8 @@ struct Vehicle { int32 profit_this_year; int32 profit_last_year; + int32 cargo_feeder_share; ///< value of feeder pickup to be paid for on delivery of cargo + TileIndex cargo_loaded_at_xy; ///< tile index where feeder cargo was loaded uint32 value; union {