(svn r659) Support for cutomized TTDPatch-style new stations (no selector GUI yet) (pasky)
authortron
Wed, 17 Nov 2004 18:03:33 +0000
changeset 449 2856e9ce0754
parent 448 159349b42f8f
child 450 a74d2f607217
(svn r659) Support for cutomized TTDPatch-style new stations (no selector GUI yet) (pasky)
docs/landscape.html
grfspecial.c
rail_gui.c
station.h
station_cmd.c
--- a/docs/landscape.html	Wed Nov 17 17:15:36 2004 +0000
+++ b/docs/landscape.html	Wed Nov 17 18:03:33 2004 +0000
@@ -370,6 +370,8 @@
 <li>map_owner: <a href="#OwnershipInfo">owner</a> of the station</li>
 <li>map2: index into the <a href="#_StationArray">array of stations</a></li>
 <li>map3_lo bits 0..3: <a href="#TrackType">track type</a> for railway stations, must be 0 for all the other stations</li>
+<li>map3_lo bit 4 = use custom sprite (valid only railway stations FOR NOW)</li>
+<li>map3_hi = custom station id</li>
 </ul>
 </td></tr>
 
--- a/grfspecial.c	Wed Nov 17 17:15:36 2004 +0000
+++ b/grfspecial.c	Wed Nov 17 18:03:33 2004 +0000
@@ -702,11 +702,6 @@
 	/* This is one single huge TODO. It doesn't handle anything more than
 	 * just waypoints for now. */
 
-	/* TODO: Differentiate between railtypes. This is missing in the new
-	 * GRF file specification yet, though, so I need to agree on this with
-	 * patchman yet. We just assume all the station stuff is for railtype 0
-	 * (railroad) for now. --pasky */
-
 	//printf("sci %d %d [0x%02x]\n", stid, numinfo, prop);
 	switch (prop) {
 		case 0x08:
@@ -729,7 +724,12 @@
 						stat->sclass = STAT_CLASS_WAYP;
 						break;
 					default:
-						stat->sclass = STAT_CLASS_CUSTOM;
+						/* TODO: No support for custom
+						 * classes for now, so stuff
+						 * everything to the single
+						 * default one. --pasky */
+						stat->sclass = STAT_CLASS_DFLT;
+						//stat->sclass = STAT_CLASS_CUSTOM;
 						break;
 				}
 			}
@@ -826,38 +826,72 @@
 			ret = 1;
 			break;
 		}
-		case 0x0c:
+		case 0x0C:
 		{	/* Platforms number */
-			/* TODO */
 			FOR_EACH_OBJECT {
-				grf_load_byte(&buf);
+				struct StationSpec *stat = &_cur_grffile->stations[stid + i];
+
+				stat->allowed_platforms = ~grf_load_byte(&buf);
 			}
-			ret = 1;
 			break;
 		}
-		case 0x0d:
+		case 0x0D:
 		{	/* Platforms length */
-			/* TODO */
 			FOR_EACH_OBJECT {
-				grf_load_byte(&buf);
+				struct StationSpec *stat = &_cur_grffile->stations[stid + i];
+
+				stat->allowed_lengths = ~grf_load_byte(&buf);
 			}
-			ret = 1;
 			break;
 		}
 		case 0x0e:
 		{	/* Define custom layout */
-			/* TODO */
 			FOR_EACH_OBJECT {
+				struct StationSpec *stat = &_cur_grffile->stations[stid + i];
+
 				while (buf < *bufp + len) {
 					byte length = grf_load_byte(&buf);
 					byte number = grf_load_byte(&buf);
-					int k = length * number;
+					StationLayout layout;
+					int l, p;
 
-					if (!length && !number) break;
-					while (k--) grf_load_byte(&buf);
+					if (length == 0 || number == 0) break;
+
+					//debug("l %d > %d ?", length, stat->lengths);
+					if (length > stat->lengths) {
+						stat->platforms = realloc(stat->platforms, length);
+						memset(stat->platforms + stat->lengths, 0, length - stat->lengths);
+
+						stat->layouts = realloc(stat->layouts, length * sizeof(*stat->layouts));
+						memset(stat->layouts + stat->lengths, 0,
+						       (length - stat->lengths) * sizeof(*stat->layouts));
+
+						stat->lengths = length;
+					}
+					l = length - 1; // index is zero-based
+
+					//debug("p %d > %d ?", number, stat->platforms[l]);
+					if (number > stat->platforms[l]) {
+						stat->layouts[l] = realloc(stat->layouts[l],
+						                               number * sizeof(**stat->layouts));
+						// We expect NULL being 0 here, but C99 guarantees that.
+						memset(stat->layouts[l] + stat->platforms[l], 0,
+						       (number - stat->platforms[l]) * sizeof(**stat->layouts));
+
+						stat->platforms[l] = number;
+					}
+
+					layout = malloc(length * number);
+					for (l = 0; l < length; l++)
+						for (p = 0; p < number; p++)
+							layout[l * number + p] = grf_load_byte(&buf);
+
+					l--;
+					p--;
+					free(stat->layouts[l][p]);
+					stat->layouts[l][p] = layout;
 				}
 			}
-			ret = 1;
 			break;
 		}
 		case 0x0f:
--- a/rail_gui.c	Wed Nov 17 17:15:36 2004 +0000
+++ b/rail_gui.c	Wed Nov 17 18:03:33 2004 +0000
@@ -140,7 +140,9 @@
 		VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED);
 		VpSetPlaceSizingLimit(_patches.station_spread);
 	} else {
-		DoCommandP(tile, _railstation.orientation | (_railstation.numtracks<<8) | (_railstation.platlength<<16),_cur_railtype, CcStation,
+		// TODO: Custom station selector GUI. Now we just try using first custom station
+		// (and fall back to normal stations if it isn't available).
+		DoCommandP(tile, _railstation.orientation | (_railstation.numtracks<<8) | (_railstation.platlength<<16),_cur_railtype|1<<4, CcStation,
 				CMD_BUILD_RAILROAD_STATION | CMD_NO_WATER | CMD_AUTO | CMD_MSG(STR_100F_CAN_T_BUILD_RAILROAD_STATION));
 	}
 }
@@ -822,6 +824,9 @@
 	if (w != NULL && button >= 0) _build_railroad_button_proc[button](w);
 }
 
+/* TODO: For custom stations, respect their allowed platforms/lengths bitmasks!
+ * --pasky */
+
 static void HandleStationPlacement(uint start, uint end)
 {
 	uint sx = GET_TILE_X(start);
@@ -836,7 +841,9 @@
 	h = ey - sy + 1;
 	if (!_railstation.orientation) intswap(w,h);
 
-	DoCommandP(TILE_XY(sx,sy), _railstation.orientation | (w<<8) | (h<<16),_cur_railtype, CcStation,
+	// TODO: Custom station selector GUI. Now we just try using first custom station
+	// (and fall back to normal stations if it isn't available).
+	DoCommandP(TILE_XY(sx,sy), _railstation.orientation | (w<<8) | (h<<16),_cur_railtype|1<<4, CcStation,
 		CMD_BUILD_RAILROAD_STATION | CMD_NO_WATER | CMD_AUTO | CMD_MSG(STR_100F_CAN_T_BUILD_RAILROAD_STATION));
 }
 
--- a/station.h	Wed Nov 17 17:15:36 2004 +0000
+++ b/station.h	Wed Nov 17 18:03:33 2004 +0000
@@ -93,6 +93,10 @@
 uint GetStationPlatforms(Station *st, uint tile);
 
 
+/* Station layout for given dimensions - it is a two-dimensional array
+ * where index is computed as (x * platforms) + platform. */
+typedef byte *StationLayout;
+
 struct StationSpec {
 	uint32 grfid;
 	int localidx; // per-GRFFile station index + 1; SetCustomStation() takes care of this
@@ -110,9 +114,41 @@
 		STAT_CLASS_CUSTOM, // some custom class
 	} sclass;
 
+	/* Bitmask of platform numbers/lengths available for the station.  Bits
+	 * 0..6 correspond to 1..7, while bit 7 corresponds to >7 platforms or
+	 * lenght. */
+	byte allowed_platforms;
+	byte allowed_lengths;
+
+	/* Custom sprites */
 	byte tiles;
+	/* 00 = plain platform
+	 * 02 = platform with building
+	 * 04 = platform with roof, left side
+	 * 06 = platform with roof, right side
+	 *
+	 * These numbers are used for stations in NE-SW direction, or these
+	 * numbers plus one for stations in the NW-SE direction.  */
 	DrawTileSprites renderdata[8];
 
+	/* Custom layouts */
+	/* The layout array is organized like [lenghts][platforms], both being
+	 * dynamic arrays, the field itself is length*platforms array containing
+	 * indexes to @renderdata (only even numbers allowed) for the given
+	 * station tile. */
+	/* @lengths is length of the @platforms and @layouts arrays, that is
+	 * number of maximal length for which the layout is defined (since
+	 * arrays are indexed from 0, the length itself is at [length - 1]). */
+	byte lengths;
+	/* @platforms is array of number of platforms defined for each length.
+	 * Zero means no platforms defined. */
+	byte *platforms;
+	/* @layout is @layouts-sized array of @platforms-sized arrays,
+	 * containing pointers to length*platforms-sized arrays or NULL if
+	 * default OTTD station layout should be used for stations of these
+	 * dimensions. */
+	StationLayout **layouts;
+
 	/* Sprite offsets for renderdata->seq->image. spritegroup[0] is default
 	 * whilst spritegroup[1] is "CID_PURCHASE". */
 	struct SpriteGroup spritegroup[2];
--- a/station_cmd.c	Wed Nov 17 17:15:36 2004 +0000
+++ b/station_cmd.c	Wed Nov 17 18:03:33 2004 +0000
@@ -700,8 +700,16 @@
 }
 
 // stolen from TTDPatch
-static void GetStationLayout(byte *layout, int numtracks, int plat_len)
+static void GetStationLayout(byte *layout, int numtracks, int plat_len, struct StationSpec *spec)
 {
+	if (spec != NULL && spec->lengths >= plat_len && spec->platforms[plat_len - 1] >= numtracks
+	    && spec->layouts[plat_len - 1][numtracks - 1]) {
+		/* Custom layout defined, follow it. */
+		memcpy(layout, spec->layouts[plat_len - 1][numtracks - 1],
+		       plat_len * numtracks);
+		return;
+	}
+
 	if (plat_len == 1) {
 		CreateSingle(layout, numtracks);
 	} else {
@@ -720,7 +728,9 @@
  * p1 & 1 - orientation
  * (p1 >> 8) & 0xFF - numtracks
  * (p1 >> 16) & 0xFF - platform length
- * p2  - railtype
+ * p2 & 0xF  - railtype
+ * p2 & 0x10 - set for custom station
+ * p2 >> 8   - custom station id
  */
 
 int32 CmdBuildRailroadStation(int x_org, int y_org, uint32 flags, uint32 p1, uint32 p2)
@@ -815,6 +825,7 @@
 		int tile_delta;
 		byte *layout_ptr;
 		uint station_index = st->index;
+		struct StationSpec *statspec;
 
 		// Now really clear the land below the station
 		// It should never return CMD_ERROR.. but you never know ;)
@@ -833,8 +844,9 @@
 
 		tile_delta = direction ? TILE_XY(0,1) : TILE_XY(1,0);
 
+		statspec = (p2 & 0x10) != 0 ? GetCustomStation(STAT_CLASS_DFLT, p2 >> 8) : NULL;
 		layout_ptr = alloca(numtracks * plat_len);
-		GetStationLayout(layout_ptr, numtracks, plat_len);
+		GetStationLayout(layout_ptr, numtracks, plat_len, statspec);
 
 		do {
 			int tile = tile_org;
@@ -843,9 +855,10 @@
 
 				ModifyTile(tile,
 					MP_SETTYPE(MP_STATION) | MP_MAPOWNER_CURRENT |
-					MP_MAP2 | MP_MAP5 | MP_MAP3LO | MP_MAP3HI_CLEAR,
+					MP_MAP2 | MP_MAP5 | MP_MAP3LO | MP_MAP3HI,
 					station_index, /* map2 parameter */
-					p2,				/* map3lo parameter */
+					p2 & 0xFF,     /* map3lo parameter */
+					p2 >> 8,       /* map3hi parameter */
 					(*layout_ptr++) + direction   /* map5 parameter */
 				);
 
@@ -958,24 +971,26 @@
 }
 
 
-/* TODO: Multiple classes! */
-
-static int _waypoint_highest_id = -1;
-static struct StationSpec _waypoint_data[256];
+/* TODO: Custom classes! */
+/* Indexed by class, just STAT_CLASS_DFLT and STAT_CLASS_WAYP supported. */
+static int _statspec_highest_id[2] = {-1, -1};
+static struct StationSpec _station_spec[2][256];
 
 void SetCustomStation(byte local_stid, struct StationSpec *spec)
 {
+	enum StationClass sclass;
 	int stid = -1;
 
-	assert(spec->sclass == STAT_CLASS_WAYP);
+	assert(spec->sclass == STAT_CLASS_DFLT || spec->sclass == STAT_CLASS_WAYP);
+	sclass = spec->sclass - 1;
 
 	if (spec->localidx != 0) {
 		/* Already allocated, try to resolve to global stid */
 		int i;
 
-		for (i = 0; i <= _waypoint_highest_id; i++) {
-			if (_waypoint_data[i].grfid == spec->grfid
-			    && _waypoint_data[i].localidx == local_stid + 1) {
+		for (i = 0; i <= _statspec_highest_id[sclass]; i++) {
+			if (_station_spec[sclass][i].grfid == spec->grfid
+			    && _station_spec[sclass][i].localidx == local_stid + 1) {
 				stid = i;
 				/* FIXME: Release original SpriteGroup to
 				 * prevent leaks. But first we need to
@@ -987,23 +1002,26 @@
 
 	if (stid == -1) {
 		/* Allocate new one. */
-		if (_waypoint_highest_id >= 255) {
+		if (_statspec_highest_id[sclass] >= 255) {
 			error("Too many custom stations allocated.");
 			return;
 		}
-		stid = ++_waypoint_highest_id;
+		stid = ++_statspec_highest_id[sclass];
 		spec->localidx = local_stid + 1;
 	}
 
-	memcpy(&_waypoint_data[stid], spec, sizeof(*spec));
+	//debug("Registering station #%d of class %d", stid, sclass);
+	memcpy(&_station_spec[sclass][stid], spec, sizeof(*spec));
 }
 
 struct StationSpec *GetCustomStation(enum StationClass sclass, byte stid)
 {
-	assert(sclass == STAT_CLASS_WAYP);
-	if (stid > _waypoint_highest_id)
+	assert(sclass == STAT_CLASS_DFLT || sclass == STAT_CLASS_WAYP);
+	sclass--;
+	//debug("Asking for station #%d of class %d", stid, sclass);
+	if (stid > _statspec_highest_id[sclass])
 		return NULL;
-	return &_waypoint_data[stid];
+	return &_station_spec[sclass][stid];
 }
 
 static struct RealSpriteGroup *
@@ -1092,8 +1110,6 @@
 {
 	struct RealSpriteGroup *rsg;
 
-	assert(spec->sclass == STAT_CLASS_WAYP);
-
 	rsg = ResolveStationSpriteGroup(&spec->spritegroup[ctype], stat);
 
 	if (rsg->sprites_per_set != 0) {
@@ -1114,8 +1130,9 @@
 
 int GetCustomStationsCount(enum StationClass sclass)
 {
-	assert(sclass == STAT_CLASS_WAYP);
-	return _waypoint_highest_id + 1;
+	assert(sclass == STAT_CLASS_DFLT || sclass == STAT_CLASS_WAYP);
+	sclass--;
+	return _statspec_highest_id[sclass] + 1;
 }
 
 
@@ -1879,17 +1896,16 @@
 #include "table/station_land.h"
 
 
+extern uint16 _custom_sprites_base;
 
 static void DrawTile_Station(TileInfo *ti)
 {
 	uint32 image_or_modificator;
-	uint32 base_img, image;
+	uint32 image;
 	const DrawTileSeqStruct *dtss;
-	const DrawTileSprites *t;
-
-	// station_land array has been increased from 82 elements to 114
-	// but this is something else. If AI builds station with 114 it looks all weird
-	base_img = (_map3_lo[ti->tile] & 0xF) * 82;
+	const DrawTileSprites *t = NULL;
+	byte railtype = _map3_lo[ti->tile] & 0xF;
+	uint32 relocation = 0;
 
 	{
 		uint owner = _map_owner[ti->tile];
@@ -1902,15 +1918,36 @@
 	if (ti->tileh != 0 && (ti->map5 < 0x4C || ti->map5 > 0x51))
 		DrawFoundation(ti, ti->tileh);
 
-	t = &_station_display_datas[ti->map5];
+	if (_map3_lo[ti->tile] & 0x10) {
+		// look for customization
+		struct StationSpec *statspec = GetCustomStation(STAT_CLASS_DFLT, _map3_hi[ti->tile]);
+
+		//debug("Cust-o-mized %p", statspec);
+
+		if (statspec != NULL) {
+			Station *st = DEREF_STATION(_map2[ti->tile]);
+
+			relocation = GetCustomStationRelocation(statspec, st, 0);
+			//debug("Relocation %d", relocation);
+			t = &statspec->renderdata[ti->map5];
+		}
+	}
+
+	if (t == NULL) t = &_station_display_datas[ti->map5];
 
 	image = t->ground_sprite;
 	if (image & 0x8000)
 		image |= image_or_modificator;
-	DrawGroundSprite(image + base_img);
+
+	// station_land array has been increased from 82 elements to 114
+	// but this is something else. If AI builds station with 114 it looks all weird
+	image += railtype * ((image < _custom_sprites_base) ? TRACKTYPE_SPRITE_PITCH : 1);
+	DrawGroundSprite(image);
 
 	foreach_draw_tile_seq(dtss, t->seq) {
-		image =	dtss->image + base_img;
+		image =	dtss->image + relocation;
+		// XXX: Do we want to do this for custom stations? --pasky
+		image += railtype * ((image < _custom_sprites_base) ? TRACKTYPE_SPRITE_PITCH : 1);
 		if (_display_opt & DO_TRANS_BUILDINGS) {
 			if (image&0x8000) image |= image_or_modificator;	
 		} else {