changeset 18159:de0749262352 draft

(svn r22984) -Feature: Display profit icons for groups in the group GUI.
author frosch <frosch@openttd.org>
date Mon, 03 Oct 2011 17:25:44 +0000
parents c68ed171b626
children 9fd018e89254
files src/group.h src/group_cmd.cpp src/group_gui.cpp src/train_cmd.cpp src/vehicle.cpp src/vehicle_func.h src/vehicle_gui.cpp
diffstat 7 files changed, 110 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/src/group.h
+++ b/src/group.h
@@ -26,18 +26,29 @@
 	uint16 num_vehicle;                     ///< Number of vehicles.
 	uint16 *num_engines;                    ///< Caches the number of engines of each type the company owns.
 
+	uint16 num_profit_vehicle;              ///< Number of vehicles considered for profit statistics;
+	Money profit_last_year;                 ///< Sum of profits for all vehicles.
+
 	GroupStatistics();
 	~GroupStatistics();
 
 	void Clear();
 
+	void ClearProfits()
+	{
+		this->num_profit_vehicle = 0;
+		this->profit_last_year = 0;
+	}
+
 	static GroupStatistics &Get(CompanyID company, GroupID id_g, VehicleType type);
 	static GroupStatistics &Get(const Vehicle *v);
 	static GroupStatistics &GetAllGroup(const Vehicle *v);
 
 	static void CountVehicle(const Vehicle *v, int delta);
 	static void CountEngine(const Vehicle *v, int delta);
+	static void VehicleReachedProfitAge(const Vehicle *v);
 
+	static void UpdateProfits();
 	static void UpdateAfterLoad();
 };
 
--- a/src/group_cmd.cpp
+++ b/src/group_cmd.cpp
@@ -48,6 +48,8 @@
 void GroupStatistics::Clear()
 {
 	this->num_vehicle = 0;
+	this->num_profit_vehicle = 0;
+	this->profit_last_year = 0;
 
 	/* This is also called when NewGRF change. So the number of engines might have changed. Reallocate. */
 	free(this->num_engines);
@@ -139,6 +141,13 @@
 
 	stats_all.num_vehicle += delta;
 	stats.num_vehicle += delta;
+
+	if (v->age > VEHICLE_PROFIT_MIN_AGE) {
+		stats_all.num_profit_vehicle += delta;
+		stats_all.profit_last_year += v->GetDisplayProfitLastYear() * delta;
+		stats.num_profit_vehicle += delta;
+		stats.profit_last_year += v->GetDisplayProfitLastYear() * delta;
+	}
 }
 
 /**
@@ -153,6 +162,45 @@
 	GroupStatistics::Get(v).num_engines[v->engine_type] += delta;
 }
 
+/**
+ * Add a vehicle to the profit sum of its group.
+ */
+/* static */ void GroupStatistics::VehicleReachedProfitAge(const Vehicle *v)
+{
+	GroupStatistics &stats_all = GroupStatistics::GetAllGroup(v);
+	GroupStatistics &stats = GroupStatistics::Get(v);
+
+	stats_all.num_profit_vehicle++;
+	stats_all.profit_last_year += v->GetDisplayProfitLastYear();
+	stats.num_profit_vehicle++;
+	stats.profit_last_year += v->GetDisplayProfitLastYear();
+}
+
+/**
+ * Recompute the profits for all groups.
+ */
+/* static */ void GroupStatistics::UpdateProfits()
+{
+	/* Set up the engine count for all companies */
+	Company *c;
+	FOR_ALL_COMPANIES(c) {
+		for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) {
+			c->group_all[type].ClearProfits();
+			c->group_default[type].ClearProfits();
+		}
+	}
+
+	/* Recalculate */
+	Group *g;
+	FOR_ALL_GROUPS(g) {
+		g->statistics.ClearProfits();
+	}
+
+	const Vehicle *v;
+	FOR_ALL_VEHICLES(v) {
+		if (v->IsPrimaryVehicle() && v->age > VEHICLE_PROFIT_MIN_AGE) GroupStatistics::VehicleReachedProfitAge(v);
+	}
+}
 
 /**
  * Update the num engines of a groupID. Decrease the old one and increase the new one
--- a/src/group_gui.cpp
+++ b/src/group_gui.cpp
@@ -117,6 +117,7 @@
 	/* Columns in the group list */
 	enum ListColumns {
 		VGC_NAME,          ///< Group name.
+		VGC_PROFIT,        ///< Profit icon.
 		VGC_NUMBER,        ///< Number of vehicles in the group.
 
 		VGC_END
@@ -185,6 +186,15 @@
 		this->column_size[VGC_NAME].width = max(170u, this->column_size[VGC_NAME].width);
 		this->tiny_step_height = this->column_size[VGC_NAME].height;
 
+		this->column_size[VGC_PROFIT].width = 0;
+		this->column_size[VGC_PROFIT].height = 0;
+		static const SpriteID profit_sprites[] = {SPR_PROFIT_NA, SPR_PROFIT_NEGATIVE, SPR_PROFIT_SOME, SPR_PROFIT_LOT};
+		for (uint i = 0; i < lengthof(profit_sprites); i++) {
+			Dimension d = GetSpriteSize(profit_sprites[i]);
+			this->column_size[VGC_PROFIT] = maxdim(this->column_size[VGC_PROFIT], d);
+		}
+		this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_PROFIT].height);
+
 		SetDParam(0, GroupStatistics::Get(this->vli.company, ALL_GROUP, this->vli.vtype).num_vehicle > 900 ? 9999 : 999);
 		this->column_size[VGC_NUMBER] = GetStringBoundingBox(STR_TINY_COMMA);
 		this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_NUMBER].height);
@@ -193,6 +203,7 @@
 
 		return WD_FRAMERECT_LEFT + 8 +
 			this->column_size[VGC_NAME].width + 8 +
+			this->column_size[VGC_PROFIT].width + 2 +
 			this->column_size[VGC_NUMBER].width + 2 +
 			WD_FRAMERECT_RIGHT;
 	}
@@ -224,8 +235,22 @@
 		int x = rtl ? right - WD_FRAMERECT_RIGHT - 8 - this->column_size[VGC_NAME].width + 1 : left + WD_FRAMERECT_LEFT + 8;
 		DrawString(x, x + this->column_size[VGC_NAME].width - 1, y + (this->tiny_step_height - this->column_size[VGC_NAME].height) / 2, str, colour);
 
+		/* draw the profit icon */
+		x = rtl ? x - 8 - this->column_size[VGC_PROFIT].width : x + 8 + this->column_size[VGC_NAME].width;
+		SpriteID spr;
+		if (stats.num_profit_vehicle == 0) {
+			spr = SPR_PROFIT_NA;
+		} else if (stats.profit_last_year < 0) {
+			spr = SPR_PROFIT_NEGATIVE;
+		} else if (stats.profit_last_year < 10000 * stats.num_profit_vehicle) { // TODO magic number
+			spr = SPR_PROFIT_SOME;
+		} else {
+			spr = SPR_PROFIT_LOT;
+		}
+		DrawSprite(spr, PAL_NONE, x, y + (this->tiny_step_height - this->column_size[VGC_PROFIT].height) / 2);
+
 		/* draw the number of vehicles of the group */
-		x = rtl ? x - 8 - this->column_size[VGC_NUMBER].width : x + 8 + this->column_size[VGC_NAME].width;
+		x = rtl ? x - 2 - this->column_size[VGC_NUMBER].width : x + 2 + this->column_size[VGC_PROFIT].width;
 		SetDParam(0, stats.num_vehicle);
 		DrawString(x, x + this->column_size[VGC_NUMBER].width - 1, y + (this->tiny_step_height - this->column_size[VGC_NUMBER].height) / 2, STR_TINY_COMMA, colour, SA_RIGHT | SA_FORCE);
 	}
--- a/src/train_cmd.cpp
+++ b/src/train_cmd.cpp
@@ -1192,6 +1192,12 @@
 	Train *original_src_head = src_head;
 	Train *original_dst_head = (dst_head == src_head ? NULL : dst_head);
 
+	if (flags & DC_EXEC) {
+		/* Remove old heads from the statistics */
+		if (original_src_head != NULL && original_src_head->IsFrontEngine()) GroupStatistics::CountVehicle(original_src_head, -1);
+		if (original_dst_head != NULL && original_dst_head->IsFrontEngine()) GroupStatistics::CountVehicle(original_dst_head, -1);
+	}
+
 	/* (Re)arrange the trains in the wanted arrangement. */
 	ArrangeTrains(&dst_head, dst, &src_head, src, move_chain);
 
@@ -1242,18 +1248,6 @@
 			DeleteWindowById(WC_VEHICLE_DETAILS, src->index);
 			DeleteWindowById(WC_VEHICLE_TIMETABLE, src->index);
 
-			/* We are going to be moved to a different train, and
-			 * we were the front engine of the original train. */
-			if (dst_head != NULL && dst_head != src && (src_head == NULL || !src_head->IsFrontEngine())) {
-				GroupStatistics::CountVehicle(src, -1);
-			}
-
-			/* The front engine is going to be moved later in the
-			 * current train, and it will not be a train anymore. */
-			if (dst_head == NULL && !src_head->IsFrontEngine()) {
-				GroupStatistics::CountVehicle(src, -1);
-			}
-
 			/* Delete orders, group stuff and the unit number as we're not the
 			 * front of any vehicle anymore. */
 			DeleteVehicleOrders(src);
@@ -1261,18 +1255,16 @@
 			src->unitnumber = 0;
 		}
 
-		/* We were a front engine and we are becoming one for a different train.
-		 * Increase the group counter accordingly. */
-		if (original_src_head == src && dst_head == src) {
-			GroupStatistics::CountVehicle(src, 1);
-		}
-
 		/* We weren't a front engine but are becoming one. So
 		 * we should be put in the default group. */
 		if (original_src_head != src && dst_head == src) {
 			SetTrainGroupID(src, DEFAULT_GROUP);
 		}
 
+		/* Add new heads to statistics */
+		if (src_head != NULL && src_head->IsFrontEngine()) GroupStatistics::CountVehicle(src_head, 1);
+		if (dst_head != NULL && dst_head->IsFrontEngine()) GroupStatistics::CountVehicle(dst_head, 1);
+
 		/* Handle 'new engine' part of cases #1b, #2b, #3b, #4b and #5 in NormaliseTrainHead. */
 		NormaliseTrainHead(src_head);
 		NormaliseTrainHead(dst_head);
@@ -1354,7 +1346,7 @@
 
 			/* Copy other important data from the front engine */
 			new_head->CopyVehicleConfigAndStatistics(first);
-			GroupStatistics::CountVehicle(new_head, 1);
+			GroupStatistics::CountVehicle(new_head, 1); // after copying over the profit
 
 			/* If we deleted a window then open a new one for the 'new' train */
 			if (IsLocalCompany() && w != NULL) ShowVehicleViewWindow(new_head);
--- a/src/vehicle.cpp
+++ b/src/vehicle.cpp
@@ -1137,7 +1137,10 @@
  */
 void AgeVehicle(Vehicle *v)
 {
-	if (v->age < MAX_DAY) v->age++;
+	if (v->age < MAX_DAY) {
+		v->age++;
+		if (v->IsPrimaryVehicle() && v->age == VEHICLE_PROFIT_MIN_AGE + 1) GroupStatistics::VehicleReachedProfitAge(v);
+	}
 
 	if (!v->IsPrimaryVehicle() && (v->type != VEH_TRAIN || !Train::From(v)->IsEngine())) return;
 
@@ -2402,6 +2405,11 @@
 			SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
 		}
 	}
+	GroupStatistics::UpdateProfits();
+	SetWindowClassesDirty(WC_TRAINS_LIST);
+	SetWindowClassesDirty(WC_SHIPS_LIST);
+	SetWindowClassesDirty(WC_ROADVEH_LIST);
+	SetWindowClassesDirty(WC_AIRCRAFT_LIST);
 }
 
 
--- a/src/vehicle_func.h
+++ b/src/vehicle_func.h
@@ -26,6 +26,9 @@
 #define IS_CUSTOM_FIRSTHEAD_SPRITE(x) (x == 0xFD)
 #define IS_CUSTOM_SECONDHEAD_SPRITE(x) (x == 0xFE)
 
+static const int VEHICLE_PROFIT_MIN_AGE = DAYS_IN_YEAR * 2; ///< Only vehicles older than this have a meaningful profit.
+static const Money VEHICLE_PROFIT_THRESHOLD = 10000;        ///< Threshold for a vehicle to be considered making good profit.
+
 typedef Vehicle *VehicleFromPosProc(Vehicle *v, void *data);
 
 void VehicleServiceInDepot(Vehicle *v);
--- a/src/vehicle_gui.cpp
+++ b/src/vehicle_gui.cpp
@@ -193,11 +193,11 @@
 	SpriteID spr;
 
 	/* draw profit-based coloured icons */
-	if (v->age <= DAYS_IN_YEAR * 2) {
+	if (v->age <= VEHICLE_PROFIT_MIN_AGE) {
 		spr = SPR_PROFIT_NA;
 	} else if (v->GetDisplayProfitLastYear() < 0) {
 		spr = SPR_PROFIT_NEGATIVE;
-	} else if (v->GetDisplayProfitLastYear() < 10000) {
+	} else if (v->GetDisplayProfitLastYear() < VEHICLE_PROFIT_THRESHOLD) {
 		spr = SPR_PROFIT_SOME;
 	} else {
 		spr = SPR_PROFIT_LOT;