(svn r12806) [NewGRF_ports] -Sync: with trunk r12773:12805. NewGRF_ports
authorrichk
Sun, 20 Apr 2008 15:27:28 +0000
branchNewGRF_ports
changeset 10274 b3c58f3df92b
parent 10243 e9066a148720
child 10275 5e46b660ca6c
(svn r12806) [NewGRF_ports] -Sync: with trunk r12773:12805.
projects/openttd_vs80.vcproj
projects/openttd_vs90.vcproj
source.list
src/aircraft_cmd.cpp
src/autoreplace_cmd.cpp
src/core/alloc_func.cpp
src/core/alloc_func.hpp
src/disaster_cmd.cpp
src/economy.cpp
src/engine_func.h
src/functions.h
src/gfx.cpp
src/industry_cmd.cpp
src/industry_gui.cpp
src/landscape.cpp
src/main_gui.cpp
src/misc.cpp
src/network/core/packet.cpp
src/newgrf.cpp
src/newgrf_callbacks.h
src/newgrf_fsmports.cpp
src/newgrf_house.cpp
src/newgrf_industrytiles.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/rail_cmd.cpp
src/road_cmd.cpp
src/roadveh_cmd.cpp
src/saveload.cpp
src/saveload.h
src/settings.cpp
src/ship_cmd.cpp
src/smallmap_gui.cpp
src/sound.cpp
src/station_base.h
src/station_cmd.cpp
src/station_gui.cpp
src/stdafx.h
src/strgen/strgen.cpp
src/strings.cpp
src/strings_func.h
src/texteff.cpp
src/town_cmd.cpp
src/town_gui.cpp
src/town_map.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/cocoa/wnd_quartz.mm
src/video/dedicated_v.cpp
src/video/null_v.cpp
src/video/sdl_v.cpp
src/video/win32_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.vcproj	Fri Apr 18 21:20:03 2008 +0000
+++ b/projects/openttd_vs80.vcproj	Sun Apr 20 15:27:28 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>
@@ -968,6 +980,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	Fri Apr 18 21:20:03 2008 +0000
+++ b/projects/openttd_vs90.vcproj	Sun Apr 20 15:27:28 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>
@@ -809,6 +817,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	Fri Apr 18 21:20:03 2008 +0000
+++ b/source.list	Sun Apr 20 15:27:28 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.h
 core/alloc_func.hpp
 core/alloc_type.hpp
+animated_tile_func.h
 articulated_vehicles.h
 autoreplace_base.h
 autoreplace_func.h
@@ -163,6 +166,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_cmd.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/aircraft_cmd.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -36,6 +36,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"
@@ -2211,7 +2212,7 @@
 		if (v->breakdown_ctr <= 2) {
 			HandleBrokenAircraft(v);
 		} else {
-			v->breakdown_ctr--;
+			if (!v->current_order.IsType(OT_LOADING)) v->breakdown_ctr--;
 		}
 	}
 
--- a/src/autoreplace_cmd.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/autoreplace_cmd.cpp	Sun Apr 20 15:27:28 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/core/alloc_func.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/core/alloc_func.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -9,7 +9,7 @@
  * Function to exit with an error message after malloc() or calloc() have failed
  * @param size number of bytes we tried to allocate
  */
-void MallocError(size_t size)
+void NORETURN MallocError(size_t size)
 {
 	error("Out of memory. Cannot allocate %i bytes", size);
 }
@@ -18,7 +18,7 @@
  * Function to exit with an error message after realloc() have failed
  * @param size number of bytes we tried to allocate
  */
-void ReallocError(size_t size)
+void NORETURN ReallocError(size_t size)
 {
 	error("Out of memory. Cannot reallocate %i bytes", size);
 }
--- a/src/core/alloc_func.hpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/core/alloc_func.hpp	Sun Apr 20 15:27:28 2008 +0000
@@ -11,8 +11,8 @@
  * duplicated in each object file making the final
  * binary needlessly large.
  */
-void MallocError(size_t size);
-void ReallocError(size_t size);
+void NORETURN MallocError(size_t size);
+void NORETURN ReallocError(size_t size);
 
 /**
  * Simplified allocation function that allocates the specified number of
--- a/src/disaster_cmd.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/disaster_cmd.cpp	Sun Apr 20 15:27:28 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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/economy.cpp	Sun Apr 20 15:27:28 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"
@@ -1691,6 +1692,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;
--- a/src/engine_func.h	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/engine_func.h	Sun Apr 20 15:27:28 2008 +0000
@@ -1,6 +1,6 @@
 /* $Id$ */
 
-/** @file engine.h */
+/** @file engine_func.h */
 
 #ifndef ENGINE_H
 #define ENGINE_H
--- a/src/functions.h	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/functions.h	Sun Apr 20 15:27:28 2008 +0000
@@ -22,21 +22,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.
@@ -68,14 +58,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/gfx.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/gfx.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -17,6 +17,7 @@
 #include "strings_func.h"
 #include "core/math_func.hpp"
 #include "settings_type.h"
+#include "core/alloc_func.hpp"
 
 #include "table/palettes.h"
 #include "table/sprites.h"
@@ -64,8 +65,12 @@
 static const byte *_color_remap_ptr;
 static byte _string_colorremap[3];
 
-#define DIRTY_BYTES_PER_LINE (MAX_SCREEN_WIDTH / 64)
-static byte _dirty_blocks[DIRTY_BYTES_PER_LINE * MAX_SCREEN_HEIGHT / 8];
+enum {
+	DIRTY_BLOCK_HEIGHT   = 8,
+	DIRTY_BLOCK_WIDTH    = 64,
+};
+static uint _dirty_bytes_per_line = 0;
+static byte *_dirty_blocks = NULL;
 
 void GfxScroll(int left, int top, int width, int height, int xo, int yo)
 {
@@ -930,6 +935,9 @@
 
 void ScreenSizeChanged()
 {
+	_dirty_bytes_per_line = (_screen.width + DIRTY_BLOCK_WIDTH - 1) / DIRTY_BLOCK_WIDTH;
+	_dirty_blocks = ReallocT<byte>(_dirty_blocks, _dirty_bytes_per_line * ((_screen.height + DIRTY_BLOCK_HEIGHT - 1) / DIRTY_BLOCK_HEIGHT));
+
 	/* check the dirty rect */
 	if (_invalid_rect.right >= _screen.width) _invalid_rect.right = _screen.width;
 	if (_invalid_rect.bottom >= _screen.height) _invalid_rect.bottom = _screen.height;
@@ -1033,8 +1041,8 @@
 void DrawDirtyBlocks()
 {
 	byte *b = _dirty_blocks;
-	const int w = Align(_screen.width, 64);
-	const int h = Align(_screen.height, 8);
+	const int w = Align(_screen.width,  DIRTY_BLOCK_WIDTH);
+	const int h = Align(_screen.height, DIRTY_BLOCK_HEIGHT);
 	int x;
 	int y;
 
@@ -1047,7 +1055,7 @@
 			if (*b != 0) {
 				int left;
 				int top;
-				int right = x + 64;
+				int right = x + DIRTY_BLOCK_WIDTH;
 				int bottom = y;
 				byte *p = b;
 				int h2;
@@ -1055,12 +1063,12 @@
 				/* First try coalescing downwards */
 				do {
 					*p = 0;
-					p += DIRTY_BYTES_PER_LINE;
-					bottom += 8;
+					p += _dirty_bytes_per_line;
+					bottom += DIRTY_BLOCK_HEIGHT;
 				} while (bottom != h && *p != 0);
 
 				/* Try coalescing to the right too. */
-				h2 = (bottom - y) >> 3;
+				h2 = (bottom - y) / DIRTY_BLOCK_HEIGHT;
 				assert(h2 > 0);
 				p = b;
 
@@ -1070,18 +1078,18 @@
 					/* Check if a full line of dirty flags is set. */
 					do {
 						if (!*p2) goto no_more_coalesc;
-						p2 += DIRTY_BYTES_PER_LINE;
+						p2 += _dirty_bytes_per_line;
 					} while (--h != 0);
 
 					/* Wohoo, can combine it one step to the right!
 					 * Do that, and clear the bits. */
-					right += 64;
+					right += DIRTY_BLOCK_WIDTH;
 
 					h = h2;
 					p2 = p;
 					do {
 						*p2 = 0;
-						p2 += DIRTY_BYTES_PER_LINE;
+						p2 += _dirty_bytes_per_line;
 					} while (--h != 0);
 				}
 				no_more_coalesc:
@@ -1099,8 +1107,8 @@
 				}
 
 			}
-		} while (b++, (x += 64) != w);
-	} while (b += -(w >> 6) + DIRTY_BYTES_PER_LINE, (y += 8) != h);
+		} while (b++, (x += DIRTY_BLOCK_WIDTH) != w);
+	} while (b += -(w / DIRTY_BLOCK_WIDTH) + _dirty_bytes_per_line, (y += DIRTY_BLOCK_HEIGHT) != h);
 
 	_invalid_rect.left = w;
 	_invalid_rect.top = h;
@@ -1147,13 +1155,13 @@
 	if (right  > _invalid_rect.right ) _invalid_rect.right  = right;
 	if (bottom > _invalid_rect.bottom) _invalid_rect.bottom = bottom;
 
-	left >>= 6;
-	top  >>= 3;
+	left /= DIRTY_BLOCK_WIDTH;
+	top  /= DIRTY_BLOCK_HEIGHT;
 
-	b = _dirty_blocks + top * DIRTY_BYTES_PER_LINE + left;
+	b = _dirty_blocks + top * _dirty_bytes_per_line + left;
 
-	width  = ((right  - 1) >> 6) - left + 1;
-	height = ((bottom - 1) >> 3) - top  + 1;
+	width  = ((right  - 1) / DIRTY_BLOCK_WIDTH)  - left + 1;
+	height = ((bottom - 1) / DIRTY_BLOCK_HEIGHT) - top  + 1;
 
 	assert(width > 0 && height > 0);
 
@@ -1162,7 +1170,7 @@
 
 		do b[--i] = 0xFF; while (i);
 
-		b += DIRTY_BYTES_PER_LINE;
+		b += _dirty_bytes_per_line;
 	} while (--height != 0);
 }
 
--- a/src/industry_cmd.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/industry_cmd.cpp	Sun Apr 20 15:27:28 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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/industry_gui.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/landscape.cpp	Sun Apr 20 15:27:28 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/main_gui.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/main_gui.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -412,7 +412,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) {
@@ -449,7 +449,7 @@
 {
 	_cur_resolution[0] = _screen.width;
 	_cur_resolution[1] = _screen.height;
+	ScreenSizeChanged();
 	RelocateAllWindows(_screen.width, _screen.height);
-	ScreenSizeChanged();
 	MarkWholeScreenDirty();
 }
--- a/src/misc.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/misc.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -23,14 +23,13 @@
 #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 "table/strings.h"
 #include "table/sprites.h"
 
-char _name_array[512][32];
 extern TileIndex _cur_tileloop_tile;
 
 void InitializeVehicles();
@@ -49,10 +48,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)
 {
@@ -93,7 +92,7 @@
 	InitializeIndustries();
 	InitializeBuildingCounts();
 
-	InitializeNameMgr();
+	InitializeOldNames();
 	InitializeVehiclesGuiList();
 	InitializeTrains();
 	InitializeNPF();
@@ -111,60 +110,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)
@@ -177,15 +122,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),
@@ -469,7 +405,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/network/core/packet.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/network/core/packet.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -11,10 +11,6 @@
 
 #include "packet.h"
 
-
-/* Do not want to include functions.h and all required headers */
-extern void NORETURN CDECL error(const char *str, ...);
-
 /**
  * Create a packet that is used to read from a network socket
  * @param cs the socket handler associated with the socket we are reading from
--- a/src/newgrf.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/newgrf.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -1127,19 +1127,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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/newgrf_callbacks.h	Sun Apr 20 15:27:28 2008 +0000
@@ -173,13 +173,13 @@
 	/* 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,
 
 	/** Called to determine station tile next animation frame. */
-	CBID_STATION_ANIM_NEXT_FRAME         = 0x141, // not implemented
+	CBID_STATION_ANIM_NEXT_FRAME         = 0x141,
 
 	/** Called to indicate how long the current animation frame should last. */
-	CBID_STATION_ANIMATION_SPEED         = 0x142, // not implemented
+	CBID_STATION_ANIMATION_SPEED         = 0x142,
 
 	/** Called to determine whether a town building can be destroyed. */
 	CBID_HOUSE_DENY_DESTRUCTION          = 0x143,
--- a/src/newgrf_fsmports.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/newgrf_fsmports.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -21,6 +21,7 @@
 #include "cargotype.h"
 #include "town_map.h"
 #include "newgrf_town.h"
+#include "date_func.h"
 #include "player_func.h"
 #include "gfx_func.h"
 #include "strings_func.h"
--- a/src/newgrf_house.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/newgrf_house.cpp	Sun Apr 20 15:27:28 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"
--- a/src/newgrf_industrytiles.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/newgrf_industrytiles.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -23,6 +23,7 @@
 #include "functions.h"
 #include "town.h"
 #include "command_func.h"
+#include "animated_tile_func.h"
 
 #include "table/sprites.h"
 #include "table/strings.h"
--- a/src/newgrf_station.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/newgrf_station.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -22,6 +22,8 @@
 #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"
@@ -741,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.
@@ -854,3 +860,178 @@
 		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 (!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;
+	}
+}
+
+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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/newgrf_station.h	Sun Apr 20 15:27:28 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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/news_func.h	Sun Apr 20 15:27:28 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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/news_gui.cpp	Sun Apr 20 15:27:28 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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/news_type.h	Sun Apr 20 15:27:28 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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/oldloader.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -24,6 +24,8 @@
 #include "date_func.h"
 #include "vehicle_func.h"
 #include "variables.h"
+#include "strings_func.h"
+#include "effectvehicle_base.h"
 
 #include "table/strings.h"
 
@@ -84,6 +86,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 +209,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 +399,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;
@@ -1079,9 +1087,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
 
@@ -1116,7 +1124,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;
 	}
 
@@ -1229,7 +1237,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;
@@ -1263,7 +1271,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);
@@ -1521,7 +1529,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
 
@@ -1601,8 +1609,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...");
@@ -1669,6 +1679,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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/openttd.cpp	Sun Apr 20 15:27:28 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"
@@ -92,6 +94,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);
@@ -259,8 +263,8 @@
 		return;
 	}
 
-	res[0] = Clamp(strtoul(s, NULL, 0), 64, MAX_SCREEN_WIDTH);
-	res[1] = Clamp(strtoul(t + 1, NULL, 0), 64, MAX_SCREEN_HEIGHT);
+	res[0] = max(strtoul(s, NULL, 0), 64UL);
+	res[1] = max(strtoul(t + 1, NULL, 0), 64UL);
 }
 
 static void InitializeDynamicVariables()
@@ -639,39 +643,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) {
@@ -1089,9 +1060,7 @@
 
 void GameLoop()
 {
-	ThreadMsg message;
-
-	if ((message = OTTD_PollThreadEvent()) != 0) ProcessSentMessage(message);
+	ProcessAsyncSaveFinish();
 
 	/* autosave game? */
 	if (_do_autosave) {
@@ -1413,6 +1382,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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/openttd.h	Sun Apr 20 15:27:28 2008 +0000
@@ -1,4 +1,5 @@
 /* $Id$ */
+
 /** @file openttd.h */
 
 #ifndef OPENTTD_H
@@ -97,11 +98,6 @@
 
 extern byte _savegame_sort_order;
 
-enum {
-	MAX_SCREEN_WIDTH  = 2048,
-	MAX_SCREEN_HEIGHT = 1200,
-};
-
 /* In certain windows you navigate with the arrow keys. Do not scroll the
  * gameview when here. Bitencoded variable that only allows scrolling if all
  * elements are zero */
@@ -113,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/rail_cmd.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/rail_cmd.cpp	Sun Apr 20 15:27:28 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/road_cmd.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/road_cmd.cpp	Sun Apr 20 15:27:28 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_cmd.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/roadveh_cmd.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -42,6 +42,7 @@
 #include "order_func.h"
 #include "depot_base.h"
 #include "depot_func.h"
+#include "effectvehicle_func.h"
 
 #include "table/strings.h"
 
@@ -704,7 +705,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;
 		}
 	}
 
@@ -1844,7 +1845,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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/saveload.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/saveload.h	Sun Apr 20 15:27:28 2008 +0000
@@ -321,7 +321,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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/settings.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -1654,20 +1654,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;
 			}
@@ -1678,18 +1676,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 */
@@ -1745,7 +1741,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;
@@ -1756,11 +1752,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;
 	}
@@ -1847,7 +1843,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);
 }
@@ -1859,7 +1855,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_cmd.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/ship_cmd.cpp	Sun Apr 20 15:27:28 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"
 
@@ -210,7 +211,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 +595,7 @@
 			HandleBrokenShip(v);
 			return;
 		}
-		v->breakdown_ctr--;
+		if (!v->current_order.IsType(OT_LOADING)) v->breakdown_ctr--;
 	}
 
 	if (v->vehstatus & VS_STOPPED) return;
--- a/src/smallmap_gui.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/smallmap_gui.cpp	Sun Apr 20 15:27:28 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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/sound.cpp	Sun Apr 20 15:27:28 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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/station_base.h	Sun Apr 20 15:27:28 2008 +0000
@@ -171,6 +171,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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/station_cmd.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -43,6 +43,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"
@@ -1127,6 +1128,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);
 
@@ -1143,6 +1150,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 */
@@ -1151,6 +1159,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;
@@ -1372,6 +1383,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);
@@ -2482,6 +2494,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++) {
@@ -2729,7 +2746,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()
@@ -2761,6 +2787,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);
 }
@@ -3135,6 +3163,8 @@
 		}
 
 		for (CargoID c = 0; c < NUM_CARGO; c++) st->goods[c].cargo.InvalidateCache();
+
+		StationUpdateAnimTriggers(st);
 	}
 }
 
--- a/src/station_gui.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/station_gui.cpp	Sun Apr 20 15:27:28 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/stdafx.h	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/stdafx.h	Sun Apr 20 15:27:28 2008 +0000
@@ -309,13 +309,7 @@
 	#define CloseConnection OTTD_CloseConnection
 #endif /* __APPLE__ */
 
-#if !defined(STRGEN)
-	/* In strgen error is not fatal and returns */
-	void NORETURN CDECL error(const char *str, ...);
-#else
-	void CDECL error(const char *str, ...);
-#endif
-
+void NORETURN CDECL error(const char *str, ...);
 #define NOT_REACHED() error("NOT_REACHED triggered at line %i of %s", __LINE__, __FILE__)
 
 #if defined(MORPHOS) || defined(__NDS__)
--- a/src/strgen/strgen.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/strgen/strgen.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -155,7 +155,7 @@
 # define LINE_NUM_FMT ":%d"
 #endif
 
-static void CDECL warning(const char *s, ...)
+static void CDECL strgen_warning(const char *s, ...)
 {
 	char buf[1024];
 	va_list va;
@@ -166,7 +166,7 @@
 	_warnings++;
 }
 
-void CDECL error(const char *s, ...)
+static void CDECL strgen_error(const char *s, ...)
 {
 	char buf[1024];
 	va_list va;
@@ -177,8 +177,7 @@
 	_errors++;
 }
 
-
-static void NORETURN CDECL fatal(const char *s, ...)
+void NORETURN CDECL error(const char *s, ...)
 {
 	char buf[1024];
 	va_list va;
@@ -191,7 +190,7 @@
 
 static void PutByte(byte c)
 {
-	if (_put_pos == lengthof(_put_buf)) fatal("Put buffer too small");
+	if (_put_pos == lengthof(_put_buf)) error("Put buffer too small");
 	_put_buf[_put_pos++] = c;
 }
 
@@ -213,7 +212,7 @@
 		PutByte(0x80 + GB(value,  6, 6));
 		PutByte(0x80 + GB(value,  0, 6));
 	} else {
-		warning("Invalid unicode value U+0x%X", value);
+		strgen_warning("Invalid unicode value U+0x%X", value);
 	}
 }
 
@@ -245,7 +244,7 @@
 
 static void EmitSingleChar(char *buf, int value)
 {
-	if (*buf != '\0') warning("Ignoring trailing letters in command");
+	if (*buf != '\0') strgen_warning("Ignoring trailing letters in command");
 	PutUtf8(value);
 }
 
@@ -254,7 +253,7 @@
 {
 	char *err;
 	int x = strtol(buf, &err, 0);
-	if (*err != 0) fatal("SetX param invalid");
+	if (*err != 0) error("SetX param invalid");
 	PutUtf8(SCC_SETX);
 	PutByte((byte)x);
 }
@@ -267,9 +266,9 @@
 	int y;
 
 	x = strtol(buf, &err, 0);
-	if (*err != ' ') fatal("SetXY param invalid");
+	if (*err != ' ') error("SetXY param invalid");
 	y = strtol(err + 1, &err, 0);
-	if (*err != 0) fatal("SetXY param invalid");
+	if (*err != 0) error("SetXY param invalid");
 
 	PutUtf8(SCC_SETXY);
 	PutByte((byte)x);
@@ -371,14 +370,14 @@
 	}
 
 	if (nw == 0)
-		fatal("%s: No plural words", _cur_ident);
+		error("%s: No plural words", _cur_ident);
 
 	if (_plural_form_counts[_lang_pluralform] != nw) {
 		if (_translated) {
-			fatal("%s: Invalid number of plural forms. Expecting %d, found %d.", _cur_ident,
+			error("%s: Invalid number of plural forms. Expecting %d, found %d.", _cur_ident,
 				_plural_form_counts[_lang_pluralform], nw);
 		} else {
-			if ((_show_todo & 2) != 0) warning("'%s' is untranslated. Tweaking english string to allow compilation for plural forms", _cur_ident);
+			if ((_show_todo & 2) != 0) strgen_warning("'%s' is untranslated. Tweaking english string to allow compilation for plural forms", _cur_ident);
 			if (nw > _plural_form_counts[_lang_pluralform]) {
 				nw = _plural_form_counts[_lang_pluralform];
 			} else {
@@ -405,7 +404,7 @@
 
 		// This is a {G=DER} command
 		for (nw = 0; ; nw++) {
-			if (nw >= 8) fatal("G argument '%s' invalid", buf);
+			if (nw >= 8) error("G argument '%s' invalid", buf);
 			if (strcmp(buf, _genders[nw]) == 0) break;
 		}
 		// now nw contains the gender index
@@ -422,7 +421,7 @@
 			words[nw] = ParseWord(&buf);
 			if (words[nw] == NULL) break;
 		}
-		if (nw != _numgenders) fatal("Bad # of arguments for gender command");
+		if (nw != _numgenders) error("Bad # of arguments for gender command");
 		PutUtf8(SCC_GENDER_LIST);
 		PutByte(TranslateArgumentIdx(argidx));
 		EmitWordList(words, nw);
@@ -553,7 +552,7 @@
 	for (i = 0; i < MAX_NUM_CASES; i++) {
 		if (memcmp(_cases[i], str, len) == 0 && _cases[i][len] == 0) return i + 1;
 	}
-	fatal("Invalid case-name '%s'", str);
+	error("Invalid case-name '%s'", str);
 }
 
 
@@ -578,7 +577,7 @@
 		char *end;
 
 		*argno = strtoul(s, &end, 0);
-		if (*end != ':') fatal("missing arg #");
+		if (*end != ':') error("missing arg #");
 		s = end + 1;
 	}
 
@@ -590,7 +589,7 @@
 
 	cmd = FindCmd(start, s - start - 1);
 	if (cmd == NULL) {
-		error("Undefined command '%.*s'", s - start - 1, start);
+		strgen_error("Undefined command '%.*s'", s - start - 1, start);
 		return NULL;
 	}
 
@@ -598,14 +597,14 @@
 		const char *casep = s;
 
 		if (!(cmd->flags & C_CASE))
-			fatal("Command '%s' can't have a case", cmd->cmd);
+			error("Command '%s' can't have a case", cmd->cmd);
 
 		do c = *s++; while (c != '}' && c != ' ' && c != '\0');
 		*casei = ResolveCaseName(casep, s - casep - 1);
 	}
 
 	if (c == '\0') {
-		error("Missing } from command '%s'", start);
+		strgen_error("Missing } from command '%s'", start);
 		return NULL;
 	}
 
@@ -618,10 +617,10 @@
 			c = *s++;
 			if (c == '}') break;
 			if (c == '\0') {
-				error("Missing } from command '%s'", start);
+				strgen_error("Missing } from command '%s'", start);
 				return NULL;
 			}
-			if (s - start == 250) fatal("param command too long");
+			if (s - start == 250) error("param command too long");
 			*param++ = c;
 		}
 	}
@@ -646,7 +645,7 @@
 	} else if (!memcmp(str, "plural ", 7)) {
 		_lang_pluralform = atoi(str + 7);
 		if (_lang_pluralform >= lengthof(_plural_form_counts))
-			fatal("Invalid pluralform %d", _lang_pluralform);
+			error("Invalid pluralform %d", _lang_pluralform);
 	} else if (!memcmp(str, "gender ", 7)) {
 		char* buf = str + 7;
 
@@ -654,7 +653,7 @@
 			const char* s = ParseWord(&buf);
 
 			if (s == NULL) break;
-			if (_numgenders >= MAX_NUM_GENDER) fatal("Too many genders, max %d", MAX_NUM_GENDER);
+			if (_numgenders >= MAX_NUM_GENDER) error("Too many genders, max %d", MAX_NUM_GENDER);
 			ttd_strlcpy(_genders[_numgenders], s, sizeof(_genders[_numgenders]));
 			_numgenders++;
 		}
@@ -665,12 +664,12 @@
 			const char* s = ParseWord(&buf);
 
 			if (s == NULL) break;
-			if (_numcases >= MAX_NUM_CASES) fatal("Too many cases, max %d", MAX_NUM_CASES);
+			if (_numcases >= MAX_NUM_CASES) error("Too many cases, max %d", MAX_NUM_CASES);
 			ttd_strlcpy(_cases[_numcases], s, sizeof(_cases[_numcases]));
 			_numcases++;
 		}
 	} else {
-		fatal("unknown pragma '%s'", str);
+		error("unknown pragma '%s'", str);
 	}
 }
 
@@ -690,16 +689,16 @@
 		if (ar == NULL) break;
 
 		// Sanity checking
-		if (argno != -1 && ar->consumes == 0) fatal("Non consumer param can't have a paramindex");
+		if (argno != -1 && ar->consumes == 0) error("Non consumer param can't have a paramindex");
 
 		if (ar->consumes) {
 			if (argno != -1) argidx = argno;
-			if (argidx < 0 || argidx >= lengthof(p->cmd)) fatal("invalid param idx %d", argidx);
-			if (p->cmd[argidx] != NULL && p->cmd[argidx] != ar) fatal("duplicate param idx %d", argidx);
+			if (argidx < 0 || argidx >= lengthof(p->cmd)) error("invalid param idx %d", argidx);
+			if (p->cmd[argidx] != NULL && p->cmd[argidx] != ar) error("duplicate param idx %d", argidx);
 
 			p->cmd[argidx++] = ar;
 		} else if (!(ar->flags & C_DONTCOUNT)) { // Ignore some of them
-			if (p->np >= lengthof(p->pairs)) fatal("too many commands in string, max %d", lengthof(p->pairs));
+			if (p->np >= lengthof(p->pairs)) error("too many commands in string, max %d", lengthof(p->pairs));
 			p->pairs[p->np].a = ar;
 			p->pairs[p->np].v = param[0] != '\0' ? strdup(param) : "";
 			p->np++;
@@ -738,7 +737,7 @@
 
 	// For each string in templ, see if we find it in lang
 	if (templ.np != lang.np) {
-		warning("%s: template string and language string have a different # of commands", name);
+		strgen_warning("%s: template string and language string have a different # of commands", name);
 		result = false;
 	}
 
@@ -756,7 +755,7 @@
 		}
 
 		if (!found) {
-			warning("%s: command '%s' exists in template file but not in language file", name, templ.pairs[i].a->cmd);
+			strgen_warning("%s: command '%s' exists in template file but not in language file", name, templ.pairs[i].a->cmd);
 			result = false;
 		}
 	}
@@ -765,7 +764,7 @@
 	// Check if the non consumer commands match up also.
 	for (i = 0; i < lengthof(templ.cmd); i++) {
 		if (TranslateCmdForCompare(templ.cmd[i]) != TranslateCmdForCompare(lang.cmd[i])) {
-			warning("%s: Param idx #%d '%s' doesn't match with template command '%s'", name, i,
+			strgen_warning("%s: Param idx #%d '%s' doesn't match with template command '%s'", name, i,
 				lang.cmd[i]  == NULL ? "<empty>" : lang.cmd[i]->cmd,
 				templ.cmd[i] == NULL ? "<empty>" : templ.cmd[i]->cmd);
 			result = false;
@@ -791,7 +790,7 @@
 
 	s = strchr(str, ':');
 	if (s == NULL) {
-		error("Line has no ':' delimiter");
+		strgen_error("Line has no ':' delimiter");
 		return;
 	}
 
@@ -806,7 +805,7 @@
 		const char *tmp;
 		for (tmp = s; *tmp != '\0';) {
 			size_t len = Utf8Validate(tmp);
-			if (len == 0) fatal("Invalid UTF-8 sequence in '%s'", s);
+			if (len == 0) error("Invalid UTF-8 sequence in '%s'", s);
 			tmp += len;
 		}
 	}
@@ -821,18 +820,18 @@
 
 	if (master) {
 		if (ent != NULL && casep == NULL) {
-			error("String name '%s' is used multiple times", str);
+			strgen_error("String name '%s' is used multiple times", str);
 			return;
 		}
 
 		if (ent == NULL && casep != NULL) {
-			error("Base string name '%s' doesn't exist yet. Define it before defining a case.", str);
+			strgen_error("Base string name '%s' doesn't exist yet. Define it before defining a case.", str);
 			return;
 		}
 
 		if (ent == NULL) {
 			if (_strings[_next_string_id]) {
-				error("String ID 0x%X for '%s' already in use by '%s'", ent, str, _strings[_next_string_id]->name);
+				strgen_error("String ID 0x%X for '%s' already in use by '%s'", ent, str, _strings[_next_string_id]->name);
 				return;
 			}
 
@@ -859,12 +858,12 @@
 
 	} else {
 		if (ent == NULL) {
-			warning("String name '%s' does not exist in master file", str);
+			strgen_warning("String name '%s' does not exist in master file", str);
 			return;
 		}
 
 		if (ent->translated && casep == NULL) {
-			error("String name '%s' is used multiple times", str);
+			strgen_error("String name '%s' is used multiple times", str);
 			return;
 		}
 
@@ -912,7 +911,7 @@
 	// derive some strings from english....
 
 	in = fopen(file, "r");
-	if (in == NULL) fatal("Cannot open file");
+	if (in == NULL) error("Cannot open file");
 	_cur_line = 1;
 	while (fgets(buf, sizeof(buf), in) != NULL) {
 		rstrip(buf);
@@ -922,7 +921,7 @@
 	fclose(in);
 
 	if (StrEmpty(_lang_name) || StrEmpty(_lang_ownname) || StrEmpty(_lang_isocode)) {
-		fatal("Language must include ##name, ##ownname and ##isocode");
+		error("Language must include ##name, ##ownname and ##isocode");
 	}
 }
 
@@ -991,7 +990,7 @@
 	if (f2 == NULL) return false;
 
 	f1 = fopen(n1, "rb");
-	if (f1 == NULL) fatal("can't open %s", n1);
+	if (f1 == NULL) error("can't open %s", n1);
 
 	do {
 		l1 = fread(b1, 1, sizeof(b1), f1);
@@ -1017,7 +1016,7 @@
 	int next = -1;
 
 	out = fopen("tmp.xxx", "w");
-	if (out == NULL) fatal("can't open tmp.xxx");
+	if (out == NULL) error("can't open tmp.xxx");
 
 	fprintf(out, "/* This file is automatically generated. Do not modify */\n\n");
 	fprintf(out, "#ifndef TABLE_STRINGS_H\n");
@@ -1052,7 +1051,7 @@
 #if defined(WIN32) || defined(WIN64)
 		unlink(filename);
 #endif
-		if (rename("tmp.xxx", filename) == -1) fatal("rename() failed");
+		if (rename("tmp.xxx", filename) == -1) error("rename() failed");
 	}
 }
 
@@ -1061,7 +1060,7 @@
 	int i, sum;
 
 	if (argidx < 0 || argidx >= lengthof(_cur_pcs.cmd))
-		fatal("invalid argidx %d", argidx);
+		error("invalid argidx %d", argidx);
 
 	for (i = sum = 0; i < argidx; i++) {
 		const CmdStruct *cs = _cur_pcs.cmd[i];
@@ -1112,7 +1111,7 @@
 			// Output the one from the master string... it's always accurate.
 			cs = _cur_pcs.cmd[_cur_argidx++];
 			if (cs == NULL) {
-				fatal("%s: No argument exists at position %d", _cur_ident, _cur_argidx - 1);
+				error("%s: No argument exists at position %d", _cur_ident, _cur_argidx - 1);
 			}
 		}
 
@@ -1128,7 +1127,7 @@
 		fputc((length >> 8) | 0xC0, f);
 		fputc(length & 0xFF, f);
 	} else {
-		fatal("string too long");
+		error("string too long");
 	}
 }
 
@@ -1142,7 +1141,7 @@
 	uint j;
 
 	f = fopen(filename, "wb");
-	if (f == NULL) fatal("can't open %s", filename);
+	if (f == NULL) error("can't open %s", filename);
 
 	memset(&hdr, 0, sizeof(hdr));
 	for (i = 0; i != 32; i++) {
@@ -1180,7 +1179,7 @@
 			// Produce a message if a string doesn't have a translation.
 			if (_show_todo > 0 && ls->translated == NULL) {
 				if ((_show_todo & 2) != 0) {
-					warning("'%s' is untranslated", ls->name);
+					strgen_warning("'%s' is untranslated", ls->name);
 				}
 				if ((_show_todo & 1) != 0) {
 					const char *s = "<TODO> ";
--- a/src/strings.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/strings.cpp	Sun Apr 20 15:27:28 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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/strings_func.h	Sun Apr 20 15:27:28 2008 +0000
@@ -78,4 +78,7 @@
 
 void CheckForMissingGlyphsInLoadedLanguagePack();
 
+StringID RemapOldStringID(StringID s);
+char *CopyFromOldName(StringID id);
+
 #endif /* STRINGS_TYPE_H */
--- a/src/texteff.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/texteff.cpp	Sun Apr 20 15:27:28 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/town_cmd.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/town_cmd.cpp	Sun Apr 20 15:27:28 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);
 }
@@ -385,6 +391,7 @@
 		/* Now that construction is complete, we can add the population of the
 		 * building to the town. */
 		ChangePopulation(GetTownByTile(tile), GetHouseSpecs(GetHouseType(tile))->population);
+		SetHouseConstructionYear(tile, _cur_year);
 	}
 	MarkTileDirtyByTile(tile);
 }
@@ -1644,6 +1651,9 @@
 	assert(CmdSucceeded(cc));
 
 	MakeHouseTile(tile, tid, counter, stage, type, random_bits);
+	if (GetHouseSpecs(type)->building_flags & BUILDING_IS_ANIMATED) AddAnimatedTile(tile);
+
+	MarkTileDirtyByTile(tile);
 }
 
 
--- a/src/town_gui.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/town_gui.cpp	Sun Apr 20 15:27:28 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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/town_map.h	Sun Apr 20 15:27:28 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_cmd.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/train_cmd.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -48,6 +48,8 @@
 #include "gfx_func.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"
@@ -2218,6 +2220,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;
@@ -2638,6 +2642,8 @@
 	}
 
 	v->BeginLoading();
+
+	StationAnimationTrigger(st, v->tile, STAT_ANIM_TRAIN_ARRIVES);
 }
 
 static byte AfterSetTrainPos(Vehicle *v, bool new_tile)
@@ -3232,7 +3238,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;
 		}
 	}
 
@@ -3421,7 +3427,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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/vehicle.cpp	Sun Apr 20 15:27:28 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;
 	}
 }
@@ -2939,7 +2359,7 @@
 };
 
 static const SaveLoad _special_desc[] = {
-	SLE_WRITEBYTE(Vehicle, type, VEH_SPECIAL),
+	SLE_WRITEBYTE(Vehicle, type, VEH_EFFECT),
 
 	    SLE_VAR(Vehicle, subtype,       SLE_UINT8),
 
@@ -2957,8 +2377,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),
@@ -3046,7 +2466,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();
@@ -3266,15 +2686,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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/vehicle_base.h	Sun Apr 20 15:27:28 2008 +0000
@@ -171,7 +171,7 @@
 	RoadTypes compatible_roadtypes;
 };
 
-struct VehicleSpecial {
+struct VehicleEffect {
 	uint16 animation_state;
 	byte animation_substate;
 };
@@ -315,7 +315,7 @@
 		VehicleRail rail;
 		VehicleAir air;
 		VehicleRoad road;
-		VehicleSpecial special;
+		VehicleEffect effect;
 		VehicleDisaster disaster;
 		VehicleShip ship;
 	} u;
@@ -541,33 +541,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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/vehicle_func.h	Sun Apr 20 15:27:28 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
@@ -71,7 +71,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);
@@ -171,13 +171,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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/vehicle_gui.cpp	Sun Apr 20 15:27:28 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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/vehicle_type.h	Sun Apr 20 15:27:28 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/cocoa/wnd_quartz.mm	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/video/cocoa/wnd_quartz.mm	Sun Apr 20 15:27:28 2008 +0000
@@ -175,7 +175,8 @@
 			CMCloseProfile(sysProfile);
 		}
 
-		assert(colorSpace != NULL);
+		if (colorSpace == NULL)
+			error("Could not get system colour space. You might need to recalibrate your monitor.");
 	}
 
 	return colorSpace;
--- a/src/video/dedicated_v.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/video/dedicated_v.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -140,6 +140,7 @@
 
 	_screen.width = _screen.pitch = _cur_resolution[0];
 	_screen.height = _cur_resolution[1];
+	ScreenSizeChanged();
 
 	SetDebugString("net=6");
 
--- a/src/video/null_v.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/video/null_v.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -15,6 +15,8 @@
 	this->ticks = GetDriverParamInt(parm, "ticks", 1000);
 	_screen.width = _screen.pitch = _cur_resolution[0];
 	_screen.height = _cur_resolution[1];
+	ScreenSizeChanged();
+
 	/* Do not render, nor blit */
 	DEBUG(misc, 1, "Forcing blitter 'null'...");
 	BlitterFactoryBase::SelectBlitter("null");
--- a/src/video/sdl_v.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/video/sdl_v.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -127,8 +127,7 @@
 		for (i = 0; modes[i]; i++) {
 			int w = modes[i]->w;
 			int h = modes[i]->h;
-			if (IsInsideMM(w, 640, MAX_SCREEN_WIDTH + 1) &&
-					IsInsideMM(h, 480, MAX_SCREEN_HEIGHT + 1)) {
+			if (w >= 640 && h >= 480) {
 				int j;
 				for (j = 0; j < n; j++) {
 					if (_resolutions[j][0] == w && _resolutions[j][1] == h) break;
@@ -419,8 +418,8 @@
 			break;
 
 		case SDL_VIDEORESIZE: {
-			int w = Clamp(ev.resize.w, 64, MAX_SCREEN_WIDTH);
-			int h = Clamp(ev.resize.h, 64, MAX_SCREEN_HEIGHT);
+			int w = max(ev.resize.w, 64);
+			int h = max(ev.resize.h, 64);
 			ChangeResInGame(w, h);
 			break;
 		}
--- a/src/video/win32_v.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/video/win32_v.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -545,8 +545,8 @@
 
 			w = r->right - r->left - (r2.right - r2.left);
 			h = r->bottom - r->top - (r2.bottom - r2.top);
-			w = Clamp(w, 64, MAX_SCREEN_WIDTH);
-			h = Clamp(h, 64, MAX_SCREEN_HEIGHT);
+			w = max(w, 64);
+			h = max(h, 64);
 			SetRect(&r2, 0, 0, w, h);
 
 			AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
@@ -677,8 +677,8 @@
 	HDC dc;
 	int bpp = BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth();
 
-	w = Clamp(w, 64, MAX_SCREEN_WIDTH);
-	h = Clamp(h, 64, MAX_SCREEN_HEIGHT);
+	w = max(w, 64);
+	h = max(h, 64);
 
 	if (bpp == 0) error("Can't use a blitter that blits 0 bpp for normal visuals");
 
@@ -737,8 +737,8 @@
 	 * Doesn't really matter since we don't pass a string anyways, but still
 	 * a letdown */
 	for (i = 0; EnumDisplaySettingsA(NULL, i, &dm) != 0; i++) {
-		if (dm.dmBitsPerPel == BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth() && IsInsideMM(dm.dmPelsWidth, 640, MAX_SCREEN_WIDTH + 1) &&
-				IsInsideMM(dm.dmPelsHeight, 480, MAX_SCREEN_HEIGHT + 1)) {
+		if (dm.dmBitsPerPel == BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth() &&
+				dm.dmPelsWidth >= 640 && dm.dmPelsHeight >= 480) {
 			uint j;
 
 			for (j = 0; j < n; j++) {
@@ -787,10 +787,10 @@
 	_wnd.height_org = _cur_resolution[1];
 
 	AllocateDibSection(_cur_resolution[0], _cur_resolution[1]);
+	MakeWindow(_fullscreen);
+
 	MarkWholeScreenDirty();
 
-	MakeWindow(_fullscreen);
-
 	return NULL;
 }
 
--- a/src/viewport.cpp	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/viewport.cpp	Sun Apr 20 15:27:28 2008 +0000
@@ -159,7 +159,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);
@@ -325,7 +337,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;
@@ -1617,11 +1636,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)
@@ -1648,6 +1668,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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/viewport_func.h	Sun Apr 20 15:27:28 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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/water_cmd.cpp	Sun Apr 20 15:27:28 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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/window.cpp	Sun Apr 20 15:27:28 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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/window_func.h	Sun Apr 20 15:27:28 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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/window_gui.h	Sun Apr 20 15:27:28 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	Fri Apr 18 21:20:03 2008 +0000
+++ b/src/zoom_func.h	Sun Apr 20 15:27:28 2008 +0000
@@ -1,6 +1,6 @@
 /* $Id$ */
 
-/** @file zoom_func.hpp */
+/** @file zoom_func.h */
 
 #ifndef ZOOM_FUNC_H
 #define ZOOM_FUNC_H