(svn r12826) [NoAI] -Sync: with trunk r12780:12824 noai
authorglx
Mon, 21 Apr 2008 21:15:50 +0000
branchnoai
changeset 10294 7798ae816af8
parent 10292 7856e972f8aa
child 10297 433b21fd002c
(svn r12826) [NoAI] -Sync: with trunk r12780:12824
projects/openttd_vs80.sln
projects/openttd_vs80.vcproj
projects/openttd_vs90.vcproj
source.list
src/aircraft.h
src/aircraft_cmd.cpp
src/animated_tile.cpp
src/animated_tile_func.h
src/articulated_vehicles.cpp
src/autoreplace_cmd.cpp
src/cargopacket.h
src/disaster_cmd.cpp
src/economy.cpp
src/effectvehicle.cpp
src/effectvehicle_base.h
src/effectvehicle_func.h
src/engine_func.h
src/functions.h
src/industry_cmd.cpp
src/industry_gui.cpp
src/landscape.cpp
src/lang/english.txt
src/main_gui.cpp
src/misc.cpp
src/newgrf.cpp
src/newgrf_callbacks.h
src/newgrf_generic.cpp
src/newgrf_house.cpp
src/newgrf_house.h
src/newgrf_industrytiles.cpp
src/newgrf_sound.cpp
src/newgrf_sound.h
src/newgrf_spritegroup.cpp
src/newgrf_station.cpp
src/newgrf_station.h
src/news_func.h
src/news_gui.cpp
src/news_type.h
src/oldloader.cpp
src/openttd.cpp
src/openttd.h
src/player_base.h
src/players.cpp
src/rail_cmd.cpp
src/rail_gui.cpp
src/road_cmd.cpp
src/roadveh.h
src/roadveh_cmd.cpp
src/saveload.cpp
src/saveload.h
src/settings.cpp
src/ship.h
src/ship_cmd.cpp
src/smallmap_gui.cpp
src/sound.cpp
src/station_base.h
src/station_cmd.cpp
src/station_gui.cpp
src/strings.cpp
src/strings_func.h
src/texteff.cpp
src/toolbar_gui.cpp
src/town_cmd.cpp
src/town_gui.cpp
src/town_map.h
src/train.h
src/train_cmd.cpp
src/vehicle.cpp
src/vehicle_base.h
src/vehicle_func.h
src/vehicle_gui.cpp
src/vehicle_type.h
src/video/dedicated_v.cpp
src/viewport.cpp
src/viewport_func.h
src/water_cmd.cpp
src/window.cpp
src/window_func.h
src/window_gui.h
src/zoom_func.h
--- a/projects/openttd_vs80.sln	Mon Apr 21 20:52:54 2008 +0000
+++ b/projects/openttd_vs80.sln	Mon Apr 21 21:15:50 2008 +0000
@@ -1,5 +1,5 @@
 Microsoft Visual Studio Solution File, Format Version 9.00
-# Visual Studio 2005
+# Visual C++ Express 2005
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openttd", "openttd_vs80.vcproj", "{668328A0-B40E-4CDB-BD72-D0064424414A}"
 	ProjectSection(ProjectDependencies) = postProject
 		{0F066B23-18DF-4284-8265-F4A5E7E3B966} = {0F066B23-18DF-4284-8265-F4A5E7E3B966}
@@ -23,12 +23,10 @@
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 		{668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|Win32.ActiveCfg = Debug|Win32
 		{668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|Win32.Build.0 = Debug|Win32
-		{668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|x64.ActiveCfg = Debug|x64
-		{668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|x64.Build.0 = Debug|x64
+		{668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|x64.ActiveCfg = Debug|Win32
 		{668328A0-B40E-4CDB-BD72-D0064424414A}.Release|Win32.ActiveCfg = Release|Win32
 		{668328A0-B40E-4CDB-BD72-D0064424414A}.Release|Win32.Build.0 = Release|Win32
-		{668328A0-B40E-4CDB-BD72-D0064424414A}.Release|x64.ActiveCfg = Release|x64
-		{668328A0-B40E-4CDB-BD72-D0064424414A}.Release|x64.Build.0 = Release|x64
+		{668328A0-B40E-4CDB-BD72-D0064424414A}.Release|x64.ActiveCfg = Release|Win32
 		{A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|Win32.ActiveCfg = Debug|Win32
 		{A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|Win32.Build.0 = Debug|Win32
 		{A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|x64.ActiveCfg = Debug|Win32
--- a/projects/openttd_vs80.vcproj	Mon Apr 21 20:52:54 2008 +0000
+++ b/projects/openttd_vs80.vcproj	Mon Apr 21 21:15:50 2008 +0000
@@ -460,6 +460,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\animated_tile.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\articulated_vehicles.cpp"
 				>
 			</File>
@@ -544,6 +548,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\effectvehicle.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\elrail.cpp"
 				>
 			</File>
@@ -816,6 +824,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\animated_tile_func.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\articulated_vehicles.h"
 				>
 			</File>
@@ -964,6 +976,14 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\effectvehicle_func.h"
+				>
+			</File>
+			<File
+				RelativePath=".\..\src\effectvehicle_base.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\core\endian_func.hpp"
 				>
 			</File>
--- a/projects/openttd_vs90.vcproj	Mon Apr 21 20:52:54 2008 +0000
+++ b/projects/openttd_vs90.vcproj	Mon Apr 21 21:15:50 2008 +0000
@@ -457,6 +457,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\animated_tile.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\articulated_vehicles.cpp"
 				>
 			</File>
@@ -541,6 +545,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\effectvehicle.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\elrail.cpp"
 				>
 			</File>
@@ -813,6 +821,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\animated_tile_func.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\articulated_vehicles.h"
 				>
 			</File>
@@ -961,6 +973,14 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\effectvehicle_func.h"
+				>
+			</File>
+			<File
+				RelativePath=".\..\src\effectvehicle_base.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\core\endian_func.hpp"
 				>
 			</File>
--- a/source.list	Mon Apr 21 20:52:54 2008 +0000
+++ b/source.list	Mon Apr 21 21:15:50 2008 +0000
@@ -1,6 +1,7 @@
 # Source Files
 airport.cpp
 core/alloc_func.cpp
+animated_tile.cpp
 articulated_vehicles.cpp
 autoreplace_cmd.cpp
 aystar.cpp
@@ -22,6 +23,7 @@
 driver.cpp
 widgets/dropdown.cpp
 economy.cpp
+effectvehicle.cpp
 elrail.cpp
 engine.cpp
 fileio.cpp
@@ -125,6 +127,7 @@
 airport_movement.h
 core/alloc_func.hpp
 core/alloc_type.hpp
+animated_tile_func.h
 articulated_vehicles.h
 autoreplace_base.h
 autoreplace_func.h
@@ -162,6 +165,8 @@
 widgets/dropdown_type.h
 economy_func.h
 economy_type.h
+effectvehicle_func.h
+effectvehicle_base.h
 core/endian_func.hpp
 engine_func.h
 engine_type.h
--- a/src/aircraft.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/aircraft.h	Mon Apr 21 21:15:50 2008 +0000
@@ -119,7 +119,7 @@
 	ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_AIRCRAFT_INC : EXPENSES_AIRCRAFT_RUN; }
 	WindowClass GetVehicleListWindowClass() const { return WC_AIRCRAFT_LIST; }
 	bool IsPrimaryVehicle() const { return IsNormalAircraft(this); }
-	int GetImage(Direction direction) const;
+	SpriteID GetImage(Direction direction) const;
 	int GetDisplaySpeed() const { return this->cur_speed * 10 / 16; }
 	int GetDisplayMaxSpeed() const { return this->max_speed * 10 / 16; }
 	Money GetRunningCost() const { return AircraftVehInfo(this->engine_type)->running_cost * _price.aircraft_running; }
--- a/src/aircraft_cmd.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/aircraft_cmd.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -37,6 +37,7 @@
 #include "player_func.h"
 #include "settings_type.h"
 #include "order_func.h"
+#include "effectvehicle_func.h"
 
 #include "table/strings.h"
 #include "table/sprites.h"
@@ -160,16 +161,17 @@
 }
 #endif
 
-int Aircraft::GetImage(Direction direction) const
+SpriteID Aircraft::GetImage(Direction direction) const
 {
-	int spritenum = this->spritenum;
+	uint8 spritenum = this->spritenum;
 
 	if (is_custom_sprite(spritenum)) {
-		int sprite = GetCustomVehicleSprite(this, direction);
+		SpriteID sprite = GetCustomVehicleSprite(this, direction);
+		if (sprite != 0) return sprite;
 
-		if (sprite != 0) return sprite;
 		spritenum = _orig_aircraft_vehicle_info[this->engine_type - AIRCRAFT_ENGINES_INDEX].image_index;
 	}
+
 	return direction + _aircraft_sprite[spritenum];
 }
 
@@ -179,31 +181,33 @@
 
 	const Vehicle *w = v->Next()->Next();
 	if (is_custom_sprite(v->spritenum)) {
-		SpriteID spritenum = GetCustomRotorSprite(v, false);
-		if (spritenum != 0) return spritenum;
+		SpriteID sprite = GetCustomRotorSprite(v, false);
+		if (sprite != 0) return sprite;
 	}
 
 	/* Return standard rotor sprites if there are no custom sprites for this helicopter */
 	return SPR_ROTOR_STOPPED + w->u.air.state;
 }
 
-void DrawAircraftEngine(int x, int y, EngineID engine, SpriteID pal)
+static SpriteID GetAircraftIcon(EngineID engine)
 {
-	const AircraftVehicleInfo* avi = AircraftVehInfo(engine);
-	int spritenum = avi->image_index;
-	SpriteID sprite = (6 + _aircraft_sprite[spritenum]);
+	uint8 spritenum = AircraftVehInfo(engine)->image_index;
 
 	if (is_custom_sprite(spritenum)) {
-		sprite = GetCustomVehicleIcon(engine, DIR_W);
-		if (sprite == 0) {
-			spritenum = _orig_aircraft_vehicle_info[engine - AIRCRAFT_ENGINES_INDEX].image_index;
-			sprite = (6 + _aircraft_sprite[spritenum]);
-		}
+		SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W);
+		if (sprite != 0) return sprite;
+
+		spritenum = _orig_aircraft_vehicle_info[engine - AIRCRAFT_ENGINES_INDEX].image_index;
 	}
 
-	DrawSprite(sprite, pal, x, y);
+	return 6 + _aircraft_sprite[spritenum];
+}
 
-	if (!(avi->subtype & AIR_CTOL)) {
+void DrawAircraftEngine(int x, int y, EngineID engine, SpriteID pal)
+{
+	DrawSprite(GetAircraftIcon(engine), pal, x, y);
+
+	if (!(AircraftVehInfo(engine)->subtype & AIR_CTOL)) {
 		SpriteID rotor_sprite = GetCustomRotorIcon(engine);
 		if (rotor_sprite == 0) rotor_sprite = SPR_ROTOR_STOPPED;
 		DrawSprite(rotor_sprite, PAL_NONE, x, y - 5);
@@ -217,21 +221,9 @@
  */
 void GetAircraftSpriteSize(EngineID engine, uint &width, uint &height)
 {
-	const AircraftVehicleInfo* avi = AircraftVehInfo(engine);
-	int spritenum = avi->image_index;
-	SpriteID sprite = (6 + _aircraft_sprite[spritenum]);
+	const Sprite *spr = GetSprite(GetAircraftIcon(engine));
 
-	if (is_custom_sprite(spritenum)) {
-		sprite = GetCustomVehicleIcon(engine, DIR_W);
-		if (sprite == 0) {
-			spritenum = _orig_aircraft_vehicle_info[engine - AIRCRAFT_ENGINES_INDEX].image_index;
-			sprite = (6 + _aircraft_sprite[spritenum]);
-		}
-	}
-
-	const Sprite *spr = GetSprite(sprite);
-
-	width  = spr->width ;
+	width  = spr->width;
 	height = spr->height;
 }
 
@@ -528,7 +520,7 @@
 	/* Check if this aircraft can be started/stopped. The callback will fail or
 	 * return 0xFF if it can. */
 	uint16 callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v);
-	if (callback != CALLBACK_FAILED && callback != 0xFF) {
+	if (callback != CALLBACK_FAILED && GB(callback, 0, 8) != 0xFF) {
 		StringID error = GetGRFStringID(GetEngineGRFID(v->engine_type), 0xD000 + callback);
 		return_cmd_error(error);
 	}
@@ -2089,7 +2081,7 @@
 		if (v->breakdown_ctr <= 2) {
 			HandleBrokenAircraft(v);
 		} else {
-			v->breakdown_ctr--;
+			if (!v->current_order.IsType(OT_LOADING)) v->breakdown_ctr--;
 		}
 	}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/animated_tile.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -0,0 +1,135 @@
+/* $Id$ */
+
+/** @file animated_tile.cpp Everything related to animated tiles. */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "saveload.h"
+#include "landscape.h"
+#include "core/alloc_func.hpp"
+#include "functions.h"
+
+/** The table/list with animated tiles. */
+TileIndex *_animated_tile_list = NULL;
+/** The number of animated tiles in the current state. */
+uint _animated_tile_count = 0;
+/** The number of slots for animated tiles allocated currently. */
+static uint _animated_tile_allocated = 0;
+
+/**
+ * Removes the given tile from the animated tile table.
+ * @param tile the tile to remove
+ */
+void DeleteAnimatedTile(TileIndex tile)
+{
+	for (TileIndex *ti = _animated_tile_list; ti < _animated_tile_list + _animated_tile_count; ti++) {
+		if (tile == *ti) {
+			/* Remove the hole
+			 * The order of the remaining elements must stay the same, otherwise the animation loop
+			 * may miss a tile; that's why we must use memmove instead of just moving the last element.
+			 */
+			memmove(ti, ti + 1, (_animated_tile_list + _animated_tile_count - (ti + 1)) * sizeof(*ti));
+			_animated_tile_count--;
+			MarkTileDirtyByTile(tile);
+			return;
+		}
+	}
+}
+
+/**
+ * Add the given tile to the animated tile table (if it does not exist
+ * on that table yet). Also increases the size of the table if necessary.
+ * @param tile the tile to make animated
+ */
+void AddAnimatedTile(TileIndex tile)
+{
+	MarkTileDirtyByTile(tile);
+
+	for (const TileIndex *ti = _animated_tile_list; ti < _animated_tile_list + _animated_tile_count; ti++) {
+		if (tile == *ti) return;
+	}
+
+	/* Table not large enough, so make it larger */
+	if (_animated_tile_count == _animated_tile_allocated) {
+		_animated_tile_allocated *= 2;
+		_animated_tile_list = ReallocT<TileIndex>(_animated_tile_list, _animated_tile_allocated);
+	}
+
+	_animated_tile_list[_animated_tile_count] = tile;
+	_animated_tile_count++;
+}
+
+/**
+ * Animate all tiles in the animated tile list, i.e.\ call AnimateTile on them.
+ */
+void AnimateAnimatedTiles()
+{
+	const TileIndex *ti = _animated_tile_list;
+	while (ti < _animated_tile_list + _animated_tile_count) {
+		const TileIndex curr = *ti;
+		AnimateTile(curr);
+		/* During the AnimateTile call, DeleteAnimatedTile could have been called,
+		 * deleting an element we've already processed and pushing the rest one
+		 * slot to the left. We can detect this by checking whether the index
+		 * in the current slot has changed - if it has, an element has been deleted,
+		 * and we should process the current slot again instead of going forward.
+		 * NOTE: this will still break if more than one animated tile is being
+		 *       deleted during the same AnimateTile call, but no code seems to
+		 *       be doing this anyway.
+		 */
+		if (*ti == curr) ++ti;
+	}
+}
+
+/**
+ * Initialize all animated tile variables to some known begin point
+ */
+void InitializeAnimatedTiles()
+{
+	_animated_tile_list = ReallocT<TileIndex>(_animated_tile_list, 256);
+	_animated_tile_count = 0;
+	_animated_tile_allocated = 256;
+}
+
+/**
+ * Save the ANIT chunk.
+ */
+static void Save_ANIT()
+{
+	SlSetLength(_animated_tile_count * sizeof(*_animated_tile_list));
+	SlArray(_animated_tile_list, _animated_tile_count, SLE_UINT32);
+}
+
+/**
+ * Load the ANIT chunk; the chunk containing the animated tiles.
+ */
+static void Load_ANIT()
+{
+	/* Before version 80 we did NOT have a variable length animated tile table */
+	if (CheckSavegameVersion(80)) {
+		/* In pre version 6, we has 16bit per tile, now we have 32bit per tile, convert it ;) */
+		SlArray(_animated_tile_list, 256, CheckSavegameVersion(6) ? (SLE_FILE_U16 | SLE_VAR_U32) : SLE_UINT32);
+
+		for (_animated_tile_count = 0; _animated_tile_count < 256; _animated_tile_count++) {
+			if (_animated_tile_list[_animated_tile_count] == 0) break;
+		}
+		return;
+	}
+
+	_animated_tile_count = SlGetFieldLength() / sizeof(*_animated_tile_list);
+
+	/* Determine a nice rounded size for the amount of allocated tiles */
+	_animated_tile_allocated = 256;
+	while (_animated_tile_allocated < _animated_tile_count) _animated_tile_allocated *= 2;
+
+	_animated_tile_list = ReallocT<TileIndex>(_animated_tile_list, _animated_tile_allocated);
+	SlArray(_animated_tile_list, _animated_tile_count, SLE_UINT32);
+}
+
+/**
+ * "Definition" imported by the saveload code to be able to load and save
+ * the animated tile table.
+ */
+extern const ChunkHandler _animated_tile_chunk_handlers[] = {
+	{ 'ANIT', Save_ANIT, Load_ANIT, CH_RIFF | CH_LAST},
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/animated_tile_func.h	Mon Apr 21 21:15:50 2008 +0000
@@ -0,0 +1,15 @@
+/* $Id$ */
+
+/** @file animated_tile.h Tile animation! */
+
+#ifndef ANIMATED_TILE_H
+#define ANIMATED_TILE_H
+
+#include "tile_type.h"
+
+void AddAnimatedTile(TileIndex tile);
+void DeleteAnimatedTile(TileIndex tile);
+void AnimateAnimatedTiles();
+void InitializeAnimatedTiles();
+
+#endif /* ANIMATED_TILE_H */
--- a/src/articulated_vehicles.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/articulated_vehicles.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -25,7 +25,7 @@
 	uint i;
 	for (i = 1; i < MAX_UVALUE(EngineID); i++) {
 		uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, engine_type, v);
-		if (callback == CALLBACK_FAILED || callback == 0xFF) break;
+		if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) break;
 	}
 
 	delete v;
@@ -52,7 +52,7 @@
 
 	for (uint i = 1; i < MAX_UVALUE(EngineID); i++) {
 		uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, engine, NULL);
-		if (callback == CALLBACK_FAILED || callback == 0xFF) break;
+		if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) break;
 
 		EngineID artic_engine = GetFirstEngineOfType(type) + GB(callback, 0, 7);
 
@@ -78,7 +78,7 @@
 
 	for (uint i = 1; i < MAX_UVALUE(EngineID); i++) {
 		uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, v->engine_type, v);
-		if (callback == CALLBACK_FAILED || callback == 0xFF) return;
+		if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) return;
 
 		/* Attempt to use pre-allocated vehicles until they run out. This can happen
 		 * if the callback returns different values depending on the cargo type. */
--- a/src/autoreplace_cmd.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/autoreplace_cmd.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -1,5 +1,7 @@
 /* $Id$ */
 
+/** @file autoreplace_cmd.cpp Deals with autoreplace execution but not the setup */
+
 #include "stdafx.h"
 #include "openttd.h"
 #include "roadveh.h"
@@ -117,31 +119,26 @@
 	return CT_NO_REFIT; // We failed to find a cargo type on the old vehicle and we will not refit the new one
 }
 
-/* Replaces a vehicle (used to be called autorenew)
+/** Replaces a vehicle (used to be called autorenew)
  * This function is only called from MaybeReplaceVehicle()
  * Must be called with _current_player set to the owner of the vehicle
  * @param w Vehicle to replace
  * @param flags is the flags to use when calling DoCommand(). Mainly DC_EXEC counts
+ * @param p The vehicle owner (faster than refinding the pointer)
+ * @param new_engine_type The EngineID to replace to
  * @return value is cost of the replacement or CMD_ERROR
  */
-static CommandCost ReplaceVehicle(Vehicle **w, byte flags, Money total_cost)
+static CommandCost ReplaceVehicle(Vehicle **w, byte flags, Money total_cost, const Player *p, EngineID new_engine_type)
 {
 	CommandCost cost;
 	CommandCost sell_value;
 	Vehicle *old_v = *w;
-	const Player *p = GetPlayer(old_v->owner);
-	EngineID new_engine_type;
 	const UnitID cached_unitnumber = old_v->unitnumber;
 	bool new_front = false;
 	Vehicle *new_v = NULL;
 	char *vehicle_name = NULL;
 	CargoID replacement_cargo_type;
 
-	/* Check if there is a autoreplacement set for the vehicle */
-	new_engine_type = EngineReplacementForPlayer(p, old_v->engine_type, old_v->group_id);
-	/* if not, just renew to the same type */
-	if (new_engine_type == INVALID_ENGINE) new_engine_type = old_v->engine_type;
-
 	replacement_cargo_type = GetNewCargoTypeForReplace(old_v, new_engine_type);
 
 	/* check if we can't refit to the needed type, so no replace takes place to prevent the vehicle from altering cargo type */
@@ -292,21 +289,103 @@
 	return cost;
 }
 
+/** Removes wagons from a train until it get a certain length
+ * @param v The vehicle
+ * @param old_total_length The wanted max length
+ * @return The profit from selling the wagons
+ */
+static CommandCost WagonRemoval(Vehicle *v, uint16 old_total_length)
+{
+	if (v->type != VEH_TRAIN) return CommandCost();
+	Vehicle *front = v;
+
+	CommandCost cost = CommandCost();
+
+	while (front->u.rail.cached_total_length > old_total_length) {
+		/* the train is too long. We will remove cars one by one from the start of the train until it's short enough */
+		while (v != NULL && RailVehInfo(v->engine_type)->railveh_type != RAILVEH_WAGON) {
+			/* We move backwards in the train until we find a wagon */
+			v = GetNextVehicle(v);
+		}
+
+		if (v == NULL) {
+			/* We sold all the wagons and the train is still not short enough */
+			SetDParam(0, front->unitnumber);
+			AddNewsItem(STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT, NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE, front->index, 0);
+			return cost;
+		}
+
+		/* We found a wagon we can sell */
+		Vehicle *temp = v;
+		v = GetNextVehicle(v);
+		DoCommand(0, (INVALID_VEHICLE << 16) | temp->index, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE); // remove the wagon from the train
+		MoveVehicleCargo(front, temp); // move the cargo back on the train
+		cost.AddCost(DoCommand(0, temp->index, 0, DC_EXEC, CMD_SELL_RAIL_WAGON)); // sell the wagon
+	}
+	return cost;
+}
+
+/** Get the EngineID of the replacement for a vehicle
+ * @param v The vehicle to find a replacement for
+ * @param p The vehicle's owner (it's faster to forward the pointer than refinding it)
+ * @return the EngineID of the replacement. INVALID_ENGINE if no buildable replacement is found
+ */
+static EngineID GetNewEngineType(const Vehicle *v, const Player *p)
+{
+	if (v->type == VEH_TRAIN && IsRearDualheaded(v)) {
+		/* we build the rear ends of multiheaded trains with the front ones */
+		return INVALID_ENGINE;
+	}
+
+	EngineID e = EngineReplacementForPlayer(p, v->engine_type, v->group_id);
+
+	if (e != INVALID_ENGINE && IsEngineBuildable(e, v->type, _current_player)) {
+		return e;
+	}
+
+	if (v->NeedsAutorenewing(p) && // replace if engine is too old
+	    IsEngineBuildable(v->engine_type, v->type, _current_player)) { // engine can still be build
+		return v->engine_type;
+	}
+
+	return INVALID_ENGINE;
+}
+
 /** replaces a vehicle if it's set for autoreplace or is too old
  * (used to be called autorenew)
  * @param v The vehicle to replace
  * if the vehicle is a train, v needs to be the front engine
- * @param check Checks if the replace is valid. No action is done at all
- * @param display_costs If set, a cost animation is shown (only if check is false)
- * @return CMD_ERROR if something went wrong. Otherwise the price of the replace
+ * @param flags
+ * @param display_costs If set, a cost animation is shown (only if DC_EXEC is set)
+ *        This bool also takes autorenew money into consideration
+ * @return the costs, the success bool and sometimes an error message
  */
-CommandCost MaybeReplaceVehicle(Vehicle *v, bool check, bool display_costs)
+CommandCost MaybeReplaceVehicle(Vehicle *v, uint32 flags, bool display_costs)
 {
 	Vehicle *w;
 	const Player *p = GetPlayer(v->owner);
-	byte flags = 0;
-	CommandCost cost, temp_cost;
-	bool stopped;
+	CommandCost cost;
+	bool stopped = false;
+
+	/* We only want "real" vehicle types. */
+	assert(IsPlayerBuildableVehicleType(v));
+
+	/* Ensure that this bool is cleared. */
+	assert(!v->leave_depot_instantly);
+
+	/* We can't sell if the current player don't own the vehicle. */
+	assert(v->owner == _current_player);
+
+	if (!v->IsInDepot()) {
+		/* The vehicle should be inside the depot */
+		switch (v->type) {
+			default: NOT_REACHED();
+			case VEH_TRAIN:    return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED); break;
+			case VEH_ROAD:     return_cmd_error(STR_9013_MUST_BE_STOPPED_INSIDE);     break;
+			case VEH_SHIP:     return_cmd_error(STR_980B_SHIP_MUST_BE_STOPPED_IN);    break;
+			case VEH_AIRCRAFT: return_cmd_error(STR_A01B_AIRCRAFT_MUST_BE_STOPPED);   break;
+		}
+	}
 
 	/* Remember the length in case we need to trim train later on
 	 * If it's not a train, the value is unused
@@ -317,38 +396,22 @@
 		-1
 	);
 
-
-	_current_player = v->owner;
-
-	assert(IsPlayerBuildableVehicleType(v));
-
-	assert(v->vehstatus & VS_STOPPED); // the vehicle should have been stopped in VehicleEnteredDepotThisTick() if needed
+	if (!(v->vehstatus & VS_STOPPED)) {
+		/* The vehicle is moving so we better stop it before we might alter consist or sell it */
+		v->vehstatus |= VS_STOPPED;
+		/* Remember that we stopped the vehicle */
+		stopped = true;
+	}
 
-	/* Remember the flag v->leave_depot_instantly because if we replace the vehicle, the vehicle holding this flag will be sold
-	 * If it is set, then we only stopped the vehicle to replace it (if needed) and we will need to start it again.
-	 * We also need to reset the flag since it should remain false except from when the vehicle enters a depot until autoreplace is handled in the same tick */
-	stopped = v->leave_depot_instantly;
-	v->leave_depot_instantly = false;
-
-	for (;;) {
+	{
 		cost = CommandCost(EXPENSES_NEW_VEHICLES);
 		w = v;
 		do {
-			if (w->type == VEH_TRAIN && IsRearDualheaded(w)) {
-				/* we build the rear ends of multiheaded trains with the front ones */
-				continue;
-			}
-
-			// check if the vehicle should be replaced
-			if (!w->NeedsAutorenewing(p) || // replace if engine is too old
-					w->max_age == 0) { // rail cars got a max age of 0
-				if (!EngineHasReplacementForPlayer(p, w->engine_type, w->group_id)) continue;
-			}
+			EngineID new_engine = GetNewEngineType(w, p);
+			if (new_engine == INVALID_ENGINE) continue;
 
 			/* Now replace the vehicle */
-			temp_cost = ReplaceVehicle(&w, flags, cost.GetCost());
-
-			if (CmdFailed(temp_cost)) break; // replace failed for some reason. Leave the vehicle alone
+			cost.AddCost(ReplaceVehicle(&w, flags, cost.GetCost(), p, new_engine));
 
 			if (flags & DC_EXEC &&
 					(w->type != VEH_TRAIN || w->u.rail.first_engine == INVALID_ENGINE)) {
@@ -358,11 +421,26 @@
 				 */
 				v = w;
 			}
-			cost.AddCost(temp_cost);
 		} while (w->type == VEH_TRAIN && (w = GetNextVehicle(w)) != NULL);
 
-		if (!(flags & DC_EXEC) && (p->player_money < (cost.GetCost() + p->engine_renew_money) || cost.GetCost() == 0)) {
-			if (!check && p->player_money < (cost.GetCost() + p->engine_renew_money) && ( _local_player == v->owner ) && cost.GetCost() != 0) {
+		if (flags & DC_QUERY_COST || cost.GetCost() == 0) {
+			/* We didn't do anything during the replace so we will just exit here */
+			if (stopped) v->vehstatus &= ~VS_STOPPED;
+			return cost;
+		}
+
+		if (display_costs && !(flags & DC_EXEC)) {
+			/* We want to ensure that we will not get below p->engine_renew_money.
+			 * We will not actually pay this amount. It's for display and checks only. */
+			cost.AddCost((Money)p->engine_renew_money);
+			if (CmdSucceeded(cost) && GetAvailableMoneyForCommand() < cost.GetCost()) {
+				/* We don't have enough money so we will set cost to failed */
+				cost.AddCost(CMD_ERROR);
+			}
+		}
+
+		if (display_costs && CmdFailed(cost)) {
+			if (GetAvailableMoneyForCommand() < cost.GetCost() && IsLocalPlayer()) {
 				StringID message;
 				SetDParam(0, v->unitnumber);
 				switch (v->type) {
@@ -376,50 +454,22 @@
 
 				AddNewsItem(message, NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, DNC_NONE, v->index, 0);
 			}
-			if (stopped) v->vehstatus &= ~VS_STOPPED;
-			if (display_costs) _current_player = OWNER_NONE;
-			return CMD_ERROR;
-		}
-
-		if (flags & DC_EXEC) {
-			break; // we are done replacing since the loop ran once with DC_EXEC
-		} else if (check) {
-			/* It's a test only and we know that we can do this
-			 * NOTE: payment for wagon removal is NOT included in this price */
-			return cost;
-		}
-		// now we redo the loop, but this time we actually do stuff since we know that we can do it
-		flags |= DC_EXEC;
-	}
-
-	/* If setting is on to try not to exceed the old length of the train with the replacement */
-	if (v->type == VEH_TRAIN && p->renew_keep_length) {
-		Vehicle *temp;
-		w = v;
-
-		while (v->u.rail.cached_total_length > old_total_length) {
-			// the train is too long. We will remove cars one by one from the start of the train until it's short enough
-			while (w != NULL && RailVehInfo(w->engine_type)->railveh_type != RAILVEH_WAGON) {
-				w = GetNextVehicle(w);
-			}
-			if (w == NULL) {
-				// we failed to make the train short enough
-				SetDParam(0, v->unitnumber);
-				AddNewsItem(STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT, NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE, v->index, 0);
-				break;
-			}
-			temp = w;
-			w = GetNextVehicle(w);
-			DoCommand(0, (INVALID_VEHICLE << 16) | temp->index, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
-			MoveVehicleCargo(v, temp);
-			cost.AddCost(DoCommand(0, temp->index, 0, DC_EXEC, CMD_SELL_RAIL_WAGON));
 		}
 	}
 
+	if (flags & DC_EXEC && CmdSucceeded(cost)) {
+		if (v->type == VEH_TRAIN && p->renew_keep_length) {
+			/* Remove wagons until the wanted length is reached */
+			cost.AddCost(WagonRemoval(v, old_total_length));
+		}
+
+		if (display_costs && IsLocalPlayer()) {
+			ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
+		}
+	}
+
+	/* Start the vehicle if we stopped it earlier */
 	if (stopped) v->vehstatus &= ~VS_STOPPED;
-	if (display_costs) {
-		if (IsLocalPlayer()) ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
-		_current_player = OWNER_NONE;
-	}
+
 	return cost;
 }
--- a/src/cargopacket.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/cargopacket.h	Mon Apr 21 21:15:50 2008 +0000
@@ -22,13 +22,13 @@
  * Container for cargo from the same location and time
  */
 struct CargoPacket : PoolItem<CargoPacket, CargoPacketID, &_CargoPacket_pool> {
-	StationID source;       ///< The station where the cargo came from first
+	Money feeder_share;     ///< Value of feeder pickup to be paid for on delivery of cargo
 	TileIndex source_xy;    ///< The origin of the cargo (first station in feeder chain)
 	TileIndex loaded_at_xy; ///< Location where this cargo has been loaded into the vehicle
+	StationID source;       ///< The station where the cargo came from first
 
 	uint16 count;           ///< The amount of cargo in this packet
 	byte days_in_transit;   ///< Amount of days this packet has been in transit
-	Money feeder_share;     ///< Value of feeder pickup to be paid for on delivery of cargo
 	bool paid_for;          ///< Have we been paid for this cargo packet?
 
 	/**
--- a/src/disaster_cmd.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/disaster_cmd.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -39,6 +39,7 @@
 #include "vehicle_func.h"
 #include "vehicle_base.h"
 #include "sound_func.h"
+#include "effectvehicle_func.h"
 
 #include "table/strings.h"
 #include "table/sprites.h"
--- a/src/economy.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/economy.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -26,6 +26,7 @@
 #include "newgrf_callbacks.h"
 #include "newgrf_industries.h"
 #include "newgrf_industrytiles.h"
+#include "newgrf_station.h"
 #include "unmovable.h"
 #include "cargotype.h"
 #include "player_face.h"
@@ -1597,7 +1598,7 @@
 		byte load_amount = EngInfo(v->engine_type)->load_amount;
 		if (_patches.gradual_loading && HasBit(EngInfo(v->engine_type)->callbackmask, CBM_VEHICLE_LOAD_AMOUNT)) {
 			uint16 cb_load_amount = GetVehicleCallback(CBID_VEHICLE_LOAD_AMOUNT, 0, 0, v->engine_type, v);
-			if (cb_load_amount != CALLBACK_FAILED && cb_load_amount != 0) load_amount = cb_load_amount & 0xFF;
+			if (cb_load_amount != CALLBACK_FAILED && GB(cb_load_amount, 0, 8) != 0) load_amount = GB(cb_load_amount, 0, 8);
 		}
 
 		GoodsEntry *ge = &st->goods[v->cargo_type];
@@ -1694,6 +1695,8 @@
 			st->time_since_load = 0;
 			st->last_vehicle_type = v->type;
 
+			StationAnimationTrigger(st, st->xy, STAT_ANIM_CARGO_TAKEN, v->cargo_type);
+
 			unloading_time += cap;
 
 			result |= 2;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/effectvehicle.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -0,0 +1,663 @@
+/* $Id$ */
+
+/** @file vehicle.cpp */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "road_map.h"
+#include "roadveh.h"
+#include "ship.h"
+#include "spritecache.h"
+#include "tile_cmd.h"
+#include "landscape.h"
+#include "timetable.h"
+#include "viewport_func.h"
+#include "gfx_func.h"
+#include "news_func.h"
+#include "command_func.h"
+#include "saveload.h"
+#include "player_func.h"
+#include "debug.h"
+#include "vehicle_gui.h"
+#include "rail_type.h"
+#include "train.h"
+#include "aircraft.h"
+#include "industry_map.h"
+#include "station_map.h"
+#include "water_map.h"
+#include "network/network.h"
+#include "yapf/yapf.h"
+#include "newgrf_callbacks.h"
+#include "newgrf_engine.h"
+#include "newgrf_sound.h"
+#include "group.h"
+#include "order_func.h"
+#include "strings_func.h"
+#include "zoom_func.h"
+#include "functions.h"
+#include "date_func.h"
+#include "window_func.h"
+#include "vehicle_func.h"
+#include "signal_func.h"
+#include "sound_func.h"
+#include "variables.h"
+#include "autoreplace_func.h"
+#include "autoreplace_gui.h"
+#include "string_func.h"
+#include "settings_type.h"
+#include "oldpool_func.h"
+#include "depot_map.h"
+#include "animated_tile_func.h"
+#include "effectvehicle_base.h"
+#include "effectvehicle_func.h"
+
+#include "table/sprites.h"
+#include "table/strings.h"
+
+static void ChimneySmokeInit(Vehicle *v)
+{
+	uint32 r = Random();
+	v->cur_image = SPR_CHIMNEY_SMOKE_0 + GB(r, 0, 3);
+	v->progress = GB(r, 16, 3);
+}
+
+static void ChimneySmokeTick(Vehicle *v)
+{
+	if (v->progress > 0) {
+		v->progress--;
+	} else {
+		BeginVehicleMove(v);
+
+		TileIndex tile = TileVirtXY(v->x_pos, v->y_pos);
+		if (!IsTileType(tile, MP_INDUSTRY)) {
+			EndVehicleMove(v);
+			delete v;
+			return;
+		}
+
+		if (v->cur_image != SPR_CHIMNEY_SMOKE_7) {
+			v->cur_image++;
+		} else {
+			v->cur_image = SPR_CHIMNEY_SMOKE_0;
+		}
+		v->progress = 7;
+		VehiclePositionChanged(v);
+		EndVehicleMove(v);
+	}
+}
+
+static void SteamSmokeInit(Vehicle *v)
+{
+	v->cur_image = SPR_STEAM_SMOKE_0;
+	v->progress = 12;
+}
+
+static void SteamSmokeTick(Vehicle *v)
+{
+	bool moved = false;
+
+	BeginVehicleMove(v);
+
+	v->progress++;
+
+	if ((v->progress & 7) == 0) {
+		v->z_pos++;
+		moved = true;
+	}
+
+	if ((v->progress & 0xF) == 4) {
+		if (v->cur_image != SPR_STEAM_SMOKE_4) {
+			v->cur_image++;
+		} else {
+			EndVehicleMove(v);
+			delete v;
+			return;
+		}
+		moved = true;
+	}
+
+	if (moved) {
+		VehiclePositionChanged(v);
+		EndVehicleMove(v);
+	}
+}
+
+static void DieselSmokeInit(Vehicle *v)
+{
+	v->cur_image = SPR_DIESEL_SMOKE_0;
+	v->progress = 0;
+}
+
+static void DieselSmokeTick(Vehicle *v)
+{
+	v->progress++;
+
+	if ((v->progress & 3) == 0) {
+		BeginVehicleMove(v);
+		v->z_pos++;
+		VehiclePositionChanged(v);
+		EndVehicleMove(v);
+	} else if ((v->progress & 7) == 1) {
+		BeginVehicleMove(v);
+		if (v->cur_image != SPR_DIESEL_SMOKE_5) {
+			v->cur_image++;
+			VehiclePositionChanged(v);
+			EndVehicleMove(v);
+		} else {
+			EndVehicleMove(v);
+			delete v;
+		}
+	}
+}
+
+static void ElectricSparkInit(Vehicle *v)
+{
+	v->cur_image = SPR_ELECTRIC_SPARK_0;
+	v->progress = 1;
+}
+
+static void ElectricSparkTick(Vehicle *v)
+{
+	if (v->progress < 2) {
+		v->progress++;
+	} else {
+		v->progress = 0;
+		BeginVehicleMove(v);
+		if (v->cur_image != SPR_ELECTRIC_SPARK_5) {
+			v->cur_image++;
+			VehiclePositionChanged(v);
+			EndVehicleMove(v);
+		} else {
+			EndVehicleMove(v);
+			delete v;
+		}
+	}
+}
+
+static void SmokeInit(Vehicle *v)
+{
+	v->cur_image = SPR_SMOKE_0;
+	v->progress = 12;
+}
+
+static void SmokeTick(Vehicle *v)
+{
+	bool moved = false;
+
+	BeginVehicleMove(v);
+
+	v->progress++;
+
+	if ((v->progress & 3) == 0) {
+		v->z_pos++;
+		moved = true;
+	}
+
+	if ((v->progress & 0xF) == 4) {
+		if (v->cur_image != SPR_SMOKE_4) {
+			v->cur_image++;
+		} else {
+			EndVehicleMove(v);
+			delete v;
+			return;
+		}
+		moved = true;
+	}
+
+	if (moved) {
+		VehiclePositionChanged(v);
+		EndVehicleMove(v);
+	}
+}
+
+static void ExplosionLargeInit(Vehicle *v)
+{
+	v->cur_image = SPR_EXPLOSION_LARGE_0;
+	v->progress = 0;
+}
+
+static void ExplosionLargeTick(Vehicle *v)
+{
+	v->progress++;
+	if ((v->progress & 3) == 0) {
+		BeginVehicleMove(v);
+		if (v->cur_image != SPR_EXPLOSION_LARGE_F) {
+			v->cur_image++;
+			VehiclePositionChanged(v);
+			EndVehicleMove(v);
+		} else {
+			EndVehicleMove(v);
+			delete v;
+		}
+	}
+}
+
+static void BreakdownSmokeInit(Vehicle *v)
+{
+	v->cur_image = SPR_BREAKDOWN_SMOKE_0;
+	v->progress = 0;
+}
+
+static void BreakdownSmokeTick(Vehicle *v)
+{
+	v->progress++;
+	if ((v->progress & 7) == 0) {
+		BeginVehicleMove(v);
+		if (v->cur_image != SPR_BREAKDOWN_SMOKE_3) {
+			v->cur_image++;
+		} else {
+			v->cur_image = SPR_BREAKDOWN_SMOKE_0;
+		}
+		VehiclePositionChanged(v);
+		EndVehicleMove(v);
+	}
+
+	v->u.effect.animation_state--;
+	if (v->u.effect.animation_state == 0) {
+		BeginVehicleMove(v);
+		EndVehicleMove(v);
+		delete v;
+	}
+}
+
+static void ExplosionSmallInit(Vehicle *v)
+{
+	v->cur_image = SPR_EXPLOSION_SMALL_0;
+	v->progress = 0;
+}
+
+static void ExplosionSmallTick(Vehicle *v)
+{
+	v->progress++;
+	if ((v->progress & 3) == 0) {
+		BeginVehicleMove(v);
+		if (v->cur_image != SPR_EXPLOSION_SMALL_B) {
+			v->cur_image++;
+			VehiclePositionChanged(v);
+			EndVehicleMove(v);
+		} else {
+			EndVehicleMove(v);
+			delete v;
+		}
+	}
+}
+
+static void BulldozerInit(Vehicle *v)
+{
+	v->cur_image = SPR_BULLDOZER_NE;
+	v->progress = 0;
+	v->u.effect.animation_state = 0;
+	v->u.effect.animation_substate = 0;
+}
+
+struct BulldozerMovement {
+	byte direction:2;
+	byte image:2;
+	byte duration:3;
+};
+
+static const BulldozerMovement _bulldozer_movement[] = {
+	{ 0, 0, 4 },
+	{ 3, 3, 4 },
+	{ 2, 2, 7 },
+	{ 0, 2, 7 },
+	{ 1, 1, 3 },
+	{ 2, 2, 7 },
+	{ 0, 2, 7 },
+	{ 1, 1, 3 },
+	{ 2, 2, 7 },
+	{ 0, 2, 7 },
+	{ 3, 3, 6 },
+	{ 2, 2, 6 },
+	{ 1, 1, 7 },
+	{ 3, 1, 7 },
+	{ 0, 0, 3 },
+	{ 1, 1, 7 },
+	{ 3, 1, 7 },
+	{ 0, 0, 3 },
+	{ 1, 1, 7 },
+	{ 3, 1, 7 }
+};
+
+static const struct {
+	int8 x;
+	int8 y;
+} _inc_by_dir[] = {
+	{ -1,  0 },
+	{  0,  1 },
+	{  1,  0 },
+	{  0, -1 }
+};
+
+static void BulldozerTick(Vehicle *v)
+{
+	v->progress++;
+	if ((v->progress & 7) == 0) {
+		const BulldozerMovement* b = &_bulldozer_movement[v->u.effect.animation_state];
+
+		BeginVehicleMove(v);
+
+		v->cur_image = SPR_BULLDOZER_NE + b->image;
+
+		v->x_pos += _inc_by_dir[b->direction].x;
+		v->y_pos += _inc_by_dir[b->direction].y;
+
+		v->u.effect.animation_substate++;
+		if (v->u.effect.animation_substate >= b->duration) {
+			v->u.effect.animation_substate = 0;
+			v->u.effect.animation_state++;
+			if (v->u.effect.animation_state == lengthof(_bulldozer_movement)) {
+				EndVehicleMove(v);
+				delete v;
+				return;
+			}
+		}
+		VehiclePositionChanged(v);
+		EndVehicleMove(v);
+	}
+}
+
+static void BubbleInit(Vehicle *v)
+{
+	v->cur_image = SPR_BUBBLE_GENERATE_0;
+	v->spritenum = 0;
+	v->progress = 0;
+}
+
+struct BubbleMovement {
+	int8 x:4;
+	int8 y:4;
+	int8 z:4;
+	byte image:4;
+};
+
+#define MK(x, y, z, i) { x, y, z, i }
+#define ME(i) { i, 4, 0, 0 }
+
+static const BubbleMovement _bubble_float_sw[] = {
+	MK(0, 0, 1, 0),
+	MK(1, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(1, 0, 1, 2),
+	ME(1)
+};
+
+
+static const BubbleMovement _bubble_float_ne[] = {
+	MK( 0, 0, 1, 0),
+	MK(-1, 0, 1, 1),
+	MK( 0, 0, 1, 0),
+	MK(-1, 0, 1, 2),
+	ME(1)
+};
+
+static const BubbleMovement _bubble_float_se[] = {
+	MK(0, 0, 1, 0),
+	MK(0, 1, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 1, 1, 2),
+	ME(1)
+};
+
+static const BubbleMovement _bubble_float_nw[] = {
+	MK(0,  0, 1, 0),
+	MK(0, -1, 1, 1),
+	MK(0,  0, 1, 0),
+	MK(0, -1, 1, 2),
+	ME(1)
+};
+
+static const BubbleMovement _bubble_burst[] = {
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 7),
+	MK(0, 0, 1, 8),
+	MK(0, 0, 1, 9),
+	ME(0)
+};
+
+static const BubbleMovement _bubble_absorb[] = {
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(0, 0, 1, 1),
+	MK(2, 1, 3, 0),
+	MK(1, 1, 3, 1),
+	MK(2, 1, 3, 0),
+	MK(1, 1, 3, 2),
+	MK(2, 1, 3, 0),
+	MK(1, 1, 3, 1),
+	MK(2, 1, 3, 0),
+	MK(1, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(1, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(1, 0, 1, 2),
+	MK(0, 0, 1, 0),
+	MK(1, 0, 1, 1),
+	MK(0, 0, 1, 0),
+	MK(1, 0, 1, 2),
+	ME(2),
+	MK(0, 0, 0, 0xA),
+	MK(0, 0, 0, 0xB),
+	MK(0, 0, 0, 0xC),
+	MK(0, 0, 0, 0xD),
+	MK(0, 0, 0, 0xE),
+	ME(0)
+};
+#undef ME
+#undef MK
+
+static const BubbleMovement * const _bubble_movement[] = {
+	_bubble_float_sw,
+	_bubble_float_ne,
+	_bubble_float_se,
+	_bubble_float_nw,
+	_bubble_burst,
+	_bubble_absorb,
+};
+
+static void BubbleTick(Vehicle *v)
+{
+	/*
+	 * Warning: those effects can NOT use Random(), and have to use
+	 *  InteractiveRandom(), because somehow someone forgot to save
+	 *  spritenum to the savegame, and so it will cause desyncs in
+	 *  multiplayer!! (that is: in ToyLand)
+	 */
+	uint et;
+
+	v->progress++;
+	if ((v->progress & 3) != 0) return;
+
+	BeginVehicleMove(v);
+
+	if (v->spritenum == 0) {
+		v->cur_image++;
+		if (v->cur_image < SPR_BUBBLE_GENERATE_3) {
+			VehiclePositionChanged(v);
+			EndVehicleMove(v);
+			return;
+		}
+		if (v->u.effect.animation_substate != 0) {
+			v->spritenum = GB(InteractiveRandom(), 0, 2) + 1;
+		} else {
+			v->spritenum = 6;
+		}
+		et = 0;
+	} else {
+		et = v->engine_type + 1;
+	}
+
+	const BubbleMovement *b = &_bubble_movement[v->spritenum - 1][et];
+
+	if (b->y == 4 && b->x == 0) {
+		EndVehicleMove(v);
+		delete v;
+		return;
+	}
+
+	if (b->y == 4 && b->x == 1) {
+		if (v->z_pos > 180 || Chance16I(1, 96, InteractiveRandom())) {
+			v->spritenum = 5;
+			SndPlayVehicleFx(SND_2F_POP, v);
+		}
+		et = 0;
+	}
+
+	if (b->y == 4 && b->x == 2) {
+		TileIndex tile;
+
+		et++;
+		SndPlayVehicleFx(SND_31_EXTRACT, v);
+
+		tile = TileVirtXY(v->x_pos, v->y_pos);
+		if (IsTileType(tile, MP_INDUSTRY) && GetIndustryGfx(tile) == GFX_BUBBLE_CATCHER) AddAnimatedTile(tile);
+	}
+
+	v->engine_type = et;
+	b = &_bubble_movement[v->spritenum - 1][et];
+
+	v->x_pos += b->x;
+	v->y_pos += b->y;
+	v->z_pos += b->z;
+	v->cur_image = SPR_BUBBLE_0 + b->image;
+
+	VehiclePositionChanged(v);
+	EndVehicleMove(v);
+}
+
+
+typedef void EffectInitProc(Vehicle *v);
+typedef void EffectTickProc(Vehicle *v);
+
+static EffectInitProc * const _effect_init_procs[] = {
+	ChimneySmokeInit,
+	SteamSmokeInit,
+	DieselSmokeInit,
+	ElectricSparkInit,
+	SmokeInit,
+	ExplosionLargeInit,
+	BreakdownSmokeInit,
+	ExplosionSmallInit,
+	BulldozerInit,
+	BubbleInit,
+};
+
+static EffectTickProc * const _effect_tick_procs[] = {
+	ChimneySmokeTick,
+	SteamSmokeTick,
+	DieselSmokeTick,
+	ElectricSparkTick,
+	SmokeTick,
+	ExplosionLargeTick,
+	BreakdownSmokeTick,
+	ExplosionSmallTick,
+	BulldozerTick,
+	BubbleTick,
+};
+
+
+Vehicle *CreateEffectVehicle(int x, int y, int z, EffectVehicleType type)
+{
+	Vehicle *v = new EffectVehicle();
+	if (v != NULL) {
+		v->subtype = type;
+		v->x_pos = x;
+		v->y_pos = y;
+		v->z_pos = z;
+		v->tile = 0;
+		v->UpdateDeltaXY(INVALID_DIR);
+		v->vehstatus = VS_UNCLICKABLE;
+
+		_effect_init_procs[type](v);
+
+		VehiclePositionChanged(v);
+		BeginVehicleMove(v);
+		EndVehicleMove(v);
+	}
+	return v;
+}
+
+Vehicle *CreateEffectVehicleAbove(int x, int y, int z, EffectVehicleType type)
+{
+	int safe_x = Clamp(x, 0, MapMaxX() * TILE_SIZE);
+	int safe_y = Clamp(y, 0, MapMaxY() * TILE_SIZE);
+	return CreateEffectVehicle(x, y, GetSlopeZ(safe_x, safe_y) + z, type);
+}
+
+Vehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicleType type)
+{
+	return CreateEffectVehicle(v->x_pos + x, v->y_pos + y, v->z_pos + z, type);
+}
+
+void EffectVehicle::Tick()
+{
+	_effect_tick_procs[this->subtype](this);
+}
+
+void EffectVehicle::UpdateDeltaXY(Direction direction)
+{
+	this->x_offs        = 0;
+	this->y_offs        = 0;
+	this->x_extent      = 1;
+	this->y_extent      = 1;
+	this->z_extent      = 1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/effectvehicle_base.h	Mon Apr 21 21:15:50 2008 +0000
@@ -0,0 +1,37 @@
+/* $Id$ */
+
+/** @file effectvehicle_base.h Base class for all effect vehicles. */
+
+#ifndef EFFECTVEHICLE_BASE_H
+#define EFFECTVEHICLE_BASE_H
+
+#include "vehicle_base.h"
+
+/**
+ * This class 'wraps' Vehicle; you do not actually instantiate this class.
+ * You create a Vehicle using AllocateVehicle, so it is added to the pool
+ * and you reinitialize that to a Train using:
+ *   v = new (v) Train();
+ *
+ * As side-effect the vehicle type is set correctly.
+ *
+ * A special vehicle is one of the following:
+ *  - smoke
+ *  - electric sparks for trains
+ *  - explosions
+ *  - bulldozer (road works)
+ *  - bubbles (industry)
+ */
+struct EffectVehicle : public Vehicle {
+	/** Initializes the Vehicle to a special vehicle */
+	EffectVehicle() { this->type = VEH_EFFECT; }
+
+	/** We want to 'destruct' the right class. */
+	virtual ~EffectVehicle() {}
+
+	const char *GetTypeString() const { return "special vehicle"; }
+	void UpdateDeltaXY(Direction direction);
+	void Tick();
+};
+
+#endif /* EFFECTVEHICLE_BASE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/effectvehicle_func.h	Mon Apr 21 21:15:50 2008 +0000
@@ -0,0 +1,28 @@
+/* $Id$ */
+
+/** @file effectvehicle.h Functions related to effect vehicles. */
+
+#ifndef EFFECTVEHICLE_FUNC_H
+#define EFFECTVEHICLE_FUNC_H
+
+#include "vehicle_type.h"
+
+/** Effect vehicle types */
+enum EffectVehicleType {
+	EV_CHIMNEY_SMOKE   = 0,
+	EV_STEAM_SMOKE     = 1,
+	EV_DIESEL_SMOKE    = 2,
+	EV_ELECTRIC_SPARK  = 3,
+	EV_SMOKE           = 4,
+	EV_EXPLOSION_LARGE = 5,
+	EV_BREAKDOWN_SMOKE = 6,
+	EV_EXPLOSION_SMALL = 7,
+	EV_BULLDOZER       = 8,
+	EV_BUBBLE          = 9
+};
+
+Vehicle *CreateEffectVehicle(int x, int y, int z, EffectVehicleType type);
+Vehicle *CreateEffectVehicleAbove(int x, int y, int z, EffectVehicleType type);
+Vehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicleType type);
+
+#endif /* EFFECTVEHICLE_FUNC_H */
--- a/src/engine_func.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/engine_func.h	Mon Apr 21 21:15:50 2008 +0000
@@ -1,6 +1,6 @@
 /* $Id$ */
 
-/** @file engine.h */
+/** @file engine_func.h */
 
 #ifndef ENGINE_H
 #define ENGINE_H
--- a/src/functions.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/functions.h	Mon Apr 21 21:15:50 2008 +0000
@@ -23,21 +23,11 @@
 bool CheckOwnership(Owner owner);
 bool CheckTileOwnership(TileIndex tile);
 
-/* texteff.cpp */
-void AddAnimatedTile(TileIndex tile);
-void DeleteAnimatedTile(TileIndex tile);
-void AnimateAnimatedTiles();
-void InitializeAnimatedTiles();
-
 /* misc_cmd.cpp */
 void PlaceTreesRandomly();
 
 void InitializeLandscapeVariables(bool only_constants);
 
-/* misc.cpp */
-bool IsCustomName(StringID id);
-char *CopyFromOldName(StringID id);
-
 /* misc functions */
 /**
  * Mark a tile given by its coordinate dirty for repaint.
@@ -69,14 +59,10 @@
 
 void RedrawAutosave();
 
-StringID RemapOldStringID(StringID s);
-
 void UpdateViewportSignPos(ViewportSign *sign, int left, int top, StringID str);
 
-
 /* callback from drivers that is called if the game size changes dynamically */
 void GameSizeChanged();
-const char *GetCurrentLocale(const char *param);
 
 int ttd_main(int argc, char* argv[]);
 void HandleExitGameRequest();
--- a/src/industry_cmd.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/industry_cmd.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -39,6 +39,8 @@
 #include "sound_func.h"
 #include "station_base.h"
 #include "oldpool_func.h"
+#include "animated_tile_func.h"
+#include "effectvehicle_func.h"
 
 #include "table/strings.h"
 #include "table/sprites.h"
@@ -620,7 +622,7 @@
 	}
 }
 
-static void CreateIndustryEffectSmoke(TileIndex tile)
+static void CreateChimneySmoke(TileIndex tile)
 {
 	uint x = TileX(tile) * TILE_SIZE;
 	uint y = TileY(tile) * TILE_SIZE;
@@ -657,7 +659,7 @@
 
 	switch (gfx) {
 	case GFX_POWERPLANT_CHIMNEY:
-		CreateIndustryEffectSmoke(tile);
+		CreateChimneySmoke(tile);
 		break;
 
 	case GFX_OILRIG_1:
@@ -684,10 +686,10 @@
 {
 	int dir;
 	Vehicle *v;
-	static const int8 _tileloop_ind_case_161[12] = {
-		11,   0, -4, -14,
-		-4, -10, -4,   1,
-		49,  59, 60,  65,
+	static const int8 _bubble_spawn_location[3][4] = {
+		{ 11,   0, -4, -14 },
+		{ -4, -10, -4,   1 },
+		{ 49,  59, 60,  65 },
 	};
 
 	SndPlayTileFx(SND_2E_EXTRACT_AND_POP, tile);
@@ -695,13 +697,13 @@
 	dir = Random() & 3;
 
 	v = CreateEffectVehicleAbove(
-		TileX(tile) * TILE_SIZE + _tileloop_ind_case_161[dir + 0],
-		TileY(tile) * TILE_SIZE + _tileloop_ind_case_161[dir + 4],
-		_tileloop_ind_case_161[dir + 8],
+		TileX(tile) * TILE_SIZE + _bubble_spawn_location[0][dir],
+		TileY(tile) * TILE_SIZE + _bubble_spawn_location[1][dir],
+		_bubble_spawn_location[2][dir],
 		EV_BUBBLE
 	);
 
-	if (v != NULL) v->u.special.animation_substate = dir;
+	if (v != NULL) v->u.effect.animation_substate = dir;
 }
 
 static void TileLoop_Industry(TileIndex tile)
--- a/src/industry_gui.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/industry_gui.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -78,8 +78,8 @@
 {
 	if (HasBit(indspec->callback_flags, CBM_IND_CARGO_SUFFIX)) {
 		bool fund = ind == NULL;
-		uint8 callback = GetIndustryCallback(CBID_INDUSTRY_CARGO_SUFFIX, 0, ((!fund) ? 1 << 8 : 0) | cargo, ind, ind_type, (!fund) ? ind->xy : INVALID_TILE);
-		if (callback != 0xFF) return GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 + callback);
+		uint16 callback = GetIndustryCallback(CBID_INDUSTRY_CARGO_SUFFIX, 0, ((!fund) ? 1 << 8 : 0) | cargo, ind, ind_type, (!fund) ? ind->xy : INVALID_TILE);
+		if (GB(callback, 0, 8) != 0xFF) return GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 + callback);
 	}
 	return STR_EMPTY;
 }
@@ -631,7 +631,7 @@
 		WP(w, indview_d).editbox_line = 0;
 		WP(w, indview_d).clicked_line = 0;
 		WP(w, indview_d).clicked_button = 0;
-		AssignWindowViewport(w, 3, 17, 0xFE, 0x56, GetIndustry(w->window_number)->xy + TileDiffXY(1, 1), ZOOM_LVL_INDUSTRY);
+		InitializeWindowViewport(w, 3, 17, 254, 86, GetIndustry(w->window_number)->xy + TileDiffXY(1, 1), ZOOM_LVL_INDUSTRY);
 	}
 }
 
--- a/src/landscape.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/landscape.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -24,6 +24,7 @@
 #include "vehicle_func.h"
 #include "settings_type.h"
 #include "water.h"
+#include "effectvehicle_func.h"
 
 #include "table/sprites.h"
 
--- a/src/lang/english.txt	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/lang/english.txt	Mon Apr 21 21:15:50 2008 +0000
@@ -1066,7 +1066,7 @@
 STR_CONFIG_PATCHES_WARN_INCOME_LESS                             :{LTBLUE}Warn if a train's income is negative: {ORANGE}{STRING1}
 STR_CONFIG_PATCHES_NEVER_EXPIRE_VEHICLES                        :{LTBLUE}Vehicles never expire: {ORANGE}{STRING1}
 STR_CONFIG_PATCHES_AUTORENEW_VEHICLE                            :{LTBLUE}Autorenew vehicle when it gets old
-STR_CONFIG_PATCHES_AUTORENEW_MONTHS                             :{LTBLUE}Autorenew when vehice is {ORANGE}{STRING1}{LTBLUE} months before/after max age
+STR_CONFIG_PATCHES_AUTORENEW_MONTHS                             :{LTBLUE}Autorenew when vehicle is {ORANGE}{STRING1}{LTBLUE} months before/after max age
 STR_CONFIG_PATCHES_AUTORENEW_MONEY                              :{LTBLUE}Autorenew minimum needed money for renew: {ORANGE}{STRING1}
 STR_CONFIG_PATCHES_ERRMSG_DURATION                              :{LTBLUE}Duration of error message: {ORANGE}{STRING1}
 STR_CONFIG_PATCHES_POPULATION_IN_LABEL                          :{LTBLUE}Show town population in the town name label: {ORANGE}{STRING1}
--- a/src/main_gui.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/main_gui.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -413,7 +413,7 @@
 	int height = _screen.height;
 
 	Window *w = AllocateWindow(0, 0, width, height, MainWindowWndProc, WC_MAIN_WINDOW, NULL);
-	AssignWindowViewport(w, 0, 0, width, height, TileXY(32, 32), ZOOM_LVL_VIEWPORT);
+	InitializeWindowViewport(w, 0, 0, width, height, TileXY(32, 32), ZOOM_LVL_VIEWPORT);
 
 	/* XXX: these are not done */
 	switch (_game_mode) {
--- a/src/misc.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/misc.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -23,15 +23,14 @@
 #include "date_func.h"
 #include "vehicle_func.h"
 #include "texteff.hpp"
-#include "string_func.h"
 #include "gfx_func.h"
 #include "core/alloc_type.hpp"
+#include "animated_tile_func.h"
 #include "settings_type.h"
 
 #include "table/strings.h"
 #include "table/sprites.h"
 
-char _name_array[512][32];
 extern TileIndex _cur_tileloop_tile;
 
 void InitializeVehicles();
@@ -50,10 +49,10 @@
 void InitializeSigns();
 void InitializeStations();
 void InitializeCargoPackets();
-static void InitializeNameMgr();
 void InitializePlayers();
 void InitializeCheats();
 void InitializeNPF();
+void InitializeOldNames();
 
 void InitializeGame(int mode, uint size_x, uint size_y)
 {
@@ -94,7 +93,7 @@
 	InitializeIndustries();
 	InitializeBuildingCounts();
 
-	InitializeNameMgr();
+	InitializeOldNames();
 	InitializeVehiclesGuiList();
 	InitializeTrains();
 	InitializeNPF();
@@ -112,60 +111,6 @@
 	ResetObjectToPlace();
 }
 
-bool IsCustomName(StringID id)
-{
-	return GB(id, 11, 5) == 15;
-}
-
-
-static void InitializeNameMgr()
-{
-	memset(_name_array, 0, sizeof(_name_array));
-}
-
-/* Copy and convert old custom names to UTF-8 */
-char *CopyFromOldName(StringID id)
-{
-	if (!IsCustomName(id)) return NULL;
-
-	if (CheckSavegameVersion(37)) {
-		/* Old names were 32 characters long, so 128 characters should be
-		 * plenty to allow for expansion when converted to UTF-8. */
-		char tmp[128];
-		const char *strfrom = _name_array[GB(id, 0, 9)];
-		char *strto = tmp;
-
-		for (; *strfrom != '\0'; strfrom++) {
-			WChar c = (byte)*strfrom;
-
-			/* Map from non-ISO8859-15 characters to UTF-8. */
-			switch (c) {
-				case 0xA4: c = 0x20AC; break; // Euro
-				case 0xA6: c = 0x0160; break; // S with caron
-				case 0xA8: c = 0x0161; break; // s with caron
-				case 0xB4: c = 0x017D; break; // Z with caron
-				case 0xB8: c = 0x017E; break; // z with caron
-				case 0xBC: c = 0x0152; break; // OE ligature
-				case 0xBD: c = 0x0153; break; // oe ligature
-				case 0xBE: c = 0x0178; break; // Y with diaresis
-				default: break;
-			}
-
-			/* Check character will fit into our buffer. */
-			if (strto + Utf8CharLen(c) > lastof(tmp)) break;
-
-			strto += Utf8Encode(strto, c);
-		}
-
-		/* Terminate the new string and copy it back to the name array */
-		*strto = '\0';
-
-		return strdup(tmp);
-	} else {
-		/* Name will already be in UTF-8. */
-		return strdup(_name_array[GB(id, 0, 9)]);
-	}
-}
 
 /* Calculate constants that depend on the landscape type. */
 void InitializeLandscapeVariables(bool only_constants)
@@ -178,15 +123,6 @@
 	}
 }
 
-static void Load_NAME()
-{
-	int index;
-
-	while ((index = SlIterateArray()) != -1) {
-		SlArray(_name_array[index], SlGetFieldLength(), SLE_UINT8);
-	}
-}
-
 static const SaveLoadGlobVarList _date_desc[] = {
 	SLEG_CONDVAR(_date,                   SLE_FILE_U16 | SLE_VAR_I32,  0,  30),
 	SLEG_CONDVAR(_date,                   SLE_INT32,                  31, SL_MAX_VERSION),
@@ -470,7 +406,6 @@
 	{ 'MAPE', Save_MAP6,     Load_MAP6,     CH_RIFF },
 	{ 'MAP7', Save_MAP7,     Load_MAP7,     CH_RIFF },
 
-	{ 'NAME', NULL,          Load_NAME,     CH_ARRAY},
 	{ 'DATE', SaveLoad_DATE, SaveLoad_DATE, CH_RIFF},
 	{ 'VIEW', SaveLoad_VIEW, SaveLoad_VIEW, CH_RIFF | CH_LAST},
 };
--- a/src/newgrf.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/newgrf.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -1120,19 +1120,17 @@
 				statspec->blocked = grf_load_byte(&buf);
 				break;
 
-			case 0x16: // @todo Animation info
-				grf_load_word(&buf);
-				ret = true;
-				break;
-
-			case 0x17: // @todo Animation speed
-				grf_load_byte(&buf);
-				ret = true;
-				break;
-
-			case 0x18: // @todo Animation triggers
-				grf_load_word(&buf);
-				ret = true;
+			case 0x16: // Animation info
+				statspec->anim_frames = grf_load_byte(&buf);
+				statspec->anim_status = grf_load_byte(&buf);
+				break;
+
+			case 0x17: // Animation speed
+				statspec->anim_speed = grf_load_byte(&buf);
+				break;
+
+			case 0x18: // Animation triggers
+				statspec->anim_triggers = grf_load_word(&buf);
 				break;
 
 			default:
--- a/src/newgrf_callbacks.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/newgrf_callbacks.h	Mon Apr 21 21:15:50 2008 +0000
@@ -28,193 +28,188 @@
 
 	/** Powered wagons, if the result is lower as 0x40 then the wagon is powered
 	 * @todo : interpret the rest of the result, aka "visual effects". */
-	CBID_TRAIN_WAGON_POWER               = 0x10,
+	CBID_TRAIN_WAGON_POWER               = 0x10, // 8 bit callback
 
 	/** Vehicle length, returns the amount of 1/8's the vehicle is shorter for trains and RVs. */
 	CBID_VEHICLE_LENGTH                  = 0x11,
 
 	/** Determine the amount of cargo to load per unit of time when using gradual loading. */
-	CBID_VEHICLE_LOAD_AMOUNT             = 0x12,
+	CBID_VEHICLE_LOAD_AMOUNT             = 0x12, // 8 bit callback
 
 	/** Determine whether a newstation should be made available to build. */
-	CBID_STATION_AVAILABILITY            = 0x13,
+	CBID_STATION_AVAILABILITY            = 0x13, // 8 bit callback
 
 	/** Choose a sprite layout to draw, instead of the standard 0-7 range. */
 	CBID_STATION_SPRITE_LAYOUT           = 0x14,
 
 	/** Refit capacity, the passed vehicle needs to have its ->cargo_type set to
 	 * the cargo we are refitting to, returns the new cargo capacity. */
-	CBID_VEHICLE_REFIT_CAPACITY          = 0x15,
+	CBID_VEHICLE_REFIT_CAPACITY          = 0x15, // 15 bit callback
 
 	/** Builds articulated engines for trains and RVs. */
-	CBID_VEHICLE_ARTIC_ENGINE            = 0x16,
+	CBID_VEHICLE_ARTIC_ENGINE            = 0x16, // 8 bit callback
 
 	/** Determine whether the house can be built on the specified tile. */
-	CBID_HOUSE_ALLOW_CONSTRUCTION        = 0x17,
+	CBID_HOUSE_ALLOW_CONSTRUCTION        = 0x17, // 8 bit callback
 
 	/** AI construction/purchase selection */
-	CBID_GENERIC_AI_PURCHASE_SELECTION   = 0x18, // not implemented
+	CBID_GENERIC_AI_PURCHASE_SELECTION   = 0x18, // 8 bit callback, not implemented
 
 	/** Determine the cargo "suffixes" for each refit possibility of a cargo. */
 	CBID_VEHICLE_CARGO_SUFFIX            = 0x19,
 
 	/** Determine the next animation frame for a house. */
-	CBID_HOUSE_ANIMATION_NEXT_FRAME      = 0x1A,
+	CBID_HOUSE_ANIMATION_NEXT_FRAME      = 0x1A, // 15 bit callback
 
 	/** Called for periodically starting or stopping the animation. */
-	CBID_HOUSE_ANIMATION_START_STOP      = 0x1B,
+	CBID_HOUSE_ANIMATION_START_STOP      = 0x1B, // 15 bit callback
 
 	/** Called whenever the construction state of a house changes. */
-	CBID_HOUSE_CONSTRUCTION_STATE_CHANGE = 0x1C,
+	CBID_HOUSE_CONSTRUCTION_STATE_CHANGE = 0x1C, // 15 bit callback
 
 	/** Determine whether a wagon can be attached to an already existing train. */
 	CBID_TRAIN_ALLOW_WAGON_ATTACH        = 0x1D,
 
 	/** Called to determine the colour of a town building. */
-	CBID_HOUSE_COLOUR                    = 0x1E,
+	CBID_HOUSE_COLOUR                    = 0x1E, // 15 bit callback
 
 	/** Called to decide how much cargo a town building can accept. */
-	CBID_HOUSE_CARGO_ACCEPTANCE          = 0x1F,
+	CBID_HOUSE_CARGO_ACCEPTANCE          = 0x1F, // 15 bit callback
 
 	/** Called to indicate how long the current animation frame should last. */
-	CBID_HOUSE_ANIMATION_SPEED           = 0x20,
+	CBID_HOUSE_ANIMATION_SPEED           = 0x20, // 8 bit callback
 
 	/** Called periodically to determine if a house should be destroyed. */
-	CBID_HOUSE_DESTRUCTION               = 0x21,
+	CBID_HOUSE_DESTRUCTION               = 0x21, // 8 bit callback
 
 	/** Called to determine if the given industry type is available */
-	CBID_INDUSTRY_AVAILABLE              = 0x22,
+	CBID_INDUSTRY_AVAILABLE              = 0x22, // 15 bit callback
 
 	/** This callback is called from vehicle purchase lists. It returns a value to be
 	 * used as a custom string ID in the 0xD000 range. */
 	CBID_VEHICLE_ADDITIONAL_TEXT         = 0x23,
 
 	/** Called when building a station to customize the tile layout */
-	CBID_STATION_TILE_LAYOUT             = 0x24,
+	CBID_STATION_TILE_LAYOUT             = 0x24, // 15 bit callback
 
 	/** Called for periodically starting or stopping the animation. */
-	CBID_INDTILE_ANIM_START_STOP         = 0x25,
+	CBID_INDTILE_ANIM_START_STOP         = 0x25, // 15 bit callback
 
 	/** Called to determine industry tile next animation frame. */
-	CBID_INDTILE_ANIM_NEXT_FRAME         = 0x26,
+	CBID_INDTILE_ANIM_NEXT_FRAME         = 0x26, // 15 bit callback
 
 	/** Called to indicate how long the current animation frame should last. */
-	CBID_INDTILE_ANIMATION_SPEED         = 0x27,
+	CBID_INDTILE_ANIMATION_SPEED         = 0x27, // 8 bit callback
 
 	/** Called to determine if the given industry can be built on specific area. */
-	CBID_INDUSTRY_LOCATION               = 0x28,
+	CBID_INDUSTRY_LOCATION               = 0x28, // 15 bit callback
 
 	/** Called on production changes, so it can be adjusted. */
-	CBID_INDUSTRY_PRODUCTION_CHANGE      = 0x29,
+	CBID_INDUSTRY_PRODUCTION_CHANGE      = 0x29, // 15 bit callback
 
 	/** Called to determine which cargoes a town building should accept. */
-	CBID_HOUSE_ACCEPT_CARGO              = 0x2A,
+	CBID_HOUSE_ACCEPT_CARGO              = 0x2A, // 15 bit callback
 
 	/** Called to query the cargo acceptance of the industry tile */
-	CBID_INDTILE_CARGO_ACCEPTANCE        = 0x2B,
+	CBID_INDTILE_CARGO_ACCEPTANCE        = 0x2B, // 15 bit callback
 
 	/** Called to determine which cargoes an industry should accept. */
-	CBID_INDTILE_ACCEPT_CARGO            = 0x2C,
+	CBID_INDTILE_ACCEPT_CARGO            = 0x2C, // 15 bit callback
 
 	/** Called to determine if a specific colour map should be used for a vehicle
 	 * instead of the default livery. */
-	CBID_VEHICLE_COLOUR_MAPPING          = 0x2D,
+	CBID_VEHICLE_COLOUR_MAPPING          = 0x2D, // 15 bit callback
 
 	/** Called to determine how much cargo a town building produces. */
-	CBID_HOUSE_PRODUCE_CARGO             = 0x2E,
+	CBID_HOUSE_PRODUCE_CARGO             = 0x2E, // 15 bit callback
 
 	/** Called to determine if the given industry tile can be built on specific tile. */
-	CBID_INDTILE_SHAPE_CHECK             = 0x2F,
+	CBID_INDTILE_SHAPE_CHECK             = 0x2F, // 15 bit callback
 
 	/** Called to determine the type (if any) of foundation to draw for industry tile. */
-	CBID_INDUSTRY_DRAW_FOUNDATIONS       = 0x30,
+	CBID_INDUSTRY_DRAW_FOUNDATIONS       = 0x30, // 15 bit callback
 
 	/** Called when the player (or AI) tries to start or stop a vehicle. Mainly
 	 * used for preventing a vehicle from leaving the depot. */
-	CBID_VEHICLE_START_STOP_CHECK        = 0x31,
+	CBID_VEHICLE_START_STOP_CHECK        = 0x31, // 15 bit callback, but 0xFF test is done with 8 bit
 
 	/** Called for every vehicle every 32 days (not all on same date though). */
-	CBID_VEHICLE_32DAY_CALLBACK          = 0x32,
+	CBID_VEHICLE_32DAY_CALLBACK          = 0x32, // 2 bit callback
 
 	/** Called to play a special sound effect */
-	CBID_VEHICLE_SOUND_EFFECT            = 0x33,
+	CBID_VEHICLE_SOUND_EFFECT            = 0x33, // 15 bit callback
 
 	/** Return the vehicles this given vehicle can be "upgraded" to. */
-	CBID_VEHICLE_AUTOREPLACE_SELECTION   = 0x34,
+	CBID_VEHICLE_AUTOREPLACE_SELECTION   = 0x34, // 15 bit callback
 
 	/** Called monthly on production changes, so it can be adjusted more frequently */
-	CBID_INDUSTRY_MONTHLYPROD_CHANGE     = 0x35,
+	CBID_INDUSTRY_MONTHLYPROD_CHANGE     = 0x35, // 15 bit callback
 
 	/** Called to modify various vehicle properties. Callback parameter 1
 	 * specifies the property index, as used in Action 0, to change. */
-	CBID_VEHICLE_MODIFY_PROPERTY         = 0x36,
+	CBID_VEHICLE_MODIFY_PROPERTY         = 0x36, // 8/15 bit depends on queried property
 
 	/** Called to determine text to display after cargo name */
-	CBID_INDUSTRY_CARGO_SUFFIX           = 0x37,
+	CBID_INDUSTRY_CARGO_SUFFIX           = 0x37, // 15 bit callback, but 0xFF test is done with 8 bit
 
 	/** Called to determine more text in the fund industry window */
-	CBID_INDUSTRY_FUND_MORE_TEXT         = 0x38,
+	CBID_INDUSTRY_FUND_MORE_TEXT         = 0x38, // 15 bit callback
 
 	/** Called to calculate the income of delivered cargo */
-	CBID_CARGO_PROFIT_CALC               = 0x39,
+	CBID_CARGO_PROFIT_CALC               = 0x39, // 15 bit callback
 
 	/** Called to determine more text in the industry window */
-	CBID_INDUSTRY_WINDOW_MORE_TEXT       = 0x3A,
+	CBID_INDUSTRY_WINDOW_MORE_TEXT       = 0x3A, // 15 bit callback
 
 	/** Called to determine industry special effects */
-	CBID_INDUSTRY_SPECIAL_EFFECT         = 0x3B,
+	CBID_INDUSTRY_SPECIAL_EFFECT         = 0x3B, // 15 bit callback
 
 	/** Called to determine if industry can alter the ground below industry tile */
-	CBID_INDUSTRY_AUTOSLOPE              = 0x3C,
+	CBID_INDUSTRY_AUTOSLOPE              = 0x3C, // 15 bit callback
 
 	/** Called to determine if the industry can still accept or refuse more cargo arrival */
-	CBID_INDUSTRY_REFUSE_CARGO           = 0x3D,
+	CBID_INDUSTRY_REFUSE_CARGO           = 0x3D, // 15 bit callback
 
 	/* There are no callbacks 0x3E - 0x13F */
 
 	/** Called for periodically starting or stopping the animation. */
-	CBID_STATION_ANIM_START_STOP         = 0x140, // not implemented
+	CBID_STATION_ANIM_START_STOP         = 0x140, // 15 bit callback
 
 	/** Called to determine station tile next animation frame. */
-	CBID_STATION_ANIM_NEXT_FRAME         = 0x141, // not implemented
+	CBID_STATION_ANIM_NEXT_FRAME         = 0x141, // 15 bit callback
 
 	/** Called to indicate how long the current animation frame should last. */
-	CBID_STATION_ANIMATION_SPEED         = 0x142, // not implemented
+	CBID_STATION_ANIMATION_SPEED         = 0x142, // 8 bit callback
 
 	/** Called to determine whether a town building can be destroyed. */
-	CBID_HOUSE_DENY_DESTRUCTION          = 0x143,
+	CBID_HOUSE_DENY_DESTRUCTION          = 0x143, // 15 bit callback
 
 	/** Select an ambient sound to play for a given type of tile. */
-	CBID_SOUNDS_AMBIENT_EFFECT           = 0x144, // not implemented
+	CBID_SOUNDS_AMBIENT_EFFECT           = 0x144, // 15 bit callback, not implemented
 
 	/** Called to calculate part of a station rating. */
-	CBID_CARGO_STATION_RATING_CALC       = 0x145,
+	CBID_CARGO_STATION_RATING_CALC       = 0x145, // 15 bit callback, not implemented
 
 	/** Allow signal sprites to be replaced dynamically. */
-	CBID_NEW_SIGNALS_SPRITE_DRAW         = 0x146, // not implemented
+	CBID_NEW_SIGNALS_SPRITE_DRAW         = 0x146, // 15 bit callback, not implemented
 
 	/** Add an offset to the default sprite numbers to show another sprite. */
-	CBID_CANALS_SPRITE_OFFSET            = 0x147, // not implemented
+	CBID_CANALS_SPRITE_OFFSET            = 0x147, // 15 bit callback, not implemented
 
 	/** Called when a cargo type specified in property 20 is accepted. */
-	CBID_HOUSE_WATCHED_CARGO_ACCEPTED    = 0x148, // not implemented
+	CBID_HOUSE_WATCHED_CARGO_ACCEPTED    = 0x148, // 15 bit callback, not implemented
 
 	/** Callback done for each tile of a station to check the slope. */
-	CBID_STATION_LAND_SLOPE_CHECK        = 0x149, // not implemented
+	CBID_STATION_LAND_SLOPE_CHECK        = 0x149, // 15 bit callback, not implemented
 
 	/** Called to determine the color of an industry. */
-	CBID_INDUSTRY_DECIDE_COLOUR          = 0x14A,
+	CBID_INDUSTRY_DECIDE_COLOUR          = 0x14A, // 4 bit callback
 
 	/** Customize the input cargo types of a newly build industry. */
-	CBID_INDUSTRY_INPUT_CARGO_TYPES      = 0x14B,
+	CBID_INDUSTRY_INPUT_CARGO_TYPES      = 0x14B, // 8 bit callback
 
 	/** Customize the output cargo types of a newly build industry. */
-	CBID_INDUSTRY_OUTPUT_CARGO_TYPES     = 0x14C,
-
-	/* ATTENTION:
-	 * When adding new callbacks and their result is 15bit, add them to newgrf_spritegroup.cpp:Is8BitCallback().
-	 * It does not harm to add them there though they are not implemented. But it does harm if they get forgotton.
-	 */
+	CBID_INDUSTRY_OUTPUT_CARGO_TYPES     = 0x14C, // 8 bit callback
 };
 
 /**
--- a/src/newgrf_generic.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/newgrf_generic.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -176,5 +176,7 @@
 	object.u.generic.count             = count;
 	object.u.generic.station_size      = station_size;
 
-	return GetGenericCallbackResult(feature, &object, file);
+	uint16 callback = GetGenericCallbackResult(feature, &object, file);
+	if (callback != CALLBACK_FAILED) callback = GB(callback, 0, 8);
+	return callback;
 }
--- a/src/newgrf_house.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/newgrf_house.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -21,6 +21,8 @@
 #include "transparency.h"
 #include "functions.h"
 #include "player_func.h"
+#include "animated_tile_func.h"
+#include "date_func.h"
 
 #include "table/strings.h"
 #include "table/sprites.h"
@@ -428,7 +430,7 @@
 
 			/* If the lower 7 bits of the upper byte of the callback
 			 * result are not empty, it is a sound effect. */
-			if (GB(callback_res, 8, 7) != 0) PlayHouseSound(GB(callback_res, 8, 7), tile);
+			if (GB(callback_res, 8, 7) != 0) PlayTileSound(hs->grffile, GB(callback_res, 8, 7), tile);
 		}
 	}
 
@@ -448,7 +450,7 @@
 	MarkTileDirtyByTile(tile);
 }
 
-void ChangeHouseAnimationFrame(TileIndex tile, uint16 callback_result)
+void ChangeHouseAnimationFrame(const GRFFile *file, TileIndex tile, uint16 callback_result)
 {
 	switch (callback_result & 0xFF) {
 		case 0xFD: /* Do nothing. */         break;
@@ -461,7 +463,7 @@
 	}
 	/* If the lower 7 bits of the upper byte of the callback
 	 * result are not empty, it is a sound effect. */
-	if (GB(callback_result, 8, 7) != 0) PlayHouseSound(GB(callback_result, 8, 7), tile);
+	if (GB(callback_result, 8, 7) != 0) PlayTileSound(file, GB(callback_result, 8, 7), tile);
 }
 
 bool CanDeleteHouse(TileIndex tile)
@@ -489,7 +491,7 @@
 		uint32 param = (hs->extra_flags & SYNCHRONISED_CALLBACK_1B) ? (GB(Random(), 0, 16) | random_bits << 16) : Random();
 		uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_START_STOP, param, 0, GetHouseType(tile), GetTownByTile(tile), tile);
 
-		if (callback_res != CALLBACK_FAILED) ChangeHouseAnimationFrame(tile, callback_res);
+		if (callback_res != CALLBACK_FAILED) ChangeHouseAnimationFrame(hs->grffile, tile, callback_res);
 	}
 }
 
@@ -525,7 +527,7 @@
 	/* Check callback 21, which determines if a house should be destroyed. */
 	if (HasBit(hs->callback_mask, CBM_HOUSE_DESTRUCTION)) {
 		uint16 callback_res = GetHouseCallback(CBID_HOUSE_DESTRUCTION, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile);
-		if (callback_res != CALLBACK_FAILED && callback_res > 0) {
+		if (callback_res != CALLBACK_FAILED && GB(callback_res, 0, 8) > 0) {
 			ClearTownHouse(GetTownByTile(tile), tile);
 			return false;
 		}
--- a/src/newgrf_house.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/newgrf_house.h	Mon Apr 21 21:15:50 2008 +0000
@@ -36,7 +36,7 @@
 
 void DrawNewHouseTile(TileInfo *ti, HouseID house_id);
 void AnimateNewHouseTile(TileIndex tile);
-void ChangeHouseAnimationFrame(TileIndex tile, uint16 callback_result);
+void ChangeHouseAnimationFrame(const struct GRFFile *file, TileIndex tile, uint16 callback_result);
 
 uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, HouseID house_id, Town *town, TileIndex tile);
 
--- a/src/newgrf_industrytiles.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/newgrf_industrytiles.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -15,6 +15,7 @@
 #include "newgrf_callbacks.h"
 #include "newgrf_industries.h"
 #include "newgrf_industrytiles.h"
+#include "newgrf_sound.h"
 #include "newgrf_text.h"
 #include "industry_map.h"
 #include "clear_map.h"
@@ -23,6 +24,7 @@
 #include "functions.h"
 #include "town.h"
 #include "command_func.h"
+#include "animated_tile_func.h"
 
 #include "table/sprites.h"
 #include "table/strings.h"
@@ -336,6 +338,10 @@
 					frame = callback_res & 0xFF;
 					break;
 			}
+
+			/* If the lower 7 bits of the upper byte of the callback
+			 * result are not empty, it is a sound effect. */
+			if (GB(callback_res, 8, 7) != 0) PlayTileSound(itspec->grf_prop.grffile, GB(callback_res, 8, 7), tile);
 		}
 	}
 
@@ -355,7 +361,7 @@
 	MarkTileDirtyByTile(tile);
 }
 
-static void ChangeIndustryTileAnimationFrame(TileIndex tile, IndustryAnimationTrigger iat, uint32 random_bits, IndustryGfx gfx, Industry *ind)
+static void ChangeIndustryTileAnimationFrame(const IndustryTileSpec *itspec, TileIndex tile, IndustryAnimationTrigger iat, uint32 random_bits, IndustryGfx gfx, Industry *ind)
 {
 	uint16 callback_res = GetIndustryTileCallback(CBID_INDTILE_ANIM_START_STOP, random_bits, iat, gfx, ind, tile);
 	if (callback_res == CALLBACK_FAILED) return;
@@ -369,6 +375,10 @@
 			AddAnimatedTile(tile);
 			break;
 	}
+
+	/* If the lower 7 bits of the upper byte of the callback
+	 * result are not empty, it is a sound effect. */
+	if (GB(callback_res, 8, 7) != 0) PlayTileSound(itspec->grf_prop.grffile, GB(callback_res, 8, 7), tile);
 }
 
 bool StartStopIndustryTileAnimation(TileIndex tile, IndustryAnimationTrigger iat, uint32 random)
@@ -379,7 +389,7 @@
 	if (!HasBit(itspec->animation_triggers, iat)) return false;
 
 	Industry *ind = GetIndustryByTile(tile);
-	ChangeIndustryTileAnimationFrame(tile, iat, random, gfx, ind);
+	ChangeIndustryTileAnimationFrame(itspec, tile, iat, random, gfx, ind);
 	return true;
 }
 
--- a/src/newgrf_sound.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/newgrf_sound.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -69,9 +69,11 @@
 	return true;
 }
 
-bool PlayHouseSound(uint16 sound_id, TileIndex tile)
+bool PlayTileSound(const GRFFile *file, uint16 sound_id, TileIndex tile)
 {
-	if (sound_id < GetNumOriginalSounds()) {
+	if (sound_id >= GetNumOriginalSounds()) sound_id += file->sound_offset - GetNumOriginalSounds();
+
+	if (sound_id < GetNumSounds()) {
 		SndPlayTileFx((SoundFx)sound_id, tile);
 		return true;
 	}
--- a/src/newgrf_sound.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/newgrf_sound.h	Mon Apr 21 21:15:50 2008 +0000
@@ -26,6 +26,6 @@
 FileEntry *GetSound(uint index);
 uint GetNumSounds();
 bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event);
-bool PlayHouseSound(uint16 sound_id, TileIndex tile);
+bool PlayTileSound(const struct GRFFile *file, uint16 sound_id, TileIndex tile);
 
 #endif /* NEWGRF_SOUND_H */
--- a/src/newgrf_spritegroup.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/newgrf_spritegroup.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -80,37 +80,6 @@
 TemporaryStorageArray<uint32, 0x110> _temp_store;
 
 
-static inline bool Is8BitCallback(const ResolverObject *object)
-{
-	/* Var 0x7E procedure results are always 15 bit */
-	if (object == NULL || object->procedure_call) return false;
-
-	switch (object->callback) {
-		/* All these functions are 15 bit callbacks */
-		case CBID_STATION_SPRITE_LAYOUT:
-		case CBID_VEHICLE_REFIT_CAPACITY:
-		case CBID_HOUSE_COLOUR:
-		case CBID_HOUSE_CARGO_ACCEPTANCE:
-		case CBID_INDUSTRY_LOCATION:
-		case CBID_HOUSE_ACCEPT_CARGO:
-		case CBID_INDTILE_CARGO_ACCEPTANCE:
-		case CBID_INDTILE_ACCEPT_CARGO:
-		case CBID_VEHICLE_COLOUR_MAPPING:
-		case CBID_HOUSE_PRODUCE_CARGO:
-		case CBID_INDTILE_SHAPE_CHECK:
-		case CBID_VEHICLE_SOUND_EFFECT:
-		case CBID_VEHICLE_MODIFY_PROPERTY: // depends on queried property
-		case CBID_CARGO_PROFIT_CALC:
-		case CBID_SOUNDS_AMBIENT_EFFECT:
-		case CBID_CARGO_STATION_RATING_CALC:
-			return false;
-
-		/* The rest is a 8 bit callback, which should be truncated properly */
-		default:
-			return true;
-	}
-}
-
 static inline uint32 GetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available)
 {
 	/* First handle variables common with Action7/9/D */
@@ -236,7 +205,7 @@
 	if (group->g.determ.num_ranges == 0) {
 		/* nvar == 0 is a special case -- we turn our value into a callback result */
 		nvarzero.type = SGT_CALLBACK;
-		nvarzero.g.callback.result = GB(value, 0, Is8BitCallback(object) ? 8 : 15);
+		nvarzero.g.callback.result = value;
 		return &nvarzero;
 	}
 
@@ -295,14 +264,6 @@
 		case SGT_REAL:          return object->ResolveReal(object, group);
 		case SGT_DETERMINISTIC: return ResolveVariable(group, object);
 		case SGT_RANDOMIZED:    return ResolveRandom(group, object);
-		case SGT_CALLBACK: {
-			if (!Is8BitCallback(object)) return group;
-
-			static SpriteGroup result8bit;
-			result8bit.type = SGT_CALLBACK;
-			result8bit.g.callback.result = GB(group->g.callback.result, 0, 8);
-			return &result8bit;
-		}
 		default:                return group;
 	}
 }
--- a/src/newgrf_station.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/newgrf_station.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -16,12 +16,15 @@
 #include "newgrf_commons.h"
 #include "newgrf_station.h"
 #include "newgrf_spritegroup.h"
+#include "newgrf_sound.h"
 #include "cargotype.h"
 #include "town_map.h"
 #include "newgrf_town.h"
 #include "gfx_func.h"
 #include "date_func.h"
 #include "player_func.h"
+#include "animated_tile_func.h"
+#include "functions.h"
 
 #include "table/sprites.h"
 #include "table/strings.h"
@@ -740,8 +743,12 @@
 			free(st->speclist);
 			st->num_specs = 0;
 			st->speclist  = NULL;
+			st->cached_anim_triggers = 0;
+			return;
 		}
 	}
+
+	StationUpdateAnimTriggers(st);
 }
 
 /** Draw representation of a station tile for GUI purposes.
@@ -853,3 +860,186 @@
 		HasBit(statspec->pylons, GetStationGfx(tile)) ||
 		!HasBit(statspec->wires, GetStationGfx(tile));
 }
+
+void AnimateStationTile(TileIndex tile)
+{
+	const StationSpec *ss = GetStationSpec(tile);
+	if (ss == NULL) return;
+
+	const Station *st = GetStationByTile(tile);
+
+	uint8 animation_speed = ss->anim_speed;
+
+	if (HasBit(ss->callbackmask, CBM_STATION_ANIMATION_SPEED)) {
+		uint16 callback = GetStationCallback(CBID_STATION_ANIMATION_SPEED, 0, 0, ss, st, tile);
+		if (callback != CALLBACK_FAILED) animation_speed = Clamp(callback & 0xFF, 0, 16);
+	}
+
+	if (_tick_counter % (1 << animation_speed) != 0) return;
+
+	uint8 frame      = GetStationAnimationFrame(tile);
+	uint8 num_frames = ss->anim_frames;
+
+	bool frame_set_by_callback = false;
+
+	if (HasBit(ss->callbackmask, CBM_STATION_ANIMATION_NEXT_FRAME)) {
+		uint32 param = HasBit(ss->flags, 2) ? Random() : 0;
+		uint16 callback = GetStationCallback(CBID_STATION_ANIM_NEXT_FRAME, param, 0, ss, st, tile);
+
+		if (callback != CALLBACK_FAILED) {
+			frame_set_by_callback = true;
+
+			switch (callback & 0xFF) {
+				case 0xFF:
+					DeleteAnimatedTile(tile);
+					break;
+
+				case 0xFE:
+					frame_set_by_callback = false;
+					break;
+
+				default:
+					frame = callback & 0xFF;
+					break;
+			}
+
+			/* If the lower 7 bits of the upper byte of the callback
+			 * result are not empty, it is a sound effect. */
+			if (GB(callback, 8, 7) != 0) PlayTileSound(ss->grffile, GB(callback, 8, 7), tile);
+		}
+	}
+
+	if (!frame_set_by_callback) {
+		if (frame < num_frames) {
+			frame++;
+		} else if (frame == num_frames && HasBit(ss->anim_status, 0)) {
+			/* This animation loops, so start again from the beginning */
+			frame = 0;
+		} else {
+			/* This animation doesn't loop, so stay here */
+			DeleteAnimatedTile(tile);
+		}
+	}
+
+	SetStationAnimationFrame(tile, frame);
+	MarkTileDirtyByTile(tile);
+}
+
+
+static void ChangeStationAnimationFrame(const StationSpec *ss, const Station *st, TileIndex tile, uint16 random_bits, StatAnimTrigger trigger, CargoID cargo_type)
+{
+	uint16 callback = GetStationCallback(CBID_STATION_ANIM_START_STOP, (random_bits << 16) | Random(), (uint8)trigger | (cargo_type << 8), ss, st, tile);
+	if (callback == CALLBACK_FAILED) return;
+
+	switch (callback & 0xFF) {
+		case 0xFD: /* Do nothing. */         break;
+		case 0xFE: AddAnimatedTile(tile);    break;
+		case 0xFF: DeleteAnimatedTile(tile); break;
+		default:
+			SetStationAnimationFrame(tile, callback);
+			AddAnimatedTile(tile);
+			break;
+	}
+
+	/* If the lower 7 bits of the upper byte of the callback
+	 * result are not empty, it is a sound effect. */
+	if (GB(callback, 8, 7) != 0) PlayTileSound(ss->grffile, GB(callback, 8, 7), tile);
+}
+
+enum TriggerArea {
+	TA_TILE,
+	TA_PLATFORM,
+	TA_WHOLE,
+};
+
+struct TileArea {
+	TileIndex tile;
+	uint8 w;
+	uint8 h;
+
+	TileArea(const Station *st, TileIndex tile, TriggerArea ta)
+	{
+		switch (ta) {
+			default: NOT_REACHED();
+
+			case TA_TILE:
+				this->tile = tile;
+				this->w    = 1;
+				this->h    = 1;
+				break;
+
+			case TA_PLATFORM: {
+				TileIndex start, end;
+				Axis axis = GetRailStationAxis(tile);
+				TileIndexDiff delta = TileOffsByDiagDir(AxisToDiagDir(axis));
+
+				for (end = tile; IsRailwayStationTile(end + delta) && IsCompatibleTrainStationTile(tile, end + delta); end += delta) { /* Nothing */ }
+				for (start = tile; IsRailwayStationTile(start - delta) && IsCompatibleTrainStationTile(tile, start - delta); start -= delta) { /* Nothing */ }
+
+				this->tile = start;
+				this->w = TileX(end) - TileX(start) + 1;
+				this->h = TileY(end) - TileY(start) + 1;
+				break;
+			}
+
+			case TA_WHOLE:
+				this->tile = st->train_tile;
+				this->w    = st->trainst_w + 1;
+				this->h    = st->trainst_h + 1;
+				break;
+		}
+	}
+};
+
+void StationAnimationTrigger(const Station *st, TileIndex tile, StatAnimTrigger trigger, CargoID cargo_type)
+{
+	/* List of coverage areas for each animation trigger */
+	static const TriggerArea tas[] = {
+		TA_TILE, TA_WHOLE, TA_WHOLE, TA_PLATFORM, TA_PLATFORM, TA_PLATFORM, TA_WHOLE
+	};
+
+	/* Get Station if it wasn't supplied */
+	if (st == NULL) st = GetStationByTile(tile);
+
+	/* Check the cached animation trigger bitmask to see if we need
+	 * to bother with any further processing. */
+	if (!HasBit(st->cached_anim_triggers, trigger)) return;
+
+	uint16 random_bits = Random();
+	TileArea area = TileArea(st, tile, tas[trigger]);
+
+	for (uint y = 0; y < area.h; y++) {
+		for (uint x = 0; x < area.w; x++) {
+			if (st->TileBelongsToRailStation(area.tile)) {
+				const StationSpec *ss = GetStationSpec(area.tile);
+				if (ss != NULL && HasBit(ss->anim_triggers, trigger)) {
+					CargoID cargo;
+					if (cargo_type == CT_INVALID) {
+						cargo = CT_INVALID;
+					} else {
+						cargo = GetReverseCargoTranslation(cargo_type, ss->grffile);
+					}
+					ChangeStationAnimationFrame(ss, st, area.tile, random_bits, trigger, cargo);
+				}
+			}
+			area.tile += TileDiffXY(1, 0);
+		}
+		area.tile += TileDiffXY(-area.w, 1);
+	}
+}
+
+/**
+ * Update the cached animation trigger bitmask for a station.
+ * @param st Station to update.
+ */
+void StationUpdateAnimTriggers(Station *st)
+{
+	st->cached_anim_triggers = 0;
+
+	/* Combine animation trigger bitmask for all station specs
+	 * of this station. */
+	for (uint i = 0; i < st->num_specs; i++) {
+		const StationSpec *ss = st->speclist[i].spec;
+		if (ss != NULL) st->cached_anim_triggers |= ss->anim_triggers;
+	}
+}
--- a/src/newgrf_station.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/newgrf_station.h	Mon Apr 21 21:15:50 2008 +0000
@@ -83,6 +83,11 @@
 	StationLayout **layouts;
 	bool copied_layouts;
 
+	uint8  anim_frames;
+	uint8  anim_status;
+	uint8  anim_speed;
+	uint16 anim_triggers;
+
 	/**
 	 * NUM_CARGO real cargo plus three pseudo cargo sprite groups.
 	 * Used for obtaining the sprite offset of custom sprites, and for
@@ -132,4 +137,18 @@
 /* Draw representation of a station tile for GUI purposes. */
 bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID sclass, uint station);
 
+enum StatAnimTrigger {
+	STAT_ANIM_BUILT,
+	STAT_ANIM_NEW_CARGO,
+	STAT_ANIM_CARGO_TAKEN,
+	STAT_ANIM_TRAIN_ARRIVES,
+	STAT_ANIM_TRAIN_DEPARTS,
+	STAT_ANIM_TRAIN_LOADS,
+	STAT_ANIM_250_TICKS,
+};
+
+void AnimateStationTile(TileIndex tile);
+void StationAnimationTrigger(const Station *st, TileIndex tile, StatAnimTrigger trigger, CargoID cargo_type = CT_INVALID);
+void StationUpdateAnimTriggers(Station *st);
+
 #endif /* NEWGRF_STATION_H */
--- a/src/news_func.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/news_func.h	Mon Apr 21 21:15:50 2008 +0000
@@ -14,10 +14,9 @@
 void InitNewsItemStructs();
 
 extern NewsItem _statusbar_news_item;
-extern uint32 _news_display_opt;
 extern bool _news_ticker_sound;
 
-extern const char *_news_display_name[NT_END];
+extern NewsTypeData _news_type_data[NT_END];
 
 /**
  * Delete a news item type about a vehicle
--- a/src/news_gui.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/news_gui.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -53,7 +53,6 @@
 #define INVALID_NEWS 255
 
 NewsItem _statusbar_news_item;
-uint32 _news_display_opt;
 bool _news_ticker_sound;
 static NewsItem _news_items[MAX_NEWS];      ///< The news FIFO queue
 static NewsID _current_news = INVALID_NEWS; ///< points to news item that should be shown next
@@ -335,25 +334,24 @@
 
 
 /**
- * Maximum age of news items.
- * Don't show item if it's older than x days, corresponds with NewsType in news_type.h
- * @see NewsType
+ * Per-NewsType data
  */
-static const byte _news_items_age[NT_END] = {
-	60,  ///< NT_ARRIVAL_PLAYER
-	60,  ///< NT_ARRIVAL_OTHER
-	90,  ///< NT_ACCIDENT
-	60,  ///< NT_COMPANY_INFO
-	90,  ///< NT_OPENCLOSE
-	30,  ///< NT_ECONOMY
-	30,  ///< NT_INDUSTRY_PLAYER
-	30,  ///< NT_INDUSTRY_OTHER
-	30,  ///< NT_INDUSTRY_NOBODY
-	150, ///< NT_ADVICE
-	30,  ///< NT_NEW_VEHICLES
-	90,  ///< NT_ACCEPTANCE
-	180, ///< NT_SUBSIDIES
-	60   ///< NT_GENERAL
+NewsTypeData _news_type_data[NT_END] = {
+	/* name,              age, sound,           display */
+	{ "arrival_player",    60, SND_1D_APPLAUSE, ND_FULL },  ///< NT_ARRIVAL_PLAYER
+	{ "arrival_other",     60, SND_1D_APPLAUSE, ND_FULL },  ///< NT_ARRIVAL_OTHER
+	{ "accident",          90, SND_BEGIN,       ND_FULL },  ///< NT_ACCIDENT
+	{ "company_info",      60, SND_BEGIN,       ND_FULL },  ///< NT_COMPANY_INFO
+	{ "openclose",         90, SND_BEGIN,       ND_FULL },  ///< NT_OPENCLOSE
+	{ "economy",           30, SND_BEGIN,       ND_FULL },  ///< NT_ECONOMY
+	{ "production_player", 30, SND_BEGIN,       ND_FULL },  ///< NT_INDUSTRY_PLAYER
+	{ "production_other",  30, SND_BEGIN,       ND_FULL },  ///< NT_INDUSTRY_OTHER
+	{ "production_nobody", 30, SND_BEGIN,       ND_FULL },  ///< NT_INDUSTRY_NOBODY
+	{ "advice",           150, SND_BEGIN,       ND_FULL },  ///< NT_ADVICE
+	{ "new_vehicles",      30, SND_1E_OOOOH,    ND_FULL },  ///< NT_NEW_VEHICLES
+	{ "acceptance",        90, SND_BEGIN,       ND_FULL },  ///< NT_ACCEPTANCE
+	{ "subsidies",        180, SND_BEGIN,       ND_FULL },  ///< NT_SUBSIDIES
+	{ "general",           60, SND_BEGIN,       ND_FULL },  ///< NT_GENERAL
 };
 
 
@@ -401,63 +399,6 @@
 	NewsWindowProc
 };
 
-static const SoundFx _news_sounds[NT_END] = {
-	SND_1D_APPLAUSE, ///< NT_ARRIVAL_PLAYER
-	SND_1D_APPLAUSE, ///< NT_ARRIVAL_OTHER
-	SND_BEGIN,       ///< NT_ACCIDENT
-	SND_BEGIN,       ///< NT_COMPANY_INFO
-	SND_BEGIN,       ///< NT_OPENCLOSE
-	SND_BEGIN,       ///< NT_ECONOMY
-	SND_BEGIN,       ///< NT_INDUSTRY_PLAYER
-	SND_BEGIN,       ///< NT_INDUSTRY_OTHER
-	SND_BEGIN,       ///< NT_INDUSTRY_NOBODY
-	SND_BEGIN,       ///< NT_ADVICE
-	SND_1E_OOOOH,    ///< NT_NEW_VEHICLES
-	SND_BEGIN,       ///< NT_ACCEPTANCE
-	SND_BEGIN,       ///< NT_SUBSIDIES
-	SND_BEGIN,       ///< NT_GENERAL
-};
-
-const char *_news_display_name[NT_END] = {
-	"arrival_player",
-	"arrival_other",
-	"accident",
-	"company_info",
-	"openclose",
-	"economy",
-	"production_player",
-	"production_other",
-	"production_nobody",
-	"advice",
-	"new_vehicles",
-	"acceptance",
-	"subsidies",
-	"general",
-};
-
-/**
- * Get the value of an item of the news-display settings. This is
- * a little tricky since on/off/summary must use 2 bits to store the value
- * @param item the item whose value is requested
- * @return return the found value which is between 0-2
- */
-static inline byte GetNewsDisplayValue(byte item)
-{
-	assert(item < NT_END && GB(_news_display_opt, item * 2, 2) <= 2);
-	return GB(_news_display_opt, item * 2, 2);
-}
-
-/**
- * Set the value of an item in the news-display settings. This is
- * a little tricky since on/off/summary must use 2 bits to store the value
- * @param item the item whose value is being set
- * @param val new value
- */
-static inline void SetNewsDisplayValue(byte item, byte val)
-{
-	assert(item < NT_END && val <= 2);
-	SB(_news_display_opt, item * 2, 2, val);
-}
 
 /** Open up an own newspaper window for the news item */
 static void ShowNewspaper(NewsItem *ni)
@@ -465,7 +406,7 @@
 	ni->flags &= ~NF_FORCE_BIG;
 	ni->duration = 555;
 
-	SoundFx sound = _news_sounds[ni->type];
+	SoundFx sound = _news_type_data[ni->type].sound;
 	if (sound != 0) SndPlayFx(sound);
 
 	int top = _screen.height;
@@ -476,7 +417,7 @@
 			_news_type13_desc.top = top;
 			w = AllocateWindowDesc(&_news_type13_desc);
 			if (ni->flags & NF_VIEWPORT) {
-				AssignWindowViewport(w, 2, 58, 0x1AA, 0x6E,
+				InitializeWindowViewport(w, 2, 58, 426, 110,
 					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS);
 			}
 			break;
@@ -485,7 +426,7 @@
 			_news_type2_desc.top = top;
 			w = AllocateWindowDesc(&_news_type2_desc);
 			if (ni->flags & NF_VIEWPORT) {
-				AssignWindowViewport(w, 2, 58, 0x1AA, 0x46,
+				InitializeWindowViewport(w, 2, 58, 426, 70,
 					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS);
 			}
 			break;
@@ -494,7 +435,7 @@
 			_news_type0_desc.top = top;
 			w = AllocateWindowDesc(&_news_type0_desc);
 			if (ni->flags & NF_VIEWPORT) {
-				AssignWindowViewport(w, 3, 17, 0x112, 0x2F,
+				InitializeWindowViewport(w, 3, 17, 274, 47,
 					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS);
 			}
 			break;
@@ -553,11 +494,11 @@
 		NewsItem *ni = &_news_items[_current_news];
 
 		/* check the date, don't show too old items */
-		if (_date - _news_items_age[ni->type] > ni->date) return;
+		if (_date - _news_type_data[ni->type].age > ni->date) return;
 
-		switch (GetNewsDisplayValue(ni->type)) {
+		switch (_news_type_data[ni->type].display) {
 			default: NOT_REACHED();
-			case 0: { // Off - show nothing only a small reminder in the status bar
+			case ND_OFF: { // Off - show nothing only a small reminder in the status bar
 				Window *w = FindWindowById(WC_STATUS_BAR, 0);
 
 				if (w != NULL) {
@@ -567,14 +508,14 @@
 				break;
 			}
 
-			case 1: // Summary - show ticker, but if forced big, cascade to full
+			case ND_SUMMARY: // Summary - show ticker, but if forced big, cascade to full
 				if (!(ni->flags & NF_FORCE_BIG)) {
 					ShowTicker(ni);
 					break;
 				}
 				/* Fallthrough */
 
-			case 2: // Full - show newspaper
+			case ND_FULL: // Full - show newspaper
 				ShowNewspaper(ni);
 				break;
 		}
@@ -803,33 +744,30 @@
 	/* WP(w, def_d).data_1 stores state of the ALL on/off/summary button */
 	switch (e->event) {
 		case WE_CREATE: {
-			uint32 val = _news_display_opt;
-			uint32 all_val;
+			NewsDisplay all_val;
 
 			/* Set up the initial disabled buttons in the case of 'off' or 'full' */
-			all_val = val & 0x3;
-			for (int i = 0; i < NT_END; i++, val >>= 2) {
-				SetMessageButtonStates(w, val & 0x3, i);
+			all_val = _news_type_data[0].display;
+			for (int i = 0; i < NT_END; i++) {
+				SetMessageButtonStates(w, _news_type_data[i].display, i);
 				/* If the value doesn't match the ALL-button value, set the ALL-button value to 'off' */
-				if ((val & 0x3) != all_val) all_val = 0;
+				if (_news_type_data[i].display != all_val) all_val = ND_OFF;
 			}
 			/* If all values are the same value, the ALL-button will take over this value */
 			WP(w, def_d).data_1 = all_val;
 		} break;
 
 		case WE_PAINT: {
-			uint32 val = _news_display_opt;
-
 			if (_news_ticker_sound) w->LowerWidget(WIDGET_NEWSOPT_SOUNDTICKER);
 
 			w->widget[WIDGET_NEWSOPT_DROP_SUMMARY].data = message_opt[WP(w, def_d).data_1];
 			DrawWindowWidgets(w);
 
 			/* Draw the string of each setting on each button. */
-			for (int i = 0, y = 26; i < NT_END; i++, y += 12, val >>= 2) {
+			for (int i = 0, y = 26; i < NT_END; i++, y += 12) {
 				/* 51 comes from 13 + 89 (left and right of the button)+1, shiefted by one as to get division,
 				 * which will give centered position */
-				DrawStringCentered(51, y + 1, message_opt[val & 0x3], TC_BLACK);
+				DrawStringCentered(51, y + 1, message_opt[_news_type_data[i].display], TC_BLACK);
 			}
 		} break;
 
@@ -849,10 +787,10 @@
 					int wid = e->we.click.widget - WIDGET_NEWSOPT_START_OPTION;
 					if (wid >= 0 && wid < (NB_WIDG_PER_SETTING * NT_END)) {
 						int element = wid / NB_WIDG_PER_SETTING;
-						byte val = (GetNewsDisplayValue(element) + ((wid % NB_WIDG_PER_SETTING) ? 1 : -1)) % 3;
+						byte val = (_news_type_data[element].display + ((wid % NB_WIDG_PER_SETTING) ? 1 : -1)) % 3;
 
 						SetMessageButtonStates(w, val, element);
-						SetNewsDisplayValue(element, val);
+						_news_type_data[element].display = (NewsDisplay)val;
 						SetWindowDirty(w);
 					}
 				} break;
@@ -864,7 +802,7 @@
 
 			for (int i = 0; i < NT_END; i++) {
 				SetMessageButtonStates(w, e->we.dropdown.index, i);
-				SetNewsDisplayValue(i, e->we.dropdown.index);
+				_news_type_data[i].display = (NewsDisplay)e->we.dropdown.index;
 			}
 			SetWindowDirty(w);
 			break;
--- a/src/news_type.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/news_type.h	Mon Apr 21 21:15:50 2008 +0000
@@ -8,6 +8,7 @@
 #include "window_type.h"
 #include "date_type.h"
 #include "strings_type.h"
+#include "sound_type.h"
 
 /**
  * Type of news.
@@ -75,6 +76,25 @@
 	NB_BNEWCOMPANY = (4 << 4), ///< A new company has been started
 };
 
+/**
+ * News display options
+ */
+enum NewsDisplay {
+	ND_OFF,        ///< Only show a reminder in the status bar
+	ND_SUMMARY,    ///< Show ticker
+	ND_FULL,       ///< Show newspaper
+};
+
+/**
+ * Per-NewsType data
+ */
+struct NewsTypeData {
+	const char *const name; ///< Name
+	const byte age;         ///< Maximum age of news items (in days)
+	const SoundFx sound;    ///< Sound
+	NewsDisplay display;    ///< Display mode (off, summary, full)
+};
+
 struct NewsItem {
 	StringID string_id;    ///< Message text (sometimes also used for storing other info)
 	uint16 duration;       ///< Remaining time for showing this news message
--- a/src/oldloader.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/oldloader.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -23,7 +23,8 @@
 #include "date_func.h"
 #include "vehicle_func.h"
 #include "variables.h"
-#include "settings_type.h"
+#include "strings_func.h"
+#include "effectvehicle_base.h"
 
 #include "table/strings.h"
 
@@ -84,6 +85,12 @@
 
 	OC_TILE      = OC_VAR_U32  | OC_FILE_U16,
 
+	/**
+	 * Dereference the pointer once before writing to it,
+	 * so we do not have to use big static arrays.
+	 */
+	OC_DEREFERENCE_POINTER = 1 << 31,
+
 	OC_END       = 0 ///< End of the whole chunk, all 32bits set to zero
 };
 
@@ -201,10 +208,10 @@
 	byte *base_ptr = (byte*)base;
 
 	while (chunk->type != OC_END) {
-		byte* ptr = (byte*)chunk->ptr;
-		uint i;
+		byte *ptr = (byte*)chunk->ptr;
+		if ((chunk->type & OC_DEREFERENCE_POINTER) != 0) ptr = *(byte**)ptr;
 
-		for (i = 0; i < chunk->amount; i++) {
+		for (uint i = 0; i < chunk->amount; i++) {
 			if (ls->failed) return false;
 
 			/* Handle simple types */
@@ -391,10 +398,10 @@
 
 extern TileIndex *_animated_tile_list;
 extern uint _animated_tile_count;
-extern char _name_array[512][32];
+extern char *_old_name_array;
 
 static byte   _old_vehicle_multiplier;
-static uint8  _old_map3[OLD_MAP_SIZE * 2];
+static uint8  *_old_map3;
 static bool   _new_ttdpatch_format;
 static uint32 _old_town_index;
 static uint16 _old_string_id;
@@ -819,7 +826,7 @@
 	OCL_SVAR( OC_FILE_U32 | OC_VAR_I64, Player, bankrupt_value ),
 	OCL_SVAR( OC_UINT16, Player, bankrupt_timeout ),
 
-	OCL_SVAR( OC_FILE_U32 | OC_VAR_U16, Player, cargo_types ),
+	OCL_SVAR( OC_UINT32, Player, cargo_types ),
 
 	OCL_CHUNK( 3, OldPlayerYearly ),
 	OCL_CHUNK( 1, OldPlayerEconomy ),
@@ -932,9 +939,9 @@
 	OCL_END()
 };
 
-static const OldChunks vehicle_special_chunk[] = {
-	OCL_SVAR( OC_UINT16, VehicleSpecial, animation_state ),
-	OCL_SVAR(  OC_UINT8, VehicleSpecial, animation_substate ),
+static const OldChunks vehicle_effect_chunk[] = {
+	OCL_SVAR( OC_UINT16, VehicleEffect, animation_state ),
+	OCL_SVAR(  OC_UINT8, VehicleEffect, animation_substate ),
 
 	OCL_NULL( 7 ), // Junk
 
@@ -969,7 +976,7 @@
 		case VEH_ROAD    : res = LoadChunk(ls, &v->u.road,     vehicle_road_chunk);     break;
 		case VEH_SHIP    : res = LoadChunk(ls, &v->u.ship,     vehicle_ship_chunk);     break;
 		case VEH_AIRCRAFT: res = LoadChunk(ls, &v->u.air,      vehicle_air_chunk);      break;
-		case VEH_SPECIAL : res = LoadChunk(ls, &v->u.special,  vehicle_special_chunk);  break;
+		case VEH_EFFECT  : res = LoadChunk(ls, &v->u.effect,   vehicle_effect_chunk);   break;
 		case VEH_DISASTER: res = LoadChunk(ls, &v->u.disaster, vehicle_disaster_chunk); break;
 	}
 
@@ -1082,7 +1089,7 @@
 			case 0x11 /*VEH_ROAD    */: v = new (_current_vehicle_id) RoadVehicle();     break;
 			case 0x12 /*VEH_SHIP    */: v = new (_current_vehicle_id) Ship();            break;
 			case 0x13 /*VEH_AIRCRAFT*/: v = new (_current_vehicle_id) Aircraft();        break;
-			case 0x14 /*VEH_SPECIAL */: v = new (_current_vehicle_id) SpecialVehicle();  break;
+			case 0x14 /*VEH_EFFECT  */: v = new (_current_vehicle_id) EffectVehicle();   break;
 			case 0x15 /*VEH_DISASTER*/: v = new (_current_vehicle_id) DisasterVehicle(); break;
 		}
 		if (!LoadChunk(ls, v, vehicle_chunk)) return false;
@@ -1116,7 +1123,7 @@
 		v->name = CopyFromOldName(_old_string_id);
 
 		/* Vehicle-subtype is different in TTD(Patch) */
-		if (v->type == VEH_SPECIAL) v->subtype = v->subtype >> 1;
+		if (v->type == VEH_EFFECT) v->subtype = v->subtype >> 1;
 
 		if (_cargo_count != 0) {
 			CargoPacket *cp = new CargoPacket((_cargo_source == 0xFF) ? INVALID_STATION : _cargo_source, _cargo_count);
@@ -1374,7 +1381,7 @@
 
 	OCL_ASSERT( 0x6F0F2 ),
 
-	OCL_VAR (  OC_UINT8, 32 * 500, &_name_array[0] ),
+	OCL_VAR (  OC_UINT8 | OC_DEREFERENCE_POINTER, 32 * 500, &_old_name_array ),
 
 	OCL_NULL( 0x2000 ),            ///< Old hash-table, no longer in use
 
@@ -1454,8 +1461,10 @@
 
 	DEBUG(oldloader, 3, "Reading main chunk...");
 	/* Load the biggest chunk */
+	_old_map3 = MallocT<byte>(OLD_MAP_SIZE * 2);
 	if (!LoadChunk(ls, NULL, main_chunk)) {
 		DEBUG(oldloader, 0, "Loading failed");
+		free(_old_map3);
 		return false;
 	}
 	DEBUG(oldloader, 3, "Done, converting game data...");
@@ -1522,6 +1531,8 @@
 	DEBUG(oldloader, 3, "Finished converting game data");
 	DEBUG(oldloader, 1, "TTD(Patch) savegame successfully converted");
 
+	free(_old_map3);
+
 	return true;
 }
 
--- a/src/openttd.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/openttd.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -59,6 +59,8 @@
 #include "date_func.h"
 #include "vehicle_func.h"
 #include "cheat_func.h"
+#include "animated_tile_func.h"
+#include "functions.h"
 
 #include "newgrf.h"
 #include "newgrf_config.h"
@@ -93,6 +95,8 @@
 void DoPaletteAnimations();
 void MusicLoop();
 void ResetMusic();
+void ResetOldNames();
+void ProcessAsyncSaveFinish();
 
 extern void SetDifficultyLevel(int mode, GameOptions *gm_opt);
 extern Player* DoStartupNewPlayer(bool is_ai);
@@ -654,39 +658,6 @@
 	}
 }
 
-
-/** Mutex so that only one thread can communicate with the main program
- * at any given time */
-static ThreadMsg _message = MSG_OTTD_NO_MESSAGE;
-
-static inline void OTTD_ReleaseMutex() {_message = MSG_OTTD_NO_MESSAGE;}
-static inline ThreadMsg OTTD_PollThreadEvent() {return _message;}
-
-/** Called by running thread to execute some action in the main game.
- * It will stall as long as the mutex is not freed (handled) by the game */
-void OTTD_SendThreadMessage(ThreadMsg msg)
-{
-	if (_exit_game) return;
-	while (_message != MSG_OTTD_NO_MESSAGE) CSleep(10);
-
-	_message = msg;
-}
-
-
-/** Handle the user-messages sent to us
- * @param message message sent
- */
-static void ProcessSentMessage(ThreadMsg message)
-{
-	switch (message) {
-		case MSG_OTTD_SAVETHREAD_DONE:  SaveFileDone(); break;
-		case MSG_OTTD_SAVETHREAD_ERROR: SaveFileError(); break;
-		default: NOT_REACHED();
-	}
-
-	OTTD_ReleaseMutex(); // release mutex so that other threads, messages can be handled
-}
-
 static void ShowScreenshotResult(bool b)
 {
 	if (b) {
@@ -1104,9 +1075,7 @@
 
 void GameLoop()
 {
-	ThreadMsg message;
-
-	if ((message = OTTD_PollThreadEvent()) != 0) ProcessSentMessage(message);
+	ProcessAsyncSaveFinish();
 
 	/* autosave game? */
 	if (_do_autosave) {
@@ -1400,6 +1369,9 @@
 		}
 	}
 
+	/* From this point the old names array is cleared. */
+	ResetOldNames();
+
 	/* convert road side to my format. */
 	if (_opt.road_side) _opt.road_side = 1;
 
--- a/src/openttd.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/openttd.h	Mon Apr 21 21:15:50 2008 +0000
@@ -1,4 +1,5 @@
 /* $Id$ */
+
 /** @file openttd.h */
 
 #ifndef OPENTTD_H
@@ -108,17 +109,6 @@
 };
 extern byte _no_scroll;
 
-/** To have a concurrently running thread interface with the main program, use
- * the OTTD_SendThreadMessage() function. Actions to perform upon the message are handled
- * in the ProcessSentMessage() function */
-enum ThreadMsg {
-	MSG_OTTD_NO_MESSAGE,
-	MSG_OTTD_SAVETHREAD_DONE,
-	MSG_OTTD_SAVETHREAD_ERROR,
-};
-
-void OTTD_SendThreadMessage(ThreadMsg msg);
-
 extern byte _game_mode;
 extern bool _exit_game;
 extern int8 _pause_game;
--- a/src/player_base.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/player_base.h	Mon Apr 21 21:15:50 2008 +0000
@@ -44,7 +44,7 @@
 	byte block_preview;
 	PlayerByte index;
 
-	uint16 cargo_types; ///< which cargo types were transported the last year
+	uint32 cargo_types; ///< which cargo types were transported the last year
 
 	TileIndex location_of_house;
 	TileIndex last_build_coordinate;
--- a/src/players.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/players.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -648,14 +648,12 @@
  */
 CommandCost CmdSetAutoReplace(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
-	Player *p;
 	if (!IsValidPlayer(_current_player)) return CMD_ERROR;
 
-	p = GetPlayer(_current_player);
+	Player *p = GetPlayer(_current_player);
 	switch (GB(p1, 0, 3)) {
 		case 0:
-			if (p->engine_renew == HasBit(p2, 0))
-				return CMD_ERROR;
+			if (p->engine_renew == HasBit(p2, 0)) return CMD_ERROR;
 
 			if (flags & DC_EXEC) {
 				p->engine_renew = HasBit(p2, 0);
@@ -665,9 +663,10 @@
 				}
 			}
 			break;
+
 		case 1:
-			if (p->engine_renew_months == (int16)p2)
-				return CMD_ERROR;
+			if (Clamp((int16)p2, -12, 12) != (int16)p2) return CMD_ERROR;
+			if (p->engine_renew_months == (int16)p2) return CMD_ERROR;
 
 			if (flags & DC_EXEC) {
 				p->engine_renew_months = (int16)p2;
@@ -677,18 +676,20 @@
 				}
 			}
 			break;
+
 		case 2:
-			if (p->engine_renew_money == (uint32)p2)
-				return CMD_ERROR;
+			if (ClampU(p2, 0, 2000000) != p2) return CMD_ERROR;
+			if (p->engine_renew_money == p2) return CMD_ERROR;
 
 			if (flags & DC_EXEC) {
-				p->engine_renew_money = (uint32)p2;
+				p->engine_renew_money = p2;
 				if (IsLocalPlayer()) {
 					_patches.autorenew_money = p->engine_renew_money;
 					InvalidateWindow(WC_GAME_OPTIONS, 0);
 				}
 			}
 			break;
+
 		case 3: {
 			EngineID old_engine_type = GB(p2, 0, 16);
 			EngineID new_engine_type = GB(p2, 16, 16);
@@ -699,21 +700,19 @@
 			if (new_engine_type != INVALID_ENGINE) {
 				/* First we make sure that it's a valid type the user requested
 				 * check that it's an engine that is in the engine array */
-				if (!IsEngineIndex(new_engine_type))
-					return CMD_ERROR;
+				if (!IsEngineIndex(new_engine_type)) return CMD_ERROR;
 
 				/* check that the new vehicle type is the same as the original one */
-				if (GetEngine(old_engine_type)->type != GetEngine(new_engine_type)->type)
-					return CMD_ERROR;
+				if (GetEngine(old_engine_type)->type != GetEngine(new_engine_type)->type) return CMD_ERROR;
 
 				/* make sure that we do not replace a plane with a helicopter or vise versa */
 				if (GetEngine(new_engine_type)->type == VEH_AIRCRAFT &&
-						(AircraftVehInfo(old_engine_type)->subtype & AIR_CTOL) != (AircraftVehInfo(new_engine_type)->subtype & AIR_CTOL))
+						(AircraftVehInfo(old_engine_type)->subtype & AIR_CTOL) != (AircraftVehInfo(new_engine_type)->subtype & AIR_CTOL)) {
 					return CMD_ERROR;
+				}
 
 				/* make sure that the player can actually buy the new engine */
-				if (!HasBit(GetEngine(new_engine_type)->player_avail, _current_player))
-					return CMD_ERROR;
+				if (!HasBit(GetEngine(new_engine_type)->player_avail, _current_player)) return CMD_ERROR;
 
 				cost = AddEngineReplacementForPlayer(p, old_engine_type, new_engine_type, id_g, flags);
 			} else {
@@ -726,10 +725,13 @@
 		}
 
 		case 4:
+			if (Clamp((int16)GB(p1, 16, 16), -12, 12) != (int16)GB(p1, 16, 16)) return CMD_ERROR;
+			if (ClampU(p2, 0, 2000000) != p2) return CMD_ERROR;
+
 			if (flags & DC_EXEC) {
 				p->engine_renew = HasBit(p1, 15);
 				p->engine_renew_months = (int16)GB(p1, 16, 16);
-				p->engine_renew_money = (uint32)p2;
+				p->engine_renew_money = p2;
 
 				if (IsLocalPlayer()) {
 					_patches.autorenew = p->engine_renew;
@@ -739,9 +741,9 @@
 				}
 			}
 			break;
+
 		case 5:
-			if (p->renew_keep_length == HasBit(p2, 0))
-				return CMD_ERROR;
+			if (p->renew_keep_length == HasBit(p2, 0)) return CMD_ERROR;
 
 			if (flags & DC_EXEC) {
 				p->renew_keep_length = HasBit(p2, 0);
@@ -750,8 +752,8 @@
 				}
 			}
 		break;
+	}
 
-	}
 	return CommandCost();
 }
 
@@ -1102,7 +1104,8 @@
 	SLE_CONDVAR(Player, avail_railtypes,       SLE_UINT8,                   0, 57),
 	    SLE_VAR(Player, block_preview,         SLE_UINT8),
 
-	    SLE_VAR(Player, cargo_types,           SLE_UINT16),
+	SLE_CONDVAR(Player, cargo_types,           SLE_FILE_U16 | SLE_VAR_U32,  0, 93),
+	SLE_CONDVAR(Player, cargo_types,           SLE_UINT32,                 94, SL_MAX_VERSION),
 	SLE_CONDVAR(Player, location_of_house,     SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
 	SLE_CONDVAR(Player, location_of_house,     SLE_UINT32,                  6, SL_MAX_VERSION),
 	SLE_CONDVAR(Player, last_build_coordinate, SLE_FILE_U16 | SLE_VAR_U32,  0,  5),
--- a/src/rail_cmd.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/rail_cmd.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -43,6 +43,7 @@
 #include "tunnelbridge.h"
 #include "station_map.h"
 #include "water_map.h"
+#include "functions.h"
 
 #include "table/sprites.h"
 #include "table/strings.h"
--- a/src/rail_gui.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/rail_gui.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -952,7 +952,7 @@
 				const StationSpec *statspec = GetCustomStationSpec(_railstation.station_class, i);
 
 				if (statspec != NULL && statspec->name != 0) {
-					if (HasBit(statspec->callbackmask, CBM_STATION_AVAIL) && GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE) == 0) {
+					if (HasBit(statspec->callbackmask, CBM_STATION_AVAIL) && GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) {
 						GfxFillRect(8, y - 2, 127, y + 10, (1 << PALETTE_MODIFIER_GREYOUT));
 					}
 
@@ -1097,7 +1097,7 @@
 			statspec = GetCustomStationSpec(_railstation.station_class, y);
 			if (statspec != NULL &&
 				HasBit(statspec->callbackmask, CBM_STATION_AVAIL) &&
-				GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE) == 0) return;
+				GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) return;
 
 			_railstation.station_type = y;
 
@@ -1510,7 +1510,7 @@
 
 				if (statspec != NULL &&
 						HasBit(statspec->callbackmask, CBM_STATION_AVAIL) &&
-						GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE) == 0) {
+						GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) {
 					GfxFillRect(4 + i * 68, 18, 67 + i * 68, 75, (1 << PALETTE_MODIFIER_GREYOUT));
 				}
 			}
@@ -1530,7 +1530,7 @@
 				const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, type);
 				if (statspec != NULL &&
 						HasBit(statspec->callbackmask, CBM_STATION_AVAIL) &&
-						GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE) == 0) return;
+						GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) return;
 
 				_cur_waypoint_type = type;
 				SndPlayFx(SND_15_BEEP);
--- a/src/road_cmd.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/road_cmd.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -36,6 +36,8 @@
 #include "road_func.h"
 #include "tunnelbridge.h"
 #include "cheat_func.h"
+#include "functions.h"
+#include "effectvehicle_func.h"
 
 #include "table/sprites.h"
 #include "table/strings.h"
--- a/src/roadveh.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/roadveh.h	Mon Apr 21 21:15:50 2008 +0000
@@ -73,7 +73,7 @@
 	ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_ROADVEH_INC : EXPENSES_ROADVEH_RUN; }
 	WindowClass GetVehicleListWindowClass() const { return WC_ROADVEH_LIST; }
 	bool IsPrimaryVehicle() const { return IsRoadVehFront(this); }
-	int GetImage(Direction direction) const;
+	SpriteID GetImage(Direction direction) const;
 	int GetDisplaySpeed() const { return this->cur_speed * 10 / 32; }
 	int GetDisplayMaxSpeed() const { return this->max_speed * 10 / 32; }
 	Money GetRunningCost() const { return RoadVehInfo(this->engine_type)->running_cost * GetPriceByIndex(RoadVehInfo(this->engine_type)->running_cost_class); }
--- a/src/roadveh_cmd.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/roadveh_cmd.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -43,6 +43,7 @@
 #include "order_func.h"
 #include "depot_base.h"
 #include "depot_func.h"
+#include "effectvehicle_func.h"
 
 #include "table/strings.h"
 
@@ -94,36 +95,42 @@
 	TRACKDIR_X_NE, TRACKDIR_Y_SE, TRACKDIR_X_SW, TRACKDIR_Y_NW
 };
 
-int RoadVehicle::GetImage(Direction direction) const
+static SpriteID GetRoadVehIcon(EngineID engine)
 {
-	int img = this->spritenum;
-	int image;
+	uint8 spritenum = RoadVehInfo(engine)->image_index;
 
-	if (is_custom_sprite(img)) {
-		image = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(img)));
-		if (image != 0) return image;
-		img = _orig_road_vehicle_info[this->engine_type - ROAD_ENGINES_INDEX].image_index;
+	if (is_custom_sprite(spritenum)) {
+		SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W);
+		if (sprite != 0) return sprite;
+
+		spritenum = _orig_road_vehicle_info[engine - ROAD_ENGINES_INDEX].image_index;
 	}
 
-	image = direction + _roadveh_images[img];
-	if (this->cargo.Count() >= this->cargo_cap / 2U) image += _roadveh_full_adder[img];
-	return image;
+	return 6 + _roadveh_images[spritenum];
+}
+
+SpriteID RoadVehicle::GetImage(Direction direction) const
+{
+	uint8 spritenum = this->spritenum;
+	SpriteID sprite;
+
+	if (is_custom_sprite(spritenum)) {
+		sprite = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)));
+		if (sprite != 0) return sprite;
+
+		spritenum = _orig_road_vehicle_info[this->engine_type - ROAD_ENGINES_INDEX].image_index;
+	}
+
+	sprite = direction + _roadveh_images[spritenum];
+
+	if (this->cargo.Count() >= this->cargo_cap / 2U) sprite += _roadveh_full_adder[spritenum];
+
+	return sprite;
 }
 
 void DrawRoadVehEngine(int x, int y, EngineID engine, SpriteID pal)
 {
-	int spritenum = RoadVehInfo(engine)->image_index;
-
-	if (is_custom_sprite(spritenum)) {
-		int sprite = GetCustomVehicleIcon(engine, DIR_W);
-
-		if (sprite != 0) {
-			DrawSprite(sprite, pal, x, y);
-			return;
-		}
-		spritenum = _orig_road_vehicle_info[engine - ROAD_ENGINES_INDEX].image_index;
-	}
-	DrawSprite(6 + _roadveh_images[spritenum], pal, x, y);
+	DrawSprite(GetRoadVehIcon(engine), pal, x, y);
 }
 
 static CommandCost EstimateRoadVehCost(EngineID engine_type)
@@ -293,19 +300,16 @@
  */
 CommandCost CmdStartStopRoadVeh(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
-	Vehicle *v;
-	uint16 callback;
-
 	if (!IsValidVehicleID(p1)) return CMD_ERROR;
 
-	v = GetVehicle(p1);
+	Vehicle *v = GetVehicle(p1);
 
 	if (v->type != VEH_ROAD || !CheckOwnership(v->owner)) return CMD_ERROR;
 
 	/* Check if this road veh can be started/stopped. The callback will fail or
 	 * return 0xFF if it can. */
-	callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v);
-	if (callback != CALLBACK_FAILED && callback != 0xFF) {
+	uint16 callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v);
+	if (callback != CALLBACK_FAILED && GB(callback, 0, 8) != 0xFF) {
 		StringID error = GetGRFStringID(GetEngineGRFID(v->engine_type), 0xD000 + callback);
 		return_cmd_error(error);
 	}
@@ -707,7 +711,7 @@
 
 		if (!(v->vehstatus & VS_HIDDEN)) {
 			Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE);
-			if (u != NULL) u->u.special.animation_state = v->breakdown_delay * 2;
+			if (u != NULL) u->u.effect.animation_state = v->breakdown_delay * 2;
 		}
 	}
 
@@ -1847,7 +1851,7 @@
 			HandleBrokenRoadVeh(v);
 			return;
 		}
-		v->breakdown_ctr--;
+		if (!v->current_order.IsType(OT_LOADING)) v->breakdown_ctr--;
 	}
 
 	if (v->vehstatus & VS_STOPPED) return;
--- a/src/saveload.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/saveload.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -34,7 +34,7 @@
 
 #include "table/strings.h"
 
-extern const uint16 SAVEGAME_VERSION = 93;
+extern const uint16 SAVEGAME_VERSION = 94;
 uint16 _sl_version;       ///< the major savegame version identifier
 byte   _sl_minor_version; ///< the minor savegame version, DO NOT USE!
 
@@ -87,6 +87,32 @@
 	throw std::exception();
 }
 
+typedef void (*AsyncSaveFinishProc)();
+static AsyncSaveFinishProc _async_save_finish = NULL;
+
+/**
+ * Called by save thread to tell we finished saving.
+ */
+static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
+{
+	if (_exit_game) return;
+	while (_async_save_finish != NULL) CSleep(10);
+
+	_async_save_finish = proc;
+}
+
+/**
+ * Handle async save finishes.
+ */
+void ProcessAsyncSaveFinish()
+{
+	if (_async_save_finish == NULL) return;
+
+	_async_save_finish();
+
+	_async_save_finish = NULL;
+}
+
 /**
  * Fill the input buffer by reading from the file with the given reader
  */
@@ -1248,6 +1274,7 @@
 
 /* these define the chunks */
 extern const ChunkHandler _misc_chunk_handlers[];
+extern const ChunkHandler _name_chunk_handlers[];
 extern const ChunkHandler _cheat_chunk_handlers[] ;
 extern const ChunkHandler _setting_chunk_handlers[];
 extern const ChunkHandler _player_chunk_handlers[];
@@ -1268,6 +1295,7 @@
 
 static const ChunkHandler * const _chunk_handlers[] = {
 	_misc_chunk_handlers,
+	_name_chunk_handlers,
 	_cheat_chunk_handlers,
 	_setting_chunk_handlers,
 	_veh_chunk_handlers,
@@ -1455,7 +1483,7 @@
 /** Update the gui accordingly when starting saving
  * and set locks on saveload. Also turn off fast-forward cause with that
  * saving takes Aaaaages */
-void SaveFileStart()
+static void SaveFileStart()
 {
 	_ts.ff_state = _fast_forward;
 	_fast_forward = 0;
@@ -1467,7 +1495,7 @@
 
 /** Update the gui accordingly when saving is done and release locks
  * on saveload */
-void SaveFileDone()
+static void SaveFileDone()
 {
 	_fast_forward = _ts.ff_state;
 	if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
@@ -1494,7 +1522,7 @@
 }
 
 /** Show a gui message when saving has failed */
-void SaveFileError()
+static void SaveFileError()
 {
 	SetDParamStr(0, GetSaveLoadErrorString());
 	ShowErrorMessage(STR_012D, STR_NULL, 0, 0);
@@ -1543,7 +1571,7 @@
 		GetSavegameFormat("memory")->uninit_write(); // clean the memorypool
 		fclose(_sl.fh);
 
-		if (threaded) OTTD_SendThreadMessage(MSG_OTTD_SAVETHREAD_DONE);
+		if (threaded) SetAsyncSaveFinish(SaveFileDone);
 
 		return SL_OK;
 	}
@@ -1555,7 +1583,7 @@
 		fprintf(stderr, GetSaveLoadErrorString());
 
 		if (threaded) {
-			OTTD_SendThreadMessage(MSG_OTTD_SAVETHREAD_ERROR);
+			SetAsyncSaveFinish(SaveFileError);
 		} else {
 			SaveFileError();
 		}
--- a/src/saveload.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/saveload.h	Mon Apr 21 21:15:50 2008 +0000
@@ -320,7 +320,4 @@
 void SlObject(void *object, const SaveLoad *sld);
 bool SlObjectMember(void *object, const SaveLoad *sld);
 
-void SaveFileStart();
-void SaveFileDone();
-void SaveFileError();
 #endif /* SAVELOAD_H */
--- a/src/settings.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/settings.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -1648,20 +1648,18 @@
 #undef NO
 #undef CR
 
-static uint NewsDisplayLoadConfig(IniFile *ini, const char *grpname)
+static void NewsDisplayLoadConfig(IniFile *ini, const char *grpname)
 {
 	IniGroup *group = ini_getgroup(ini, grpname, -1);
 	IniItem *item;
-	/* By default, set everything to full (0xAAAAAAAA = 1010101010101010) */
-	uint res = 0xAAAAAAAA;
 
-	/* If no group exists, return everything full */
-	if (group == NULL) return res;
+	/* If no group exists, return */
+	if (group == NULL) return;
 
 	for (item = group->item; item != NULL; item = item->next) {
 		int news_item = -1;
 		for (int i = 0; i < NT_END; i++) {
-			if (strcasecmp(item->name, _news_display_name[i]) == 0) {
+			if (strcasecmp(item->name, _news_type_data[i].name) == 0) {
 				news_item = i;
 				break;
 			}
@@ -1672,18 +1670,16 @@
 		}
 
 		if (strcasecmp(item->value, "full") == 0) {
-			SB(res, news_item * 2, 2, 2);
+			_news_type_data[news_item].display = ND_FULL;
 		} else if (strcasecmp(item->value, "off") == 0) {
-			SB(res, news_item * 2, 2, 0);
+			_news_type_data[news_item].display = ND_OFF;
 		} else if (strcasecmp(item->value, "summarized") == 0) {
-			SB(res, news_item * 2, 2, 1);
+			_news_type_data[news_item].display = ND_SUMMARY;
 		} else {
 			DEBUG(misc, 0, "Invalid display value: %s", item->value);
 			continue;
 		}
 	}
-
-	return res;
 }
 
 /* Load a GRF configuration from the given group name */
@@ -1739,7 +1735,7 @@
 	return first;
 }
 
-static void NewsDisplaySaveConfig(IniFile *ini, const char *grpname, uint news_display)
+static void NewsDisplaySaveConfig(IniFile *ini, const char *grpname)
 {
 	IniGroup *group = ini_getgroup(ini, grpname, -1);
 	IniItem **item;
@@ -1750,11 +1746,11 @@
 
 	for (int i = 0; i < NT_END; i++) {
 		const char *value;
-		int v = GB(news_display, i * 2, 2);
+		int v = _news_type_data[i].display;
 
-		value = (v == 0 ? "off" : (v == 1 ? "summarized" : "full"));
+		value = (v == ND_OFF ? "off" : (v == ND_SUMMARY ? "summarized" : "full"));
 
-		*item = ini_item_alloc(group, _news_display_name[i], strlen(_news_display_name[i]));
+		*item = ini_item_alloc(group, _news_type_data[i].name, strlen(_news_type_data[i].name));
 		(*item)->value = (char*)pool_strdup(&ini->pool, value, strlen(value));
 		item = &(*item)->next;
 	}
@@ -1841,7 +1837,7 @@
 	HandleSettingDescs(ini, ini_load_settings, ini_load_setting_list);
 	_grfconfig_newgame = GRFLoadConfig(ini, "newgrf", false);
 	_grfconfig_static  = GRFLoadConfig(ini, "newgrf-static", true);
-	_news_display_opt  = NewsDisplayLoadConfig(ini, "news_display");
+	NewsDisplayLoadConfig(ini, "news_display");
 	CheckDifficultyLevels();
 	ini_free(ini);
 }
@@ -1853,7 +1849,7 @@
 	HandleSettingDescs(ini, ini_save_settings, ini_save_setting_list);
 	GRFSaveConfig(ini, "newgrf", _grfconfig_newgame);
 	GRFSaveConfig(ini, "newgrf-static", _grfconfig_static);
-	NewsDisplaySaveConfig(ini, "news_display", _news_display_opt);
+	NewsDisplaySaveConfig(ini, "news_display");
 	SaveVersionInConfig(ini);
 	ini_save(_config_file, ini);
 	ini_free(ini);
--- a/src/ship.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/ship.h	Mon Apr 21 21:15:50 2008 +0000
@@ -35,7 +35,7 @@
 	WindowClass GetVehicleListWindowClass() const { return WC_SHIPS_LIST; }
 	void PlayLeaveStationSound() const;
 	bool IsPrimaryVehicle() const { return true; }
-	int GetImage(Direction direction) const;
+	SpriteID GetImage(Direction direction) const;
 	int GetDisplaySpeed() const { return this->cur_speed * 10 / 32; }
 	int GetDisplayMaxSpeed() const { return this->max_speed * 10 / 32; }
 	Money GetRunningCost() const { return ShipVehInfo(this->engine_type)->running_cost * _price.ship_running; }
--- a/src/ship_cmd.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/ship_cmd.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -40,6 +40,7 @@
 #include "gfx_func.h"
 #include "settings_type.h"
 #include "order_func.h"
+#include "effectvehicle_func.h"
 
 #include "table/strings.h"
 
@@ -57,20 +58,23 @@
 	return TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_WATER, 0));
 }
 
-void DrawShipEngine(int x, int y, EngineID engine, SpriteID pal)
+static SpriteID GetShipIcon(EngineID engine)
 {
-	int spritenum = ShipVehInfo(engine)->image_index;
+	uint8 spritenum = ShipVehInfo(engine)->image_index;
 
 	if (is_custom_sprite(spritenum)) {
-		int sprite = GetCustomVehicleIcon(engine, DIR_W);
+		SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W);
+		if (sprite != 0) return sprite;
 
-		if (sprite != 0) {
-			DrawSprite(sprite, pal, x, y);
-			return;
-		}
 		spritenum = _orig_ship_vehicle_info[engine - SHIP_ENGINES_INDEX].image_index;
 	}
-	DrawSprite(6 + _ship_sprites[spritenum], pal, x, y);
+
+	return 6 + _ship_sprites[spritenum];
+}
+
+void DrawShipEngine(int x, int y, EngineID engine, SpriteID pal)
+{
+	DrawSprite(GetShipIcon(engine), pal, x, y);
 }
 
 /** Get the size of the sprite of a ship sprite heading west (used for lists)
@@ -80,35 +84,23 @@
  */
 void GetShipSpriteSize(EngineID engine, uint &width, uint &height)
 {
-	SpriteID spritenum = ShipVehInfo(engine)->image_index;
-	SpriteID custom_sprite = 0;
-
-	if (is_custom_sprite(spritenum)) {
-		custom_sprite = GetCustomVehicleIcon(engine, DIR_W);
-		spritenum = _orig_ship_vehicle_info[engine - SHIP_ENGINES_INDEX].image_index;
-	}
-	if (custom_sprite == 0) {
-		spritenum = 6 + _ship_sprites[spritenum];
-	} else {
-		spritenum = custom_sprite;
-	}
-
-	const Sprite *spr = GetSprite(spritenum);
+	const Sprite *spr = GetSprite(GetShipIcon(engine));
 
 	width  = spr->width;
 	height = spr->height;
 }
 
-int Ship::GetImage(Direction direction) const
+SpriteID Ship::GetImage(Direction direction) const
 {
-	int spritenum = this->spritenum;
+	uint8 spritenum = this->spritenum;
 
 	if (is_custom_sprite(spritenum)) {
-		int sprite = GetCustomVehicleSprite(this, direction);
+		SpriteID sprite = GetCustomVehicleSprite(this, direction);
+		if (sprite != 0) return sprite;
 
-		if (sprite != 0) return sprite;
 		spritenum = _orig_ship_vehicle_info[this->engine_type - SHIP_ENGINES_INDEX].image_index;
 	}
+
 	return _ship_sprites[spritenum] + direction;
 }
 
@@ -210,7 +202,7 @@
 
 		if (!(v->vehstatus & VS_HIDDEN)) {
 			Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE);
-			if (u != NULL) u->u.special.animation_state = v->breakdown_delay * 2;
+			if (u != NULL) u->u.effect.animation_state = v->breakdown_delay * 2;
 		}
 	}
 
@@ -594,7 +586,7 @@
 			HandleBrokenShip(v);
 			return;
 		}
-		v->breakdown_ctr--;
+		if (!v->current_order.IsType(OT_LOADING)) v->breakdown_ctr--;
 	}
 
 	if (v->vehstatus & VS_STOPPED) return;
@@ -881,19 +873,16 @@
  */
 CommandCost CmdStartStopShip(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
-	Vehicle *v;
-	uint16 callback;
-
 	if (!IsValidVehicleID(p1)) return CMD_ERROR;
 
-	v = GetVehicle(p1);
+	Vehicle *v = GetVehicle(p1);
 
 	if (v->type != VEH_SHIP || !CheckOwnership(v->owner)) return CMD_ERROR;
 
 	/* Check if this ship can be started/stopped. The callback will fail or
 	 * return 0xFF if it can. */
-	callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v);
-	if (callback != CALLBACK_FAILED && callback != 0xFF) {
+	uint16 callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v);
+	if (callback != CALLBACK_FAILED && GB(callback, 0, 8) != 0xFF) {
 		StringID error = GetGRFStringID(GetEngineGRFID(v->engine_type), 0xD000 + callback);
 		return_cmd_error(error);
 	}
--- a/src/smallmap_gui.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/smallmap_gui.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -682,7 +682,7 @@
 		byte color;
 
 		FOR_ALL_VEHICLES(v) {
-			if (v->type != VEH_SPECIAL &&
+			if (v->type != VEH_EFFECT &&
 					(v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0) {
 				/* Remap into flat coordinates. */
 				Point pt = RemapCoords(
@@ -1108,15 +1108,15 @@
 static void ExtraViewPortWndProc(Window *w, WindowEvent *e)
 {
 	switch (e->event) {
-	case WE_CREATE: /* Disable zoom in button */
+	case WE_CREATE: // Disable zoom in button
 		/* New viewport start at (zero,zero) */
-		AssignWindowViewport(w, 3, 17, w->widget[4].right - w->widget[4].left - 1, w->widget[4].bottom - w->widget[4].top - 1, 0, ZOOM_LVL_VIEWPORT);
+		InitializeWindowViewport(w, 3, 17, w->widget[4].right - w->widget[4].left - 1, w->widget[4].bottom - w->widget[4].top - 1, 0, ZOOM_LVL_VIEWPORT);
 
 		w->DisableWidget(5);
 		break;
 
 	case WE_PAINT:
-		// set the number in the title bar
+		/* set the number in the title bar */
 		SetDParam(0, w->window_number + 1);
 
 		DrawWindowWidgets(w);
@@ -1128,7 +1128,7 @@
 			case 5: DoZoomInOutWindow(ZOOM_IN,  w); break;
 			case 6: DoZoomInOutWindow(ZOOM_OUT, w); break;
 
-		case 7: { /* location button (move main view to same spot as this view) 'Paste Location' */
+		case 7: { // location button (move main view to same spot as this view) 'Paste Location'
 			Window *w2 = FindWindowById(WC_MAIN_WINDOW, 0);
 			int x = WP(w, vp_d).scrollpos_x; // Where is the main looking at
 			int y = WP(w, vp_d).scrollpos_y;
@@ -1138,7 +1138,7 @@
 			WP(w2, vp_d).dest_scrollpos_y =  y - (w2->viewport->virtual_height - w->viewport->virtual_height) / 2;
 		} break;
 
-		case 8: { /* inverse location button (move this view to same spot as main view) 'Copy Location' */
+		case 8: { // inverse location button (move this view to same spot as main view) 'Copy Location'
 			const Window *w2 = FindWindowById(WC_MAIN_WINDOW, 0);
 			int x = WP(w2, const vp_d).scrollpos_x;
 			int y = WP(w2, const vp_d).scrollpos_y;
--- a/src/sound.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/sound.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -207,6 +207,14 @@
 	}
 }
 
+/**
+ * Decide 'where' (between left and right speaker) to play the sound effect.
+ * @param sound Sound effect to play
+ * @param left   Left edge of virtual coordinates where the sound is produced
+ * @param right  Right edge of virtual coordinates where the sound is produced
+ * @param top    Top edge of virtual coordinates where the sound is produced
+ * @param bottom Bottom edge of virtual coordinates where the sound is produced
+ */
 static void SndPlayScreenCoordFx(SoundFx sound, int left, int right, int top, int bottom)
 {
 	Window* const *wz;
@@ -231,7 +239,6 @@
 			return;
 		}
 	}
-
 }
 
 void SndPlayTileFx(SoundFx sound, TileIndex tile)
--- a/src/station_base.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/station_base.h	Mon Apr 21 21:15:50 2008 +0000
@@ -159,6 +159,7 @@
 
 	uint16 random_bits;
 	byte waiting_triggers;
+	uint8 cached_anim_triggers; ///< Combined animation trigger bitmask, used to determine if trigger processing should happen.
 
 	StationRect rect; ///< Station spread out rectangle (not saved) maintained by StationRect_xxx() functions
 
--- a/src/station_cmd.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/station_cmd.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -42,6 +42,7 @@
 #include "string_func.h"
 #include "signal_func.h"
 #include "oldpool_func.h"
+#include "animated_tile_func.h"
 
 #include "table/sprites.h"
 #include "table/strings.h"
@@ -1013,7 +1014,7 @@
 		}
 
 		/* Check if the station is buildable */
-		if (HasBit(statspec->callbackmask, CBM_STATION_AVAIL) && GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE) == 0) {
+		if (HasBit(statspec->callbackmask, CBM_STATION_AVAIL) && GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) {
 			return CMD_ERROR;
 		}
 	}
@@ -1038,6 +1039,12 @@
 
 		st->rect.BeforeAddRect(tile_org, w_org, h_org, StationRect::ADD_TRY);
 
+		if (statspec != NULL) {
+			/* Include this station spec's animation trigger bitmask
+			 * in the station's cached copy. */
+			st->cached_anim_triggers |= statspec->anim_triggers;
+		}
+
 		tile_delta = (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
 		track = AxisToTrack(axis);
 
@@ -1054,6 +1061,7 @@
 				MakeRailStation(tile, st->owner, st->index, axis, layout & ~1, (RailType)GB(p2, 0, 4));
 				SetCustomStationSpecIndex(tile, specindex);
 				SetStationTileRandomBits(tile, GB(Random(), 0, 4));
+				SetStationAnimationFrame(tile, 0);
 
 				if (statspec != NULL) {
 					/* Use a fixed axis for GetPlatformInfo as our platforms / numtracks are always the right way around */
@@ -1062,6 +1070,9 @@
 					/* As the station is not yet completely finished, the station does not yet exist. */
 					uint16 callback = GetStationCallback(CBID_STATION_TILE_LAYOUT, platinfo, 0, statspec, NULL, tile);
 					if (callback != CALLBACK_FAILED && callback < 8) SetStationGfx(tile, (callback & ~1) + axis);
+
+					/* Trigger station animation -- after building? */
+					StationAnimationTrigger(st, tile, STAT_ANIM_BUILT);
 				}
 
 				tile += tile_delta;
@@ -1283,6 +1294,7 @@
 		free(st->speclist);
 		st->num_specs = 0;
 		st->speclist  = NULL;
+		st->cached_anim_triggers = 0;
 
 		InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_TRAINS);
 		UpdateStationVirtCoordDirty(st);
@@ -2368,6 +2380,11 @@
 		{ GFX_WINDSACK_INTERCON_FIRST,   GFX_WINDSACK_INTERCON_LAST,   1 }
 	};
 
+	if (IsRailwayStation(tile)) {
+		AnimateStationTile(tile);
+		return;
+	}
+
 	StationGfx gfx = GetStationGfx(tile);
 
 	for (const AnimData *i = data; i != endof(data); i++) {
@@ -2614,7 +2631,16 @@
 	if (IsValidStationID(i)) StationHandleBigTick(GetStation(i));
 
 	Station *st;
-	FOR_ALL_STATIONS(st) StationHandleSmallTick(st);
+	FOR_ALL_STATIONS(st) {
+		StationHandleSmallTick(st);
+
+		/* Run 250 tick interval trigger for station animation.
+		 * Station index is included so that triggers are not all done
+		 * at the same time. */
+		if ((_tick_counter + st->index) % 250 == 0) {
+			StationAnimationTrigger(st, st->xy, STAT_ANIM_250_TICKS);
+		}
+	}
 }
 
 void StationMonthlyLoop()
@@ -2646,6 +2672,8 @@
 	st->goods[type].cargo.Append(new CargoPacket(st->index, amount));
 	SetBit(st->goods[type].acceptance_pickup, GoodsEntry::PICKUP);
 
+	StationAnimationTrigger(st, st->xy, STAT_ANIM_NEW_CARGO, type);
+
 	InvalidateWindow(WC_STATION_VIEW, st->index);
 	st->MarkTilesDirty(true);
 }
@@ -3008,6 +3036,8 @@
 		}
 
 		for (CargoID c = 0; c < NUM_CARGO; c++) st->goods[c].cargo.InvalidateCache();
+
+		StationUpdateAnimTriggers(st);
 	}
 }
 
--- a/src/station_gui.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/station_gui.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -184,35 +184,36 @@
 assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(plstations_d));
 
 /**
- * Set the 'SL_REBUILD' flag for all station lists
+ * Set the station sort flag for all station-list windows.
+ * @param sl_flag Sort list flag to set for all station-list windows
  */
-void RebuildStationLists()
+static void SetStationListsFlag(StationListFlags sl_flag)
 {
 	Window *const *wz;
 
 	FOR_ALL_WINDOWS(wz) {
 		Window *w = *wz;
 		if (w->window_class == WC_STATION_LIST) {
-			WP(w, plstations_d).flags |= SL_REBUILD;
+			WP(w, plstations_d).flags |= sl_flag;
 			SetWindowDirty(w);
 		}
 	}
 }
 
 /**
+ * Set the 'SL_REBUILD' flag for all station lists
+ */
+void RebuildStationLists()
+{
+	SetStationListsFlag(SL_REBUILD);
+}
+
+/**
  * Set the 'SL_RESORT' flag for all station lists
  */
 void ResortStationLists()
 {
-	Window *const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
-		if (w->window_class == WC_STATION_LIST) {
-			WP(w, plstations_d).flags |= SL_RESORT;
-			SetWindowDirty(w);
-		}
-	}
+	SetStationListsFlag(SL_RESORT);
 }
 
 /**
--- a/src/strings.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/strings.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -37,6 +37,7 @@
 #include "settings_type.h"
 #include "video/video_driver.hpp"
 #include "engine_func.h"
+#include "saveload.h"
 
 #include "table/strings.h"
 #include "table/control_codes.h"
@@ -1045,11 +1046,11 @@
 
 static char *StationGetSpecialString(char *buff, int x, const char* last)
 {
-	if ((x & 0x01) && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
-	if ((x & 0x02) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
-	if ((x & 0x04) && (buff + Utf8CharLen(SCC_BUS)   < last)) buff += Utf8Encode(buff, SCC_BUS);
-	if ((x & 0x08) && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
-	if ((x & 0x10) && (buff + Utf8CharLen(SCC_SHIP)  < last)) buff += Utf8Encode(buff, SCC_SHIP);
+	if ((x & FACIL_TRAIN)      && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
+	if ((x & FACIL_TRUCK_STOP) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
+	if ((x & FACIL_BUS_STOP)   && (buff + Utf8CharLen(SCC_BUS)   < last)) buff += Utf8Encode(buff, SCC_BUS);
+	if ((x & FACIL_AIRPORT)    && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
+	if ((x & FACIL_DOCK)       && (buff + Utf8CharLen(SCC_SHIP)  < last)) buff += Utf8Encode(buff, SCC_SHIP);
 	*buff = '\0';
 	return buff;
 }
@@ -1226,31 +1227,6 @@
 	return NULL;
 }
 
-/**
- * remap a string ID from the old format to the new format
- * @param s StringID that requires remapping
- * @return translated ID*/
-StringID RemapOldStringID(StringID s)
-{
-	switch (s) {
-		case 0x0006: return STR_SV_EMPTY;
-		case 0x7000: return STR_SV_UNNAMED;
-		case 0x70E4: return SPECSTR_PLAYERNAME_ENGLISH;
-		case 0x70E9: return SPECSTR_PLAYERNAME_ENGLISH;
-		case 0x8864: return STR_SV_TRAIN_NAME;
-		case 0x902B: return STR_SV_ROADVEH_NAME;
-		case 0x9830: return STR_SV_SHIP_NAME;
-		case 0xA02F: return STR_SV_AIRCRAFT_NAME;
-
-		default:
-			if (IsInsideMM(s, 0x300F, 0x3030)) {
-				return s - 0x300F + STR_SV_STNAME;
-			} else {
-				return s;
-			}
-	}
-}
-
 #ifdef ENABLE_NETWORK
 extern void SortNetworkLanguages();
 #else /* ENABLE_NETWORK */
@@ -1342,6 +1318,8 @@
 
 	return getenv("LANG");
 }
+#else
+const char *GetCurrentLocale(const char *param);
 #endif /* !(defined(WIN32) || defined(__APPLE__)) */
 
 int CDECL StringIDSorter(const void *a, const void *b)
@@ -1548,3 +1526,118 @@
 		}
 	}
 }
+
+
+/* --- Handling of saving/loading string IDs from old savegames --- */
+
+/**
+ * Remap a string ID from the old format to the new format
+ * @param s StringID that requires remapping
+ * @return translated ID
+ */
+StringID RemapOldStringID(StringID s)
+{
+	switch (s) {
+		case 0x0006: return STR_SV_EMPTY;
+		case 0x7000: return STR_SV_UNNAMED;
+		case 0x70E4: return SPECSTR_PLAYERNAME_ENGLISH;
+		case 0x70E9: return SPECSTR_PLAYERNAME_ENGLISH;
+		case 0x8864: return STR_SV_TRAIN_NAME;
+		case 0x902B: return STR_SV_ROADVEH_NAME;
+		case 0x9830: return STR_SV_SHIP_NAME;
+		case 0xA02F: return STR_SV_AIRCRAFT_NAME;
+
+		default:
+			if (IsInsideMM(s, 0x300F, 0x3030)) {
+				return s - 0x300F + STR_SV_STNAME;
+			} else {
+				return s;
+			}
+	}
+}
+
+/** Location to load the old names to. */
+char *_old_name_array = NULL;
+
+/**
+ * Copy and convert old custom names to UTF-8.
+ * They were all stored in a 512 by 32 long string array and are
+ * now stored with stations, waypoints and other places with names.
+ * @param id the StringID of the custom name to clone.
+ * @return the clones custom name.
+ */
+char *CopyFromOldName(StringID id)
+{
+	/* Is this name an (old) custom name? */
+	if (GB(id, 11, 5) != 15) return NULL;
+
+	if (CheckSavegameVersion(37)) {
+		/* Old names were 32 characters long, so 128 characters should be
+		 * plenty to allow for expansion when converted to UTF-8. */
+		char tmp[128];
+		const char *strfrom = &_old_name_array[32 * GB(id, 0, 9)];
+		char *strto = tmp;
+
+		for (; *strfrom != '\0'; strfrom++) {
+			WChar c = (byte)*strfrom;
+
+			/* Map from non-ISO8859-15 characters to UTF-8. */
+			switch (c) {
+				case 0xA4: c = 0x20AC; break; // Euro
+				case 0xA6: c = 0x0160; break; // S with caron
+				case 0xA8: c = 0x0161; break; // s with caron
+				case 0xB4: c = 0x017D; break; // Z with caron
+				case 0xB8: c = 0x017E; break; // z with caron
+				case 0xBC: c = 0x0152; break; // OE ligature
+				case 0xBD: c = 0x0153; break; // oe ligature
+				case 0xBE: c = 0x0178; break; // Y with diaresis
+				default: break;
+			}
+
+			/* Check character will fit into our buffer. */
+			if (strto + Utf8CharLen(c) > lastof(tmp)) break;
+
+			strto += Utf8Encode(strto, c);
+		}
+
+		/* Terminate the new string and copy it back to the name array */
+		*strto = '\0';
+
+		return strdup(tmp);
+	} else {
+		/* Name will already be in UTF-8. */
+		return strdup(&_old_name_array[32 * GB(id, 0, 9)]);
+	}
+}
+
+/**
+ * Free the memory of the old names array.
+ * Should be called once the old names have all been converted.
+ */
+void ResetOldNames()
+{
+	free(_old_name_array);
+	_old_name_array = NULL;
+}
+
+/**
+ * Initialize the old names table memory.
+ */
+void InitializeOldNames()
+{
+	free(_old_name_array);
+	_old_name_array = CallocT<char>(512 * 32);
+}
+
+static void Load_NAME()
+{
+	int index;
+
+	while ((index = SlIterateArray()) != -1) {
+		SlArray(&_old_name_array[32 * index], SlGetFieldLength(), SLE_UINT8);
+	}
+}
+
+extern const ChunkHandler _name_chunk_handlers[] = {
+	{ 'NAME', NULL, Load_NAME, CH_ARRAY | CH_LAST},
+};
--- a/src/strings_func.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/strings_func.h	Mon Apr 21 21:15:50 2008 +0000
@@ -78,4 +78,7 @@
 
 void CheckForMissingGlyphsInLoadedLanguagePack();
 
+StringID RemapOldStringID(StringID s);
+char *CopyFromOldName(StringID id);
+
 #endif /* STRINGS_TYPE_H */
--- a/src/texteff.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/texteff.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -4,10 +4,8 @@
 
 #include "stdafx.h"
 #include "openttd.h"
-#include "tile_cmd.h"
 #include "landscape.h"
 #include "gfx_func.h"
-#include "saveload.h"
 #include "console.h"
 #include "variables.h"
 #include "blitter/factory.hpp"
@@ -423,128 +421,3 @@
 		default: NOT_REACHED();
 	}
 }
-
-/** The table/list with animated tiles. */
-TileIndex *_animated_tile_list = NULL;
-/** The number of animated tiles in the current state. */
-uint _animated_tile_count = 0;
-/** The number of slots for animated tiles allocated currently. */
-static uint _animated_tile_allocated = 0;
-
-/**
- * Removes the given tile from the animated tile table.
- * @param tile the tile to remove
- */
-void DeleteAnimatedTile(TileIndex tile)
-{
-	for (TileIndex *ti = _animated_tile_list; ti < _animated_tile_list + _animated_tile_count; ti++) {
-		if (tile == *ti) {
-			/* Remove the hole
-			 * The order of the remaining elements must stay the same, otherwise the animation loop
-			 * may miss a tile; that's why we must use memmove instead of just moving the last element.
-			 */
-			memmove(ti, ti + 1, (_animated_tile_list + _animated_tile_count - (ti + 1)) * sizeof(*ti));
-			_animated_tile_count--;
-			MarkTileDirtyByTile(tile);
-			return;
-		}
-	}
-}
-
-/**
- * Add the given tile to the animated tile table (if it does not exist
- * on that table yet). Also increases the size of the table if necessary.
- * @param tile the tile to make animated
- */
-void AddAnimatedTile(TileIndex tile)
-{
-	MarkTileDirtyByTile(tile);
-
-	for (const TileIndex *ti = _animated_tile_list; ti < _animated_tile_list + _animated_tile_count; ti++) {
-		if (tile == *ti) return;
-	}
-
-	/* Table not large enough, so make it larger */
-	if (_animated_tile_count == _animated_tile_allocated) {
-		_animated_tile_allocated *= 2;
-		_animated_tile_list = ReallocT<TileIndex>(_animated_tile_list, _animated_tile_allocated);
-	}
-
-	_animated_tile_list[_animated_tile_count] = tile;
-	_animated_tile_count++;
-}
-
-/**
- * Animate all tiles in the animated tile list, i.e.\ call AnimateTile on them.
- */
-void AnimateAnimatedTiles()
-{
-	const TileIndex *ti = _animated_tile_list;
-	while (ti < _animated_tile_list + _animated_tile_count) {
-		const TileIndex curr = *ti;
-		AnimateTile(curr);
-		/* During the AnimateTile call, DeleteAnimatedTile could have been called,
-		 * deleting an element we've already processed and pushing the rest one
-		 * slot to the left. We can detect this by checking whether the index
-		 * in the current slot has changed - if it has, an element has been deleted,
-		 * and we should process the current slot again instead of going forward.
-		 * NOTE: this will still break if more than one animated tile is being
-		 *       deleted during the same AnimateTile call, but no code seems to
-		 *       be doing this anyway.
-		 */
-		if (*ti == curr) ++ti;
-	}
-}
-
-/**
- * Initialize all animated tile variables to some known begin point
- */
-void InitializeAnimatedTiles()
-{
-	_animated_tile_list = ReallocT<TileIndex>(_animated_tile_list, 256);
-	_animated_tile_count = 0;
-	_animated_tile_allocated = 256;
-}
-
-/**
- * Save the ANIT chunk.
- */
-static void Save_ANIT()
-{
-	SlSetLength(_animated_tile_count * sizeof(*_animated_tile_list));
-	SlArray(_animated_tile_list, _animated_tile_count, SLE_UINT32);
-}
-
-/**
- * Load the ANIT chunk; the chunk containing the animated tiles.
- */
-static void Load_ANIT()
-{
-	/* Before version 80 we did NOT have a variable length animated tile table */
-	if (CheckSavegameVersion(80)) {
-		/* In pre version 6, we has 16bit per tile, now we have 32bit per tile, convert it ;) */
-		SlArray(_animated_tile_list, 256, CheckSavegameVersion(6) ? (SLE_FILE_U16 | SLE_VAR_U32) : SLE_UINT32);
-
-		for (_animated_tile_count = 0; _animated_tile_count < 256; _animated_tile_count++) {
-			if (_animated_tile_list[_animated_tile_count] == 0) break;
-		}
-		return;
-	}
-
-	_animated_tile_count = SlGetFieldLength() / sizeof(*_animated_tile_list);
-
-	/* Determine a nice rounded size for the amount of allocated tiles */
-	_animated_tile_allocated = 256;
-	while (_animated_tile_allocated < _animated_tile_count) _animated_tile_allocated *= 2;
-
-	_animated_tile_list = ReallocT<TileIndex>(_animated_tile_list, _animated_tile_allocated);
-	SlArray(_animated_tile_list, _animated_tile_count, SLE_UINT32);
-}
-
-/**
- * "Definition" imported by the saveload code to be able to load and save
- * the animated tile table.
- */
-extern const ChunkHandler _animated_tile_chunk_handlers[] = {
-	{ 'ANIT', Save_ANIT, Load_ANIT, CH_RIFF | CH_LAST},
-};
--- a/src/toolbar_gui.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/toolbar_gui.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -1419,8 +1419,7 @@
 
 Window *AllocateToolbar()
 {
-	/* Clean old GUI values */
-	_last_built_railtype = RAILTYPE_RAIL;
+	/* Clean old GUI values; railtype is (re)set by rail_gui.cpp */
 	_last_built_roadtype = ROADTYPE_ROAD;
 
 	Window *w = AllocateWindowDesc((_game_mode != GM_EDITOR) ? &_toolb_normal_desc : &_toolb_scen_desc);
--- a/src/town_cmd.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/town_cmd.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -45,6 +45,9 @@
 #include "economy_func.h"
 #include "station_func.h"
 #include "cheat_func.h"
+#include "functions.h"
+#include "animated_tile_func.h"
+#include "date_func.h"
 
 #include "table/strings.h"
 #include "table/sprites.h"
@@ -268,7 +271,10 @@
 	pos += (pos < dest) ? 1 : -1;
 	SetLiftPosition(tile, pos);
 
-	if (pos == dest) HaltLift(tile);
+	if (pos == dest) {
+		HaltLift(tile);
+		DeleteAnimatedTile(tile);
+	}
 
 	MarkTileDirtyByTile(tile);
 }
@@ -375,16 +381,19 @@
 	IncHouseConstructionTick(tile);
 	if (GetHouseConstructionTick(tile) != 0) return;
 
+	const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile));
+
 	/* Check and/or  */
-	if (HasBit(GetHouseSpecs(GetHouseType(tile))->callback_mask, CBM_HOUSE_CONSTRUCTION_STATE_CHANGE)) {
+	if (HasBit(hs->callback_mask, CBM_HOUSE_CONSTRUCTION_STATE_CHANGE)) {
 		uint16 callback_res = GetHouseCallback(CBID_HOUSE_CONSTRUCTION_STATE_CHANGE, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile);
-		if (callback_res != CALLBACK_FAILED) ChangeHouseAnimationFrame(tile, callback_res);
+		if (callback_res != CALLBACK_FAILED) ChangeHouseAnimationFrame(hs->grffile, tile, callback_res);
 	}
 
 	if (IsHouseCompleted(tile)) {
 		/* Now that construction is complete, we can add the population of the
 		 * building to the town. */
-		ChangePopulation(GetTownByTile(tile), GetHouseSpecs(GetHouseType(tile))->population);
+		ChangePopulation(GetTownByTile(tile), hs->population);
+		SetHouseConstructionYear(tile, _cur_year);
 	}
 	MarkTileDirtyByTile(tile);
 }
@@ -1644,6 +1653,9 @@
 	assert(CmdSucceeded(cc));
 
 	MakeHouseTile(tile, tid, counter, stage, type, random_bits);
+	if (GetHouseSpecs(type)->building_flags & BUILDING_IS_ANIMATED) AddAnimatedTile(tile);
+
+	MarkTileDirtyByTile(tile);
 }
 
 
@@ -1924,7 +1936,7 @@
 
 			if (HasBit(hs->callback_mask, CBM_HOUSE_ALLOW_CONSTRUCTION)) {
 				uint16 callback_res = GetHouseCallback(CBID_HOUSE_ALLOW_CONSTRUCTION, 0, 0, house, t, tile);
-				if (callback_res != CALLBACK_FAILED && callback_res == 0) continue;
+				if (callback_res != CALLBACK_FAILED && GB(callback_res, 0, 8) == 0) continue;
 			}
 		}
 
--- a/src/town_gui.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/town_gui.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -396,7 +396,7 @@
 
 	if (w != NULL) {
 		w->flags4 |= WF_DISABLE_VP_SCROLL;
-		AssignWindowViewport(w, 3, 17, 0xFE, 0x56, GetTown(town)->xy, ZOOM_LVL_TOWN);
+		InitializeWindowViewport(w, 3, 17, 254, 86, GetTown(town)->xy, ZOOM_LVL_TOWN);
 	}
 }
 
--- a/src/town_map.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/town_map.h	Mon Apr 21 21:15:50 2008 +0000
@@ -6,9 +6,8 @@
 #define TOWN_MAP_H
 
 #include "town.h"
-#include "date_func.h"
+#include "date_type.h"
 #include "tile_map.h"
-#include "functions.h"
 
 /**
  * Get the index of which town this house/street is attached to.
@@ -113,7 +112,6 @@
 static inline void HaltLift(TileIndex t)
 {
 	SB(_me[t].m7, 0, 4, 0);
-	DeleteAnimatedTile(t);
 }
 
 /**
@@ -206,9 +204,6 @@
 	_m[t].m5 = IsHouseCompleted(t) ? 0 : (stage << 3 | counter);
 	SetHouseAnimationFrame(t, 0);
 	_me[t].m7 = GetHouseSpecs(type)->processing_time;
-
-	if (GetHouseSpecs(type)->building_flags & BUILDING_IS_ANIMATED) AddAnimatedTile(t);
-	MarkTileDirtyByTile(t);
 }
 
 /**
@@ -266,11 +261,22 @@
 		/* House is now completed.
 		 * Store the year of construction as well, for newgrf house purpose */
 		SetHouseCompleted(t, true);
-		_m[t].m5 = Clamp(_cur_year - ORIGINAL_BASE_YEAR, 0, 0xFF);
 	}
 }
 
 /**
+ * Set the year that this house was constructed (between 1920 and 2175).
+ * @param t the tile of this house
+ * @param year the year to set
+ * @pre IsTileType(t, MP_HOUSE) && IsHouseCompleted(t)
+ */
+static inline void SetHouseConstructionYear(TileIndex t, Year year)
+{
+	assert(IsTileType(t, MP_HOUSE) && IsHouseCompleted(t));
+	_m[t].m5 = Clamp(year - ORIGINAL_BASE_YEAR, 0, 0xFF);
+}
+
+/**
  * Get the year that this house was constructed (between 1920 and 2175).
  * @param t the tile of this house
  * @pre IsTileType(t, MP_HOUSE)
--- a/src/train.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/train.h	Mon Apr 21 21:15:50 2008 +0000
@@ -296,7 +296,7 @@
 	WindowClass GetVehicleListWindowClass() const { return WC_TRAINS_LIST; }
 	void PlayLeaveStationSound() const;
 	bool IsPrimaryVehicle() const { return IsFrontEngine(this); }
-	int GetImage(Direction direction) const;
+	SpriteID GetImage(Direction direction) const;
 	int GetDisplaySpeed() const { return this->u.rail.last_speed * 10 / 16; }
 	int GetDisplayMaxSpeed() const { return this->u.rail.cached_max_speed * 10 / 16; }
 	Money GetRunningCost() const;
--- a/src/train_cmd.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/train_cmd.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -49,6 +49,8 @@
 #include "ai/ai.h"
 #include "settings_type.h"
 #include "order_func.h"
+#include "newgrf_station.h"
+#include "effectvehicle_func.h"
 
 #include "table/strings.h"
 #include "table/train_cmd.h"
@@ -239,7 +241,7 @@
 			if (HasBit(EngInfo(u->engine_type)->callbackmask, CBM_TRAIN_WAGON_POWER)) {
 				uint16 callback = GetVehicleCallback(CBID_TRAIN_WAGON_POWER, 0, 0, u->engine_type, u);
 
-				if (callback != CALLBACK_FAILED) u->u.rail.cached_vis_effect = callback;
+				if (callback != CALLBACK_FAILED) u->u.rail.cached_vis_effect = GB(callback, 0, 8);
 			}
 
 			if (rvi_v->pow_wag_power != 0 && rvi_u->railveh_type == RAILVEH_WAGON &&
@@ -466,59 +468,61 @@
 	v->acceleration = Clamp(power / weight * 4, 1, 255);
 }
 
-int Train::GetImage(Direction direction) const
+SpriteID Train::GetImage(Direction direction) const
 {
-	int img = this->spritenum;
-	int base;
+	uint8 spritenum = this->spritenum;
+	SpriteID sprite;
 
 	if (HasBit(this->u.rail.flags, VRF_REVERSE_DIRECTION)) direction = ReverseDir(direction);
 
-	if (is_custom_sprite(img)) {
-		base = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(img)));
-		if (base != 0) return base;
-		img = _orig_rail_vehicle_info[this->engine_type].image_index;
+	if (is_custom_sprite(spritenum)) {
+		sprite = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)));
+		if (sprite != 0) return sprite;
+
+		spritenum = _orig_rail_vehicle_info[this->engine_type].image_index;
 	}
 
-	base = _engine_sprite_base[img] + ((direction + _engine_sprite_add[img]) & _engine_sprite_and[img]);
-
-	if (this->cargo.Count() >= this->cargo_cap / 2U) base += _wagon_full_adder[img];
-	return base;
+	sprite = _engine_sprite_base[spritenum] + ((direction + _engine_sprite_add[spritenum]) & _engine_sprite_and[spritenum]);
+
+	if (this->cargo.Count() >= this->cargo_cap / 2U) sprite += _wagon_full_adder[spritenum];
+
+	return sprite;
+}
+
+static SpriteID GetRailIcon(EngineID engine, bool rear_head, int &y)
+{
+	Direction dir = rear_head ? DIR_E : DIR_W;
+	uint8 spritenum = RailVehInfo(engine)->image_index;
+
+	if (is_custom_sprite(spritenum)) {
+		SpriteID sprite = GetCustomVehicleIcon(engine, dir);
+		if (sprite != 0) {
+			y += _traininfo_vehicle_pitch; // TODO Make this per-GRF
+			return sprite;
+		}
+
+		spritenum = _orig_rail_vehicle_info[engine].image_index;
+	}
+
+	if (rear_head) spritenum++;
+
+	return ((6 + _engine_sprite_add[spritenum]) & _engine_sprite_and[spritenum]) + _engine_sprite_base[spritenum];
 }
 
 void DrawTrainEngine(int x, int y, EngineID engine, SpriteID pal)
 {
-	const RailVehicleInfo *rvi = RailVehInfo(engine);
-
-	int img = rvi->image_index;
-	SpriteID image = 0;
-
-	if (is_custom_sprite(img)) {
-		image = GetCustomVehicleIcon(engine, DIR_W);
-		if (image == 0) {
-			img = _orig_rail_vehicle_info[engine].image_index;
-		} else {
-			y += _traininfo_vehicle_pitch;
-		}
-	}
-	if (image == 0) {
-		image = (6 & _engine_sprite_and[img]) + _engine_sprite_base[img];
+	if (RailVehInfo(engine)->railveh_type == RAILVEH_MULTIHEAD) {
+		int yf = y;
+		int yr = y;
+
+		SpriteID spritef = GetRailIcon(engine, false, yf);
+		SpriteID spriter = GetRailIcon(engine, true, yr);
+		DrawSprite(spritef, pal, x - 14, yf);
+		DrawSprite(spriter, pal, x + 15, yr);
+	} else {
+		SpriteID sprite = GetRailIcon(engine, false, y);
+		DrawSprite(sprite, pal, x, y);
 	}
-
-	if (rvi->railveh_type == RAILVEH_MULTIHEAD) {
-		DrawSprite(image, pal, x - 14, y);
-		x += 15;
-		image = 0;
-		if (is_custom_sprite(img)) {
-			image = GetCustomVehicleIcon(engine, DIR_E);
-			if (image == 0) img = _orig_rail_vehicle_info[engine].image_index;
-		}
-		if (image == 0) {
-			image =
-				((6 + _engine_sprite_add[img + 1]) & _engine_sprite_and[img + 1]) +
-				_engine_sprite_base[img + 1];
-		}
-	}
-	DrawSprite(image, pal, x, y);
 }
 
 static CommandCost CmdBuildRailWagon(EngineID engine, TileIndex tile, uint32 flags)
@@ -1279,7 +1283,7 @@
 	/* Check if this train can be started/stopped. The callback will fail or
 	 * return 0xFF if it can. */
 	uint16 callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v);
-	if (callback != CALLBACK_FAILED && callback != 0xFF) {
+	if (callback != CALLBACK_FAILED && GB(callback, 0, 8) != 0xFF) {
 		StringID error = GetGRFStringID(GetEngineGRFID(v->engine_type), 0xD000 + callback);
 		return_cmd_error(error);
 	}
@@ -2219,6 +2223,8 @@
 		SND_41_MAGLEV
 	};
 
+	if (IsTileType(this->tile, MP_STATION)) StationAnimationTrigger(NULL, this->tile, STAT_ANIM_TRAIN_DEPARTS);
+
 	if (PlayVehicleSound(this, VSE_START)) return;
 
 	EngineID engtype = this->engine_type;
@@ -2639,6 +2645,8 @@
 	}
 
 	v->BeginLoading();
+
+	StationAnimationTrigger(st, v->tile, STAT_ANIM_TRAIN_ARRIVES);
 }
 
 static byte AfterSetTrainPos(Vehicle *v, bool new_tile)
@@ -3234,7 +3242,7 @@
 
 		if (!(v->vehstatus & VS_HIDDEN)) {
 			Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE);
-			if (u != NULL) u->u.special.animation_state = v->breakdown_delay * 2;
+			if (u != NULL) u->u.effect.animation_state = v->breakdown_delay * 2;
 		}
 	}
 
@@ -3423,7 +3431,7 @@
 			HandleBrokenTrain(v);
 			return;
 		}
-		v->breakdown_ctr--;
+		if (!v->current_order.IsType(OT_LOADING)) v->breakdown_ctr--;
 	}
 
 	if (HasBit(v->u.rail.flags, VRF_REVERSING) && v->cur_speed == 0) {
--- a/src/vehicle.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/vehicle.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -47,6 +47,8 @@
 #include "settings_type.h"
 #include "oldpool_func.h"
 #include "depot_map.h"
+#include "animated_tile_func.h"
+#include "effectvehicle_base.h"
 
 #include "table/sprites.h"
 #include "table/strings.h"
@@ -106,6 +108,7 @@
 
 	if (!p->engine_renew) return false;
 	if (this->age - this->max_age < (p->engine_renew_months * 30)) return false;
+	if (this->age == 0) return false; // rail cars don't age and lacks a max age
 
 	return true;
 }
@@ -691,11 +694,32 @@
 
 	/* now we handle all the vehicles that entered a depot this tick */
 	v = _first_veh_in_depot_list;
-	while (v != NULL) {
-		Vehicle *w = v->depot_list;
-		v->depot_list = NULL; // it should always be NULL at the end of each tick
-		MaybeReplaceVehicle(v, false, true);
-		v = w;
+	if (v != NULL) {
+		while (v != NULL) {
+			/* Autoreplace needs the current player set as the vehicle owner */
+			_current_player = v->owner;
+
+			/* Buffer v->depot_list and clear it.
+			 * Autoreplace might clear this so it has to be buffered. */
+			Vehicle *w = v->depot_list;
+			v->depot_list = NULL; // it should always be NULL at the end of each tick
+
+			/* Start vehicle if we stopped them in VehicleEnteredDepotThisTick()
+			 * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that
+			 * they are already leaving the depot again before being replaced. */
+			if (v->leave_depot_instantly) {
+				v->leave_depot_instantly = false;
+				v->vehstatus &= ~VS_STOPPED;
+			}
+
+			CommandCost cost = MaybeReplaceVehicle(v, 0, true);
+			if (CmdSucceeded(cost) && cost.GetCost() != 0) {
+				/* Looks like we can replace this vehicle so we go ahead and do so */
+				MaybeReplaceVehicle(v, DC_EXEC, true);
+			}
+			v = w;
+		}
+		_current_player = OWNER_NONE;
 	}
 }
 
@@ -823,605 +847,6 @@
 	}
 }
 
-static void ChimneySmokeInit(Vehicle *v)
-{
-	uint32 r = Random();
-	v->cur_image = SPR_CHIMNEY_SMOKE_0 + GB(r, 0, 3);
-	v->progress = GB(r, 16, 3);
-}
-
-static void ChimneySmokeTick(Vehicle *v)
-{
-	if (v->progress > 0) {
-		v->progress--;
-	} else {
-		BeginVehicleMove(v);
-
-		TileIndex tile = TileVirtXY(v->x_pos, v->y_pos);
-		if (!IsTileType(tile, MP_INDUSTRY)) {
-			EndVehicleMove(v);
-			delete v;
-			return;
-		}
-
-		if (v->cur_image != SPR_CHIMNEY_SMOKE_7) {
-			v->cur_image++;
-		} else {
-			v->cur_image = SPR_CHIMNEY_SMOKE_0;
-		}
-		v->progress = 7;
-		VehiclePositionChanged(v);
-		EndVehicleMove(v);
-	}
-}
-
-static void SteamSmokeInit(Vehicle *v)
-{
-	v->cur_image = SPR_STEAM_SMOKE_0;
-	v->progress = 12;
-}
-
-static void SteamSmokeTick(Vehicle *v)
-{
-	bool moved = false;
-
-	BeginVehicleMove(v);
-
-	v->progress++;
-
-	if ((v->progress & 7) == 0) {
-		v->z_pos++;
-		moved = true;
-	}
-
-	if ((v->progress & 0xF) == 4) {
-		if (v->cur_image != SPR_STEAM_SMOKE_4) {
-			v->cur_image++;
-		} else {
-			EndVehicleMove(v);
-			delete v;
-			return;
-		}
-		moved = true;
-	}
-
-	if (moved) {
-		VehiclePositionChanged(v);
-		EndVehicleMove(v);
-	}
-}
-
-static void DieselSmokeInit(Vehicle *v)
-{
-	v->cur_image = SPR_DIESEL_SMOKE_0;
-	v->progress = 0;
-}
-
-static void DieselSmokeTick(Vehicle *v)
-{
-	v->progress++;
-
-	if ((v->progress & 3) == 0) {
-		BeginVehicleMove(v);
-		v->z_pos++;
-		VehiclePositionChanged(v);
-		EndVehicleMove(v);
-	} else if ((v->progress & 7) == 1) {
-		BeginVehicleMove(v);
-		if (v->cur_image != SPR_DIESEL_SMOKE_5) {
-			v->cur_image++;
-			VehiclePositionChanged(v);
-			EndVehicleMove(v);
-		} else {
-			EndVehicleMove(v);
-			delete v;
-		}
-	}
-}
-
-static void ElectricSparkInit(Vehicle *v)
-{
-	v->cur_image = SPR_ELECTRIC_SPARK_0;
-	v->progress = 1;
-}
-
-static void ElectricSparkTick(Vehicle *v)
-{
-	if (v->progress < 2) {
-		v->progress++;
-	} else {
-		v->progress = 0;
-		BeginVehicleMove(v);
-		if (v->cur_image != SPR_ELECTRIC_SPARK_5) {
-			v->cur_image++;
-			VehiclePositionChanged(v);
-			EndVehicleMove(v);
-		} else {
-			EndVehicleMove(v);
-			delete v;
-		}
-	}
-}
-
-static void SmokeInit(Vehicle *v)
-{
-	v->cur_image = SPR_SMOKE_0;
-	v->progress = 12;
-}
-
-static void SmokeTick(Vehicle *v)
-{
-	bool moved = false;
-
-	BeginVehicleMove(v);
-
-	v->progress++;
-
-	if ((v->progress & 3) == 0) {
-		v->z_pos++;
-		moved = true;
-	}
-
-	if ((v->progress & 0xF) == 4) {
-		if (v->cur_image != SPR_SMOKE_4) {
-			v->cur_image++;
-		} else {
-			EndVehicleMove(v);
-			delete v;
-			return;
-		}
-		moved = true;
-	}
-
-	if (moved) {
-		VehiclePositionChanged(v);
-		EndVehicleMove(v);
-	}
-}
-
-static void ExplosionLargeInit(Vehicle *v)
-{
-	v->cur_image = SPR_EXPLOSION_LARGE_0;
-	v->progress = 0;
-}
-
-static void ExplosionLargeTick(Vehicle *v)
-{
-	v->progress++;
-	if ((v->progress & 3) == 0) {
-		BeginVehicleMove(v);
-		if (v->cur_image != SPR_EXPLOSION_LARGE_F) {
-			v->cur_image++;
-			VehiclePositionChanged(v);
-			EndVehicleMove(v);
-		} else {
-			EndVehicleMove(v);
-			delete v;
-		}
-	}
-}
-
-static void BreakdownSmokeInit(Vehicle *v)
-{
-	v->cur_image = SPR_BREAKDOWN_SMOKE_0;
-	v->progress = 0;
-}
-
-static void BreakdownSmokeTick(Vehicle *v)
-{
-	v->progress++;
-	if ((v->progress & 7) == 0) {
-		BeginVehicleMove(v);
-		if (v->cur_image != SPR_BREAKDOWN_SMOKE_3) {
-			v->cur_image++;
-		} else {
-			v->cur_image = SPR_BREAKDOWN_SMOKE_0;
-		}
-		VehiclePositionChanged(v);
-		EndVehicleMove(v);
-	}
-
-	v->u.special.animation_state--;
-	if (v->u.special.animation_state == 0) {
-		BeginVehicleMove(v);
-		EndVehicleMove(v);
-		delete v;
-	}
-}
-
-static void ExplosionSmallInit(Vehicle *v)
-{
-	v->cur_image = SPR_EXPLOSION_SMALL_0;
-	v->progress = 0;
-}
-
-static void ExplosionSmallTick(Vehicle *v)
-{
-	v->progress++;
-	if ((v->progress & 3) == 0) {
-		BeginVehicleMove(v);
-		if (v->cur_image != SPR_EXPLOSION_SMALL_B) {
-			v->cur_image++;
-			VehiclePositionChanged(v);
-			EndVehicleMove(v);
-		} else {
-			EndVehicleMove(v);
-			delete v;
-		}
-	}
-}
-
-static void BulldozerInit(Vehicle *v)
-{
-	v->cur_image = SPR_BULLDOZER_NE;
-	v->progress = 0;
-	v->u.special.animation_state = 0;
-	v->u.special.animation_substate = 0;
-}
-
-struct BulldozerMovement {
-	byte direction:2;
-	byte image:2;
-	byte duration:3;
-};
-
-static const BulldozerMovement _bulldozer_movement[] = {
-	{ 0, 0, 4 },
-	{ 3, 3, 4 },
-	{ 2, 2, 7 },
-	{ 0, 2, 7 },
-	{ 1, 1, 3 },
-	{ 2, 2, 7 },
-	{ 0, 2, 7 },
-	{ 1, 1, 3 },
-	{ 2, 2, 7 },
-	{ 0, 2, 7 },
-	{ 3, 3, 6 },
-	{ 2, 2, 6 },
-	{ 1, 1, 7 },
-	{ 3, 1, 7 },
-	{ 0, 0, 3 },
-	{ 1, 1, 7 },
-	{ 3, 1, 7 },
-	{ 0, 0, 3 },
-	{ 1, 1, 7 },
-	{ 3, 1, 7 }
-};
-
-static const struct {
-	int8 x;
-	int8 y;
-} _inc_by_dir[] = {
-	{ -1,  0 },
-	{  0,  1 },
-	{  1,  0 },
-	{  0, -1 }
-};
-
-static void BulldozerTick(Vehicle *v)
-{
-	v->progress++;
-	if ((v->progress & 7) == 0) {
-		const BulldozerMovement* b = &_bulldozer_movement[v->u.special.animation_state];
-
-		BeginVehicleMove(v);
-
-		v->cur_image = SPR_BULLDOZER_NE + b->image;
-
-		v->x_pos += _inc_by_dir[b->direction].x;
-		v->y_pos += _inc_by_dir[b->direction].y;
-
-		v->u.special.animation_substate++;
-		if (v->u.special.animation_substate >= b->duration) {
-			v->u.special.animation_substate = 0;
-			v->u.special.animation_state++;
-			if (v->u.special.animation_state == lengthof(_bulldozer_movement)) {
-				EndVehicleMove(v);
-				delete v;
-				return;
-			}
-		}
-		VehiclePositionChanged(v);
-		EndVehicleMove(v);
-	}
-}
-
-static void BubbleInit(Vehicle *v)
-{
-	v->cur_image = SPR_BUBBLE_GENERATE_0;
-	v->spritenum = 0;
-	v->progress = 0;
-}
-
-struct BubbleMovement {
-	int8 x:4;
-	int8 y:4;
-	int8 z:4;
-	byte image:4;
-};
-
-#define MK(x, y, z, i) { x, y, z, i }
-#define ME(i) { i, 4, 0, 0 }
-
-static const BubbleMovement _bubble_float_sw[] = {
-	MK(0, 0, 1, 0),
-	MK(1, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(1, 0, 1, 2),
-	ME(1)
-};
-
-
-static const BubbleMovement _bubble_float_ne[] = {
-	MK( 0, 0, 1, 0),
-	MK(-1, 0, 1, 1),
-	MK( 0, 0, 1, 0),
-	MK(-1, 0, 1, 2),
-	ME(1)
-};
-
-static const BubbleMovement _bubble_float_se[] = {
-	MK(0, 0, 1, 0),
-	MK(0, 1, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 1, 1, 2),
-	ME(1)
-};
-
-static const BubbleMovement _bubble_float_nw[] = {
-	MK(0,  0, 1, 0),
-	MK(0, -1, 1, 1),
-	MK(0,  0, 1, 0),
-	MK(0, -1, 1, 2),
-	ME(1)
-};
-
-static const BubbleMovement _bubble_burst[] = {
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 7),
-	MK(0, 0, 1, 8),
-	MK(0, 0, 1, 9),
-	ME(0)
-};
-
-static const BubbleMovement _bubble_absorb[] = {
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(0, 0, 1, 1),
-	MK(2, 1, 3, 0),
-	MK(1, 1, 3, 1),
-	MK(2, 1, 3, 0),
-	MK(1, 1, 3, 2),
-	MK(2, 1, 3, 0),
-	MK(1, 1, 3, 1),
-	MK(2, 1, 3, 0),
-	MK(1, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(1, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(1, 0, 1, 2),
-	MK(0, 0, 1, 0),
-	MK(1, 0, 1, 1),
-	MK(0, 0, 1, 0),
-	MK(1, 0, 1, 2),
-	ME(2),
-	MK(0, 0, 0, 0xA),
-	MK(0, 0, 0, 0xB),
-	MK(0, 0, 0, 0xC),
-	MK(0, 0, 0, 0xD),
-	MK(0, 0, 0, 0xE),
-	ME(0)
-};
-#undef ME
-#undef MK
-
-static const BubbleMovement * const _bubble_movement[] = {
-	_bubble_float_sw,
-	_bubble_float_ne,
-	_bubble_float_se,
-	_bubble_float_nw,
-	_bubble_burst,
-	_bubble_absorb,
-};
-
-static void BubbleTick(Vehicle *v)
-{
-	/*
-	 * Warning: those effects can NOT use Random(), and have to use
-	 *  InteractiveRandom(), because somehow someone forgot to save
-	 *  spritenum to the savegame, and so it will cause desyncs in
-	 *  multiplayer!! (that is: in ToyLand)
-	 */
-	uint et;
-
-	v->progress++;
-	if ((v->progress & 3) != 0) return;
-
-	BeginVehicleMove(v);
-
-	if (v->spritenum == 0) {
-		v->cur_image++;
-		if (v->cur_image < SPR_BUBBLE_GENERATE_3) {
-			VehiclePositionChanged(v);
-			EndVehicleMove(v);
-			return;
-		}
-		if (v->u.special.animation_substate != 0) {
-			v->spritenum = GB(InteractiveRandom(), 0, 2) + 1;
-		} else {
-			v->spritenum = 6;
-		}
-		et = 0;
-	} else {
-		et = v->engine_type + 1;
-	}
-
-	const BubbleMovement *b = &_bubble_movement[v->spritenum - 1][et];
-
-	if (b->y == 4 && b->x == 0) {
-		EndVehicleMove(v);
-		delete v;
-		return;
-	}
-
-	if (b->y == 4 && b->x == 1) {
-		if (v->z_pos > 180 || Chance16I(1, 96, InteractiveRandom())) {
-			v->spritenum = 5;
-			SndPlayVehicleFx(SND_2F_POP, v);
-		}
-		et = 0;
-	}
-
-	if (b->y == 4 && b->x == 2) {
-		TileIndex tile;
-
-		et++;
-		SndPlayVehicleFx(SND_31_EXTRACT, v);
-
-		tile = TileVirtXY(v->x_pos, v->y_pos);
-		if (IsTileType(tile, MP_INDUSTRY) && GetIndustryGfx(tile) == GFX_BUBBLE_CATCHER) AddAnimatedTile(tile);
-	}
-
-	v->engine_type = et;
-	b = &_bubble_movement[v->spritenum - 1][et];
-
-	v->x_pos += b->x;
-	v->y_pos += b->y;
-	v->z_pos += b->z;
-	v->cur_image = SPR_BUBBLE_0 + b->image;
-
-	VehiclePositionChanged(v);
-	EndVehicleMove(v);
-}
-
-
-typedef void EffectInitProc(Vehicle *v);
-typedef void EffectTickProc(Vehicle *v);
-
-static EffectInitProc * const _effect_init_procs[] = {
-	ChimneySmokeInit,
-	SteamSmokeInit,
-	DieselSmokeInit,
-	ElectricSparkInit,
-	SmokeInit,
-	ExplosionLargeInit,
-	BreakdownSmokeInit,
-	ExplosionSmallInit,
-	BulldozerInit,
-	BubbleInit,
-};
-
-static EffectTickProc * const _effect_tick_procs[] = {
-	ChimneySmokeTick,
-	SteamSmokeTick,
-	DieselSmokeTick,
-	ElectricSparkTick,
-	SmokeTick,
-	ExplosionLargeTick,
-	BreakdownSmokeTick,
-	ExplosionSmallTick,
-	BulldozerTick,
-	BubbleTick,
-};
-
-
-Vehicle *CreateEffectVehicle(int x, int y, int z, EffectVehicle type)
-{
-	Vehicle *v = new SpecialVehicle();
-	if (v != NULL) {
-		v->subtype = type;
-		v->x_pos = x;
-		v->y_pos = y;
-		v->z_pos = z;
-		v->tile = 0;
-		v->UpdateDeltaXY(INVALID_DIR);
-		v->vehstatus = VS_UNCLICKABLE;
-
-		_effect_init_procs[type](v);
-
-		VehiclePositionChanged(v);
-		BeginVehicleMove(v);
-		EndVehicleMove(v);
-	}
-	return v;
-}
-
-Vehicle *CreateEffectVehicleAbove(int x, int y, int z, EffectVehicle type)
-{
-	int safe_x = Clamp(x, 0, MapMaxX() * TILE_SIZE);
-	int safe_y = Clamp(y, 0, MapMaxY() * TILE_SIZE);
-	return CreateEffectVehicle(x, y, GetSlopeZ(safe_x, safe_y) + z, type);
-}
-
-Vehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicle type)
-{
-	return CreateEffectVehicle(v->x_pos + x, v->y_pos + y, v->z_pos + z, type);
-}
-
-void SpecialVehicle::Tick()
-{
-	_effect_tick_procs[this->subtype](this);
-}
-
 Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y)
 {
 	Vehicle *found = NULL, *v;
@@ -1695,16 +1120,11 @@
 
 	for (uint i = 0; i < engine_count; i++) {
 		Vehicle *v = vl[i];
-		bool stopped = !(v->vehstatus & VS_STOPPED);
 
 		/* Ensure that the vehicle completely in the depot */
 		if (!v->IsInDepot()) continue;
 
-		if (stopped) {
-			v->vehstatus |= VS_STOPPED; // Stop the vehicle
-			v->leave_depot_instantly = true;
-		}
-		CommandCost ret = MaybeReplaceVehicle(v, !(flags & DC_EXEC), false);
+		CommandCost ret = MaybeReplaceVehicle(v, flags, false);
 
 		if (CmdSucceeded(ret)) {
 			cost.AddCost(ret);
@@ -2480,7 +1900,7 @@
 			/* Vehicle is turning around, get the direction from vehicle's direction */
 			return DiagdirToDiagTrackdir(DirToDiagDir(v->direction));
 
-		/* case VEH_AIRCRAFT: case VEH_SPECIAL: case VEH_DISASTER: */
+		/* case VEH_AIRCRAFT: case VEH_EFFECT: case VEH_DISASTER: */
 		default: return INVALID_TRACKDIR;
 	}
 }
@@ -2937,7 +2357,7 @@
 };
 
 static const SaveLoad _special_desc[] = {
-	SLE_WRITEBYTE(Vehicle, type, VEH_SPECIAL),
+	SLE_WRITEBYTE(Vehicle, type, VEH_EFFECT),
 
 	    SLE_VAR(Vehicle, subtype,       SLE_UINT8),
 
@@ -2955,8 +2375,8 @@
 	    SLE_VAR(Vehicle, progress,      SLE_UINT8),
 	    SLE_VAR(Vehicle, vehstatus,     SLE_UINT8),
 
-	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleSpecial, animation_state),    SLE_UINT16),
-	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleSpecial, animation_substate), SLE_UINT8),
+	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleEffect, animation_state),    SLE_UINT16),
+	    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleEffect, animation_substate), SLE_UINT8),
 
 	/* reserve extra space in savegame here. (currently 16 bytes) */
 	SLE_CONDNULL(16, 2, SL_MAX_VERSION),
@@ -3044,7 +2464,7 @@
 			case VEH_ROAD:     v = new (index) RoadVehicle();     break;
 			case VEH_SHIP:     v = new (index) Ship();            break;
 			case VEH_AIRCRAFT: v = new (index) Aircraft();        break;
-			case VEH_SPECIAL:  v = new (index) SpecialVehicle();  break;
+			case VEH_EFFECT:   v = new (index) EffectVehicle();   break;
 			case VEH_DISASTER: v = new (index) DisasterVehicle(); break;
 			case VEH_INVALID:  v = new (index) InvalidVehicle();  break;
 			default: NOT_REACHED();
@@ -3264,15 +2684,6 @@
 	}
 }
 
-void SpecialVehicle::UpdateDeltaXY(Direction direction)
-{
-	this->x_offs        = 0;
-	this->y_offs        = 0;
-	this->x_extent      = 1;
-	this->y_extent      = 1;
-	this->z_extent      = 1;
-}
-
 void StopAllVehicles()
 {
 	Vehicle *v;
--- a/src/vehicle_base.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/vehicle_base.h	Mon Apr 21 21:15:50 2008 +0000
@@ -78,20 +78,27 @@
 };
 
 struct VehicleRail {
+	/* Link between the two ends of a multiheaded engine */
+	Vehicle *other_multiheaded_part;
+
+	/* Cached wagon override spritegroup */
+	const struct SpriteGroup *cached_override;
+
 	uint16 last_speed; // NOSAVE: only used in UI
 	uint16 crash_anim_pos;
 
 	/* cached values, recalculated on load and each time a vehicle is added to/removed from the consist. */
-	uint16 cached_max_speed;  // max speed of the consist. (minimum of the max speed of all vehicles in the consist)
-	uint32 cached_power;      // total power of the consist.
-	bool cached_tilt;         // train can tilt; feature provides a bonus in curves
-	uint8 cached_veh_length;  // length of this vehicle in units of 1/8 of normal length, cached because this can be set by a callback
+	uint32 cached_power;        ///< total power of the consist.
+	uint16 cached_max_speed;    ///< max speed of the consist. (minimum of the max speed of all vehicles in the consist)
 	uint16 cached_total_length; ///< Length of the whole train, valid only for first engine.
+	uint8 cached_veh_length;    ///< length of this vehicle in units of 1/8 of normal length, cached because this can be set by a callback
+	bool cached_tilt;           ///< train can tilt; feature provides a bonus in curves
 
 	/* cached values, recalculated when the cargo on a train changes (in addition to the conditions above) */
-	uint32 cached_weight;     // total weight of the consist.
-	uint32 cached_veh_weight; // weight of the vehicle.
-	uint32 cached_max_te;     // max tractive effort of consist
+	uint32 cached_weight;     ///< total weight of the consist.
+	uint32 cached_veh_weight; ///< weight of the vehicle.
+	uint32 cached_max_te;     ///< max tractive effort of consist
+
 	/**
 	 * Position/type of visual effect.
 	 * bit 0 - 3 = position of effect relative to vehicle. (0 = front, 8 = centre, 15 = rear)
@@ -106,18 +113,11 @@
 	 * 0xffff == not in train */
 	EngineID first_engine;
 
+	byte flags;
 	TrackBitsByte track;
 	byte force_proceed;
 	RailTypeByte railtype;
 	RailTypes compatible_railtypes;
-
-	byte flags;
-
-	/* Link between the two ends of a multiheaded engine */
-	Vehicle *other_multiheaded_part;
-
-	/* Cached wagon override spritegroup */
-	const struct SpriteGroup *cached_override;
 };
 
 enum VehicleRailFlags {
@@ -169,7 +169,7 @@
 	RoadTypes compatible_roadtypes;
 };
 
-struct VehicleSpecial {
+struct VehicleEffect {
 	uint16 animation_state;
 	byte animation_substate;
 };
@@ -193,32 +193,64 @@
 extern bool LoadOldVehicle(LoadgameState *ls, int num);
 
 struct Vehicle : PoolItem<Vehicle, VehicleID, &_Vehicle_pool>, BaseVehicle {
-	byte subtype;            // subtype (Filled with values from EffectVehicles/TrainSubTypes/AircraftSubTypes)
-
 private:
-	Vehicle *next;           // pointer to the next vehicle in the chain
-	Vehicle *previous;       // NOSAVE: pointer to the previous vehicle in the chain
-	Vehicle *first;          // NOSAVE: pointer to the first vehicle in the chain
+	Vehicle *next;           ///< pointer to the next vehicle in the chain
+	Vehicle *previous;       ///< NOSAVE: pointer to the previous vehicle in the chain
+	Vehicle *first;          ///< NOSAVE: pointer to the first vehicle in the chain
 public:
-	friend const SaveLoad *GetVehicleDescription(VehicleType vt); // So we can use private/protected variables in the saveload code
-	friend void AfterLoadVehicles(bool clear_te_id);              // So we can set the previous and first pointers while loading
-	friend bool LoadOldVehicle(LoadgameState *ls, int num);       // So we can set the proper next pointer while loading
+	friend const SaveLoad *GetVehicleDescription(VehicleType vt); ///< So we can use private/protected variables in the saveload code
+	friend void AfterLoadVehicles(bool clear_te_id);              ///< So we can set the previous and first pointers while loading
+	friend bool LoadOldVehicle(LoadgameState *ls, int num);       ///< So we can set the proper next pointer while loading
 
-	Vehicle *depot_list;     // NOSAVE: linked list to tell what vehicles entered a depot during the last tick. Used by autoreplace
+	Vehicle *depot_list;     ///< NOSAVE: linked list to tell what vehicles entered a depot during the last tick. Used by autoreplace
 
 	char *name;              ///< Name of vehicle
 
-	UnitID unitnumber;       // unit number, for display purposes only
-	PlayerByte owner;        // which player owns the vehicle?
+	TileIndex tile;          ///< Current tile index
+	TileIndex dest_tile;     ///< Heading for this tile
 
-	TileIndex tile;          // Current tile index
-	TileIndex dest_tile;     // Heading for this tile
+	Vehicle *next_shared;    ///< If not NULL, this points to the next vehicle that shared the order
+	Vehicle *prev_shared;    ///< If not NULL, this points to the prev vehicle that shared the order
+
+	Money profit_this_year;        ///< Profit this year << 8, low 8 bits are fract
+	Money profit_last_year;        ///< Profit last year << 8, low 8 bits are fract
+	Money value;
+
+	/* Used for timetabling. */
+	uint32 current_order_time;     ///< How many ticks have passed since this order started.
+	int32 lateness_counter;        ///< How many ticks late (or early if negative) this vehicle is.
+
+	/* Boundaries for the current position in the world and a next hash link.
+	 * NOSAVE: All of those can be updated with VehiclePositionChanged() */
+	int32 left_coord;
+	int32 top_coord;
+	int32 right_coord;
+	int32 bottom_coord;
+	Vehicle *next_hash;
+	Vehicle *next_new_hash;
+	Vehicle **old_new_hash;
+
+	SpriteID colormap; // NOSAVE: cached color mapping
+
+	/* Related to age and service time */
+	Year build_year;
+	Date age;     // Age in days
+	Date max_age; // Maximum age
+	Date date_of_last_service;
+	Date service_interval;
+	uint16 reliability;
+	uint16 reliability_spd_dec;
+	byte breakdown_ctr;
+	byte breakdown_delay;
+	byte breakdowns_since_last_service;
+	byte breakdown_chance;
 
 	int32 x_pos;             // coordinates
 	int32 y_pos;
 	byte z_pos;
 	DirectionByte direction; // facing
 
+	PlayerByte owner;        // which player owns the vehicle?
 	byte spritenum;          // currently displayed sprite index
 	                         // 0xfd == custom sprite, 0xfe == custom second head sprite
 	                         // 0xff == reserved for another custom sprite
@@ -231,89 +263,53 @@
 	EngineID engine_type;
 
 	TextEffectID fill_percent_te_id; // a text-effect id to a loading indicator object
+	UnitID unitnumber;       // unit number, for display purposes only
+
+	uint16 max_speed;        ///< maximum speed
+	uint16 cur_speed;        ///< current speed
+	byte subspeed;           ///< fractional speed
+	byte acceleration;       ///< used by train & aircraft
+	uint32 motion_counter;
+	byte progress;
 
 	/* for randomized variational spritegroups
 	 * bitmask used to resolve them; parts of it get reseeded when triggers
 	 * of corresponding spritegroups get matched */
 	byte random_bits;
-	byte waiting_triggers;   // triggers to be yet matched
+	byte waiting_triggers;   ///< triggers to be yet matched
 
-	uint16 max_speed;        // maximum speed
-	uint16 cur_speed;        // current speed
-	byte subspeed;           // fractional speed
-	byte acceleration;       // used by train & aircraft
-	byte progress;
-	uint32 motion_counter;
-
-	byte vehstatus;          // Status
 	StationID last_station_visited;
 
-	CargoID cargo_type;      // type of cargo this vehicle is carrying
-	uint16 cargo_cap;        // total capacity
+	CargoID cargo_type;      ///< type of cargo this vehicle is carrying
 	byte cargo_subtype;      ///< Used for livery refits (NewGRF variations)
+	uint16 cargo_cap;        ///< total capacity
 	CargoList cargo;         ///< The cargo this vehicle is carrying
 
-
 	byte day_counter;        ///< Increased by one for each day
 	byte tick_counter;       ///< Increased by one for each tick
 	byte running_ticks;      ///< Number of ticks this vehicle was not stopped this day
 
-	/* Begin Order-stuff */
-	Order current_order;     ///< The current order (+ status, like: loading)
+	byte vehstatus;                 ///< Status
+	Order current_order;            ///< The current order (+ status, like: loading)
+	VehicleOrderID num_orders;      ///< How many orders there are in the list
 	VehicleOrderID cur_order_index; ///< The index to the current order
 
-	Order *orders;           ///< Pointer to the first order for this vehicle
-	VehicleOrderID num_orders;      ///< How many orders there are in the list
-
-	Vehicle *next_shared;    ///< If not NULL, this points to the next vehicle that shared the order
-	Vehicle *prev_shared;    ///< If not NULL, this points to the prev vehicle that shared the order
-	/* End Order-stuff */
-
-	/* Boundaries for the current position in the world and a next hash link.
-	 * NOSAVE: All of those can be updated with VehiclePositionChanged() */
-	int32 left_coord;
-	int32 top_coord;
-	int32 right_coord;
-	int32 bottom_coord;
-	Vehicle *next_hash;
-	Vehicle *next_new_hash;
-	Vehicle **old_new_hash;
+	Order *orders;                  ///< Pointer to the first order for this vehicle
 
-	/* Related to age and service time */
-	Date age;     // Age in days
-	Date max_age; // Maximum age
-	Date date_of_last_service;
-	Date service_interval;
-	uint16 reliability;
-	uint16 reliability_spd_dec;
-	byte breakdown_ctr;
-	byte breakdown_delay;
-	byte breakdowns_since_last_service;
-	byte breakdown_chance;
-	Year build_year;
+	bool leave_depot_instantly;     ///< NOSAVE: stores if the vehicle needs to leave the depot it just entered. Used by autoreplace
 
-	bool leave_depot_instantly; // NOSAVE: stores if the vehicle needs to leave the depot it just entered. Used by autoreplace
-
+	byte vehicle_flags;             ///< Used for gradual loading and other miscellaneous things (@see VehicleFlags enum)
 	uint16 load_unload_time_rem;
-	byte vehicle_flags;         // Used for gradual loading and other miscellaneous things (@see VehicleFlags enum)
 
-	Money profit_this_year;        ///< Profit this year << 8, low 8 bits are fract
-	Money profit_last_year;        ///< Profit last year << 8, low 8 bits are fract
-	Money value;
+	GroupID group_id;               ///< Index of group Pool array
 
-	GroupID group_id;              ///< Index of group Pool array
-
-	/* Used for timetabling. */
-	uint32 current_order_time;     ///< How many ticks have passed since this order started.
-	int32 lateness_counter;        ///< How many ticks late (or early if negative) this vehicle is.
-
-	SpriteID colormap; // NOSAVE: cached color mapping
+	byte subtype;                   ///< subtype (Filled with values from EffectVehicles/TrainSubTypes/AircraftSubTypes)
 
 	union {
 		VehicleRail rail;
 		VehicleAir air;
 		VehicleRoad road;
-		VehicleSpecial special;
+		VehicleEffect effect;
 		VehicleDisaster disaster;
 		VehicleShip ship;
 	} u;
@@ -394,7 +390,7 @@
 	 * @param direction the direction the vehicle is facing
 	 * @return the sprite for the given vehicle in the given direction
 	 */
-	virtual int GetImage(Direction direction) const { return 0; }
+	virtual SpriteID GetImage(Direction direction) const { return 0; }
 
 	/**
 	 * Gets the speed in mph that can be sent into SetDParam for string processing.
@@ -539,33 +535,6 @@
  *   v = new (v) Train();
  *
  * As side-effect the vehicle type is set correctly.
- *
- * A special vehicle is one of the following:
- *  - smoke
- *  - electric sparks for trains
- *  - explosions
- *  - bulldozer (road works)
- *  - bubbles (industry)
- */
-struct SpecialVehicle : public Vehicle {
-	/** Initializes the Vehicle to a special vehicle */
-	SpecialVehicle() { this->type = VEH_SPECIAL; }
-
-	/** We want to 'destruct' the right class. */
-	virtual ~SpecialVehicle() {}
-
-	const char *GetTypeString() const { return "special vehicle"; }
-	void UpdateDeltaXY(Direction direction);
-	void Tick();
-};
-
-/**
- * This class 'wraps' Vehicle; you do not actually instantiate this class.
- * You create a Vehicle using AllocateVehicle, so it is added to the pool
- * and you reinitialize that to a Train using:
- *   v = new (v) Train();
- *
- * As side-effect the vehicle type is set correctly.
  */
 struct DisasterVehicle : public Vehicle {
 	/** Initializes the Vehicle to a disaster vehicle */
--- a/src/vehicle_func.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/vehicle_func.h	Mon Apr 21 21:15:50 2008 +0000
@@ -1,6 +1,6 @@
 /* $Id$ */
 
-/** @vehicle.h Functions related to vehicles. */
+/** @file vehicle.h Functions related to vehicles. */
 
 #ifndef VEHICLE_FUNC_H
 #define VEHICLE_FUNC_H
@@ -72,7 +72,7 @@
 CommandCost SendAllVehiclesToDepot(VehicleType type, uint32 flags, bool service, PlayerID owner, uint16 vlw_flag, uint32 id);
 void VehicleEnterDepot(Vehicle *v);
 
-CommandCost MaybeReplaceVehicle(Vehicle *v, bool check, bool display_costs);
+CommandCost MaybeReplaceVehicle(Vehicle *v, uint32 flags, bool display_costs);
 bool CanBuildVehicleInfrastructure(VehicleType type);
 
 void CcCloneVehicle(bool success, TileIndex tile, uint32 p1, uint32 p2);
@@ -172,13 +172,9 @@
 bool EnsureNoVehicleOnGround(TileIndex tile);
 void StopAllVehicles();
 
-Vehicle *CreateEffectVehicle(int x, int y, int z, EffectVehicle type);
-Vehicle *CreateEffectVehicleAbove(int x, int y, int z, EffectVehicle type);
-Vehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicle type);
-
 extern VehicleID _vehicle_id_ctr_day;
 extern Vehicle *_place_clicked_vehicle;
 extern VehicleID _new_vehicle_id;
 extern uint16 _returned_refit_capacity;
 
-#endif /* VEHICLE_H */
+#endif /* VEHICLE_FUNC_H */
--- a/src/vehicle_gui.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/vehicle_gui.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -35,7 +35,6 @@
 #include "settings_type.h"
 #include "widgets/dropdown_func.h"
 #include "order_func.h"
-#include "depot_base.h"
 
 #include "table/sprites.h"
 #include "table/strings.h"
@@ -103,7 +102,11 @@
 	INVALID_STRING_ID
 };
 
-void RebuildVehicleLists()
+/**
+ * Set sort list flag for all vehicle list windows
+ * @param sl_flag Sort list flag to set
+ */
+static void SetVehicleListsFlag(SortListFlags sl_flag)
 {
 	Window* const *wz;
 
@@ -115,7 +118,7 @@
 			case WC_ROADVEH_LIST:
 			case WC_SHIPS_LIST:
 			case WC_AIRCRAFT_LIST:
-				WP(w, vehiclelist_d).l.flags |= VL_REBUILD;
+				WP(w, vehiclelist_d).l.flags |= sl_flag;
 				SetWindowDirty(w);
 				break;
 
@@ -124,25 +127,20 @@
 	}
 }
 
+/**
+ * Rebuild all vehicle list windows
+ */
+void RebuildVehicleLists()
+{
+	SetVehicleListsFlag(VL_REBUILD);
+}
+
+/**
+ * Resort all vehicle list windows
+ */
 void ResortVehicleLists()
 {
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
-
-		switch (w->window_class) {
-			case WC_TRAINS_LIST:
-			case WC_ROADVEH_LIST:
-			case WC_SHIPS_LIST:
-			case WC_AIRCRAFT_LIST:
-				WP(w, vehiclelist_d).l.flags |= VL_RESORT;
-				SetWindowDirty(w);
-				break;
-
-			default: break;
-		}
-	}
+	SetVehicleListsFlag(VL_RESORT);
 }
 
 void BuildVehicleList(vehiclelist_d *vl, PlayerID owner, uint16 index, uint16 window_type)
@@ -1753,7 +1751,7 @@
 
 	if (w != NULL) {
 		w->caption_color = v->owner;
-		AssignWindowViewport(w, VV_VIEWPORT_X, VV_VIEWPORT_Y, VV_INITIAL_VIEWPORT_WIDTH,
+		InitializeWindowViewport(w, VV_VIEWPORT_X, VV_VIEWPORT_Y, VV_INITIAL_VIEWPORT_WIDTH,
 												 (v->type == VEH_TRAIN) ? VV_INITIAL_VIEWPORT_HEIGHT_TRAIN : VV_INITIAL_VIEWPORT_HEIGHT,
 												 w->window_number | (1 << 31), _vehicle_view_zoom_levels[v->type]);
 	}
--- a/src/vehicle_type.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/vehicle_type.h	Mon Apr 21 21:15:50 2008 +0000
@@ -14,7 +14,7 @@
 	VEH_ROAD,
 	VEH_SHIP,
 	VEH_AIRCRAFT,
-	VEH_SPECIAL,
+	VEH_EFFECT,
 	VEH_DISASTER,
 	VEH_END,
 	VEH_INVALID = 0xFF,
@@ -38,20 +38,6 @@
 
 static const VehicleID INVALID_VEHICLE = 0xFFFF;
 
-/* Effect vehicle types */
-enum EffectVehicle {
-	EV_CHIMNEY_SMOKE   = 0,
-	EV_STEAM_SMOKE     = 1,
-	EV_DIESEL_SMOKE    = 2,
-	EV_ELECTRIC_SPARK  = 3,
-	EV_SMOKE           = 4,
-	EV_EXPLOSION_LARGE = 5,
-	EV_BREAKDOWN_SMOKE = 6,
-	EV_EXPLOSION_SMALL = 7,
-	EV_BULLDOZER       = 8,
-	EV_BUBBLE          = 9
-};
-
 /** Pathfinding option states */
 enum {
 	VPF_OPF  = 0, ///< The Original PathFinder
--- a/src/video/dedicated_v.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/video/dedicated_v.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -140,6 +140,7 @@
 
 	_screen.width = _screen.pitch = _cur_resolution[0];
 	_screen.height = _cur_resolution[1];
+	ScreenSizeChanged();
 
 	SetDebugString("net=6");
 
--- a/src/viewport.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/viewport.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -158,7 +158,19 @@
 	w->viewport = NULL;
 }
 
-void AssignWindowViewport(Window *w, int x, int y,
+/**
+ * Initialize viewport of the window for use.
+ * @param w Window to use/display the viewport in
+ * @param x Offset of left edge of viewport with respect to left edge window \a w
+ * @param y Offset of top edge of viewport with respect to top edge window \a w
+ * @param width Width of the viewport
+ * @param height Height of the viewport
+ * @param follow_flags Flags controlling the viewport.
+ *        - If bit 31 is set, the lower 16 bits are the vehicle that the viewport should follow.
+ *        - If bit 31 is clear, it is a tile position.
+ * @param zoom Zoomlevel to display
+ */
+void InitializeWindowViewport(Window *w, int x, int y,
 	int width, int height, uint32 follow_flags, ZoomLevel zoom)
 {
 	assert(w->viewport == NULL);
@@ -324,7 +336,14 @@
 	}
 }
 
-
+/**
+ * Is a xy position inside the viewport of the window?
+ * @param w Window to examine its viewport
+ * @param x X coordinate of the xy position
+ * @param y Y coordinate of the xy position
+ * @return Pointer to the viewport if the xy position is in the viewport of the window,
+ *         otherwise \c NULL is returned.
+ */
 ViewPort *IsPtInWindowViewport(const Window *w, int x, int y)
 {
 	ViewPort *vp = w->viewport;
@@ -1591,11 +1610,12 @@
 }
 
 /**
- * Marks a viewport as dirty for repaint.
- *
- * @param vp The viewport to mark as dirty
- * @todo documents the missing parameters @c left, @c top, @c right and @c bottom
- * @todo detailed description missing
+ * Marks a viewport as dirty for repaint if it displays (a part of) the area the needs to be repainted.
+ * @param vp     The viewport to mark as dirty
+ * @param left   Left edge of area to repaint
+ * @param top    Top edge of area to repaint
+ * @param right  Right edge of area to repaint
+ * @param bottom Bottom edge of area to repaint
  * @ingroup dirty
  */
 static void MarkViewportDirty(const ViewPort *vp, int left, int top, int right, int bottom)
@@ -1622,6 +1642,14 @@
 	);
 }
 
+/**
+ * Mark all viewports that display an area as dirty (in need of repaint).
+ * @param left   Left edge of area to repaint
+ * @param top    Top edge of area to repaint
+ * @param right  Right edge of area to repaint
+ * @param bottom Bottom edge of area to repaint
+ * @ingroup dirty
+ */
 void MarkAllViewportsDirty(int left, int top, int right, int bottom)
 {
 	Window **wz;
--- a/src/viewport_func.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/viewport_func.h	Mon Apr 21 21:15:50 2008 +0000
@@ -13,7 +13,7 @@
 void SetSelectionRed(bool);
 
 void DeleteWindowViewport(Window *w);
-void AssignWindowViewport(Window *w, int x, int y, int width, int height, uint32 follow_flags, ZoomLevel zoom);
+void InitializeWindowViewport(Window *w, int x, int y, int width, int height, uint32 follow_flags, ZoomLevel zoom);
 ViewPort *IsPtInWindowViewport(const Window *w, int x, int y);
 Point GetTileBelowCursor();
 void UpdateViewportPosition(Window *w);
--- a/src/water_cmd.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/water_cmd.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -39,6 +39,7 @@
 #include "station_base.h"
 #include "airport.h"
 #include "newgrf_cargo.h"
+#include "effectvehicle_func.h"
 
 #include "table/sprites.h"
 #include "table/strings.h"
--- a/src/window.cpp	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/window.cpp	Mon Apr 21 21:15:50 2008 +0000
@@ -303,6 +303,7 @@
 		}
 	}
 
+	/* Setup blitter, and dispatch a repaint event to window *wz */
 	DrawPixelInfo *dp = _cur_dpi;
 	dp->width = right - left;
 	dp->height = bottom - top;
@@ -334,6 +335,7 @@
 				bottom > w->top &&
 				left < w->left + w->width &&
 				top < w->top + w->height) {
+			/* Window w intersects with the rectangle => needs repaint */
 			DrawOverlappedWindow(wz, left, top, right, bottom);
 		}
 	}
@@ -398,7 +400,8 @@
 }
 
 /**
- * Remove window and all its child windows from the window stack
+ * Remove window and all its child windows from the window stack.
+ * @param w Window to delete
  */
 void DeleteWindow(Window *w)
 {
@@ -622,11 +625,11 @@
 {
 	Window* const *wz;
 
-	for (wz = _z_windows;; wz++) {
+	FOR_ALL_WINDOWS(wz) {
 		Window *w = *wz;
-		assert(wz < _last_z_window);
 		if (w->window_class != WC_MAIN_WINDOW && !IsVitalWindow(w)) return w;
 	}
+	NOT_REACHED();
 }
 
 bool IsWindowOfPrototype(const Window *w, const Widget *widget)
@@ -1018,9 +1021,7 @@
  * @return a pointer to the found window if any, NULL otherwise */
 Window *FindWindowFromPt(int x, int y)
 {
-	Window* const *wz;
-
-	for (wz = _last_z_window; wz != _z_windows;) {
+	for (Window * const *wz = _last_z_window; wz != _z_windows;) {
 		Window *w = *--wz;
 		if (IsInsideBS(x, w->left, w->width) && IsInsideBS(y, w->top, w->height)) {
 			return w;
@@ -1038,6 +1039,7 @@
 	IConsoleClose();
 
 	_last_z_window = _z_windows;
+	_mouseover_last_w = NULL;
 	_no_scroll = 0;
 }
 
@@ -1604,8 +1606,7 @@
 static bool MaybeBringWindowToFront(const Window *w)
 {
 	bool bring_to_front = false;
-	Window* const *wz;
-	Window* const *uz;
+	Window * const *wz;
 
 	if (w->window_class == WC_MAIN_WINDOW ||
 			IsVitalWindow(w) ||
@@ -1615,7 +1616,7 @@
 	}
 
 	wz = FindWindowZPosition(w);
-	for (uz = wz; ++uz != _last_z_window;) {
+	for (Window * const *uz = wz; ++uz != _last_z_window;) {
 		Window *u = *uz;
 
 		/* A modal child will prevent the activation of the parent window */
@@ -1789,9 +1790,6 @@
 	}
 }
 
-extern void UpdateTileSelection();
-extern bool VpHandlePlaceSizingDrag();
-
 /**
  * Local counter that is incremented each time an mouse input event is detected.
  * The counter is used to stop auto-scrolling.
@@ -1852,6 +1850,9 @@
 	TIME_BETWEEN_DOUBLE_CLICK = 500, ///< Time between 2 left clicks before it becoming a double click, in ms
 };
 
+extern void UpdateTileSelection();
+extern bool VpHandlePlaceSizingDrag();
+
 void MouseLoop(MouseClick click, int mousewheel)
 {
 	int x,y;
@@ -2064,8 +2065,9 @@
 }
 
 /**
- * Mark window data as invalid (in need of re-computing)
- * @param w Window with invalid data
+ * Mark window as dirty (in need of repainting)
+ * @param cls Window class
+ * @param number Window number in that class
  */
 void InvalidateWindow(WindowClass cls, WindowNumber number)
 {
@@ -2077,7 +2079,7 @@
 	}
 }
 
-/*
+/**
  * Mark a particular widget in a particular window as dirty (in need of repainting)
  * @param cls Window class
  * @param number Window number in that class
@@ -2095,7 +2097,7 @@
 	}
 }
 
-/*
+/**
  * Mark all windows of a particular class as dirty (in need of repainting)
  * @param cls Window class
  */
@@ -2119,7 +2121,7 @@
 }
 
 /**
- * Mark window data the window of a given class and specific window number as invalid (in need of re-computing)
+ * Mark window data of the window of a given class and specific window number as invalid (in need of re-computing)
  * @param cls Window class
  * @param number Window number within the class
  */
@@ -2151,13 +2153,17 @@
  */
 void CallWindowTickEvent()
 {
-	Window* const *wz;
-
-	for (wz = _last_z_window; wz != _z_windows;) {
+	for (Window * const *wz = _last_z_window; wz != _z_windows;) {
 		CallWindowEventNP(*--wz, WE_TICK);
 	}
 }
 
+/**
+ * Try to delete a non-vital window.
+ * Non-vital windows are windows other than the game selection, main toolbar,
+ * status bar, toolbar menu, and tooltip windows. Stickied windows are also
+ * considered vital.
+ */
 void DeleteNonVitalWindows()
 {
 	Window* const *wz;
--- a/src/window_func.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/window_func.h	Mon Apr 21 21:15:50 2008 +0000
@@ -32,7 +32,6 @@
 void DeleteAllNonVitalWindows();
 void HideVitalWindows();
 void ShowVitalWindows();
-Window **FindWindowZPosition(const Window *w);
 
 void InvalidateWindow(WindowClass cls, WindowNumber number);
 void InvalidateWindowWidget(WindowClass cls, WindowNumber number, byte widget_index);
--- a/src/window_gui.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/window_gui.h	Mon Apr 21 21:15:50 2008 +0000
@@ -549,15 +549,9 @@
 
 bool IsWindowOfPrototype(const Window *w, const Widget *widget);
 void AssignWidgetToWindow(Window *w, const Widget *widget);
-Window *AllocateWindow(
-							int x,
-							int y,
-							int width,
-							int height,
-							WindowProc *proc,
-							WindowClass cls,
-							const Widget *widget,
-							void *data = NULL);
+Window *AllocateWindow(int x, int y, int width, int height,
+			WindowProc *proc, WindowClass cls, const Widget *widget,
+			void *data = NULL);
 
 Window *AllocateWindowDesc(const WindowDesc *desc, void *data = NULL);
 Window *AllocateWindowDescFront(const WindowDesc *desc, int window_number, void *data = NULL);
@@ -594,12 +588,6 @@
 void DrawSortButtonState(const Window *w, int widget, SortButtonState state);
 
 
-Window *GetCallbackWnd();
-void DeleteNonVitalWindows();
-void DeleteAllNonVitalWindows();
-void HideVitalWindows();
-void ShowVitalWindows();
-Window **FindWindowZPosition(const Window *w);
 
 /* window.cpp */
 extern Window *_z_windows[];
@@ -624,6 +612,13 @@
 	WSM_PRESIZE  = 3,
 };
 
+Window *GetCallbackWnd();
+void DeleteNonVitalWindows();
+void DeleteAllNonVitalWindows();
+void HideVitalWindows();
+void ShowVitalWindows();
+Window **FindWindowZPosition(const Window *w);
+
 void ScrollbarClickHandler(Window *w, const Widget *wi, int x, int y);
 
 void ResizeButtons(Window *w, byte left, byte right);
--- a/src/zoom_func.h	Mon Apr 21 20:52:54 2008 +0000
+++ b/src/zoom_func.h	Mon Apr 21 21:15:50 2008 +0000
@@ -1,6 +1,6 @@
 /* $Id$ */
 
-/** @file zoom_func.hpp */
+/** @file zoom_func.h */
 
 #ifndef ZOOM_FUNC_H
 #define ZOOM_FUNC_H