summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authortruelight <truelight@openttd.org>2007-06-21 16:17:47 +0000
committertruelight <truelight@openttd.org>2007-06-21 16:17:47 +0000
commit56eb1738ee6de39367047a3cd0f20011560eb393 (patch)
tree9a8cf5e86397687ed30d3da2567447b1d843509d /src
parent2792019b78fbfd10702b93a2d570562397cf8cb2 (diff)
downloadopenttd-56eb1738ee6de39367047a3cd0f20011560eb393.tar.xz
(svn r10254) -Feature: loading indicator, which shows in % how full a vehicle is while loading/unloading (TheJosh)
Diffstat (limited to 'src')
-rw-r--r--src/economy.cpp10
-rw-r--r--src/functions.h10
-rw-r--r--src/gfx.cpp1
-rw-r--r--src/lang/english.txt5
-rw-r--r--src/misc_gui.cpp23
-rw-r--r--src/openttd.h1
-rw-r--r--src/settings.cpp1
-rw-r--r--src/settings_gui.cpp1
-rw-r--r--src/texteff.cpp86
-rw-r--r--src/texteff.hpp35
-rw-r--r--src/transparency_gui.cpp10
-rw-r--r--src/variables.h1
-rw-r--r--src/vehicle.cpp28
-rw-r--r--src/vehicle.h4
14 files changed, 180 insertions, 36 deletions
diff --git a/src/economy.cpp b/src/economy.cpp
index b12a912e1..9c55781d2 100644
--- a/src/economy.cpp
+++ b/src/economy.cpp
@@ -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) {
diff --git a/src/functions.h b/src/functions.h
index ba6d737e3..7c032b70c 100644
--- a/src/functions.h
+++ b/src/functions.h
@@ -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();
diff --git a/src/gfx.cpp b/src/gfx.cpp
index 4cf2820cf..7d2c9b273 100644
--- a/src/gfx.cpp
+++ b/src/gfx.cpp
@@ -19,6 +19,7 @@
#include "genworld.h"
#include "debug.h"
#include "zoom.hpp"
+#include "texteff.hpp"
#include "blitter/factory.hpp"
#ifdef _DEBUG
diff --git a/src/lang/english.txt b/src/lang/english.txt
index dd9a1ba84..889d8b263 100644
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -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}
diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp
index 5d887cc17..1a5b9bbd8 100644
--- a/src/misc_gui.cpp
+++ b/src/misc_gui.cpp
@@ -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[] = {
diff --git a/src/openttd.h b/src/openttd.h
index a768da3bd..6f2b1556c 100644
--- a/src/openttd.h
+++ b/src/openttd.h
@@ -192,6 +192,7 @@ enum {
TO_BUILDINGS,
TO_BRIDGES,
TO_STRUCTURES,
+ TO_LOADING,
};
/* Landscape types */
diff --git a/src/settings.cpp b/src/settings.cpp
index f0454ad73..7db552a72 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -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 */
diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp
index 000d50f2c..8148f61df 100644
--- a/src/settings_gui.cpp
+++ b/src/settings_gui.cpp
@@ -652,6 +652,7 @@ static const char *_patches_ui[] = {
"scrollwheel_multiplier",
"pause_on_newgame",
"advanced_vehicle_list",
+ "loading_indicators",
"timetable_in_ticks",
};
diff --git a/src/texteff.cpp b/src/texteff.cpp
index 0a35973e1..ca3bdf4cf 100644
--- a/src/texteff.cpp
+++ b/src/texteff.cpp
@@ -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;
diff --git a/src/texteff.hpp b/src/texteff.hpp
new file mode 100644
index 000000000..96971d8ef
--- /dev/null
+++ b/src/texteff.hpp
@@ -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 */
diff --git a/src/transparency_gui.cpp b/src/transparency_gui.cpp
index 889e117f1..4fcf37f44 100644
--- a/src/transparency_gui.cpp
+++ b/src/transparency_gui.cpp
@@ -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,
diff --git a/src/variables.h b/src/variables.h
index de6a0b738..761f5f2a3 100644
--- a/src/variables.h
+++ b/src/variables.h
@@ -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
diff --git a/src/vehicle.cpp b/src/vehicle.cpp
index c00c3fe4a..53bdfdf51 100644
--- a/src/vehicle.cpp
+++ b/src/vehicle.cpp
@@ -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);
}
diff --git a/src/vehicle.h b/src/vehicle.h
index c40017879..9ab0bb6de 100644
--- a/src/vehicle.h
+++ b/src/vehicle.h
@@ -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();