(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)
pull/155/head
celestar 20 years ago
parent a9a852a4d6
commit eb50427670

@ -135,6 +135,8 @@ map5 bits 7 and 6 set: railway depot / checkpoints
<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>

@ -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;

@ -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(uint engine, int numinfo, int prop, byte *
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, int len)
/* 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, int len)
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, int len)
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 len)
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, int len)
* 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, int len)
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, int len)
//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, int len)
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, int len)
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_SpriteGroupMapping(byte *buf, int len)
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_SpriteGroupMapping(byte *buf, int len)
// 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_SpriteGroupMapping(byte *buf, int len)
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_SpriteGroupMapping(byte *buf, int len)
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_SpriteGroupMapping(byte *buf, int len)
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, int len)
* (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, int sprite_offset)
{
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 *filename, int num, int spriteid, int stage)
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 *filename, int num, int spriteid, int stage)
* 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 *filename, int num, int spriteid, int stage)
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);

@ -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 y, uint32 flags, uint32 p1, uint32 p2)
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 tile, uint32 flags, bool justremove)
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_track_proc[16] = {
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++;
}
}

@ -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));
}

@ -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 */

@ -957,6 +957,38 @@ uint GetStationPlatforms(Station *st, uint tile)
}
/* 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;

Loading…
Cancel
Save