mirror of https://github.com/OpenTTD/OpenTTD.git
(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)
This commit is contained in:
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>
|
||||
|
||||
|
|
6
engine.h
6
engine.h
|
@ -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;
|
||||
|
|
377
grfspecial.c
377
grfspecial.c
|
@ -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 = ∅
|
||||
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 = ∅
|
||||
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);
|
||||
|
||||
|
|
53
rail_cmd.c
53
rail_cmd.c
|
@ -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…
Reference in New Issue