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"
45 if (ctype >= cargo_list.size()) {
46 GrfMsg(1,
"TranslateCargo: Cargo type {} out of range (max {}), skipping.", ctype, (
unsigned int)_cur_gps.
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, std::string_view function)
70 if (groupid >
MAX_SPRITEGROUP || _cur_gps.spritegroups[groupid] ==
nullptr) {
71 GrfMsg(1,
"{}: Spritegroup 0x{:04X} out of range or empty, skipping.", function, groupid);
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, feature, 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_gps.spritegroups[groupid], last_engines);
134 SetCustomEngineSprites(engine, cargo_type, _cur_gps.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_gps.
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 CargoType cargo_type = TranslateCargo(GSF_STATIONS, ctype);
205 for (
auto &station : stations) {
206 StationSpec *statspec = station >= _cur_gps.
grffile->stations.size() ? nullptr : _cur_gps.
grffile->stations[station].get();
208 if (statspec ==
nullptr) {
209 GrfMsg(1,
"StationMapSpriteGroup: Station {} undefined, skipping", station);
218 if (!IsValidGroupID(groupid,
"StationMapSpriteGroup"))
return;
220 for (
auto &station : stations) {
221 StationSpec *statspec = station >= _cur_gps.
grffile->stations.size() ? nullptr : _cur_gps.
grffile->stations[station].get();
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_gps.
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++) {
255 if (!IsValidGroupID(groupid,
"TownHouseMapSpriteGroup"))
return;
257 for (
auto &house : houses) {
258 HouseSpec *hs = house >= _cur_gps.
grffile->housespec.size() ? nullptr : _cur_gps.
grffile->housespec[house].get();
260 GrfMsg(1,
"TownHouseMapSpriteGroup: House {} undefined, skipping.", house);
269 for (uint c = 0; c < cidcount; c++) {
275 GrfMsg(1,
"TownHouseMapSpriteGroup: Invalid cargo bitnum {} for houses, skipping.", ctype);
281static void IndustryMapSpriteGroup(
ByteReader &buf, uint8_t idcount)
283 if (_cur_gps.
grffile->industryspec.empty()) {
284 GrfMsg(1,
"IndustryMapSpriteGroup: No industries defined, skipping");
288 std::vector<uint16_t> industries;
289 industries.reserve(idcount);
290 for (uint i = 0; i < idcount; i++) {
295 if (!IsValidGroupID(groupid,
"IndustryMapSpriteGroup"))
return;
297 for (
auto &industry : industries) {
298 IndustrySpec *indsp = industry >= _cur_gps.
grffile->industryspec.size() ? nullptr : _cur_gps.
grffile->industryspec[industry].get();
299 if (indsp ==
nullptr) {
300 GrfMsg(1,
"IndustryMapSpriteGroup: Industry {} undefined, skipping", industry);
309 for (uint c = 0; c < cidcount; c++) {
315 GrfMsg(1,
"IndustryMapSpriteGroup: Invalid cargo bitnum {} for industries, skipping.", ctype);
321static void IndustrytileMapSpriteGroup(
ByteReader &buf, uint8_t idcount)
323 if (_cur_gps.
grffile->indtspec.empty()) {
324 GrfMsg(1,
"IndustrytileMapSpriteGroup: No industry tiles defined, skipping");
328 std::vector<uint16_t> indtiles;
329 indtiles.reserve(idcount);
330 for (uint i = 0; i < idcount; i++) {
335 if (!IsValidGroupID(groupid,
"IndustrytileMapSpriteGroup"))
return;
337 for (
auto &indtile : indtiles) {
339 if (indtsp ==
nullptr) {
340 GrfMsg(1,
"IndustrytileMapSpriteGroup: Industry tile {} undefined, skipping", indtile);
349 for (uint c = 0; c < cidcount; c++) {
355 GrfMsg(1,
"IndustrytileMapSpriteGroup: Invalid cargo bitnum {} for industry tiles, skipping.", ctype);
361static void CargoMapSpriteGroup(
ByteReader &buf, uint8_t idcount)
363 std::vector<uint16_t> cargoes;
364 cargoes.reserve(idcount);
365 for (uint i = 0; i < idcount; i++) {
371 buf.Skip(cidcount * 3);
374 if (!IsValidGroupID(groupid,
"CargoMapSpriteGroup"))
return;
376 for (
auto &cargo_type : cargoes) {
378 GrfMsg(1,
"CargoMapSpriteGroup: Cargo type {} out of range, skipping", cargo_type);
384 cs->group = _cur_gps.spritegroups[groupid];
388static void ObjectMapSpriteGroup(
ByteReader &buf, uint8_t idcount)
390 if (_cur_gps.
grffile->objectspec.empty()) {
391 GrfMsg(1,
"ObjectMapSpriteGroup: No object tiles defined, skipping");
395 std::vector<uint16_t> objects;
396 objects.reserve(idcount);
397 for (uint i = 0; i < idcount; i++) {
402 for (uint c = 0; c < cidcount; c++) {
405 if (!IsValidGroupID(groupid,
"ObjectMapSpriteGroup"))
continue;
409 GrfMsg(1,
"ObjectMapSpriteGroup: Invalid cargo bitnum {} for objects, skipping.", ctype);
413 for (
auto &
object : objects) {
414 ObjectSpec *spec =
object >= _cur_gps.
grffile->objectspec.size() ? nullptr : _cur_gps.
grffile->objectspec[object].get();
416 if (spec ==
nullptr) {
417 GrfMsg(1,
"ObjectMapSpriteGroup: Object {} undefined, skipping",
object);
426 if (!IsValidGroupID(groupid,
"ObjectMapSpriteGroup"))
return;
428 for (
auto &
object : objects) {
429 ObjectSpec *spec =
object >= _cur_gps.
grffile->objectspec.size() ? nullptr : _cur_gps.
grffile->objectspec[object].get();
431 if (spec ==
nullptr) {
432 GrfMsg(1,
"ObjectMapSpriteGroup: Object {} undefined, skipping",
object);
437 GrfMsg(1,
"ObjectMapSpriteGroup: Object {} mapped multiple times, skipping",
object);
447static void RailTypeMapSpriteGroup(
ByteReader &buf, uint8_t idcount)
449 std::vector<uint8_t> railtypes;
450 railtypes.reserve(idcount);
451 for (uint i = 0; i < idcount; i++) {
453 railtypes.push_back(id < RAILTYPE_END ? _cur_gps.grffile->railtype_map[
id] :
INVALID_RAILTYPE);
457 for (uint c = 0; c < cidcount; c++) {
460 if (!IsValidGroupID(groupid,
"RailTypeMapSpriteGroup"))
continue;
462 if (ctype >= RTSG_END)
continue;
465 for (
auto &railtype : railtypes) {
470 rti->
group[ctype] = _cur_gps.spritegroups[groupid];
479static void RoadTypeMapSpriteGroup(
ByteReader &buf, uint8_t idcount, RoadTramType rtt)
481 std::array<RoadType, ROADTYPE_END> &type_map = (rtt == RTT_TRAM) ? _cur_gps.
grffile->tramtype_map : _cur_gps.grffile->roadtype_map;
483 std::vector<uint8_t> roadtypes;
484 roadtypes.reserve(idcount);
485 for (uint i = 0; i < idcount; i++) {
491 for (uint c = 0; c < cidcount; c++) {
494 if (!IsValidGroupID(groupid,
"RoadTypeMapSpriteGroup"))
continue;
496 if (ctype >= ROTSG_END)
continue;
499 for (
auto &roadtype : roadtypes) {
504 rti->
group[ctype] = _cur_gps.spritegroups[groupid];
513static void AirportMapSpriteGroup(
ByteReader &buf, uint8_t idcount)
515 if (_cur_gps.
grffile->airportspec.empty()) {
516 GrfMsg(1,
"AirportMapSpriteGroup: No airports defined, skipping");
520 std::vector<uint16_t> airports;
521 airports.reserve(idcount);
522 for (uint i = 0; i < idcount; i++) {
527 if (!IsValidGroupID(groupid,
"AirportMapSpriteGroup"))
return;
529 for (
auto &airport : airports) {
530 AirportSpec *as = airport >= _cur_gps.
grffile->airportspec.size() ? nullptr : _cur_gps.
grffile->airportspec[airport].get();
532 GrfMsg(1,
"AirportMapSpriteGroup: Airport {} undefined, skipping", airport);
541 for (uint c = 0; c < cidcount; c++) {
547 GrfMsg(1,
"AirportMapSpriteGroup: Invalid cargo bitnum {} for airports, skipping.", ctype);
553static void AirportTileMapSpriteGroup(
ByteReader &buf, uint8_t idcount)
555 if (_cur_gps.
grffile->airtspec.empty()) {
556 GrfMsg(1,
"AirportTileMapSpriteGroup: No airport tiles defined, skipping");
560 std::vector<uint16_t> airptiles;
561 airptiles.reserve(idcount);
562 for (uint i = 0; i < idcount; i++) {
567 if (!IsValidGroupID(groupid,
"AirportTileMapSpriteGroup"))
return;
569 for (
auto &airptile : airptiles) {
571 if (airtsp ==
nullptr) {
572 GrfMsg(1,
"AirportTileMapSpriteGroup: Airport tile {} undefined, skipping", airptile);
581 for (uint c = 0; c < cidcount; c++) {
587 GrfMsg(1,
"AirportTileMapSpriteGroup: Invalid cargo bitnum {} for airport tiles, skipping.", ctype);
593static void RoadStopMapSpriteGroup(
ByteReader &buf, uint8_t idcount)
595 if (_cur_gps.
grffile->roadstops.empty()) {
596 GrfMsg(1,
"RoadStopMapSpriteGroup: No roadstops defined, skipping");
600 std::vector<uint16_t> roadstops;
601 roadstops.reserve(idcount);
602 for (uint i = 0; i < idcount; i++) {
607 for (uint c = 0; c < cidcount; c++) {
610 if (!IsValidGroupID(groupid,
"RoadStopMapSpriteGroup"))
continue;
612 CargoType cargo_type = TranslateCargo(GSF_ROADSTOPS, ctype);
615 for (
auto &roadstop : roadstops) {
616 RoadStopSpec *roadstopspec = roadstop >= _cur_gps.
grffile->roadstops.size() ? nullptr : _cur_gps.
grffile->roadstops[roadstop].get();
618 if (roadstopspec ==
nullptr) {
619 GrfMsg(1,
"RoadStopMapSpriteGroup: Road stop {} undefined, skipping", roadstop);
628 if (!IsValidGroupID(groupid,
"RoadStopMapSpriteGroup"))
return;
630 for (
auto &roadstop : roadstops) {
631 RoadStopSpec *roadstopspec = roadstop >= _cur_gps.
grffile->roadstops.size() ? nullptr : _cur_gps.
grffile->roadstops[roadstop].get();
633 if (roadstopspec ==
nullptr) {
634 GrfMsg(1,
"RoadStopMapSpriteGroup: Road stop {} undefined, skipping.", roadstop);
639 GrfMsg(1,
"RoadStopMapSpriteGroup: Road stop {} mapped multiple times, skipping", roadstop);
650static void BadgeMapSpriteGroup(
ByteReader &buf, uint8_t idcount)
652 if (_cur_gps.
grffile->badge_map.empty()) {
653 GrfMsg(1,
"BadgeMapSpriteGroup: No badges defined, skipping");
657 std::vector<uint16_t> local_ids;
658 local_ids.reserve(idcount);
659 for (uint i = 0; i < idcount; i++) {
664 for (uint c = 0; c < cidcount; c++) {
667 if (!IsValidGroupID(groupid,
"BadgeMapSpriteGroup"))
continue;
669 if (ctype >= GSF_END)
continue;
671 for (
const auto &local_id : local_ids) {
672 auto found = _cur_gps.
grffile->badge_map.find(local_id);
673 if (found == std::end(_cur_gps.
grffile->badge_map)) {
674 GrfMsg(1,
"BadgeMapSpriteGroup: Badge {} undefined, skipping", local_id);
678 auto &badge = *
GetBadge(found->second);
679 badge.grf_prop.SetSpriteGroup(
static_cast<GrfSpecFeature>(ctype), _cur_gps.spritegroups[groupid]);
684 if (!IsValidGroupID(groupid,
"BadgeMapSpriteGroup"))
return;
686 for (
auto &local_id : local_ids) {
687 auto found = _cur_gps.
grffile->badge_map.find(local_id);
688 if (found == std::end(_cur_gps.
grffile->badge_map)) {
689 GrfMsg(1,
"BadgeMapSpriteGroup: Badge {} undefined, skipping", local_id);
693 auto &badge = *
GetBadge(found->second);
694 badge.grf_prop.SetSpriteGroup(
GSF_DEFAULT, _cur_gps.spritegroups[groupid]);
695 badge.grf_prop.SetGRFFile(_cur_gps.
grffile);
696 badge.grf_prop.local_id = local_id;
701static void FeatureMapSpriteGroup(
ByteReader &buf)
720 if (feature >= GSF_END) {
721 GrfMsg(1,
"FeatureMapSpriteGroup: Unsupported feature 0x{:02X}, skipping", feature);
730 if (!IsValidGroupID(groupid,
"FeatureMapSpriteGroup"))
return;
732 GrfMsg(6,
"FeatureMapSpriteGroup: Adding generic feature callback for feature 0x{:02X}", feature);
741 GrfMsg(6,
"FeatureMapSpriteGroup: Feature 0x{:02X}, {} ids", feature, idcount);
745 case GSF_ROADVEHICLES:
748 VehicleMapSpriteGroup(buf, feature, idcount);
752 CanalMapSpriteGroup(buf, idcount);
756 StationMapSpriteGroup(buf, idcount);
760 TownHouseMapSpriteGroup(buf, idcount);
764 IndustryMapSpriteGroup(buf, idcount);
767 case GSF_INDUSTRYTILES:
768 IndustrytileMapSpriteGroup(buf, idcount);
772 CargoMapSpriteGroup(buf, idcount);
776 AirportMapSpriteGroup(buf, idcount);
780 ObjectMapSpriteGroup(buf, idcount);
784 RailTypeMapSpriteGroup(buf, idcount);
788 RoadTypeMapSpriteGroup(buf, idcount, RTT_ROAD);
792 RoadTypeMapSpriteGroup(buf, idcount, RTT_TRAM);
795 case GSF_AIRPORTTILES:
796 AirportTileMapSpriteGroup(buf, idcount);
800 RoadStopMapSpriteGroup(buf, idcount);
804 BadgeMapSpriteGroup(buf, idcount);
808 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.
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.
constexpr Timpl & Set()
Set all bits.
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.
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.
@ GSF_DEFAULT
Unspecified feature, default badge.
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.
StandardSpriteGroup
Standard sprite groups.
@ Purchase
Used before an entity exists.
@ Default
Default type used when no more-specific group matches.
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(GrfSpecFeature 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.
SubstituteGRFFileProps grf_prop
Properties related to the grf file.
Defines the data structure of each individual tile of an airport.
SubstituteGRFFileProps grf_prop
properties related the the grf file
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.
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(Tkey 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.
std::vector< CargoLabel > cargo_list
Cargo translation table (local ID -> label)
GrfSpecFeatures grf_features
Bitset of GrfSpecFeature the grf uses.
GRFFile * grffile
Currently processed GRF file.
SubstituteGRFFileProps grf_prop
Properties related the the grf file.
Defines the data structure for constructing industry.
SubstituteGRFFileProps grf_prop
properties related to the grf file
Defines the data structure of each individual tile of an industry.
SubstituteGRFFileProps grf_prop
properties related to the grf file
Allow incrementing of ObjectClassID variables.
StandardGRFFileProps grf_prop
Properties related the the grf file.
Tindex index
Index of this pool item.
CargoGRFFileProps grf_prop
Link to NewGRF.
CargoGRFFileProps grf_prop
Link to NewGRF.
void SetSpriteGroup(Tkey index, const SpriteGroup *spritegroup)
Set the SpriteGroup at the specified index.
VehicleType
Available vehicle types.