Changeset - r389:1542bc0da3c8
[Not reviewed]
master
0 7 0
celestar - 20 years ago 2004-11-14 09:07:15
celestar@openttd.org
(svn r581) -newgrf: Basic support for new stations - only waypoints supported now and only
the first custom one can be placed (no selector GUI, coming soon). This
also moves some global variables to {struct GRFFile} and reorders which
actions are processed in what stage, to get it all working together --
(pasky)
7 files changed with 383 insertions and 98 deletions:
0 comments (0 inline, 0 general)
docs/landscape.html
Show inline comments
 
@@ -135,6 +135,8 @@ map5 bits 7 and 6 set: railway depot / c
 
<br>
 
<li>map_owner: <a href="#OwnershipInfo">owner</a> of the depot / checkpoint</li>
 
<li>map3_lo bits 0..3 = <a href="#TrackType">track type</a></li>
 
<li>map3_lo bit 4 = use custom sprite (valid only for the checkpoint)</li>
 
<li>map3_hi = custom station id</li>
 
</ul>
 
</td></tr>
 
engine.h
Show inline comments
 
@@ -84,8 +84,14 @@ struct SpriteGroup {
 
	// 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 group 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 da stuff.
 

	
 
	byte loaded_count;
 
	uint16 loaded[16]; // sprite ids
 
	byte loading_count;
grfspecial.c
Show inline comments
 
@@ -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)
 
@@ -26,6 +27,29 @@ struct GRFFile {
 
	uint16 flags;
 
	uint16 sprite_offset;
 
	struct GRFFile *next;
 

	
 
	/* A sprite group contains all sprites of a given vehicle (or multiple
 
	 * vehicles) when carrying given cargo. It consists of several sprite
 
	 * sets.  Group ids are refered as "cargo id"s by TTDPatch
 
	 * documentation, contributing to the global confusion.
 
	 *
 
	 * A sprite set contains all sprites of a given vehicle carrying given
 
	 * cargo at a given *stage* - that is usually its load stage. Ie. you
 
	 * can have a spriteset for an empty wagon, wagon full of coal,
 
	 * half-filled wagon etc.  Each spriteset contains eight sprites (one
 
	 * per direction) or four sprites if the vehicle is symmetric. */
 

	
 
	int spriteset_start;
 
	int spriteset_numsets;
 
	int spriteset_numents;
 
	int spriteset_feature;
 

	
 
	int spritesset_count;
 
	struct SpriteGroup *spritesset;
 

	
 
	uint32 statinfo_classid[256];
 
	byte statinfo_tiles[256];
 
	DrawTileSprites statinfo_renderdata[256][8];
 
};
 

	
 
static struct GRFFile *_cur_grffile, *_first_grffile;
 
@@ -664,8 +688,178 @@ static bool AircraftVehicleChangeInfo(ui
 
	return ret;
 
}
 

	
 
static bool 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 anything more than
 
	 * just waypoints for now. */
 

	
 
	//printf("sci %d %d [0x%02x]\n", stid, numinfo, prop);
 
	switch (prop) {
 
		case 0x08:
 
		{	/* Class ID */
 
			FOR_EACH_ENGINE {
 
				/* classid, for a change, is always little-endian */
 
				_cur_grffile->statinfo_classid[stid+i] = *(buf++) << 24;
 
				_cur_grffile->statinfo_classid[stid+i] |= *(buf++) << 16;
 
				_cur_grffile->statinfo_classid[stid+i] |= *(buf++) << 8;
 
				_cur_grffile->statinfo_classid[stid+i] |= *(buf++);
 
			}
 
			break;
 
		}
 
		case 0x09:
 
		{	/* Define sprite layout */
 
			FOR_EACH_ENGINE {
 
				int t;
 
				_cur_grffile->statinfo_tiles[stid+i] = grf_load_byte(&buf);
 
				for (t = 0; t < _cur_grffile->statinfo_tiles[stid+i]; t++) {
 
					DrawTileSprites *dts = &_cur_grffile->statinfo_renderdata[stid+i][t];
 
					int seq_count = 0;
 

	
 
					if (t >= 8) {
 
						grfmsg(GMS_WARN, "StationChangeInfo: Sprite %d>=8, skipping.", t);
 
						grf_load_dword(&buf); // at least something
 
						continue;
 
					}
 

	
 
					dts->ground_sprite = grf_load_dword(&buf);
 
					if (!dts->ground_sprite) {
 
						static const DrawTileSeqStruct empty = {0x80};
 
						dts->seq = &empty;
 
						continue;
 
					}
 

	
 
					dts->seq = NULL;
 
					while (buf < *bufp + len) {
 
						DrawTileSeqStruct *dtss;
 

	
 
						// no relative bounding box support
 
						dts->seq = realloc((void*)dts->seq, ++seq_count * sizeof(DrawTileSeqStruct));
 
						dtss = (DrawTileSeqStruct*) &dts->seq[seq_count - 1];
 

	
 
						dtss->delta_x = grf_load_byte(&buf);
 
						if ((byte) dtss->delta_x == 0x80) break;
 
						dtss->delta_y = grf_load_byte(&buf);
 
						dtss->delta_z = grf_load_byte(&buf);
 
						dtss->width = grf_load_byte(&buf);
 
						dtss->height = grf_load_byte(&buf);
 
						dtss->unk = grf_load_byte(&buf);
 
						dtss->image = grf_load_dword(&buf) - 0x42d;
 
					}
 
				}
 
			}
 
			break;
 
		}
 
		case 0x0a:
 
		{	/* Copy sprite layout */
 
			FOR_EACH_ENGINE {
 
				byte src = grf_load_byte(&buf);
 
				int t;
 
				_cur_grffile->statinfo_tiles[stid+i] = _cur_grffile->statinfo_tiles[src];
 
				for (t = 0; t < _cur_grffile->statinfo_tiles[stid+i]; t++) {
 
					DrawTileSprites *dts = &_cur_grffile->statinfo_renderdata[stid+i][t];
 
					DrawTileSprites *sdts = &_cur_grffile->statinfo_renderdata[src][t];
 
					DrawTileSeqStruct const *sdtss = sdts->seq;
 
					int seq_count = 0;
 

	
 
					dts->ground_sprite = sdts->ground_sprite;
 
					if (!dts->ground_sprite) {
 
						static const DrawTileSeqStruct empty = {0x80};
 
						dts->seq = &empty;
 
						continue;
 
					}
 

	
 
					dts->seq = NULL;
 
					while (1) {
 
						DrawTileSeqStruct *dtss;
 

	
 
						// no relative bounding box support
 
						dts->seq = realloc((void*)dts->seq, ++seq_count * sizeof(DrawTileSeqStruct));
 
						dtss = (DrawTileSeqStruct*) &dts->seq[seq_count - 1];
 
						*dtss = *sdtss;
 
						if ((byte) dtss->delta_x == 0x80) break;
 
						sdtss++;
 
					}
 
				}
 
			}
 
			break;
 
		}
 
		case 0x0b:
 
		{	/* Callback */
 
			/* TODO */
 
			FOR_EACH_ENGINE {
 
				grf_load_byte(&buf);
 
			}
 
			ret = 1;
 
			break;
 
		}
 
		case 0x0c:
 
		{	/* Platforms number */
 
			/* TODO */
 
			FOR_EACH_ENGINE {
 
				grf_load_byte(&buf);
 
			}
 
			ret = 1;
 
			break;
 
		}
 
		case 0x0d:
 
		{	/* Platforms length */
 
			/* TODO */
 
			FOR_EACH_ENGINE {
 
				grf_load_byte(&buf);
 
			}
 
			ret = 1;
 
			break;
 
		}
 
		case 0x0e:
 
		{	/* Define custom layout */
 
			/* TODO */
 
			FOR_EACH_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 */
 
			FOR_EACH_ENGINE {
 
				grf_load_byte(&buf);
 
			}
 
			ret = 1;
 
			break;
 
		}
 
		case 0x10:
 
		{	/* Little/lots cargo threshold */
 
			/* TODO */
 
			FOR_EACH_ENGINE {
 
				grf_load_word(&buf);
 
			}
 
			ret = 1;
 
			break;
 
		}
 
		default:
 
			ret = 1;
 
			break;
 
	}
 

	
 
	*bufp = buf;
 
	return ret;
 
}
 

	
 
#undef shift_buf
 

	
 

	
 
/* Action 0x00 */
 
static void VehicleChangeInfo(byte *buf, int len)
 
{
 
@@ -690,7 +884,7 @@ static void VehicleChangeInfo(byte *buf,
 
		/* GSF_ROAD */     RoadVehicleChangeInfo,
 
		/* GSF_SHIP */     ShipVehicleChangeInfo,
 
		/* GSF_AIRCRAFT */ AircraftVehicleChangeInfo,
 
		/* GSF_STATION */  NULL,
 
		/* GSF_STATION */  StationChangeInfo,
 
	};
 

	
 
	uint8 feature;
 
@@ -708,18 +902,18 @@ static void VehicleChangeInfo(byte *buf,
 
	DEBUG(grf, 6) ("VehicleChangeInfo: Feature %d, %d properties, to apply to %d+%d",
 
	               feature, numprops, engine, numinfo);
 

	
 
	if (feature == GSF_STATION) {
 
		grfmsg(GMS_WARN, "VehicleChangeInfo: Stations unsupported, skipping.");
 
		return;
 
	}
 

	
 
	ei = &_engine_info[engine + _vehshifts[feature]];
 
	if (feature != GSF_STATION)
 
		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 */
 
			FOR_EACH_ENGINE {
 
@@ -771,6 +965,7 @@ static void VehicleChangeInfo(byte *buf,
 
			goto ignoring;
 
		}
 
		default: {
 
run_handler:
 
			if (handler[feature](engine, numinfo, prop, &buf, bufend - buf)) {
 
ignoring:
 
				grfmsg(GMS_NOTICE, "VehicleChangeInfo: Ignoring property %x (not implemented).", prop);
 
@@ -783,25 +978,6 @@ ignoring:
 
}
 

	
 

	
 
/* A sprite group contains all sprites of a given vehicle (or multiple
 
 * vehicles) when carrying given cargo. It consists of several sprite sets.
 
 * Group ids are refered as "cargo id"s by TTDPatch documentation,
 
 * contributing to the global confusion.
 
 *
 
 * A sprite set contains all sprites of a given vehicle carrying given cargo at
 
 * a given *stage* - that is usually its load stage. Ie. you can have a
 
 * spriteset for an empty wagon, wagon full of coal, half-filled wagon etc.
 
 * Each spriteset contains eight sprites (one per direction) or four sprites if
 
 * the vehicle is symmetric. */
 

	
 
static int _spriteset_start;
 
static int _spriteset_numsets;
 
static int _spriteset_numents;
 
static int _spriteset_feature;
 

	
 
static int _spritesset_count;
 
static struct SpriteGroup *_spritesset;
 

	
 
/* Action 0x01 */
 
static void NewSpriteSet(byte *buf, int len)
 
{
 
@@ -823,16 +999,10 @@ static void NewSpriteSet(byte *buf, int 
 
	check_length(len, 4, "NewSpriteSet");
 
	feature = buf[1];
 

	
 
	if (feature == GSF_STATION) {
 
		_spriteset_start = 0;
 
		grfmsg(GMS_WARN, "NewSpriteSet: Stations unsupported, skipping.");
 
		return;
 
	}
 

	
 
	_spriteset_start = _cur_spriteid + 1;
 
	_spriteset_feature = feature;
 
	_spriteset_numsets = buf[2];
 
	_spriteset_numents = buf[3];
 
	_cur_grffile->spriteset_start = _cur_spriteid + 1;
 
	_cur_grffile->spriteset_feature = feature;
 
	_cur_grffile->spriteset_numsets = buf[2];
 
	_cur_grffile->spriteset_numents = buf[3];
 
}
 

	
 
/* Action 0x02 */
 
@@ -850,12 +1020,13 @@ static void NewSpriteGroup(byte *buf, in
 
	 *                 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 */
 
	uint8 feature;
 
	uint8 setid;
 
	/* XXX: For stations, these two are "little cargo" and "lotsa cargo" sets. */
 
	uint8 numloaded;
 
	uint8 numloading;
 
	struct SpriteGroup *group;
 
@@ -869,19 +1040,9 @@ static void NewSpriteGroup(byte *buf, in
 
	numloaded = buf[3];
 
	numloading = buf[4];
 

	
 
	if (feature == GSF_STATION) {
 
		grfmsg(GMS_WARN, "NewSpriteGroup: 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 group 01, otherwise it uses group 00. Now
 
		// if _you_ understand _that_... We just assume it is never
 
		// 0xff and therefore go for group 00. --pasky
 
		/* XXX: This just goes for the default superset for now,
 
		 * straight and safe. --pasky */
 
		uint8 var = buf[4];
 
		//uint8 shiftnum = buf[5];
 
		//uint8 andmask = buf[6];
 
@@ -893,14 +1054,13 @@ static void NewSpriteGroup(byte *buf, in
 

	
 
		//val = (0xff << shiftnum) & andmask;
 

	
 
		//Go for the default.
 
		if (setid >= _spritesset_count) {
 
			_spritesset_count = setid + 1;
 
			_spritesset = realloc(_spritesset, _spritesset_count * sizeof(struct SpriteGroup));
 
		if (setid >= _cur_grffile->spritesset_count) {
 
			_cur_grffile->spritesset_count = setid + 1;
 
			_cur_grffile->spritesset = realloc(_cur_grffile->spritesset, _cur_grffile->spritesset_count * sizeof(struct SpriteGroup));
 
		}
 
		buf += 8 + nvar * 4;
 
		def = grf_load_word(&buf);
 
		_spritesset[setid] = _spritesset[def];
 
		_cur_grffile->spritesset[setid] = _cur_grffile->spritesset[def];
 
		return;
 

	
 
	} else if (numloaded & 0x80) {
 
@@ -908,14 +1068,14 @@ static void NewSpriteGroup(byte *buf, in
 
		return;
 
	}
 

	
 
	if (!_spriteset_start) {
 
	if (!_cur_grffile->spriteset_start) {
 
		grfmsg(GMS_ERROR, "NewSpriteGroup: No sprite set to work on! Skipping.");
 
		return;
 
	}
 

	
 
	if (_spriteset_feature != feature) {
 
		grfmsg(GMS_ERROR, "NewSpriteGroup: Group feature %x doesn't match set feature %x! Skipping.", feature, _spriteset_feature);
 
		return;
 
	if (_cur_grffile->spriteset_feature != feature) {
 
		grfmsg(GMS_ERROR, "NewSpriteGroup: Group feature %x doesn't match set feature %x! Playing it risky and trying to use it anyway.", feature, _cur_grffile->spriteset_feature);
 
		// return; // XXX: we can't because of MB's newstats.grf --pasky
 
	}
 

	
 
	check_length(bufend - buf, 5, "NewSpriteGroup");
 
@@ -933,30 +1093,30 @@ static void NewSpriteGroup(byte *buf, in
 
		numloading = 16;
 
	}
 

	
 
	if (setid >= _spritesset_count) {
 
		_spritesset_count = setid + 1;
 
		_spritesset = realloc(_spritesset, _spritesset_count * sizeof(struct SpriteGroup));
 
	if (setid >= _cur_grffile->spritesset_count) {
 
		_cur_grffile->spritesset_count = setid + 1;
 
		_cur_grffile->spritesset = realloc(_cur_grffile->spritesset, _cur_grffile->spritesset_count * sizeof(struct SpriteGroup));
 
	}
 
	group = &_spritesset[setid];
 
	group = &_cur_grffile->spritesset[setid];
 
	memset(group, 0, sizeof(struct SpriteGroup));
 
	group->sprites_per_set = _spriteset_numents;
 
	group->sprites_per_set = _cur_grffile->spriteset_numents;
 
	group->loaded_count  = numloaded;
 
	group->loading_count = numloading;
 

	
 
	DEBUG(grf, 6) ("NewSpriteGroup: New SpriteGroup 0x%02hhx, %u views, %u loaded, %u loading, sprites %u - %u",
 
			setid, group->sprites_per_set, group->loaded_count, group->loading_count,
 
			_spriteset_start - _cur_grffile->sprite_offset,
 
			_spriteset_start + (_spriteset_numents * (numloaded + numloading)) - _cur_grffile->sprite_offset);
 
			_cur_grffile->spriteset_start - _cur_grffile->sprite_offset,
 
			_cur_grffile->spriteset_start + (_cur_grffile->spriteset_numents * (numloaded + numloading)) - _cur_grffile->sprite_offset);
 

	
 
	for (i = 0; i < numloaded; i++) {
 
		uint16 spriteset_id = grf_load_word(&loaded_ptr);
 
		group->loaded[i] = _spriteset_start + spriteset_id * _spriteset_numents;
 
		group->loaded[i] = _cur_grffile->spriteset_start + spriteset_id * _cur_grffile->spriteset_numents;
 
		DEBUG(grf, 8) ("NewSpriteGroup: + group->loaded[%i]  = %u (subset %u)", i, group->loaded[i], spriteset_id);
 
	}
 

	
 
	for (i = 0; i < numloading; i++) {
 
		uint16 spriteset_id = grf_load_word(&loading_ptr);
 
		group->loading[i] = _spriteset_start + spriteset_id * _spriteset_numents;
 
		group->loading[i] = _cur_grffile->spriteset_start + spriteset_id * _cur_grffile->spriteset_numents;
 
		DEBUG(grf, 8) ("NewSpriteGroup: + group->loading[%i] = %u (subset %u)", i, group->loading[i], spriteset_id);
 
	}
 
}
 
@@ -1000,11 +1160,43 @@ static void NewVehicle_SpriteGroupMappin
 
	DEBUG(grf, 6) ("VehicleMapSpriteGroup: Feature %d, %d ids, %d cids, wagon override %d.",
 
			feature, idcount, cidcount, wagover);
 

	
 

	
 
	if (feature == GSF_STATION) {
 
		grfmsg(GMS_WARN, "VehicleMapSpriteGroup: Stations unsupported, skipping.");
 
		// We do things differently for stations.
 

	
 
		/* XXX: Currently we don't support cargo-specific images, so
 
		 * we go straight to the defaults. */
 
		byte *bp = buf + 4 + idcount + cidcount * 3;
 
		uint16 groupid = grf_load_word(&bp);
 

	
 
		for (i = 0; i < idcount; i++) {
 
			uint8 stid = buf[3 + i];
 
			int j;
 

	
 
			if (groupid >= _cur_grffile->spritesset_count) {
 
				grfmsg(GMS_WARN, "VehicleMapSpriteGroup: Spriteset %x out of range %x, skipping.",
 
				       groupid, _cur_grffile->spritesset_count);
 
				return;
 
			}
 

	
 
			// relocate sprite indexes based on spriteset locations
 
			for (j = 0; j < _cur_grffile->statinfo_tiles[stid]; j++) {
 
				DrawTileSeqStruct *seq;
 

	
 
				foreach_draw_tile_seq(seq, (DrawTileSeqStruct*) _cur_grffile->statinfo_renderdata[stid][j].seq) {
 
					seq->image += _cur_grffile->spritesset[groupid].loading[0];
 
				}
 
			}
 
			/* FIXME: This means several GRF files defining new stations
 
			 * will override each other, but the stid should be GRF-specific
 
			 * instead! --pasky */
 
			SetCustomStation(_cur_grffile->statinfo_classid[stid], stid, _cur_grffile->statinfo_renderdata[stid], _cur_grffile->statinfo_tiles[stid]);
 
			_cur_grffile->statinfo_classid[stid] = 0;
 
		}
 
		return;
 
	}
 

	
 

	
 
	/* If ``n-id'' (or ``idcount'') is zero, this is a ``feature
 
	 * callback''. I have no idea how this works, so we will ignore it for
 
	 * now.  --octo */
 
@@ -1017,7 +1209,7 @@ static void NewVehicle_SpriteGroupMappin
 
	// 03 00 01 19 01 00 00 00 00 - this is missing one 00 at the end,
 
	// what should we exactly do with that? --pasky
 

	
 
	if (!_spriteset_start || !_spritesset) {
 
	if (!_cur_grffile->spriteset_start || !_cur_grffile->spritesset) {
 
		grfmsg(GMS_WARN, "VehicleMapSpriteGroup: No sprite set to work on! Skipping.");
 
		return;
 
	}
 
@@ -1056,8 +1248,8 @@ static void NewVehicle_SpriteGroupMappin
 

	
 
			DEBUG(grf, 8) ("VehicleMapSpriteGroup: * [%d] Cargo type %x, group id %x", c, ctype, groupid);
 

	
 
			if (groupid >= _spritesset_count) {
 
				grfmsg(GMS_WARN, "VehicleMapSpriteGroup: Spriteset %x out of range %x, skipping.", groupid, _spritesset_count);
 
			if (groupid >= _cur_grffile->spritesset_count) {
 
				grfmsg(GMS_WARN, "VehicleMapSpriteGroup: Spriteset %x out of range %x, skipping.", groupid, _cur_grffile->spritesset_count);
 
				return;
 
			}
 

	
 
@@ -1066,9 +1258,9 @@ static void NewVehicle_SpriteGroupMappin
 

	
 
			if (wagover) {
 
				// TODO: No multiple cargo types per vehicle yet. --pasky
 
				SetWagonOverrideSprites(engine, &_spritesset[groupid], last_engines, last_engines_count);
 
				SetWagonOverrideSprites(engine, &_cur_grffile->spritesset[groupid], last_engines, last_engines_count);
 
			} else {
 
				SetCustomEngineSprites(engine, ctype, &_spritesset[groupid]);
 
				SetCustomEngineSprites(engine, ctype, &_cur_grffile->spritesset[groupid]);
 
				last_engines[i] = engine;
 
			}
 
		}
 
@@ -1084,16 +1276,16 @@ static void NewVehicle_SpriteGroupMappin
 
			uint8 engine = buf[3 + i] + _vehshifts[feature];
 

	
 
			// Don't tell me you don't love duplicated code!
 
			if (groupid >= _spritesset_count) {
 
				grfmsg(GMS_WARN, "VehicleMapSpriteGroup: Spriteset %x out of range %x, skipping.", groupid, _spritesset_count);
 
			if (groupid >= _cur_grffile->spritesset_count) {
 
				grfmsg(GMS_WARN, "VehicleMapSpriteGroup: Spriteset %x out of range %x, skipping.", groupid, _cur_grffile->spritesset_count);
 
				return;
 
			}
 

	
 
			if (wagover) {
 
				// TODO: No multiple cargo types per vehicle yet. --pasky
 
				SetWagonOverrideSprites(engine, &_spritesset[groupid], last_engines, last_engines_count);
 
				SetWagonOverrideSprites(engine, &_cur_grffile->spritesset[groupid], last_engines, last_engines_count);
 
			} else {
 
				SetCustomEngineSprites(engine, CID_DEFAULT, &_spritesset[groupid]);
 
				SetCustomEngineSprites(engine, CID_DEFAULT, &_cur_grffile->spritesset[groupid]);
 
				last_engines[i] = engine;
 
			}
 
		}
 
@@ -1116,6 +1308,7 @@ static void VehicleNewName(byte *buf, in
 
	 * (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. */
 

	
 
	uint8 feature;
 
	uint8 lang;
 
@@ -1577,16 +1770,13 @@ void InitNewGRFFile(const char *filename
 
{
 
	struct GRFFile *newfile;
 

	
 
	newfile = malloc(sizeof(struct GRFFile));
 
	newfile = calloc(1, sizeof(struct GRFFile));
 

	
 
	if (newfile == NULL)
 
		error ("Out of memory");
 

	
 
	newfile->filename = strdup(filename);
 
	newfile->grfid = 0;
 
	newfile->flags = 0x0000;
 
	newfile->sprite_offset = sprite_offset;
 
	newfile->next = NULL;
 

	
 
	if (_first_grffile == NULL) {
 
		_cur_grffile = newfile;
 
@@ -1645,15 +1835,21 @@ void DecodeSpecialSprite(const char *fil
 

	
 
	action = buf[0];
 

	
 
	/* XXX: Action 0x03 is temporarily processed together with actions 0x01
 
	 * and 0x02 before it is fixed to be reentrant (probably storing the
 
	 * group information in {struct GRFFile}). --pasky */
 
	/* XXX: There is a difference between staged loading in TTDPatch and
 
	 * here.  In TTDPatch, for some reason actions 1 and 2 are carried out
 
	 * during stage 0, whilst action 3 is carried out during stage 1 (to
 
	 * "resolve" cargo IDs... wtf). This is a little problem, because cargo
 
	 * IDs are valid only within a given set (action 1) block, and may be
 
	 * overwritten after action 3 associates them. But overwriting happens
 
	 * in an earlier stage than associating, so...  We just process actions
 
	 * 1 and 2 in stage 1 now, let's hope that won't get us into problems.
 
	 * --pasky */
 

	
 
	if (stage == 0) {
 
		/* During initialization, actions 0, 3, 4, 5 and 7 are ignored. */
 
		/* During initialization, actions 0, 1, 2, 3, 4, 5 and 7 are ignored. */
 

	
 
		if ((action == 0x00) /*|| (action == 0x03)*/ || (action == 0x04)
 
		    || (action == 0x05) || (action == 0x07)) {
 
		if ((action == 0x00) || (action == 0x01) || (action == 0x02) || (action == 0x03)
 
		    || (action == 0x04) || (action == 0x05) || (action == 0x07)) {
 
			DEBUG (grf, 7) ("DecodeSpecialSprite: Action: %x, Stage 0, Skipped", action);
 
			/* Do nothing. */
 

	
 
@@ -1672,7 +1868,7 @@ void DecodeSpecialSprite(const char *fil
 
		 * considered active if its action 8 has been processed, i.e. its
 
		 * action 8 hasn't been skipped using an action 7.
 
		 *
 
		 * During activation, only actions 0, 3, 4, 5, 7, 8, 9 and 0A are
 
		 * During activation, only actions 0, 1, 2, 3, 4, 5, 7, 8, 9 and 0A are
 
		 * carried out.  All others are ignored, because they only need to be
 
		 * processed once at initialization.  */
 

	
 
@@ -1686,8 +1882,9 @@ void DecodeSpecialSprite(const char *fil
 
			DEBUG (grf, 7) ("DecodeSpecialSprite: Action: %x, Stage 1, Not activated", action);
 
			/* Do nothing. */
 

	
 
		} else if ((action == 0x00) /*|| (action == 0x03)*/ || (action == 0x04) || (action == 0x05)
 
		           || (action == 0x07) || (action == 0x08) || (action == 0x09) || (action == 0x0A)) {
 
		} else if ((action == 0x00) || (action == 0x01) || (action == 0x02) || (action == 0x03)
 
			   || (action == 0x04) || (action == 0x05) || (action == 0x07) || (action == 0x08)
 
			   || (action == 0x09) || (action == 0x0A)) {
 
			DEBUG (grf, 7) ("DecodeSpecialSprite: Action: %x, Stage 1", action);
 
			handlers[action](buf, num);
 

	
rail_cmd.c
Show inline comments
 
@@ -6,6 +6,7 @@
 
#include "pathfind.h"
 
#include "town.h"
 
#include "sound.h"
 
#include "station.h"
 

	
 
void ShowTrainDepotWindow(uint tile);
 

	
 
@@ -734,6 +735,11 @@ int32 CmdBuildTrainCheckpoint(int x, int
 

	
 
	if (flags & DC_EXEC) {
 
		ModifyTile(tile, MP_MAP5, RAIL_TYPE_CHECKPOINT | dir);
 
		if (p1 & 0x100) {
 
			// custom graphics
 
			_map3_lo[tile] |= 16;
 
			_map3_hi[tile] = p1 & 0xff;
 
		}
 

	
 
		cp->deleted = 0;
 
		cp->xy = tile;
 
@@ -790,6 +796,8 @@ static int32 RemoveTrainCheckpoint(uint 
 

	
 
		if (justremove) {
 
			ModifyTile(tile, MP_MAP5, 1<<direction);
 
			_map3_lo[tile] &= ~16;
 
			_map3_hi[tile] = 0;
 
		} else {
 
			DoClearSquare(tile);
 
			SetSignalsOnBothDir(tile, direction);
 
@@ -1405,6 +1413,19 @@ DetailedTrackProc * const _detailed_trac
 
	DetTrackDrawProc_Null,
 
};
 

	
 
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)) // show transparent depots
 
		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;
 
@@ -1521,6 +1542,28 @@ static void DrawTile_Track(TileInfo *ti)
 

	
 
		if (ti->tileh != 0) { DrawFoundation(ti, ti->tileh); }
 

	
 
		if (!IS_RAIL_DEPOT(m5) && IS_RAIL_CHECKPOINT(m5) && _map3_lo[ti->tile]&16) {
 
			// look for customization
 
			DrawTileSprites *cust = GetCustomStation('WAYP', _map3_hi[ti->tile]);
 

	
 
			if (cust) {
 
				DrawTileSeqStruct const *seq;
 

	
 
				cust = &cust[2 + (m5 & 0x1)]; // emulate station tile - open with building
 

	
 
				image = cust->ground_sprite;
 
				if (image & 0x8000) image = (image & 0x7FFF) + tracktype_offs;
 
				DrawGroundSprite(image);
 

	
 
				foreach_draw_tile_seq(seq, cust->seq) {
 
					DrawSpecialBuilding(seq->image|0x8000, 0, ti,
 
					                    seq->delta_x, seq->delta_y, seq->delta_z,
 
					                    seq->width, seq->height, seq->unk);
 
				}
 
				return;
 
			}
 
		}
 

	
 
		s = _track_depot_layout_table[type];
 

	
 
		image = *(const uint16*)s;
 
@@ -1541,13 +1584,9 @@ static void DrawTile_Track(TileInfo *ti)
 
		drss = (const DrawTrackSeqStruct*)(s + sizeof(uint16));
 

	
 
		while ((image=drss->image) != 0) {
 
			if (image & 0x8000)
 
				image |= _drawtile_track_palette;
 
			image += (type<4)?tracktype_offs:0;
 
			if (!(_display_opt & DO_TRANS_BUILDINGS)) // show transparent depots
 
				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, type < 4 ? tracktype_offs : 0, ti,
 
			                    drss->subcoord_x, drss->subcoord_y, 0,
 
			                    drss->width, drss->height, 0x17);
 
			drss++;
 
		}
 
	}
rail_gui.c
Show inline comments
 
@@ -114,7 +114,12 @@ static void PlaceRail_Depot(uint tile)
 
static void PlaceRail_Checkpoint(uint tile)
 
{
 
	if (!_remove_button_clicked) {
 
		DoCommandP(tile, 0, 0, CcPlaySound1E, CMD_BUILD_TRAIN_CHECKPOINT | CMD_MSG(STR_CANT_BUILD_TRAIN_CHECKPOINT));
 
		/* TODO: We need a graphics selector. In the meantime we use the first
 
		 * custom station ID which works ok with newstats.grf (if you add it
 
		 * to openttd.cfg you want custom checkpoints) and if you don't have
 
		 * any custom station graphics it will fall back to the railstation
 
		 * sprites anyway. --pasky */
 
		DoCommandP(tile, 0x100, 0, CcPlaySound1E, CMD_BUILD_TRAIN_CHECKPOINT | CMD_MSG(STR_CANT_BUILD_TRAIN_CHECKPOINT));
 
	} else {
 
		DoCommandP(tile, 0, 0, CcPlaySound1E, CMD_REMOVE_TRAIN_CHECKPOINT | CMD_MSG(STR_CANT_REMOVE_TRAIN_CHECKPOINT));
 
	}
station.h
Show inline comments
 
@@ -107,4 +107,8 @@ typedef struct DrawTileSprites {
 

	
 
#define foreach_draw_tile_seq(idx, list) for (idx = list; ((byte) idx->delta_x) != 0x80; idx++)
 

	
 
void SetCustomStation(uint32 classid, byte stid, DrawTileSprites *data, byte tiles);
 
DrawTileSprites *GetCustomStation(uint32 classid, byte stid);
 
int GetCustomStationsCount(uint32 classid);
 

	
 
#endif /* STATION_H */
station_cmd.c
Show inline comments
 
@@ -957,6 +957,38 @@ uint GetStationPlatforms(Station *st, ui
 
}
 

	
 

	
 
/* TODO: Multiple classes! */
 
/* FIXME: Also, we should actually allocate the station id (but
 
 * SetCustomStation() needs to be able to override an existing custom station
 
 * as well) on our own. This would also prevent possible weirdness if some GRF
 
 * file used non-contignuous station ids. --pasky */
 

	
 
static int _waypoint_highest_id = -1;
 
static DrawTileSprites _waypoint_data[256][8];
 

	
 
void SetCustomStation(uint32 classid, byte stid, DrawTileSprites *data, byte tiles)
 
{
 
	assert(classid == 'WAYP');
 
	if (stid > _waypoint_highest_id)
 
		_waypoint_highest_id = stid;
 
	memcpy(_waypoint_data[stid], data, sizeof(DrawTileSprites) * tiles);
 
}
 

	
 
DrawTileSprites *GetCustomStation(uint32 classid, byte stid)
 
{
 
	assert(classid == 'WAYP');
 
	if (stid > _waypoint_highest_id || !_waypoint_data || !_waypoint_data[stid])
 
		return NULL;
 
	return _waypoint_data[stid];
 
}
 

	
 
int GetCustomStationsCount(uint32 classid)
 
{
 
	assert(classid == 'WAYP');
 
	return _waypoint_highest_id + 1;
 
}
 

	
 

	
 
static int32 RemoveRailroadStation(Station *st, TileIndex tile, uint32 flags)
 
{
 
	int w,h;
0 comments (0 inline, 0 general)