Add: NewGRF road stops
This commit is contained in:

committed by
rubidium42

parent
a18182e24b
commit
4c1406a4b5
209
src/newgrf.cpp
209
src/newgrf.cpp
@@ -48,6 +48,7 @@
|
||||
#include "language.h"
|
||||
#include "vehicle_base.h"
|
||||
#include "road.h"
|
||||
#include "newgrf_roadstop.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
#include "table/build_industry.h"
|
||||
@@ -4747,6 +4748,131 @@ static ChangeInfoResult AirportTilesChangeInfo(uint airtid, int numinfo, int pro
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignore properties for roadstops
|
||||
* @param prop The property to ignore.
|
||||
* @param buf The property value.
|
||||
* @return ChangeInfoResult.
|
||||
*/
|
||||
static ChangeInfoResult IgnoreRoadStopProperty(uint prop, ByteReader *buf)
|
||||
{
|
||||
ChangeInfoResult ret = CIR_SUCCESS;
|
||||
|
||||
switch (prop) {
|
||||
case 0x09:
|
||||
case 0x0C:
|
||||
buf->ReadByte();
|
||||
break;
|
||||
|
||||
case 0x0A:
|
||||
case 0x0B:
|
||||
buf->ReadWord();
|
||||
break;
|
||||
|
||||
case 0x08:
|
||||
case 0x0D:
|
||||
buf->ReadDWord();
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = CIR_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ChangeInfoResult RoadStopChangeInfo(uint id, int numinfo, int prop, ByteReader *buf)
|
||||
{
|
||||
ChangeInfoResult ret = CIR_SUCCESS;
|
||||
|
||||
if (id + numinfo > 255) {
|
||||
grfmsg(1, "RoadStopChangeInfo: RoadStop %u is invalid, max %u, ignoring", id + numinfo, 255);
|
||||
return CIR_INVALID_ID;
|
||||
}
|
||||
|
||||
if (_cur.grffile->roadstops == nullptr) _cur.grffile->roadstops = CallocT<RoadStopSpec*>(255);
|
||||
|
||||
for (int i = 0; i < numinfo; i++) {
|
||||
RoadStopSpec *rs = _cur.grffile->roadstops[id + i];
|
||||
|
||||
if (rs == nullptr && prop != 0x08) {
|
||||
grfmsg(1, "RoadStopChangeInfo: Attempt to modify undefined road stop %u, ignoring", id + i);
|
||||
ChangeInfoResult cir = IgnoreRoadStopProperty(prop, buf);
|
||||
if (cir > ret) ret = cir;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (prop) {
|
||||
case 0x08: { // Road Stop Class ID
|
||||
RoadStopSpec **spec = &_cur.grffile->roadstops[id + i];
|
||||
|
||||
if (*spec == nullptr) {
|
||||
*spec = CallocT<RoadStopSpec>(1);
|
||||
new (*spec) RoadStopSpec();
|
||||
}
|
||||
|
||||
uint32 classid = buf->ReadDWord();
|
||||
(*spec)->cls_id = RoadStopClass::Allocate(BSWAP32(classid));
|
||||
(*spec)->spec_id = id + i;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x09: // Road stop type
|
||||
rs->stop_type = (RoadStopAvailabilityType)buf->ReadByte();
|
||||
break;
|
||||
|
||||
case 0x0A: // Road Stop Name
|
||||
AddStringForMapping(buf->ReadWord(), &rs->name);
|
||||
break;
|
||||
|
||||
case 0x0B: // Road Stop Class name
|
||||
AddStringForMapping(buf->ReadWord(), &RoadStopClass::Get(rs->cls_id)->name);
|
||||
break;
|
||||
|
||||
case 0x0C: // The draw mode
|
||||
rs->draw_mode = (RoadStopDrawMode)buf->ReadByte();
|
||||
break;
|
||||
|
||||
case 0x0D: // Cargo types for random triggers
|
||||
rs->cargo_triggers = TranslateRefitMask(buf->ReadDWord());
|
||||
break;
|
||||
|
||||
case 0x0E: // Animation info
|
||||
rs->animation.frames = buf->ReadByte();
|
||||
rs->animation.status = buf->ReadByte();
|
||||
break;
|
||||
|
||||
case 0x0F: // Animation speed
|
||||
rs->animation.speed = buf->ReadByte();
|
||||
break;
|
||||
|
||||
case 0x10: // Animation triggers
|
||||
rs->animation.triggers = buf->ReadWord();
|
||||
break;
|
||||
|
||||
case 0x11: // Callback mask
|
||||
rs->callback_mask = buf->ReadByte();
|
||||
break;
|
||||
|
||||
case 0x12: // General flags
|
||||
rs->flags = (uint8)buf->ReadDWord(); // Future-proofing, size this as 4 bytes, but we only need one byte's worth of flags at present
|
||||
break;
|
||||
|
||||
case 0x15: // Cost multipliers
|
||||
rs->build_cost_multiplier = buf->ReadByte();
|
||||
rs->clear_cost_multiplier = buf->ReadByte();
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = CIR_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool HandleChangeInfoResult(const char *caller, ChangeInfoResult cir, uint8 feature, uint8 property)
|
||||
{
|
||||
switch (cir) {
|
||||
@@ -4811,6 +4937,7 @@ static void FeatureChangeInfo(ByteReader *buf)
|
||||
/* GSF_AIRPORTTILES */ AirportTilesChangeInfo,
|
||||
/* GSF_ROADTYPES */ RoadTypeChangeInfo,
|
||||
/* GSF_TRAMTYPES */ TramTypeChangeInfo,
|
||||
/* GSF_ROADSTOPS */ RoadStopChangeInfo,
|
||||
};
|
||||
static_assert(GSF_END == lengthof(handler));
|
||||
|
||||
@@ -5289,7 +5416,8 @@ static void NewSpriteGroup(ByteReader *buf)
|
||||
case GSF_HOUSES:
|
||||
case GSF_AIRPORTTILES:
|
||||
case GSF_OBJECTS:
|
||||
case GSF_INDUSTRYTILES: {
|
||||
case GSF_INDUSTRYTILES:
|
||||
case GSF_ROADSTOPS: {
|
||||
byte num_building_sprites = std::max((uint8)1, type);
|
||||
|
||||
assert(TileLayoutSpriteGroup::CanAllocateItem());
|
||||
@@ -5404,7 +5532,7 @@ static CargoID TranslateCargo(uint8 feature, uint8 ctype)
|
||||
}
|
||||
}
|
||||
/* Special cargo types for purchase list and stations */
|
||||
if (feature == GSF_STATIONS && ctype == 0xFE) return CT_DEFAULT_NA;
|
||||
if ((feature == GSF_STATIONS || feature == GSF_ROADSTOPS) && ctype == 0xFE) return CT_DEFAULT_NA;
|
||||
if (ctype == 0xFF) return CT_PURCHASE;
|
||||
|
||||
if (_cur.grffile->cargo_list.size() == 0) {
|
||||
@@ -5923,6 +6051,61 @@ static void AirportTileMapSpriteGroup(ByteReader *buf, uint8 idcount)
|
||||
}
|
||||
}
|
||||
|
||||
static void RoadStopMapSpriteGroup(ByteReader *buf, uint8 idcount)
|
||||
{
|
||||
uint8 *roadstops = AllocaM(uint8, idcount);
|
||||
for (uint i = 0; i < idcount; i++) {
|
||||
roadstops[i] = buf->ReadByte();
|
||||
}
|
||||
|
||||
uint8 cidcount = buf->ReadByte();
|
||||
for (uint c = 0; c < cidcount; c++) {
|
||||
uint8 ctype = buf->ReadByte();
|
||||
uint16 groupid = buf->ReadWord();
|
||||
if (!IsValidGroupID(groupid, "RoadStopMapSpriteGroup")) continue;
|
||||
|
||||
ctype = TranslateCargo(GSF_ROADSTOPS, ctype);
|
||||
if (ctype == CT_INVALID) continue;
|
||||
|
||||
for (uint i = 0; i < idcount; i++) {
|
||||
RoadStopSpec *roadstopspec = _cur.grffile->roadstops == nullptr ? nullptr : _cur.grffile->roadstops[roadstops[i]];
|
||||
|
||||
if (roadstopspec == nullptr) {
|
||||
grfmsg(1, "RoadStopMapSpriteGroup: Road stop with ID 0x%02X does not exist, skipping", roadstops[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
roadstopspec->grf_prop.spritegroup[ctype] = _cur.spritegroups[groupid];
|
||||
}
|
||||
}
|
||||
|
||||
uint16 groupid = buf->ReadWord();
|
||||
if (!IsValidGroupID(groupid, "RoadStopMapSpriteGroup")) return;
|
||||
|
||||
if (_cur.grffile->roadstops == nullptr) {
|
||||
grfmsg(0, "RoadStopMapSpriteGroup: No roadstops defined, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint i = 0; i < idcount; i++) {
|
||||
RoadStopSpec *roadstopspec = _cur.grffile->roadstops == nullptr ? nullptr : _cur.grffile->roadstops[roadstops[i]];
|
||||
|
||||
if (roadstopspec == nullptr) {
|
||||
grfmsg(1, "RoadStopMapSpriteGroup: Road stop with ID 0x%02X does not exist, skipping.", roadstops[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (roadstopspec->grf_prop.grffile != nullptr) {
|
||||
grfmsg(1, "RoadStopMapSpriteGroup: Road stop with ID 0x%02X mapped multiple times, skipping", roadstops[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
roadstopspec->grf_prop.spritegroup[CT_DEFAULT] = _cur.spritegroups[groupid];
|
||||
roadstopspec->grf_prop.grffile = _cur.grffile;
|
||||
roadstopspec->grf_prop.local_id = roadstops[i];
|
||||
RoadStopClass::Assign(roadstopspec);
|
||||
}
|
||||
}
|
||||
|
||||
/* Action 0x03 */
|
||||
static void FeatureMapSpriteGroup(ByteReader *buf)
|
||||
@@ -6023,6 +6206,10 @@ static void FeatureMapSpriteGroup(ByteReader *buf)
|
||||
AirportTileMapSpriteGroup(buf, idcount);
|
||||
return;
|
||||
|
||||
case GSF_ROADSTOPS:
|
||||
RoadStopMapSpriteGroup(buf, idcount);
|
||||
return;
|
||||
|
||||
default:
|
||||
grfmsg(1, "FeatureMapSpriteGroup: Unsupported feature 0x%02X, skipping", feature);
|
||||
return;
|
||||
@@ -8601,6 +8788,20 @@ static void ResetCustomObjects()
|
||||
}
|
||||
}
|
||||
|
||||
static void ResetCustomRoadStops()
|
||||
{
|
||||
for (auto file : _grf_files) {
|
||||
RoadStopSpec **&roadstopspec = file->roadstops;
|
||||
if (roadstopspec == nullptr) continue;
|
||||
for (uint i = 0; i < NUM_ROADSTOPS_PER_GRF; i++) {
|
||||
free(roadstopspec[i]);
|
||||
}
|
||||
|
||||
free(roadstopspec);
|
||||
roadstopspec = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/** Reset and clear all NewGRFs */
|
||||
static void ResetNewGRF()
|
||||
{
|
||||
@@ -8687,6 +8888,10 @@ void ResetNewGRFData()
|
||||
AirportSpec::ResetAirports();
|
||||
AirportTileSpec::ResetAirportTiles();
|
||||
|
||||
/* Reset road stop classes */
|
||||
RoadStopClass::Reset();
|
||||
ResetCustomRoadStops();
|
||||
|
||||
/* Reset canal sprite groups and flags */
|
||||
memset(_water_feature, 0, sizeof(_water_feature));
|
||||
|
||||
|
Reference in New Issue
Block a user