(svn r10254) -Feature: loading indicator, which shows in % how full a vehicle is while loading/unloading (TheJosh)

This commit is contained in:
truelight 2007-06-21 16:17:47 +00:00
parent 2792019b78
commit 56eb1738ee
14 changed files with 180 additions and 36 deletions

View File

@ -1718,6 +1718,16 @@ static void LoadUnloadVehicle(Vehicle *v, int *cargo_left)
}
}
/* 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) {

View File

@ -79,16 +79,6 @@ uint32 InteractiveRandom(); // Used for random sequences that are not the same o
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();

View File

@ -19,6 +19,7 @@
#include "genworld.h"
#include "debug.h"
#include "zoom.hpp"
#include "texteff.hpp"
#include "blitter/factory.hpp"
#ifdef _DEBUG

View File

@ -1103,6 +1103,7 @@ STR_CONFIG_PATCHES_SCROLLWHEEL_OFF :Off
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_INDUSTRIES_DESC :{BLACK}Toggle t
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}

View File

@ -633,7 +633,7 @@ void ShowCostOrIncomeAnimation(int x, int y, int z, Money cost)
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 @@ void ShowFeederIncomeAnimation(int x, int y, int z, Money cost)
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[] = {

View File

@ -192,6 +192,7 @@ enum {
TO_BUILDINGS,
TO_BRIDGES,
TO_STRUCTURES,
TO_LOADING,
};
/* Landscape types */

View File

@ -1350,6 +1350,7 @@ const SettingDesc _patch_settings[] = {
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 */

View File

@ -652,6 +652,7 @@ static const char *_patches_ui[] = {
"scrollwheel_multiplier",
"pause_on_newgame",
"advanced_vehicle_list",
"loading_indicators",
"timetable_in_ticks",
};

View File

@ -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 @@ struct TextEffect {
uint16 duration;
uint32 params_1;
uint32 params_2;
TextEffectMode mode;
};
@ -45,12 +47,13 @@ struct TextMessage {
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 @@ static void MarkTextEffectAreaDirty(TextEffect *te)
);
}
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 @@ void AddTextEffect(StringID msg, int x, int y, uint16 duration)
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 @@ static void MoveTextEffect(TextEffect *te)
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;

35
src/texteff.hpp Normal file
View File

@ -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 */

View File

@ -23,6 +23,7 @@ enum TransparencyToolbarWidgets{
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 void TransparencyToolbWndProc(Window *w, WindowEvent *e)
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 @@ static const Widget _transparency_widgets[] = {
{ 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,

View File

@ -133,6 +133,7 @@ struct Patches {
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

View File

@ -229,6 +229,7 @@ void AfterLoadVehicles()
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 @@ static Vehicle *InitializeVehicle(Vehicle *v)
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 @@ bool IsVehicleInDepot(const Vehicle *v)
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 @@ void Vehicle::LeaveStation()
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);
}

View File

@ -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 @@ struct Vehicle {
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 *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc);
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();