(svn r10254) -Feature: loading indicator, which shows in % how full a vehicle is while loading/unloading (TheJosh)
authortruelight
Thu, 21 Jun 2007 16:17:47 +0000
changeset 7494 99eac2a2cd8b
parent 7493 ab4bd5356d4c
child 7495 3bed6c98b8f3
(svn r10254) -Feature: loading indicator, which shows in % how full a vehicle is while loading/unloading (TheJosh)
src/economy.cpp
src/functions.h
src/gfx.cpp
src/lang/english.txt
src/misc_gui.cpp
src/openttd.h
src/settings.cpp
src/settings_gui.cpp
src/texteff.cpp
src/texteff.hpp
src/transparency_gui.cpp
src/variables.h
src/vehicle.cpp
src/vehicle.h
--- a/src/economy.cpp	Thu Jun 21 16:12:31 2007 +0000
+++ b/src/economy.cpp	Thu Jun 21 16:17:47 2007 +0000
@@ -1718,6 +1718,16 @@
 		}
 	}
 
+	/* Calculate the loading indicator fill percent and display */
+	if (_patches.loading_indicators && _game_mode != GM_MENU && v->owner == _local_player) {
+		int percent = CalcPercentVehicleFilled(v);
+		if (v->fill_percent_te_id == INVALID_TE_ID) {
+			v->fill_percent_te_id = ShowFillingPercent(v->x_pos, v->y_pos, v->z_pos + 20, percent);
+		} else {
+			UpdateFillingPercent(v->fill_percent_te_id, percent);
+		}
+	}
+
 	v->load_unload_time_rem = unloading_time;
 
 	if (completely_empty) {
--- a/src/functions.h	Thu Jun 21 16:12:31 2007 +0000
+++ b/src/functions.h	Thu Jun 21 16:17:47 2007 +0000
@@ -79,16 +79,6 @@
 uint InteractiveRandomRange(uint max);
 
 /* texteff.cpp */
-void MoveAllTextEffects();
-void AddTextEffect(StringID msg, int x, int y, uint16 duration);
-void InitTextEffects();
-void DrawTextEffects(DrawPixelInfo *dpi);
-
-void InitTextMessage();
-void DrawTextMessage();
-void CDECL AddTextMessage(uint16 color, uint8 duration, const char *message, ...);
-void UndrawTextMessage();
-
 bool AddAnimatedTile(TileIndex tile);
 void DeleteAnimatedTile(TileIndex tile);
 void AnimateAnimatedTiles();
--- a/src/gfx.cpp	Thu Jun 21 16:12:31 2007 +0000
+++ b/src/gfx.cpp	Thu Jun 21 16:17:47 2007 +0000
@@ -19,6 +19,7 @@
 #include "genworld.h"
 #include "debug.h"
 #include "zoom.hpp"
+#include "texteff.hpp"
 #include "blitter/factory.hpp"
 
 #ifdef _DEBUG
--- a/src/lang/english.txt	Thu Jun 21 16:12:31 2007 +0000
+++ b/src/lang/english.txt	Thu Jun 21 16:17:47 2007 +0000
@@ -1103,6 +1103,7 @@
 STR_CONFIG_PATCHES_SCROLLWHEEL_MULTIPLIER                       :{LTBLUE}Map scrollwheel speed: {ORANGE}{STRING1}
 STR_CONFIG_PATCHES_PAUSE_ON_NEW_GAME                            :{LTBLUE}Automatically pause when starting a new game: {ORANGE}{STRING1}
 STR_CONFIG_PATCHES_ADVANCED_VEHICLE_LISTS                       :{LTBLUE}Use the advanced vehicle list: {ORANGE}{STRING1}
+STR_CONFIG_PATCHES_LOADING_INDICATORS                           :{LTBLUE}Use loading indicators: {ORANGE}{STRING1}
 STR_CONFIG_PATCHES_TIMETABLE_ALLOW                              :{LTBLUE}Enable timetabling for vehicles: {ORANGE}{STRING1}
 STR_CONFIG_PATCHES_TIMETABLE_IN_TICKS                           :{LTBLUE}Show timetable in ticks rather than days: {ORANGE}{STRING1}
 
@@ -3289,6 +3290,10 @@
 STR_TRANSPARENT_BUILDINGS_DESC                                  :{BLACK}Toggle transparency for buildables like stations, depots, waypoints and catenary
 STR_TRANSPARENT_BRIDGES_DESC                                    :{BLACK}Toggle transparency for bridges
 STR_TRANSPARENT_STRUCTURES_DESC                                 :{BLACK}Toggle transparency for structures like lighthouses and antennas, maybe in future for eyecandy
+STR_TRANSPARENT_LOADING_DESC                                    :{BLACK}Toggle transparency for loading indicators
+
+STR_PERCENT_FULL_SMALL                                          :{TINYFONT}{WHITE}{NUM}%
+STR_PERCENT_FULL                                                :{WHITE}{NUM}%
 
 ##### Mass Order
 STR_GROUP_NAME_FORMAT                                           :Group {COMMA}
--- a/src/misc_gui.cpp	Thu Jun 21 16:12:31 2007 +0000
+++ b/src/misc_gui.cpp	Thu Jun 21 16:17:47 2007 +0000
@@ -633,7 +633,7 @@
 		msg = STR_0803_INCOME;
 	}
 	SetDParamMoney(0, cost);
-	AddTextEffect(msg, pt.x, pt.y, 0x250);
+	AddTextEffect(msg, pt.x, pt.y, 0x250, TE_RISING);
 }
 
 void ShowFeederIncomeAnimation(int x, int y, int z, Money cost)
@@ -641,7 +641,26 @@
 	Point pt = RemapCoords(x,y,z);
 
 	SetDParamMoney(0, cost);
-	AddTextEffect(STR_FEEDER, pt.x, pt.y, 0x250);
+	AddTextEffect(STR_FEEDER, pt.x, pt.y, 0x250, TE_RISING);
+}
+
+TextEffectID ShowFillingPercent(int x, int y, int z, uint8 percent)
+{
+	Point pt = RemapCoords(x, y, z);
+
+	SetDParam(0, percent);
+	return AddTextEffect(STR_PERCENT_FULL, pt.x, pt.y, 0xFFFF, TE_STATIC);
+}
+
+void UpdateFillingPercent(TextEffectID te_id, uint8 percent)
+{
+	SetDParam(0, percent);
+	UpdateTextEffect(te_id, STR_PERCENT_FULL);
+}
+
+void HideFillingPercent(TextEffectID te_id)
+{
+	if (te_id != INVALID_TE_ID) RemoveTextEffect(te_id);
 }
 
 static const Widget _tooltips_widgets[] = {
--- a/src/openttd.h	Thu Jun 21 16:12:31 2007 +0000
+++ b/src/openttd.h	Thu Jun 21 16:17:47 2007 +0000
@@ -192,6 +192,7 @@
 	TO_BUILDINGS,
 	TO_BRIDGES,
 	TO_STRUCTURES,
+	TO_LOADING,
 };
 
 /* Landscape types */
--- a/src/settings.cpp	Thu Jun 21 16:12:31 2007 +0000
+++ b/src/settings.cpp	Thu Jun 21 16:17:47 2007 +0000
@@ -1350,6 +1350,7 @@
 	SDT_BOOL(Patches, pause_on_newgame,              S, 0, false,        STR_CONFIG_PATCHES_PAUSE_ON_NEW_GAME,     NULL),
 	SDT_BOOL(Patches, advanced_vehicle_list,         S, 0, true,         STR_CONFIG_PATCHES_ADVANCED_VEHICLE_LISTS,     NULL),
 	SDT_BOOL(Patches, timetable_in_ticks,            S, 0, false,        STR_CONFIG_PATCHES_TIMETABLE_IN_TICKS,    NULL),
+	SDT_BOOL(Patches, loading_indicators,            S, 0, true,         STR_CONFIG_PATCHES_LOADING_INDICATORS,    RedrawScreen),
 
 	/***************************************************************************/
 	/* Construction section of the GUI-configure patches window */
--- a/src/settings_gui.cpp	Thu Jun 21 16:12:31 2007 +0000
+++ b/src/settings_gui.cpp	Thu Jun 21 16:17:47 2007 +0000
@@ -652,6 +652,7 @@
 	"scrollwheel_multiplier",
 	"pause_on_newgame",
 	"advanced_vehicle_list",
+	"loading_indicators",
 	"timetable_in_ticks",
 };
 
--- a/src/texteff.cpp	Thu Jun 21 16:12:31 2007 +0000
+++ b/src/texteff.cpp	Thu Jun 21 16:17:47 2007 +0000
@@ -19,10 +19,11 @@
 #include "blitter/factory.hpp"
 #include <stdarg.h> /* va_list */
 #include "date.h"
+#include "texteff.hpp"
 
 enum {
 	MAX_TEXTMESSAGE_LENGTH = 200,
-	MAX_TEXT_MESSAGES      =  30,
+	INIT_NUM_TEXT_MESSAGES =  20,
 	MAX_CHAT_MESSAGES      =  10,
 	MAX_ANIMATED_TILES     = 256,
 };
@@ -36,6 +37,7 @@
 	uint16 duration;
 	uint32 params_1;
 	uint32 params_2;
+	TextEffectMode mode;
 };
 
 
@@ -45,12 +47,13 @@
 	Date end_date;
 };
 
-static TextEffect _text_effect_list[MAX_TEXT_MESSAGES];
+static TextEffect *_text_effect_list = NULL;
 static TextMessage _textmsg_list[MAX_CHAT_MESSAGES];
 TileIndex _animated_tile_list[MAX_ANIMATED_TILES];
 
 static bool _textmessage_dirty = false;
 static bool _textmessage_visible = false;
+static uint16 _num_text_effects = INIT_NUM_TEXT_MESSAGES;
 
 /* The chatbox grows from the bottom so the coordinates are pixels from
  * the left and pixels from the bottom. The height is the maximum height */
@@ -261,24 +264,38 @@
 	);
 }
 
-void AddTextEffect(StringID msg, int x, int y, uint16 duration)
+TextEffectID AddTextEffect(StringID msg, int x, int y, uint16 duration, TextEffectMode mode)
 {
 	TextEffect *te;
 	int w;
 	char buffer[100];
+	TextEffectID i;
 
-	if (_game_mode == GM_MENU) return;
+	if (_game_mode == GM_MENU) return INVALID_TE_ID;
 
-	for (te = _text_effect_list; te->string_id != INVALID_STRING_ID; ) {
-		if (++te == endof(_text_effect_list)) return;
+	/* Look for a free spot in the text effect array */
+	for (i = 0; i < _num_text_effects; i++) {
+		if (_text_effect_list[i].string_id == INVALID_STRING_ID) break;
 	}
 
+	/* If there is none found, we grow the array */
+	if (i == _num_text_effects) {
+		_num_text_effects += 25;
+		_text_effect_list = (TextEffect*) realloc(_text_effect_list, _num_text_effects * sizeof(TextEffect));
+		for (; i < _num_text_effects; i++) _text_effect_list[i].string_id = INVALID_STRING_ID;
+		i = _num_text_effects - 1;
+	}
+
+	te = &_text_effect_list[i];
+
+	/* Start defining this object */
 	te->string_id = msg;
 	te->duration = duration;
 	te->y = y - 5;
 	te->bottom = y + 5;
 	te->params_1 = GetDParam(0);
 	te->params_2 = GetDParam(4);
+	te->mode = mode;
 
 	GetString(buffer, msg, lastof(buffer));
 	w = GetStringBoundingBox(buffer).width;
@@ -286,10 +303,38 @@
 	te->x = x - (w >> 1);
 	te->right = x + (w >> 1) - 1;
 	MarkTextEffectAreaDirty(te);
+
+	return i;
+}
+
+void UpdateTextEffect(TextEffectID te_id, StringID msg)
+{
+	assert(te_id < _num_text_effects);
+	TextEffect *te;
+
+	/* Update details */
+	te = &_text_effect_list[te_id];
+	te->string_id = msg;
+	te->params_1 = GetDParam(0);
+	te->params_2 = GetDParam(4);
+
+	MarkTextEffectAreaDirty(te);
+}
+
+void RemoveTextEffect(TextEffectID te_id)
+{
+	assert(te_id < _num_text_effects);
+	TextEffect *te;
+
+	te = &_text_effect_list[te_id];
+	MarkTextEffectAreaDirty(te);
+	te->string_id = INVALID_STRING_ID;
 }
 
 static void MoveTextEffect(TextEffect *te)
 {
+	/* Never expire for duration of 0xFFFF */
+	if (te->duration == 0xFFFF) return;
 	if (te->duration < 8) {
 		te->string_id = INVALID_STRING_ID;
 	} else {
@@ -302,47 +347,48 @@
 
 void MoveAllTextEffects()
 {
-	TextEffect *te;
-
-	for (te = _text_effect_list; te != endof(_text_effect_list); te++) {
-		if (te->string_id != INVALID_STRING_ID) MoveTextEffect(te);
+	for (TextEffectID i = 0; i < _num_text_effects; i++) {
+		TextEffect *te = &_text_effect_list[i];
+		if (te->string_id != INVALID_STRING_ID && te->mode == TE_RISING) MoveTextEffect(te);
 	}
 }
 
 void InitTextEffects()
 {
-	TextEffect *te;
+	if (_text_effect_list == NULL) _text_effect_list = MallocT<TextEffect>(_num_text_effects);
 
-	for (te = _text_effect_list; te != endof(_text_effect_list); te++) {
-		te->string_id = INVALID_STRING_ID;
-	}
+	for (TextEffectID i = 0; i < _num_text_effects; i++) _text_effect_list[i].string_id = INVALID_STRING_ID;
 }
 
 void DrawTextEffects(DrawPixelInfo *dpi)
 {
-	const TextEffect* te;
-
 	switch (dpi->zoom) {
 		case ZOOM_LVL_NORMAL:
-			for (te = _text_effect_list; te != endof(_text_effect_list); te++) {
+			for (TextEffectID i = 0; i < _num_text_effects; i++) {
+				TextEffect *te = &_text_effect_list[i];
 				if (te->string_id != INVALID_STRING_ID &&
 						dpi->left <= te->right &&
 						dpi->top  <= te->bottom &&
 						dpi->left + dpi->width  > te->x &&
 						dpi->top  + dpi->height > te->y) {
-					AddStringToDraw(te->x, te->y, te->string_id, te->params_1, te->params_2);
+					if (te->mode == TE_RISING || (_patches.loading_indicators && !HASBIT(_transparent_opt, TO_LOADING))) {
+						AddStringToDraw(te->x, te->y, te->string_id, te->params_1, te->params_2);
+					}
 				}
 			}
 			break;
 
 		case ZOOM_LVL_OUT_2X:
-			for (te = _text_effect_list; te != endof(_text_effect_list); te++) {
+			for (TextEffectID i = 0; i < _num_text_effects; i++) {
+				TextEffect *te = &_text_effect_list[i];
 				if (te->string_id != INVALID_STRING_ID &&
 						dpi->left <= te->right  * 2 - te->x &&
 						dpi->top  <= te->bottom * 2 - te->y &&
 						dpi->left + dpi->width  > te->x &&
 						dpi->top  + dpi->height > te->y) {
-					AddStringToDraw(te->x, te->y, (StringID)(te->string_id-1), te->params_1, te->params_2);
+					if (te->mode == TE_RISING || (_patches.loading_indicators && !HASBIT(_transparent_opt, TO_LOADING))) {
+						AddStringToDraw(te->x, te->y, (StringID)(te->string_id - 1), te->params_1, te->params_2);
+					}
 				}
 			}
 			break;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/texteff.hpp	Thu Jun 21 16:17:47 2007 +0000
@@ -0,0 +1,35 @@
+/* $Id$ */
+
+#ifndef TEXTEFF_HPP
+#define TEXTEFF_HPP
+
+/**
+ * Text effect modes.
+ */
+enum TextEffectMode {
+	TE_RISING, ///< Make the text effect slowly go upwards
+	TE_STATIC, ///< Keep the text effect static
+
+	INVALID_TE_ID = 0xFFFF,
+};
+
+typedef uint16 TextEffectID;
+
+void MoveAllTextEffects();
+TextEffectID AddTextEffect(StringID msg, int x, int y, uint16 duration, TextEffectMode mode);
+void InitTextEffects();
+void DrawTextEffects(DrawPixelInfo *dpi);
+void UpdateTextEffect(TextEffectID effect_id, StringID msg);
+void RemoveTextEffect(TextEffectID effect_id);
+
+void InitTextMessage();
+void DrawTextMessage();
+void CDECL AddTextMessage(uint16 color, uint8 duration, const char *message, ...);
+void UndrawTextMessage();
+
+/* misc_gui.cpp */
+TextEffectID ShowFillingPercent(int x, int y, int z, uint8 percent);
+void UpdateFillingPercent(TextEffectID te_id, uint8 percent);
+void HideFillingPercent(TextEffectID te_id);
+
+#endif /* TEXTEFF_HPP */
--- a/src/transparency_gui.cpp	Thu Jun 21 16:12:31 2007 +0000
+++ b/src/transparency_gui.cpp	Thu Jun 21 16:17:47 2007 +0000
@@ -23,6 +23,7 @@
 	TTW_WIDGET_BUILDINGS,    ///< Make player buildings and structures transparent
 	TTW_WIDGET_BRIDGES,      ///< Make bridges transparent
 	TTW_WIDGET_STRUCTURES,   ///< Make unmovable structures transparent
+	TTW_WIDGET_LOADING,      ///< Make loading indicators transperent
 	TTW_WIDGET_END,          ///< End of toggle buttons
 };
 
@@ -59,11 +60,11 @@
 
 static const Widget _transparency_widgets[] = {
 { WWT_CLOSEBOX,   RESIZE_NONE,  7,   0,  10,   0,  13, STR_00C5,                 STR_018B_CLOSE_WINDOW},
-{  WWT_CAPTION,   RESIZE_NONE,  7,  11, 162,   0,  13, STR_TRANSPARENCY_TOOLB,   STR_018C_WINDOW_TITLE_DRAG_THIS},
-{WWT_STICKYBOX,   RESIZE_NONE,  7, 163, 174,   0,  13, STR_NULL,                 STR_STICKY_BUTTON},
+{  WWT_CAPTION,   RESIZE_NONE,  7,  11, 184,   0,  13, STR_TRANSPARENCY_TOOLB,   STR_018C_WINDOW_TITLE_DRAG_THIS},
+{WWT_STICKYBOX,   RESIZE_NONE,  7, 185, 196,   0,  13, STR_NULL,                 STR_STICKY_BUTTON},
 
 /* transparency widgets:
- * transparent signs, trees, houses, industries, player's buildings, bridges and unmovable structures */
+ * transparent signs, trees, houses, industries, player's buildings, bridges, unmovable structures and loading indicators */
 {   WWT_IMGBTN,   RESIZE_NONE,  7,   0,  21,  14,  35, SPR_IMG_SIGN,         STR_TRANSPARENT_SIGNS_DESC},
 {   WWT_IMGBTN,   RESIZE_NONE,  7,  22,  43,  14,  35, SPR_IMG_PLANTTREES,   STR_TRANSPARENT_TREES_DESC},
 {   WWT_IMGBTN,   RESIZE_NONE,  7,  44,  65,  14,  35, SPR_IMG_TOWN,         STR_TRANSPARENT_HOUSES_DESC},
@@ -71,12 +72,13 @@
 {   WWT_IMGBTN,   RESIZE_NONE,  7,  88, 109,  14,  35, SPR_IMG_COMPANY_LIST, STR_TRANSPARENT_BUILDINGS_DESC},
 {   WWT_IMGBTN,   RESIZE_NONE,  7, 110, 152,  14,  35, SPR_IMG_BRIDGE,       STR_TRANSPARENT_BRIDGES_DESC},
 {   WWT_IMGBTN,   RESIZE_NONE,  7, 153, 174,  14,  35, SPR_IMG_TRANSMITTER,  STR_TRANSPARENT_STRUCTURES_DESC},
+{   WWT_IMGBTN,   RESIZE_NONE,  7, 175, 196,  14,  35, SPR_IMG_TRAINLIST,    STR_TRANSPARENT_LOADING_DESC},
 
 {   WIDGETS_END},
 };
 
 static const WindowDesc _transparency_desc = {
-	WDP_ALIGN_TBR, 58+36, 175, 36,
+	WDP_ALIGN_TBR, 58+36, 197, 36,
 	WC_TRANSPARENCY_TOOLBAR, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
 	_transparency_widgets,
--- a/src/variables.h	Thu Jun 21 16:12:31 2007 +0000
+++ b/src/variables.h	Thu Jun 21 16:17:47 2007 +0000
@@ -133,6 +133,7 @@
 	byte liveries;                      // Options for displaying company liveries, 0=none, 1=self, 2=all
 	bool prefer_teamchat;               // Choose the chat message target with <ENTER>, true=all players, false=your team
 	bool advanced_vehicle_list;         // Use the "advanced" vehicle list
+	bool loading_indicators;            // Show loading indicators
 
 	uint8 toolbar_pos;                  // position of toolbars, 0=left, 1=center, 2=right
 	uint8 window_snap_radius;           // Windows snap at each other if closer than this
--- a/src/vehicle.cpp	Thu Jun 21 16:12:31 2007 +0000
+++ b/src/vehicle.cpp	Thu Jun 21 16:17:47 2007 +0000
@@ -229,6 +229,7 @@
 	FOR_ALL_VEHICLES(v) {
 		v->UpdateDeltaXY(v->direction);
 
+		v->fill_percent_te_id = INVALID_TE_ID;
 		v->first = NULL;
 		if (v->type == VEH_TRAIN) v->u.rail.first_engine = INVALID_ENGINE;
 		if (v->type == VEH_ROAD)  v->u.road.first_engine = INVALID_ENGINE;
@@ -296,6 +297,7 @@
 	v->depot_list  = NULL;
 	v->random_bits = 0;
 	v->group_id = DEFAULT_GROUP;
+	v->fill_percent_te_id = INVALID_TE_ID;
 
 	return v;
 }
@@ -2263,6 +2265,29 @@
 	return false;
 }
 
+/**
+ * Calculates how full a vehicle is.
+ * @param v The Vehicle to check. For trains, use the first engine.
+ * @return A percentage of how full the Vehicle is.
+ */
+uint8 CalcPercentVehicleFilled(Vehicle *v)
+{
+	int count = 0;
+	int max = 0;
+
+	/* Count up max and used */
+	for (; v != NULL; v = v->next) {
+		count += v->cargo_count;
+		max += v->cargo_cap;
+	}
+
+	/* Train without capacity */
+	if (max == 0) return 100;
+
+	/* Return the percentage */
+	return (count * 100) / max;
+}
+
 void VehicleEnterDepot(Vehicle *v)
 {
 	switch (v->type) {
@@ -3107,6 +3132,9 @@
 	current_order.flags = 0;
 	GetStation(this->last_station_visited)->loading_vehicles.remove(this);
 
+	HideFillingPercent(this->fill_percent_te_id);
+	this->fill_percent_te_id = INVALID_TE_ID;
+
 	UpdateVehicleTimetable(this, false);
 }
 
--- a/src/vehicle.h	Thu Jun 21 16:12:31 2007 +0000
+++ b/src/vehicle.h	Thu Jun 21 16:17:47 2007 +0000
@@ -9,6 +9,7 @@
 #include "order.h"
 #include "rail.h"
 #include "road.h"
+#include "texteff.hpp"
 
 /** The returned bits of VehicleEnterTile. */
 enum VehicleEnterTileStatus {
@@ -245,6 +246,8 @@
 	int8 y_offs;             // y offset for vehicle sprite
 	EngineID engine_type;
 
+	TextEffectID fill_percent_te_id; // a text-effect id to a loading indicator object
+
 	/* for randomized variational spritegroups
 	 * bitmask used to resolve them; parts of it get reseeded when triggers
 	 * of corresponding spritegroups get matched */
@@ -506,6 +509,7 @@
 void *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc);
 void CallVehicleTicks();
 Vehicle *FindVehicleOnTileZ(TileIndex tile, byte z);
+uint8 CalcPercentVehicleFilled(Vehicle *v);
 
 void InitializeTrains();
 byte VehicleRandomBits();