Initial support for NewGRF road stops (bus and lorry stops)

This commit is contained in:
Jonathan G Rennison
2022-02-09 02:11:55 +00:00
parent a3c003546b
commit 1084bb8566
28 changed files with 1592 additions and 119 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"
@@ -4923,6 +4924,120 @@ 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 = HandleAction0PropertyDefault(buf, prop);
break;
}
return ret;
}
static ChangeInfoResult RoadStopChangeInfo(uint id, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, 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 && prop != A0RPI_ROADSTOP_CLASS_ID) {
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 A0RPI_ROADSTOP_CLASS_ID:
if (MappedPropertyLengthMismatch(buf, 4, mapping_entry)) break;
FALLTHROUGH;
case 0x08: { // Road Stop Class ID
RoadStopSpec **spec = &_cur.grffile->roadstops[id + i];
if (*spec == nullptr) *spec = CallocT<RoadStopSpec>(1);
uint32 classid = buf->ReadDWord();
(*spec)->cls_id = RoadStopClass::Allocate(BSWAP32(classid));
(*spec)->spec_id = id + i;
break;
}
case A0RPI_ROADSTOP_STOP_TYPE:
if (MappedPropertyLengthMismatch(buf, 4, mapping_entry)) break;
FALLTHROUGH;
case 0x09: // Road stop type
rs->stop_type = (RoadStopAvailabilityType)buf->ReadByte();
break;
case A0RPI_ROADSTOP_STOP_NAME:
if (MappedPropertyLengthMismatch(buf, 2, mapping_entry)) break;
FALLTHROUGH;
case 0x0A: // Road Stop Name
AddStringForMapping(buf->ReadWord(), &rs->name);
break;
case A0RPI_ROADSTOP_CLASS_NAME:
if (MappedPropertyLengthMismatch(buf, 2, mapping_entry)) break;
FALLTHROUGH;
case 0x0B: // Road Stop Class name
AddStringForMapping(buf->ReadWord(), &RoadStopClass::Get(rs->cls_id)->name);
break;
case A0RPI_ROADSTOP_DRAW_MODE:
if (MappedPropertyLengthMismatch(buf, 1, mapping_entry)) break;
FALLTHROUGH;
case 0x0C: // The draw mode
rs->draw_mode = (RoadStopDrawMode)buf->ReadByte();
break;
case A0RPI_ROADSTOP_TRIGGER_CARGOES:
if (MappedPropertyLengthMismatch(buf, 4, mapping_entry)) break;
FALLTHROUGH;
case 0x0D: // Cargo types for random triggers
rs->cargo_triggers = TranslateRefitMask(buf->ReadDWord());
break;
default:
ret = CIR_UNKNOWN;
break;
}
}
return ret;
}
static bool HandleChangeInfoResult(const char *caller, ChangeInfoResult cir, GrfSpecFeature feature, int property)
{
switch (cir) {
@@ -5002,6 +5117,7 @@ static const char *_feature_names[] = {
"AIRPORTTILES",
"ROADTYPES",
"TRAMTYPES",
"ROADSTOPS",
};
static_assert(lengthof(_feature_names) == GSF_END);
@@ -5106,6 +5222,7 @@ static void FeatureChangeInfo(ByteReader *buf)
/* GSF_AIRPORTTILES */ AirportTilesChangeInfo,
/* GSF_ROADTYPES */ RoadTypeChangeInfo,
/* GSF_TRAMTYPES */ TramTypeChangeInfo,
/* GSF_ROADSTOPS */ RoadStopChangeInfo,
};
static_assert(GSF_END == lengthof(handler));
static_assert(lengthof(handler) == lengthof(_cur.grffile->action0_property_remaps), "Action 0 feature list length mismatch");
@@ -5616,7 +5733,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());
@@ -6283,6 +6401,44 @@ 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();
}
/* Skip the cargo type section, we only care about the default group */
uint8 cidcount = buf->ReadByte();
buf->Skip(cidcount * 3);
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)
@@ -6388,6 +6544,10 @@ static void FeatureMapSpriteGroup(ByteReader *buf)
AirportTileMapSpriteGroup(buf, idcount);
return;
case GSF_ROADSTOPS:
RoadStopMapSpriteGroup(buf, idcount);
return;
default:
grfmsg(1, "FeatureMapSpriteGroup: Unsupported feature %s, skipping", GetFeatureString(feature_ref));
return;
@@ -9620,6 +9780,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()
{
@@ -9707,6 +9881,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));