14#include "../newgrf_engine.h"
15#include "../newgrf_badge.h"
16#include "../newgrf_badge_type.h"
17#include "../newgrf_cargo.h"
18#include "../newgrf_house.h"
19#include "../newgrf_station.h"
20#include "../industrytype.h"
21#include "../newgrf_canal.h"
22#include "../newgrf_airporttiles.h"
23#include "../newgrf_airport.h"
24#include "../newgrf_object.h"
26#include "../vehicle_base.h"
28#include "../newgrf_roadstop.h"
33#include "../safeguards.h"
36static CargoType TranslateCargo(uint8_t feature, uint8_t ctype)
45 if (ctype >= cargo_list.size()) {
46 GrfMsg(1,
"TranslateCargo: Cargo type {} out of range (max {}), skipping.", ctype, (
unsigned int)_cur.
grffile->
cargo_list.size() - 1);
53 GrfMsg(5,
"TranslateCargo: Cargo type {} not available in this climate, skipping.", ctype);
57 CargoType cargo_type = GetCargoTypeByLabel(cl);
59 GrfMsg(5,
"TranslateCargo: Cargo '{:c}{:c}{:c}{:c}' unsupported, skipping.",
GB(cl.base(), 24, 8),
GB(cl.base(), 16, 8),
GB(cl.base(), 8, 8),
GB(cl.base(), 0, 8));
63 GrfMsg(6,
"TranslateCargo: Cargo '{:c}{:c}{:c}{:c}' mapped to cargo type {}.",
GB(cl.base(), 24, 8),
GB(cl.base(), 16, 8),
GB(cl.base(), 8, 8),
GB(cl.base(), 0, 8), cargo_type);
68static bool IsValidGroupID(uint16_t groupid,
const char *function)
70 if (groupid >
MAX_SPRITEGROUP || _cur.spritegroups[groupid] ==
nullptr) {
71 GrfMsg(1,
"{}: Spritegroup 0x{:04X} out of range or empty, skipping.", function, groupid);
78static void VehicleMapSpriteGroup(
ByteReader &buf, uint8_t feature, uint8_t idcount)
80 static std::vector<EngineID> last_engines;
87 idcount =
GB(idcount, 0, 7);
89 if (last_engines.empty()) {
90 GrfMsg(0,
"VehicleMapSpriteGroup: WagonOverride: No engine to do override with");
94 GrfMsg(6,
"VehicleMapSpriteGroup: WagonOverride: {} engines, {} wagons", last_engines.size(), idcount);
96 last_engines.resize(idcount);
99 std::vector<EngineID> engines;
100 engines.reserve(idcount);
101 for (uint i = 0; i < idcount; i++) {
107 HandleChangeInfoResult(
"VehicleMapSpriteGroup",
CIR_INVALID_ID, 0, 0);
111 engines.push_back(e->
index);
112 if (!wagover) last_engines[i] = engines[i];
116 for (uint c = 0; c < cidcount; c++) {
119 if (!IsValidGroupID(groupid,
"VehicleMapSpriteGroup"))
continue;
121 GrfMsg(8,
"VehicleMapSpriteGroup: * [{}] Cargo type 0x{:X}, group id 0x{:02X}", c, ctype, groupid);
123 CargoType cargo_type = TranslateCargo(feature, ctype);
126 for (uint i = 0; i < idcount; i++) {
129 GrfMsg(7,
"VehicleMapSpriteGroup: [{}] Engine {}...", i, engine);
132 SetWagonOverrideSprites(engine, cargo_type, _cur.spritegroups[groupid], last_engines);
134 SetCustomEngineSprites(engine, cargo_type, _cur.spritegroups[groupid]);
140 if (!IsValidGroupID(groupid,
"VehicleMapSpriteGroup"))
return;
142 GrfMsg(8,
"-- Default group id 0x{:04X}", groupid);
144 for (uint i = 0; i < idcount; i++) {
157static void CanalMapSpriteGroup(
ByteReader &buf, uint8_t idcount)
159 std::vector<uint16_t> cfs;
160 cfs.reserve(idcount);
161 for (uint i = 0; i < idcount; i++) {
166 buf.Skip(cidcount * 3);
169 if (!IsValidGroupID(groupid,
"CanalMapSpriteGroup"))
return;
171 for (
auto &cf : cfs) {
173 GrfMsg(1,
"CanalMapSpriteGroup: Canal subset {} out of range, skipping", cf);
183static void StationMapSpriteGroup(
ByteReader &buf, uint8_t idcount)
185 if (_cur.
grffile->stations.empty()) {
186 GrfMsg(1,
"StationMapSpriteGroup: No stations defined, skipping");
190 std::vector<uint16_t> stations;
191 stations.reserve(idcount);
192 for (uint i = 0; i < idcount; i++) {
197 for (uint c = 0; c < cidcount; c++) {
200 if (!IsValidGroupID(groupid,
"StationMapSpriteGroup"))
continue;
202 ctype = TranslateCargo(GSF_STATIONS, ctype);
205 for (
auto &station : stations) {
208 if (statspec ==
nullptr) {
209 GrfMsg(1,
"StationMapSpriteGroup: Station {} undefined, skipping", station);
218 if (!IsValidGroupID(groupid,
"StationMapSpriteGroup"))
return;
220 for (
auto &station : stations) {
223 if (statspec ==
nullptr) {
224 GrfMsg(1,
"StationMapSpriteGroup: Station {} undefined, skipping", station);
229 GrfMsg(1,
"StationMapSpriteGroup: Station {} mapped multiple times, skipping", station);
241static void TownHouseMapSpriteGroup(
ByteReader &buf, uint8_t idcount)
243 if (_cur.
grffile->housespec.empty()) {
244 GrfMsg(1,
"TownHouseMapSpriteGroup: No houses defined, skipping");
248 std::vector<uint16_t> houses;
249 houses.reserve(idcount);
250 for (uint i = 0; i < idcount; i++) {
256 buf.Skip(cidcount * 3);
259 if (!IsValidGroupID(groupid,
"TownHouseMapSpriteGroup"))
return;
261 for (
auto &house : houses) {
265 GrfMsg(1,
"TownHouseMapSpriteGroup: House {} undefined, skipping.", house);
273static void IndustryMapSpriteGroup(
ByteReader &buf, uint8_t idcount)
275 if (_cur.
grffile->industryspec.empty()) {
276 GrfMsg(1,
"IndustryMapSpriteGroup: No industries defined, skipping");
280 std::vector<uint16_t> industries;
281 industries.reserve(idcount);
282 for (uint i = 0; i < idcount; i++) {
288 buf.Skip(cidcount * 3);
291 if (!IsValidGroupID(groupid,
"IndustryMapSpriteGroup"))
return;
293 for (
auto &industry : industries) {
296 if (indsp ==
nullptr) {
297 GrfMsg(1,
"IndustryMapSpriteGroup: Industry {} undefined, skipping", industry);
305static void IndustrytileMapSpriteGroup(
ByteReader &buf, uint8_t idcount)
307 if (_cur.
grffile->indtspec.empty()) {
308 GrfMsg(1,
"IndustrytileMapSpriteGroup: No industry tiles defined, skipping");
312 std::vector<uint16_t> indtiles;
313 indtiles.reserve(idcount);
314 for (uint i = 0; i < idcount; i++) {
320 buf.Skip(cidcount * 3);
323 if (!IsValidGroupID(groupid,
"IndustrytileMapSpriteGroup"))
return;
325 for (
auto &indtile : indtiles) {
328 if (indtsp ==
nullptr) {
329 GrfMsg(1,
"IndustrytileMapSpriteGroup: Industry tile {} undefined, skipping", indtile);
337static void CargoMapSpriteGroup(
ByteReader &buf, uint8_t idcount)
339 std::vector<uint16_t> cargoes;
340 cargoes.reserve(idcount);
341 for (uint i = 0; i < idcount; i++) {
347 buf.Skip(cidcount * 3);
350 if (!IsValidGroupID(groupid,
"CargoMapSpriteGroup"))
return;
352 for (
auto &cargo_type : cargoes) {
354 GrfMsg(1,
"CargoMapSpriteGroup: Cargo type {} out of range, skipping", cargo_type);
360 cs->group = _cur.spritegroups[groupid];
364static void ObjectMapSpriteGroup(
ByteReader &buf, uint8_t idcount)
366 if (_cur.
grffile->objectspec.empty()) {
367 GrfMsg(1,
"ObjectMapSpriteGroup: No object tiles defined, skipping");
371 std::vector<uint16_t> objects;
372 objects.reserve(idcount);
373 for (uint i = 0; i < idcount; i++) {
378 for (uint c = 0; c < cidcount; c++) {
381 if (!IsValidGroupID(groupid,
"ObjectMapSpriteGroup"))
continue;
385 GrfMsg(1,
"ObjectMapSpriteGroup: Invalid cargo bitnum {} for objects, skipping.", ctype);
389 for (
auto &
object : objects) {
392 if (spec ==
nullptr) {
393 GrfMsg(1,
"ObjectMapSpriteGroup: Object {} undefined, skipping",
object);
402 if (!IsValidGroupID(groupid,
"ObjectMapSpriteGroup"))
return;
404 for (
auto &
object : objects) {
407 if (spec ==
nullptr) {
408 GrfMsg(1,
"ObjectMapSpriteGroup: Object {} undefined, skipping",
object);
413 GrfMsg(1,
"ObjectMapSpriteGroup: Object {} mapped multiple times, skipping",
object);
423static void RailTypeMapSpriteGroup(
ByteReader &buf, uint8_t idcount)
425 std::vector<uint8_t> railtypes;
426 railtypes.reserve(idcount);
427 for (uint i = 0; i < idcount; i++) {
429 railtypes.push_back(id < RAILTYPE_END ? _cur.grffile->railtype_map[
id] :
INVALID_RAILTYPE);
433 for (uint c = 0; c < cidcount; c++) {
436 if (!IsValidGroupID(groupid,
"RailTypeMapSpriteGroup"))
continue;
438 if (ctype >= RTSG_END)
continue;
441 for (
auto &railtype : railtypes) {
446 rti->
group[ctype] = _cur.spritegroups[groupid];
455static void RoadTypeMapSpriteGroup(
ByteReader &buf, uint8_t idcount, RoadTramType rtt)
457 std::array<RoadType, ROADTYPE_END> &type_map = (rtt == RTT_TRAM) ? _cur.
grffile->tramtype_map : _cur.grffile->roadtype_map;
459 std::vector<uint8_t> roadtypes;
460 roadtypes.reserve(idcount);
461 for (uint i = 0; i < idcount; i++) {
467 for (uint c = 0; c < cidcount; c++) {
470 if (!IsValidGroupID(groupid,
"RoadTypeMapSpriteGroup"))
continue;
472 if (ctype >= ROTSG_END)
continue;
475 for (
auto &roadtype : roadtypes) {
480 rti->
group[ctype] = _cur.spritegroups[groupid];
489static void AirportMapSpriteGroup(
ByteReader &buf, uint8_t idcount)
491 if (_cur.
grffile->airportspec.empty()) {
492 GrfMsg(1,
"AirportMapSpriteGroup: No airports defined, skipping");
496 std::vector<uint16_t> airports;
497 airports.reserve(idcount);
498 for (uint i = 0; i < idcount; i++) {
504 buf.Skip(cidcount * 3);
507 if (!IsValidGroupID(groupid,
"AirportMapSpriteGroup"))
return;
509 for (
auto &airport : airports) {
513 GrfMsg(1,
"AirportMapSpriteGroup: Airport {} undefined, skipping", airport);
521static void AirportTileMapSpriteGroup(
ByteReader &buf, uint8_t idcount)
523 if (_cur.
grffile->airtspec.empty()) {
524 GrfMsg(1,
"AirportTileMapSpriteGroup: No airport tiles defined, skipping");
528 std::vector<uint16_t> airptiles;
529 airptiles.reserve(idcount);
530 for (uint i = 0; i < idcount; i++) {
536 buf.Skip(cidcount * 3);
539 if (!IsValidGroupID(groupid,
"AirportTileMapSpriteGroup"))
return;
541 for (
auto &airptile : airptiles) {
544 if (airtsp ==
nullptr) {
545 GrfMsg(1,
"AirportTileMapSpriteGroup: Airport tile {} undefined, skipping", airptile);
553static void RoadStopMapSpriteGroup(
ByteReader &buf, uint8_t idcount)
555 if (_cur.
grffile->roadstops.empty()) {
556 GrfMsg(1,
"RoadStopMapSpriteGroup: No roadstops defined, skipping");
560 std::vector<uint16_t> roadstops;
561 roadstops.reserve(idcount);
562 for (uint i = 0; i < idcount; i++) {
567 for (uint c = 0; c < cidcount; c++) {
570 if (!IsValidGroupID(groupid,
"RoadStopMapSpriteGroup"))
continue;
572 ctype = TranslateCargo(GSF_ROADSTOPS, ctype);
575 for (
auto &roadstop : roadstops) {
578 if (roadstopspec ==
nullptr) {
579 GrfMsg(1,
"RoadStopMapSpriteGroup: Road stop {} undefined, skipping", roadstop);
588 if (!IsValidGroupID(groupid,
"RoadStopMapSpriteGroup"))
return;
590 for (
auto &roadstop : roadstops) {
593 if (roadstopspec ==
nullptr) {
594 GrfMsg(1,
"RoadStopMapSpriteGroup: Road stop {} undefined, skipping.", roadstop);
599 GrfMsg(1,
"RoadStopMapSpriteGroup: Road stop {} mapped multiple times, skipping", roadstop);
610static void BadgeMapSpriteGroup(
ByteReader &buf, uint8_t idcount)
612 if (_cur.
grffile->badge_map.empty()) {
613 GrfMsg(1,
"BadgeMapSpriteGroup: No badges defined, skipping");
617 std::vector<uint16_t> local_ids;
618 local_ids.reserve(idcount);
619 for (uint i = 0; i < idcount; i++) {
624 for (uint c = 0; c < cidcount; c++) {
627 if (!IsValidGroupID(groupid,
"BadgeMapSpriteGroup"))
continue;
629 if (ctype >= GSF_END)
continue;
631 for (
const auto &local_id : local_ids) {
632 auto found = _cur.
grffile->badge_map.find(local_id);
633 if (found == std::end(_cur.
grffile->badge_map)) {
634 GrfMsg(1,
"BadgeMapSpriteGroup: Badge {} undefined, skipping", local_id);
638 auto &badge = *
GetBadge(found->second);
639 badge.grf_prop.SetSpriteGroup(ctype, _cur.spritegroups[groupid]);
644 if (!IsValidGroupID(groupid,
"BadgeMapSpriteGroup"))
return;
646 for (
auto &local_id : local_ids) {
647 auto found = _cur.
grffile->badge_map.find(local_id);
648 if (found == std::end(_cur.
grffile->badge_map)) {
649 GrfMsg(1,
"BadgeMapSpriteGroup: Badge {} undefined, skipping", local_id);
653 auto &badge = *
GetBadge(found->second);
654 badge.grf_prop.SetSpriteGroup(GSF_END, _cur.spritegroups[groupid]);
655 badge.grf_prop.SetGRFFile(_cur.
grffile);
656 badge.grf_prop.local_id = local_id;
661static void FeatureMapSpriteGroup(
ByteReader &buf)
680 if (feature >= GSF_END) {
681 GrfMsg(1,
"FeatureMapSpriteGroup: Unsupported feature 0x{:02X}, skipping", feature);
690 if (!IsValidGroupID(groupid,
"FeatureMapSpriteGroup"))
return;
692 GrfMsg(6,
"FeatureMapSpriteGroup: Adding generic feature callback for feature 0x{:02X}", feature);
701 GrfMsg(6,
"FeatureMapSpriteGroup: Feature 0x{:02X}, {} ids", feature, idcount);
705 case GSF_ROADVEHICLES:
708 VehicleMapSpriteGroup(buf, feature, idcount);
712 CanalMapSpriteGroup(buf, idcount);
716 StationMapSpriteGroup(buf, idcount);
720 TownHouseMapSpriteGroup(buf, idcount);
724 IndustryMapSpriteGroup(buf, idcount);
727 case GSF_INDUSTRYTILES:
728 IndustrytileMapSpriteGroup(buf, idcount);
732 CargoMapSpriteGroup(buf, idcount);
736 AirportMapSpriteGroup(buf, idcount);
740 ObjectMapSpriteGroup(buf, idcount);
744 RailTypeMapSpriteGroup(buf, idcount);
748 RoadTypeMapSpriteGroup(buf, idcount, RTT_ROAD);
752 RoadTypeMapSpriteGroup(buf, idcount, RTT_TRAM);
755 case GSF_AIRPORTTILES:
756 AirportTileMapSpriteGroup(buf, idcount);
760 RoadStopMapSpriteGroup(buf, idcount);
764 BadgeMapSpriteGroup(buf, idcount);
768 GrfMsg(1,
"FeatureMapSpriteGroup: Unsupported feature 0x{:02X}, skipping", feature);
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit 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.
static constexpr CargoLabel CT_INVALID
Invalid cargo type.
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
static const CargoType NUM_CARGO
Maximum number of cargo types in a game.
Class to read from a NewGRF file.
uint16_t ReadWord()
Read a single Word (16 bits).
uint16_t ReadExtendedByte()
Read a single Extended Byte (8 or 16 bits).
uint8_t ReadByte()
Read a single byte (8 bits).
static void Assign(Tspec *spec)
Assign a spec to one of the classes.
This struct contains all the info that is needed to draw and construct tracks.
const SpriteGroup * group[RTSG_END]
Sprite groups for resolving sprites.
const GRFFile * grffile[RTSG_END]
NewGRF providing the Action3 for the railtype.
const SpriteGroup * group[ROTSG_END]
Sprite groups for resolving sprites.
const GRFFile * grffile[ROTSG_END]
NewGRF providing the Action3 for the roadtype.
static constexpr CargoType SG_PURCHASE
Used in purchase lists before an item exists.
static constexpr CargoType SG_DEFAULT
Default type used when no more-specific cargo matches.
static constexpr CargoType SG_DEFAULT_NA
Used only by stations and roads when no more-specific cargo matches.
std::span< const CargoLabel > GetCargoTranslationTable(const GRFFile &grffile)
Get the cargo translation table to use for the given GRF file.
void GRFUnsafe(ByteReader &)
Set the current NewGRF as unsafe for static use.
Engine * GetNewEngine(const GRFFile *file, VehicleType type, uint16_t internal_id, bool static_access)
Returns the engine associated to a certain internal_id, resp.
Badge * GetBadge(BadgeID index)
Get a badge if it exists.
NewGRF buffer reader definition.
std::array< WaterFeature, CF_END > _water_feature
Table of canal 'feature' sprite groups.
void SetEngineGRF(EngineID engine, const GRFFile *file)
Tie a GRFFile entry to an engine, to allow us to retrieve GRF parameters etc during a game.
void AddGenericCallback(uint8_t feature, const GRFFile *file, const SpriteGroup *group)
Add a generic feature callback sprite group to the appropriate feature list.
NewGRF internal processing state.
@ CIR_INVALID_ID
Attempt to modify an invalid ID.
static constexpr uint MAX_SPRITEGROUP
Maximum GRF-local ID for a spritegroup.
NewGRF internal processing state for vehicles.
@ RAILTYPE_END
Used for iterations.
@ INVALID_RAILTYPE
Flag for invalid railtype.
@ INVALID_ROADTYPE
flag for invalid roadtype
@ ROADTYPE_END
Used for iterations.
Defines the data structure for an airport.
struct GRFFileProps grf_prop
Properties related to the grf file.
Defines the data structure of each individual tile of an airport.
GRFFileProps grf_prop
properties related the the grf file
Specification of a cargo type.
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
const struct GRFFile * grffile
NewGRF where group belongs to.
void SetSpriteGroup(size_t index, const struct SpriteGroup *spritegroup)
Set the SpriteGroup at the specified index.
uint16_t local_id
id defined by the grf file for this entity
void SetGRFFile(const struct GRFFile *grffile)
Set the NewGRF file, and its grfid, associated with grf props.
bool HasGrfFile() const
Test if this entity was introduced by NewGRF.
uint32_t grf_features
Bitset of GrfSpecFeature the grf uses.
std::vector< CargoLabel > cargo_list
Cargo translation table (local ID -> label)
GRFFile * grffile
Currently processed GRF file.
GRFFileProps grf_prop
Properties related the the grf file.
Defines the data structure for constructing industry.
GRFFileProps grf_prop
properties related to the grf file
Defines the data structure of each individual tile of an industry.
GRFFileProps grf_prop
properties related to the grf file
Allow incrementing of ObjectClassID variables.
FixedGRFFileProps< 2 > grf_prop
Properties related the the grf file.
Tindex index
Index of this pool item.
VariableGRFFileProps grf_prop
Properties related the the grf file.
VariableGRFFileProps grf_prop
Properties related the the grf file.
void SetSpriteGroup(size_t index, const struct SpriteGroup *spritegroup)
Set the SpriteGroup at the specified index.
VehicleType
Available vehicle types.