Seems to be obsoleted by waypts.patch.

Index: station_cmd.c
===================================================================
--- station_cmd.c	(revision 762)
+++ station_cmd.c	(working copy)
@@ -980,6 +980,28 @@
 }
 
 
+/* This is very simplistic infrastructure yet. We need to be able to store
+ * multiple sprites (<- most important) for multiple stations of multiple
+ * classes. --pasky */
+
+static bool _waypoint_data_set;
+static DrawTileSeqStruct _waypoint_data[8];
+
+void SetCustomStation(uint32 classid, DrawTileSeqStruct *data)
+{
+	assert(classid == 'WAYP');
+	memcpy(_waypoint_data, data, sizeof(DrawTileSeqStruct) * 8);
+	_waypoint_data_set = 1;
+}
+
+DrawTileSeqStruct *GetCustomStation(uint32 classid)
+{
+	assert(classid == 'WAYP');
+	if (!_waypoint_data_set) return NULL;
+	return _waypoint_data;
+}
+
+
 static int32 RemoveRailroadStation(Station *st, uint32 flags)
 {
 	uint tile;
@@ -1727,16 +1749,7 @@
 #include "table/station_land.h"
 
 
-typedef struct DrawTileSeqStruct {
-	int8 delta_x;
-	int8 delta_y;
-	int8 delta_z;
-	byte width,height;
-	byte unk;
-	SpriteID image;
-} DrawTileSeqStruct;
 
-
 static void DrawTile_Station(TileInfo *ti)
 {
 	uint32 image_or_modificator;
Index: engine.h
===================================================================
--- engine.h	(revision 762)
+++ engine.h	(working copy)
@@ -63,8 +63,14 @@
 	// XXX: Would anyone ever need more than 16 spritesets? Maybe we should
 	// use even less, now we take whole 8kb for custom sprites table, oh my!
 	byte sprites_per_set; // means number of directions - 4 or 8
+
 	// Loaded = in motion, loading = not moving
 	// Each superset contains several spritesets, for various loading stages
+
+	// XXX: For stations the meaning is different - loaded is for stations
+	// with small amount of cargo whilst loading is for stations with a lot
+	// of it.
+
 	byte loaded_count;
 	uint16 loaded[16]; // sprite ids
 	byte loading_count;
Index: rail_cmd.c
===================================================================
--- rail_cmd.c	(revision 762)
+++ rail_cmd.c	(working copy)
@@ -5,6 +5,7 @@
 #include "command.h"
 #include "pathfind.h"
 #include "city.h"
+#include "station.h"
 
 void ShowTrainDepotWindow(uint tile);
 
@@ -1255,6 +1256,19 @@
 	}
 }
 
+static void DrawSpecialBuilding(uint32 image, uint32 tracktype_offs,
+                                TileInfo *ti,
+                                byte x, byte y, byte z,
+                                byte xsize, byte ysize, byte zsize)
+{
+	if (image & 0x8000)
+		image |= _drawtile_track_palette;
+	image += tracktype_offs;
+	if (!(_display_opt & DO_TRANS_BUILDINGS)) 
+		image = (image & 0x3FFF) | 0x3224000;
+	AddSortableSpriteToDraw(image, ti->x + x, ti->y + y, xsize, ysize, zsize, ti->z + z);
+}
+
 static void DrawTile_Track(TileInfo *ti)
 {
 	uint32 tracktype_offs, image;
@@ -1374,17 +1388,26 @@
 		image = *(uint16*)s;
 		if (image & 0x8000) image = (image & 0x7FFF) + tracktype_offs;
 		DrawGroundSprite(image);
+
+		if (!IS_RAIL_DEPOT(m5) && IS_RAIL_CHECKPOINT(m5)) {
+			// look for customization
+			DrawTileSeqStruct *cust = GetCustomStation('WAYP');
+
+			if (cust && !tracktype_offs) {
+				cust = &cust[2 + (m5 & 0x1)]; // emulate station tile - open with building
+				DrawSpecialBuilding(cust->image|0x8000, 0, ti,
+				                    cust->delta_x, cust->delta_y, cust->delta_z - 0x10 /*just because wrong assoc*/,
+				                    cust->width, cust->height, cust->unk);
+				return;
+			}
+		}
 		
 		drss = (const DrawTrackSeqStruct*)(s + sizeof(uint16));
 
 		while ((image=drss->image) != 0) {
-			if (image & 0x8000)
-				image |= _drawtile_track_palette;
-			image += tracktype_offs;
-			if (!(_display_opt & DO_TRANS_BUILDINGS)) 
-				image = (image & 0x3FFF) | 0x3224000;
-			AddSortableSpriteToDraw(image, ti->x | drss->subcoord_x, 
-				ti->y | drss->subcoord_y, drss->width, drss->height, 0x17, ti->z);
+			DrawSpecialBuilding(image, tracktype_offs, ti,
+			                    drss->subcoord_x, drss->subcoord_y, 0,
+			                    drss->width, drss->height, 0x17);
 			drss++;
 		}
 	}
Index: station.h
===================================================================
--- station.h	(revision 762)
+++ station.h	(working copy)
@@ -82,4 +82,18 @@
 void GetProductionAroundTiles(uint *produced, uint tile, int w, int h);
 void GetAcceptanceAroundTiles(uint *accepts, uint tile, int w, int h);
 uint GetStationPlatforms(Station *st, uint tile);
+
+
+typedef struct DrawTileSeqStruct {
+	int8 delta_x;
+	int8 delta_y;
+	int8 delta_z;
+	byte width,height;
+	byte unk; // 'depth', just z-size; TODO: rename
+	SpriteID image;
+} DrawTileSeqStruct;
+
+void SetCustomStation(uint32 classid, DrawTileSeqStruct *data);
+DrawTileSeqStruct *GetCustomStation(uint32 classid);
+
 #endif /* STATION_H */
Index: grfspecial.c
===================================================================
--- grfspecial.c	(revision 762)
+++ grfspecial.c	(working copy)
@@ -6,6 +6,7 @@
 #include "gfx.h"
 #include "fileio.h"
 #include "engine.h"
+#include "station.h"
 
 /* TTDPatch extended GRF format codec
  * (c) Petr Baudis 2004 (GPL'd)
@@ -417,8 +418,148 @@
 	return ret;
 }
 
-#undef shift_buf
+static uint32 _statinfo_classid;
+static DrawTileSeqStruct _statinfo_renderdata[8];
 
+static int StationChangeInfo(uint stid, int numinfo, int prop, byte **bufp, int len)
+{
+	byte *buf = *bufp;
+	int i;
+	int ret = 0;
+
+	/* This is one single huge TODO. It doesn't handle more than just
+	 * waypoints for now. Well, _one_ waypoint - it doesn't support
+	 * multiple stations per one station class for now because there's
+	 * no code to support multiple ones anyway. */
+
+	switch (prop) {
+		case 0x08:
+		{	/* Class ID */
+			foreach_engine {
+				/* classid, for a change, is always little-endian */
+				_statinfo_classid = *(buf++) << 24;
+				_statinfo_classid |= *(buf++) << 16;
+				_statinfo_classid |= *(buf++) << 8;
+				_statinfo_classid |= *(buf++);
+			}
+			break;
+		}
+		case 0x09:
+		{	/* Define sprite layout */
+			/* XXX: This is also rather hackish. We ignore some stuff.
+			 * Also, we don't conform to the latest GRF specification
+			 * (we omit the num field, always assuming 8 tiles),
+			 * because current MB's newstats.grf doesn't neither. --pasky */
+			foreach_engine {
+				int t;
+				for (t = 0; t < 8; t++) {
+					DrawTileSeqStruct *sird = &_statinfo_renderdata[t];
+					uint32 groundsprite = grf_load_dword(&buf);
+
+					if (!groundsprite) {
+						static const DrawTileSeqStruct empty = {0};
+						*sird = empty;
+						continue;
+					}
+					while (buf < *bufp + len) {
+						byte xofs;
+						// no relative bounding box support
+						// no multiple sprites support for now
+
+						xofs = grf_load_byte(&buf);
+						if (xofs == 0x80) break;
+						sird->delta_x = xofs;
+						sird->delta_y = grf_load_byte(&buf);
+						sird->delta_z = grf_load_byte(&buf);
+						sird->width = grf_load_byte(&buf);
+						sird->height = grf_load_byte(&buf);
+						sird->unk = grf_load_byte(&buf);
+						sird->image = grf_load_dword(&buf) - 0x42d;
+					}
+				}
+			}
+			break;
+		}
+		case 0x0a:
+		{	/* Copy sprite layout */
+			/* TODO */
+			foreach_engine {
+				grf_load_byte(&buf);
+			}
+			ret = 1;
+			break;
+		}
+		case 0x0b:
+		{	/* Callback */
+			/* TODO */
+			foreach_engine {
+				grf_load_byte(&buf);
+			}
+			ret = 1;
+			break;
+		}
+		case 0x0c:
+		{	/* Platforms number */
+			/* TODO */
+			foreach_engine {
+				grf_load_byte(&buf);
+			}
+			ret = 1;
+			break;
+		}
+		case 0x0d:
+		{	/* Platforms length */
+			/* TODO */
+			foreach_engine {
+				grf_load_byte(&buf);
+			}
+			ret = 1;
+			break;
+		}
+		case 0x0e:
+		{	/* Define custom layout */
+			/* TODO */
+			foreach_engine {
+				while (buf < *bufp + len) {
+					byte length = grf_load_byte(&buf);
+					byte number = grf_load_byte(&buf);
+					int k = length * number;
+
+					if (!length && !number) break;
+					while (k--) grf_load_byte(&buf);
+				}
+			}
+			ret = 1;
+			break;
+		}
+		case 0x0f:
+		{	/* Copy custom layout */
+			/* TODO */
+			foreach_engine {
+				grf_load_byte(&buf);
+			}
+			ret = 1;
+			break;
+		}
+		case 0x10:
+		{	/* Little/lots cargo threshold */
+			/* TODO */
+			foreach_engine {
+				grf_load_word(&buf);
+			}
+			ret = 1;
+			break;
+		}
+		default:
+			ret = 1;
+			break;
+	}
+
+	*bufp = buf;
+	return ret;
+}
+
+
 static void VehicleChangeInfo(byte *buf, int len)
 {
 	byte *bufend = buf + len;
@@ -442,7 +583,7 @@
 		NULL,
 		ShipVehicleChangeInfo,
 		NULL,
-		NULL,
+		StationChangeInfo,
 	};
 
 	if (len > 5) {
@@ -452,18 +593,23 @@
 		byte engine = buf[4];
 		EngineInfo *ei;
 
-		if (feature != 0 && feature != 2) {
+		buf += 5;
+
+		if (feature != 0 && feature != 2 && feature != 4) {
 			grfmsg(GMS_WARN, "VehicleChangeInfo: Unsupported vehicle type %x, skipping.", feature);
 			return;
 		}
 
-		ei = &_engine_info[engine + _vehshifts[feature]];
+		if (feature != 4)
+			ei = &_engine_info[engine + _vehshifts[feature]];
 
-		buf += 5;
-
 		while (numprops-- && buf < bufend) {
 			uint8 prop = grf_load_byte(&buf);
 
+			if (feature == 4)
+				// stations don't share those common properties
+				goto run_handler;
+
 			switch (prop) {
 			case 0x00: {	
 				/* Introduction date */
@@ -526,6 +672,7 @@
 			}
 			default:
 			{
+run_handler:
 				if (handler[feature](engine, numinfo, prop, &buf, bufend - buf)) {
 ignoring:
 					grfmsg(GMS_WARN, "VehicleChangeInfo: Ignoring property %x.", prop);
@@ -535,7 +682,6 @@
 			}
 		}
 	}
-#undef shift_buf
 }
 
 
@@ -577,12 +723,6 @@
 	if (len == 4) {
 		uint8 feature = buf[1];
 
-		if (feature == 4) {
-			_spriteset_start = 0;
-			grfmsg(GMS_WARN, "SpriteNewSet: Stations unsupported, skipping.");
-			return;
-		}
-
 		_spriteset_start = _cur_spriteid + 1;
 		_spriteset_numsets = buf[2];
 		_spriteset_numents = buf[3];
@@ -604,32 +744,23 @@
 	 *                 otherwise it specifies a number of entries, the exact
 	 *                 meaning depends on the feature
 	 * V feature-specific-data (huge mess, don't even look it up --pasky) */
-	/* TODO: Only trains supported now. No 0x80-types (ugh). */
+	/* TODO: No 0x80-types (ugh). */
 	/* TODO: Also, empty sprites aren't handled for now. Need to investigate
 	 * the "opacity" rules for these, that is which sprite to fall back to
-	 * when. --pasky */
+	 * when. And dunno if the lack of support for those actually hurts.
+	 * --pasky */
 
 	if (bufend - buf > 4) {
 		uint8 feature = buf[1];
 		uint8 setid = buf[2];
+		/* XXX: For cargo these two are "little cargo" and "lotsa cargo" sets. */
 		uint8 numloaded = buf[3];
 		uint8 numloading = buf[4];
 		struct SpriteSuperSet *superset;
 		int i;
 
-		if (feature == 4) {
-			grfmsg(GMS_WARN, "SpriteNewSuperset: Stations unsupported, skipping.");
-			return;
-		}
-
 		if (numloaded == 0x81) {
-			// XXX: This is _VERY_ ad hoc just to handle Dm3. And that is
-			// a semi-futile ask because the great Patchman himself says
-			// this is just buggy. It dereferences last (first) byte of
-			// a schedule list pointer of the vehicle and if it's 0xff
-			// it uses superset 01, otherwise it uses superset 00. Now
-			// if _you_ understand _that_... We just assume it is never
-			// 0xff and therefore go for superset 00. --pasky
+			// XXX: This just goes for the default superset for now. --pasky
 			uint8 var = buf[4];
 			//uint8 shiftnum = buf[5];
 			//uint8 andmask = buf[6];
@@ -641,13 +772,13 @@
 
 			//val = (0xff << shiftnum) & andmask;
 
-			//Go for the default.
 			if (setid >= _spritesset_count) {
 				_spritesset_count = setid + 1;
 				_spritesset = realloc(_spritesset, _spritesset_count * sizeof(struct SpriteSuperSet));
 			}
 			buf += 8 + nvar * 4;
 			def = grf_load_word(&buf);
+			printf("Cloning %x (%x) -> %x\n", def, _spritesset[def].loading[0], setid);
 			_spritesset[setid] = _spritesset[def];
 			return;
 
@@ -662,8 +793,8 @@
 		}
 
 		if (_spriteset_feature != feature) {
-			grfmsg(GMS_WARN, "SpriteNewSuperset: Superset feature %x doesn't match set feature %x! Skipping.", feature, _spriteset_feature);
-			return;
+			grfmsg(GMS_WARN, "SpriteNewSuperset: Superset feature %x doesn't match set feature %x! Trying to use it anyway.", feature, _spriteset_feature);
+			//return; - we can't because of MB's newstats.grf
 		}
 
 		if (setid >= _spritesset_count) {
@@ -728,7 +859,34 @@
 		int c, i;
 
 		if (feature == 4) {
-			grfmsg(GMS_WARN, "VehicleMapSpriteSuperset: Stations unsupported, skipping.");
+			// We do things differently.
+			// Currently we don't support cargo-specific images, so
+			// we go straight to the defaults.
+			byte *bp = buf + 4 + idcount + cidcount * 3;
+			uint16 supersetid = grf_load_word(&bp);
+
+			if (!_statinfo_classid) {
+				/* Someone already used this statinfo out. */
+				return;
+			}
+
+			for (i = 0; i < idcount; i++) {
+				//uint8 statid = buf[3 + i];
+				int j;
+
+				if (supersetid >= _spritesset_count) {
+					grfmsg(GMS_WARN, "VehicleMapSpriteSuperset: Spriteset %x out of range %x, skipping.", supersetid, _spritesset_count);
+					return;
+				}
+
+				for (j = 0; j < 8; j++) {
+					printf("ss %d, j %d, %x + %x\n", supersetid, j, _statinfo_renderdata[j].image, _spritesset[supersetid].loading[0]);
+					// XXX: This is just ad hoc for a single waypoint.
+					_statinfo_renderdata[j].image += _spritesset[supersetid].loading[0];
+				}
+				SetCustomStation(_statinfo_classid, _statinfo_renderdata);
+				_statinfo_classid = 0;
+			}
 			return;
 		}
 
@@ -812,6 +970,7 @@
 	 * (completely new scenarios changing all graphics and logically also
 	 * factory names etc). We should then also support all languages (by
 	 * name), not only the original four ones. --pasky */
+	/* TODO: Support for custom station class/type names. */
 
 	if (len > 5) {
 		uint8 feature = buf[1];
Index: unmovable_cmd.c
===================================================================
--- unmovable_cmd.c	(revision 762)
+++ unmovable_cmd.c	(working copy)
@@ -4,6 +4,7 @@
 #include "viewport.h"
 #include "player.h"
 #include "gui.h"
+#include "station.h"
 
 typedef struct DrawTileUnmovableStruct {
 	uint16 image;
@@ -15,15 +16,6 @@
 	byte unused;
 } DrawTileUnmovableStruct;
 
-typedef struct DrawTileSeqStruct {
-	int8 delta_x;
-	int8 delta_y;
-	int8 delta_z;
-	byte width,height;
-	byte unk;
-	SpriteID image;
-} DrawTileSeqStruct;
-
 #include "table/unmovable_land.h"
 
 static void DrawTile_Unmovable(TileInfo *ti)
