(svn r8978) -Feature: Rewrite of transfer system.
authorrichk
Fri, 02 Mar 2007 18:49:11 +0000
changeset 6524 44e22a9b2c97
parent 6523 d41352ca5c1e
child 6525 52bebe2b485e
(svn r8978) -Feature: Rewrite of transfer system.
This major feature-fix keeps track of the value of transfers offloaded at a station, and hands on to a loading vehicle a credit note proportionate to the cargo loaded. The transferring vehicle is paid only for the distance it has travelled. eg. B-C in a transfer chain A-B-C-D.
When the final cargo is delivered, these credit notes are cashed, and the final vehicle is paid for A-D minus any credit notes it is carrying. The company bank balance increases by the value of the A-D route.
You still need to set up a profitable route; it is still easy to make a loss on transfers by bad planning. :)
src/aircraft_gui.cpp
src/economy.cpp
src/lang/english.txt
src/roadveh_gui.cpp
src/saveload.cpp
src/ship_gui.cpp
src/station.h
src/station_cmd.cpp
src/train_gui.cpp
src/vehicle.cpp
src/vehicle.h
--- a/src/aircraft_gui.cpp	Fri Mar 02 17:54:52 2007 +0000
+++ b/src/aircraft_gui.cpp	Fri Mar 02 18:49:11 2007 +0000
@@ -106,7 +106,13 @@
 		{
 			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 @@
 {    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,
--- a/src/economy.cpp	Fri Mar 02 17:54:52 2007 +0000
+++ b/src/economy.cpp	Fri Mar 02 18:49:11 2007 +0000
@@ -1331,13 +1331,15 @@
 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 @@
 	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 @@
 				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;
+
+				/* handle transfer */
 				if (just_arrived && (u->current_order.flags & OF_TRANSFER) && v->cargo_paid_for < v->cargo_count) {
-					v_profit = GetTransportedGoodsIncome(
+					virtual_profit = GetTransportedGoodsIncome(
 						v->cargo_count - v->cargo_paid_for,
-						DistanceManhattan(v->cargo_source_xy, GetStation(last_visited)->xy),
+						/* 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) * 3 / 2;
+						v->cargo_type);
 
-					v_profit_total += v_profit;
-					v->cargo_paid_for = v->cargo_count;
+					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 @@
 				/* 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 @@
 		 * 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 @@
 			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 @@
 
 	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 @@
 		}
 	}
 
-	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 @@
 
 		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);
 		}
 	}
 
--- a/src/lang/english.txt	Fri Mar 02 17:54:52 2007 +0000
+++ b/src/lang/english.txt	Fri Mar 02 18:49:11 2007 +0000
@@ -3143,3 +3143,5 @@
 STR_DATE_LONG                                                   :{STRING} {STRING} {NUM}
 
 ########
+
+STR_FEEDER_CARGO_VALUE                                          :{BLACK}Transfer Credits: {LTBLUE}{CURRENCY}
--- a/src/roadveh_gui.cpp	Fri Mar 02 17:54:52 2007 +0000
+++ b/src/roadveh_gui.cpp	Fri Mar 02 18:49:11 2007 +0000
@@ -78,7 +78,7 @@
 		{
 			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 @@
 			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 @@
 {    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,
--- a/src/saveload.cpp	Fri Mar 02 17:54:52 2007 +0000
+++ b/src/saveload.cpp	Fri Mar 02 18:49:11 2007 +0000
@@ -28,7 +28,7 @@
 #include "variables.h"
 #include <setjmp.h>
 
-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!
 
--- a/src/ship_gui.cpp	Fri Mar 02 17:54:52 2007 +0000
+++ b/src/ship_gui.cpp	Fri Mar 02 18:49:11 2007 +0000
@@ -76,7 +76,7 @@
 		{
 			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 @@
 			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 @@
 {    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,
--- a/src/station.h	Fri Mar 02 17:54:52 2007 +0000
+++ b/src/station.h	Fri Mar 02 18:49:11 2007 +0000
@@ -15,6 +15,7 @@
 typedef struct GoodsEntry {
 	GoodsEntry() :
 		waiting_acceptance(0),
+		unload_pending(0),
 		days_since_pickup(0),
 		rating(175),
 		enroute_from(INVALID_STATION),
@@ -25,6 +26,7 @@
 	{}
 
 	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;
--- a/src/station_cmd.cpp	Fri Mar 02 17:54:52 2007 +0000
+++ b/src/station_cmd.cpp	Fri Mar 02 18:49:11 2007 +0000
@@ -2764,6 +2764,7 @@
 
 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),
--- a/src/train_gui.cpp	Fri Mar 02 17:54:52 2007 +0000
+++ b/src/train_gui.cpp	Fri Mar 02 18:49:11 2007 +0000
@@ -503,6 +503,8 @@
 				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);
 	}
 }
 
--- a/src/vehicle.cpp	Fri Mar 02 17:54:52 2007 +0000
+++ b/src/vehicle.cpp	Fri Mar 02 18:49:11 2007 +0000
@@ -3053,6 +3053,8 @@
 
 	    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),
--- a/src/vehicle.h	Fri Mar 02 17:54:52 2007 +0000
+++ b/src/vehicle.h	Fri Mar 02 18:49:11 2007 +0000
@@ -298,6 +298,8 @@
 
 	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 {