OpenTTD Source 20250529-master-g10c159a79f
newgrf_roadtype.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10#include "stdafx.h"
12#include "debug.h"
13#include "newgrf_roadtype.h"
14#include "newgrf_railtype.h"
16#include "depot_base.h"
17#include "town.h"
18#include "tunnelbridge_map.h"
19
20#include "safeguards.h"
21
34uint32_t GetTrackTypes(TileIndex tile, const GRFFile *grffile)
35{
36 uint8_t road = 0xFF;
37 uint8_t tram = 0xFF;
38 if (MayHaveRoad(tile)) {
39 if (auto tt = GetRoadTypeRoad(tile); tt != INVALID_ROADTYPE) {
40 road = GetReverseRoadTypeTranslation(tt, grffile);
41 if (road == 0xFF) road = 0xFE;
42 }
43 if (auto tt = GetRoadTypeTram(tile); tt != INVALID_ROADTYPE) {
44 tram = GetReverseRoadTypeTranslation(tt, grffile);
45 if (tram == 0xFF) tram = 0xFE;
46 }
47 }
48 uint8_t rail = 0xFF;
49 if (auto tt = GetTileRailType(tile); tt != INVALID_RAILTYPE) {
50 rail = GetReverseRailTypeTranslation(tt, grffile);
51 if (rail == 0xFF) rail = 0xFE;
52 }
53 return road | tram << 8 | rail << 16;
54}
55
56/* virtual */ uint32_t RoadTypeScopeResolver::GetRandomBits() const
57{
58 uint tmp = CountBits(this->tile.base() + (TileX(this->tile) + TileY(this->tile)) * TILE_SIZE);
59 return GB(tmp, 0, 2);
60}
61
62/* virtual */ uint32_t RoadTypeScopeResolver::GetVariable(uint8_t variable, [[maybe_unused]] uint32_t parameter, bool &available) const
63{
64 if (this->tile == INVALID_TILE) {
65 switch (variable) {
66 case 0x40: return 0;
67 case 0x41: return 0;
68 case 0x42: return 0;
69 case 0x43: return TimerGameCalendar::date.base();
70 case 0x44: return to_underlying(HouseZone::TownEdge);
71 case 0x45: {
72 auto rt = GetRoadTypeInfoIndex(this->rti);
73 uint8_t local = GetReverseRoadTypeTranslation(rt, this->ro.grffile);
74 if (local == 0xFF) local = 0xFE;
75 if (RoadTypeIsRoad(rt)) {
76 return 0xFFFF00 | local;
77 } else {
78 return 0xFF00FF | local << 8;
79 }
80 }
81 }
82 }
83
84 switch (variable) {
85 case 0x40: return GetTerrainType(this->tile, this->context);
86 case 0x41: return 0;
87 case 0x42: return IsLevelCrossingTile(this->tile) && IsCrossingBarred(this->tile);
88 case 0x43:
89 if (IsRoadDepotTile(this->tile)) return Depot::GetByTile(this->tile)->build_date.base();
90 return TimerGameCalendar::date.base();
91 case 0x44: {
92 const Town *t = nullptr;
93 if (IsRoadDepotTile(this->tile)) {
94 t = Depot::GetByTile(this->tile)->town;
95 } else {
96 t = ClosestTownFromTile(this->tile, UINT_MAX);
97 }
98 return to_underlying(t != nullptr ? GetTownRadiusGroup(t, this->tile) : HouseZone::TownEdge);
99 }
100 case 0x45:
101 return GetTrackTypes(this->tile, ro.grffile);
102 }
103
104 Debug(grf, 1, "Unhandled road type tile variable 0x{:X}", variable);
105
106 available = false;
107 return UINT_MAX;
108}
109
111{
112 RoadType rt = GetRoadTypeByLabel(this->roadtype_scope.rti->label, false);
113 switch (GetRoadTramType(rt)) {
114 case RTT_ROAD: return GSF_ROADTYPES;
115 case RTT_TRAM: return GSF_TRAMTYPES;
116 default: return GSF_INVALID;
117 }
118}
119
121{
122 return this->roadtype_scope.rti->label;
123}
124
134RoadTypeResolverObject::RoadTypeResolverObject(const RoadTypeInfo *rti, TileIndex tile, TileContext context, RoadTypeSpriteGroup rtsg, uint32_t param1, uint32_t param2)
135 : ResolverObject(rti != nullptr ? rti->grffile[rtsg] : nullptr, CBID_NO_CALLBACK, param1, param2), roadtype_scope(*this, rti, tile, context)
136{
137 this->root_spritegroup = rti != nullptr ? rti->group[rtsg] : nullptr;
138}
139
149SpriteID GetCustomRoadSprite(const RoadTypeInfo *rti, TileIndex tile, RoadTypeSpriteGroup rtsg, TileContext context, uint *num_results)
150{
151 assert(rtsg < ROTSG_END);
152
153 if (rti->group[rtsg] == nullptr) return 0;
154
155 RoadTypeResolverObject object(rti, tile, context, rtsg);
156 const auto *group = object.Resolve<ResultSpriteGroup>();
157 if (group == nullptr || group->num_sprites == 0) return 0;
158
159 if (num_results) *num_results = group->num_sprites;
160
161 return group->sprite;
162}
163
171RoadType GetRoadTypeTranslation(RoadTramType rtt, uint8_t tracktype, const GRFFile *grffile)
172{
173 /* Because OpenTTD mixes RoadTypes and TramTypes into the same type,
174 * the mapping of the original road- and tramtypes does not match the default GRF-local mapping.
175 * So, this function cannot provide any similar behavior to GetCargoTranslation() and GetRailTypeTranslation()
176 * when the GRF defines no translation table.
177 * But since there is only one default road/tram-type, this makes little sense anyway.
178 * So for GRF without translation table, we always return INVALID_ROADTYPE.
179 */
180
181 if (grffile == nullptr) return INVALID_ROADTYPE;
182
183 const auto &list = rtt == RTT_TRAM ? grffile->tramtype_list : grffile->roadtype_list;
184 if (tracktype >= list.size()) return INVALID_ROADTYPE;
185
186 /* Look up roadtype including alternate labels. */
187 RoadType result = GetRoadTypeByLabel(list[tracktype]);
188
189 /* Check whether the result is actually the wanted road/tram-type */
190 if (result != INVALID_ROADTYPE && GetRoadTramType(result) != rtt) return INVALID_ROADTYPE;
191
192 return result;
193}
194
201uint8_t GetReverseRoadTypeTranslation(RoadType roadtype, const GRFFile *grffile)
202{
203 /* No road type table present, return road type as-is */
204 if (grffile == nullptr) return roadtype;
205
206 const std::vector<RoadTypeLabel> *list = RoadTypeIsRoad(roadtype) ? &grffile->roadtype_list : &grffile->tramtype_list;
207 if (list->empty()) return roadtype;
208
209 /* Look for a matching road type label in the table */
210 RoadTypeLabel label = GetRoadTypeInfo(roadtype)->label;
211
212 int index = find_index(*list, label);
213 if (index >= 0) return index;
214
215 /* If not found, return as invalid */
216 return 0xFF;
217}
218
219std::vector<LabelObject<RoadTypeLabel>> _roadtype_list;
220
226{
227 std::vector<RoadType> roadtype_conversion_map;
228 bool needs_conversion = false;
229 for (auto it = std::begin(_roadtype_list); it != std::end(_roadtype_list); ++it) {
230 RoadType rt = GetRoadTypeByLabel(it->label);
231 if (rt == INVALID_ROADTYPE || GetRoadTramType(rt) != it->subtype) {
232 rt = it->subtype ? ROADTYPE_TRAM : ROADTYPE_ROAD;
233 }
234
235 roadtype_conversion_map.push_back(rt);
236
237 /* Conversion is needed if the road type is in a different position than the list. */
238 if (it->label != 0 && rt != std::distance(std::begin(_roadtype_list), it)) needs_conversion = true;
239 }
240 if (!needs_conversion) return;
241
242 for (TileIndex t : Map::Iterate()) {
243 switch (GetTileType(t)) {
244 case MP_ROAD:
245 if (RoadType rt = GetRoadTypeRoad(t); rt != INVALID_ROADTYPE) SetRoadTypeRoad(t, roadtype_conversion_map[rt]);
246 if (RoadType rt = GetRoadTypeTram(t); rt != INVALID_ROADTYPE) SetRoadTypeTram(t, roadtype_conversion_map[rt]);
247 break;
248
249 case MP_STATION:
250 if (IsAnyRoadStop(t)) {
251 if (RoadType rt = GetRoadTypeRoad(t); rt != INVALID_ROADTYPE) SetRoadTypeRoad(t, roadtype_conversion_map[rt]);
252 if (RoadType rt = GetRoadTypeTram(t); rt != INVALID_ROADTYPE) SetRoadTypeTram(t, roadtype_conversion_map[rt]);
253 }
254 break;
255
256 case MP_TUNNELBRIDGE:
258 if (RoadType rt = GetRoadTypeRoad(t); rt != INVALID_ROADTYPE) SetRoadTypeRoad(t, roadtype_conversion_map[rt]);
259 if (RoadType rt = GetRoadTypeTram(t); rt != INVALID_ROADTYPE) SetRoadTypeTram(t, roadtype_conversion_map[rt]);
260 }
261 break;
262
263 default:
264 break;
265 }
266 }
267}
268
271{
272 _roadtype_list.clear();
273 for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) {
274 _roadtype_list.emplace_back(GetRoadTypeInfo(rt)->label, GetRoadTramType(rt));
275 }
276}
277
278void ClearRoadTypeLabelList()
279{
280 _roadtype_list.clear();
281}
constexpr uint CountBits(T value)
Counts the number of set bits in a variable.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
RoadTypeLabel label
Unique 32 bit road type identifier.
Definition road.h:138
const SpriteGroup * group[ROTSG_END]
Sprite groups for resolving sprites.
Definition road.h:183
static Date date
Current date in days (day counter).
Some simple functions to help with accessing containers.
int find_index(Container const &container, typename Container::const_reference item)
Helper function to get the index of an item Consider using std::set, std::unordered_set or std::flat_...
Functions related to debugging.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
Base for all depots (except hangars)
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
static debug_inline uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:424
static debug_inline uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:414
GrfSpecFeature
Definition newgrf.h:69
@ GSF_INVALID
An invalid spec feature.
Definition newgrf.h:100
@ CBID_NO_CALLBACK
Set when using the callback resolve system, but not to resolve a callback.
uint32_t GetTerrainType(TileIndex tile, TileContext context)
Function used by houses (and soon industries) to get information on type of "terrain" the tile it is ...
TileContext
Context for tile accesses.
uint8_t GetReverseRailTypeTranslation(RailType railtype, const GRFFile *grffile)
Perform a reverse railtype lookup to get the GRF internal ID.
NewGRF handling of rail types.
void SetCurrentRoadTypeLabelList()
Populate road type label list with current values.
SpriteID GetCustomRoadSprite(const RoadTypeInfo *rti, TileIndex tile, RoadTypeSpriteGroup rtsg, TileContext context, uint *num_results)
Get the sprite to draw for the given tile.
void ConvertRoadTypes()
Test if any saved road type labels are different to the currently loaded road types.
uint8_t GetReverseRoadTypeTranslation(RoadType roadtype, const GRFFile *grffile)
Perform a reverse roadtype lookup to get the GRF internal ID.
uint32_t GetTrackTypes(TileIndex tile, const GRFFile *grffile)
Variable 0x45 of road-/tram-/rail-types to query track types on a tile.
RoadType GetRoadTypeTranslation(RoadTramType rtt, uint8_t tracktype, const GRFFile *grffile)
Translate an index to the GRF-local road/tramtype-translation table into a RoadType.
NewGRF handling of road types.
uint8_t GetReverseRoadTypeTranslation(RoadType roadtype, const GRFFile *grffile)
Perform a reverse roadtype lookup to get the GRF internal ID.
uint32_t GetTrackTypes(TileIndex tile, const GRFFile *grffile)
Variable 0x45 of road-/tram-/rail-types to query track types on a tile.
RailType GetTileRailType(Tile tile)
Return the rail type of tile, or INVALID_RAILTYPE if this is no rail tile.
Definition rail.cpp:155
@ INVALID_RAILTYPE
Flag for invalid railtype.
Definition rail_type.h:32
RoadType GetRoadTypeByLabel(RoadTypeLabel label, bool allow_alternate_labels)
Get the road type for a given label.
Definition road.cpp:253
RoadType GetRoadTypeInfoIndex(const RoadTypeInfo *rti)
Returns the railtype for a Railtype information.
Definition road.h:242
const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition road.h:230
RoadTypeSpriteGroup
Sprite groups for a roadtype.
Definition road.h:50
bool MayHaveRoad(Tile t)
Test whether a tile can have road/tram types.
Definition road_map.cpp:21
void SetRoadTypeRoad(Tile t, RoadType rt)
Set the road road type of a tile.
Definition road_map.h:559
void SetRoadTypeTram(Tile t, RoadType rt)
Set the tram road type of a tile.
Definition road_map.h:571
bool IsLevelCrossingTile(Tile t)
Return whether a tile is a level crossing tile.
Definition road_map.h:79
static debug_inline bool IsRoadDepotTile(Tile t)
Return whether a tile is a road depot tile.
Definition road_map.h:100
bool IsCrossingBarred(Tile t)
Check if the level crossing is barred.
Definition road_map.h:400
RoadType
The different roadtypes we support.
Definition road_type.h:23
@ INVALID_ROADTYPE
flag for invalid roadtype
Definition road_type.h:28
@ ROADTYPE_TRAM
Trams.
Definition road_type.h:26
@ ROADTYPE_ROAD
Basic road type.
Definition road_type.h:25
@ ROADTYPE_END
Used for iterations.
Definition road_type.h:27
@ ROADTYPE_BEGIN
Used for iterations.
Definition road_type.h:24
A number of safeguards to prevent using unsafe methods.
bool IsAnyRoadStop(Tile t)
Is the station at t a road station?
Definition of base types and functions in a cross-platform compatible way.
TimerGameCalendar::Date build_date
Date of construction.
Definition depot_base.h:26
Dynamic data of a loaded NewGRF.
Definition newgrf.h:115
std::vector< RoadTypeLabel > roadtype_list
Roadtype translation table (road)
Definition newgrf.h:145
std::vector< RoadTypeLabel > tramtype_list
Roadtype translation table (tram)
Definition newgrf.h:148
static IterateWrapper Iterate()
Returns an iterable ensemble of all Tiles.
Definition map_func.h:362
Interface for SpriteGroup-s to access the gamestate.
const GRFFile * grffile
GRFFile the resolved SpriteGroup belongs to.
const SpriteGroup * root_spritegroup
Root SpriteGroup to use for resolving.
Resolver object for road types.
RoadTypeScopeResolver roadtype_scope
Resolver for the roadtype scope.
RoadTypeResolverObject(const RoadTypeInfo *rti, TileIndex tile, TileContext context, RoadTypeSpriteGroup rtsg, uint32_t param1=0, uint32_t param2=0)
Resolver object for road types.
uint32_t GetDebugID() const override
Get an identifier for the item being resolved.
GrfSpecFeature GetFeature() const override
Get the feature number being resolved for.
TileContext context
Are we resolving sprites for the upper halftile, or on a bridge?
uint32_t GetVariable(uint8_t variable, uint32_t parameter, bool &available) const override
Get a variable value.
uint32_t GetRandomBits() const override
Get a few random bits.
TileIndex tile
Tracktile. For track on a bridge this is the southern bridgehead.
ResolverObject & ro
Surrounding resolver object.
Town data structure.
Definition town.h:52
static debug_inline TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition tile_map.h:96
static const uint TILE_SIZE
Tile size in world coordinates.
Definition tile_type.h:15
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
@ MP_ROAD
A tile with road (or tram tracks)
Definition tile_type.h:50
@ MP_STATION
A tile of a station.
Definition tile_type.h:53
@ MP_TUNNELBRIDGE
Tunnel entry/exit and bridge heads.
Definition tile_type.h:57
Definition of the game-calendar-timer.
Base of the town class.
Town * ClosestTownFromTile(TileIndex tile, uint threshold)
Return the town closest (in distance or ownership) to a given tile, within a given threshold.
HouseZone GetTownRadiusGroup(const Town *t, TileIndex tile)
Returns the bit corresponding to the town zone of the specified tile.
@ TRANSPORT_ROAD
Transport by road vehicle.
Functions that have tunnels and bridges in common.
TransportType GetTunnelBridgeTransportType(Tile t)
Tunnel: Get the transport type of the tunnel (road or rail) Bridge: Get the transport type of the bri...