diff --git a/src/lang/english.txt b/src/lang/english.txt index a115ddac14..e1d6a3bc8c 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -4227,6 +4227,7 @@ STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT :{STRING1} at {H STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_OBJECT :Object STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE :Rail type STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_ROAD_TYPE :Road/tram type +STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_SIGNALS :Signals STR_NEWGRF_INSPECT_QUERY_CAPTION :{WHITE}NewGRF variable 60+x parameter (hexadecimal) diff --git a/src/newgrf_debug_gui.cpp b/src/newgrf_debug_gui.cpp index cb2e75bab6..e69d14a1cf 100644 --- a/src/newgrf_debug_gui.cpp +++ b/src/newgrf_debug_gui.cpp @@ -1144,7 +1144,13 @@ GrfSpecFeature GetGrfSpecFeature(TileIndex tile) { switch (GetTileType(tile)) { default: return GSF_INVALID; - case MP_RAILWAY: return GSF_RAILTYPES; + case MP_RAILWAY: { + extern std::vector _new_signals_grfs; + if (HasSignals(tile) && !_new_signals_grfs.empty()) { + return GSF_SIGNALS; + } + return GSF_RAILTYPES; + } case MP_ROAD: return IsLevelCrossing(tile) ? GSF_RAILTYPES : GSF_ROADTYPES; case MP_HOUSE: return GSF_HOUSES; case MP_INDUSTRY: return GSF_INDUSTRYTILES; @@ -1163,6 +1169,13 @@ GrfSpecFeature GetGrfSpecFeature(TileIndex tile) default: return GSF_INVALID; } + + case MP_TUNNELBRIDGE: { + extern std::vector _new_signals_grfs; + if (IsTunnelBridgeWithSignalSimulation(tile) && !_new_signals_grfs.empty()) return GSF_SIGNALS; + return GSF_INVALID; + } + } } diff --git a/src/newgrf_newsignals.cpp b/src/newgrf_newsignals.cpp index 95f1c95b83..619296597d 100644 --- a/src/newgrf_newsignals.cpp +++ b/src/newgrf_newsignals.cpp @@ -13,6 +13,7 @@ #include "newgrf_extension.h" #include "map_func.h" #include "tracerestrict.h" +#include "string_func.h" #include "safeguards.h" @@ -85,3 +86,17 @@ uint GetNewSignalsRestrictedSignalsInfo(const TraceRestrictProgram *prog, TileIn if ((prog->actions_used_flags & TRPAUF_REVERSE) && !IsTileType(tile, MP_TUNNELBRIDGE)) result |= 4; return result; } + +void DumpNewSignalsSpriteGroups(DumpSpriteGroupPrinter print) +{ + SpriteGroupDumper dumper(print); + bool first = true; + for (const GRFFile *grf : _new_signals_grfs) { + if (!first) print(nullptr, DSGPO_PRINT, 0, ""); + char buffer[64]; + seprintf(buffer, lastof(buffer), "GRF: %08X", BSWAP32(grf->grfid)); + print(nullptr, DSGPO_PRINT, 0, buffer); + first = false; + dumper.DumpSpriteGroup(grf->new_signals_group, 0, 0); + } +} diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index b4b2fe1f0b..7125708a3a 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -12,6 +12,7 @@ #include "../newgrf_roadtype.h" #include "../newgrf_roadstop.h" #include "../newgrf_cargo.h" +#include "../newgrf_newsignals.h" #include "../date_func.h" #include "../timetable.h" #include "../ship.h" @@ -865,6 +866,72 @@ static const NIFeature _nif_industry = { }; +/*** NewGRF signals ***/ +void DumpTileSignalsInfo(char *buffer, const char *last, uint index, NIExtraInfoOutput &output) +{ + for (Trackdir td = TRACKDIR_BEGIN; td < TRACKDIR_END; td = (Trackdir)(td + 1)) { + if (!IsValidTrackdir(td)) continue; + if (HasTrack(index, TrackdirToTrack(td)) && HasSignalOnTrackdir(index, td)) { + char *b = buffer; + const SignalState state = GetSignalStateByTrackdir(index, td); + b += seprintf(b, last, " trackdir: %d, state: %d", td, state); + if (_extra_aspects > 0 && state == SIGNAL_STATE_GREEN) seprintf(b, last, ", aspect: %d", GetSignalAspect(index, TrackdirToTrack(td))); + output.print(buffer); + } + } +} + +static const NIVariable _niv_signals[] = { + NIV(0x40, "terrain type"), + NIV(A2VRI_SIGNALS_SIGNAL_RESTRICTION_INFO, "restriction info"), + NIV(A2VRI_SIGNALS_SIGNAL_CONTEXT, "context"), + NIV_END() +}; + +class NIHSignals : public NIHelper { + bool IsInspectable(uint index) const override { return !_new_signals_grfs.empty(); } + bool ShowSpriteDumpButton(uint index) const override { return true; } + uint GetParent(uint index) const override { return UINT32_MAX; } + const void *GetInstance(uint index)const override { return nullptr; } + const void *GetSpec(uint index) const override { return nullptr; } + void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_SIGNALS, INVALID_STRING_ID, index); } + uint32 GetGRFID(uint index) const override { return 0; } + + uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override + { + extern TraceRestrictProgram *GetFirstTraceRestrictProgramOnTile(TileIndex t); + CustomSignalSpriteContext ctx = CSSC_TRACK; + if (IsTunnelBridgeWithSignalSimulation(index)) { + ctx = IsTunnelBridgeSignalSimulationEntrance(index) ? CSSC_TUNNEL_BRIDGE_ENTRANCE : CSSC_TUNNEL_BRIDGE_EXIT; + } + NewSignalsResolverObject ro(nullptr, index, TCX_NORMAL, 0, 0, ctx, GetFirstTraceRestrictProgramOnTile(index)); + return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, extra); + } + + void ExtraInfo(uint index, NIExtraInfoOutput &output) const override + { + char buffer[1024]; + output.print("Debug Info:"); + if (IsTileType(index, MP_RAILWAY) && HasSignals(index)) { + output.print("Signals:"); + DumpTileSignalsInfo(buffer, lastof(buffer), index, output); + } + } + + /* virtual */ void SpriteDump(uint index, DumpSpriteGroupPrinter print) const override + { + extern void DumpNewSignalsSpriteGroups(DumpSpriteGroupPrinter print); + DumpNewSignalsSpriteGroups(std::move(print)); + } +}; + +static const NIFeature _nif_signals = { + nullptr, + nullptr, + _niv_signals, + new NIHSignals(), +}; + /*** NewGRF objects ***/ #define NICO(cb_id, bit) NIC(cb_id, ObjectSpec, callback_mask, bit) @@ -1100,16 +1167,7 @@ class NIHRailType : public NIHelper { if (IsTileType(index, MP_RAILWAY) && HasSignals(index)) { output.print("Signals:"); - for (Trackdir td = TRACKDIR_BEGIN; td < TRACKDIR_END; td = (Trackdir)(td + 1)) { - if (!IsValidTrackdir(td)) continue; - if (HasTrack(index, TrackdirToTrack(td)) && HasSignalOnTrackdir(index, td)) { - char *b = buffer; - const SignalState state = GetSignalStateByTrackdir(index, td); - b += seprintf(b, lastof(buffer), " trackdir: %d, state: %d", td, state); - if (_extra_aspects > 0 && state == SIGNAL_STATE_GREEN) seprintf(b, lastof(buffer), ", aspect: %d", GetSignalAspect(index, TrackdirToTrack(td))); - output.print(buffer); - } - } + DumpTileSignalsInfo(buffer, lastof(buffer), index, output); } if (IsTileType(index, MP_RAILWAY) && IsRailDepot(index)) { seprintf(buffer, lastof(buffer), "Depot: reserved: %u", HasDepotReservation(index)); @@ -1527,7 +1585,7 @@ static const NIFeature * const _nifeatures[] = { nullptr, // GSF_CARGOES (has no "physical" objects) nullptr, // GSF_SOUNDFX (has no "physical" objects) nullptr, // GSF_AIRPORTS (feature not implemented) - nullptr, // GSF_SIGNALS (feature not implemented) + &_nif_signals, // GSF_SIGNALS &_nif_object, // GSF_OBJECTS &_nif_railtype, // GSF_RAILTYPES &_nif_airporttile, // GSF_AIRPORTTILES diff --git a/src/tracerestrict.cpp b/src/tracerestrict.cpp index 2a0ff8505e..1c992e9ae7 100644 --- a/src/tracerestrict.cpp +++ b/src/tracerestrict.cpp @@ -1378,6 +1378,21 @@ TraceRestrictProgram *GetTraceRestrictProgram(TraceRestrictRefId ref, bool creat } } +/** + * Gets the first signal program for the given tile + * This is for debug/display purposes only + */ +TraceRestrictProgram *GetFirstTraceRestrictProgramOnTile(TileIndex t) +{ + // First mapping for this tile, or later + TraceRestrictMapping::iterator lower_bound = _tracerestrictprogram_mapping.lower_bound(MakeTraceRestrictRefId(t, static_cast(0))); + + if ((lower_bound != _tracerestrictprogram_mapping.end()) && (GetTraceRestrictRefIdTileIndex(lower_bound->first) == t)) { + return _tracerestrictprogram_pool.Get(lower_bound->second.program_id); + } + return nullptr; +} + /** * Notify that a signal is being removed * Remove any trace restrict mappings associated with it