Add: NewGRF road stops

This commit is contained in:
Jonathan G Rennison
2022-11-06 15:01:27 +00:00
committed by rubidium42
parent a18182e24b
commit 4c1406a4b5
33 changed files with 2086 additions and 132 deletions

View File

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