OpenTTD Source 20260206-master-g4d4e37dbf1
newgrf_act4.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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "../stdafx.h"
11#include "../debug.h"
12#include "../engine_base.h"
13#include "../house.h"
14#include "../newgrf_engine.h"
15#include "../newgrf_text.h"
16#include "../newgrf_badge.h"
18#include "../newgrf_cargo.h"
19#include "../newgrf_station.h"
21#include "../string_func.h"
22#include "newgrf_bytereader.h"
24#include "newgrf_internal.h"
25
26#include "table/strings.h"
27
28#include "../safeguards.h"
29
30/* Action 0x04 */
31static void FeatureNewName(ByteReader &buf)
32{
33 /* <04> <veh-type> <language-id> <num-veh> <offset> <data...>
34 *
35 * B veh-type see action 0 (as 00..07, + 0A
36 * But IF veh-type = 48, then generic text
37 * B language-id If bit 6 is set, This is the extended language scheme,
38 * with up to 64 language.
39 * Otherwise, it is a mapping where set bits have meaning
40 * 0 = american, 1 = english, 2 = german, 3 = french, 4 = spanish
41 * Bit 7 set means this is a generic text, not a vehicle one (or else)
42 * B num-veh number of vehicles which are getting a new name
43 * B/W offset number of the first vehicle that gets a new name
44 * Byte : ID of vehicle to change
45 * Word : ID of string to change/add
46 * S data new texts, each of them zero-terminated, after
47 * which the next name begins. */
48
49 bool new_scheme = _cur_gps.grffile->grf_version >= 7;
50
51 GrfSpecFeature feature{buf.ReadByte()};
52 if (feature >= GSF_END && feature != GSF_ORIGINAL_STRINGS) {
53 GrfMsg(1, "FeatureNewName: Unsupported feature 0x{:02X}, skipping", feature);
54 return;
55 }
56
57 uint8_t lang = buf.ReadByte();
58 uint8_t num = buf.ReadByte();
59 bool generic = HasBit(lang, 7);
60 uint16_t id;
61 if (generic) {
62 id = buf.ReadWord();
63 } else if (feature <= GSF_AIRCRAFT || feature == GSF_BADGES) {
64 id = buf.ReadExtendedByte();
65 } else {
66 id = buf.ReadByte();
67 }
68
69 ClrBit(lang, 7);
70
71 uint16_t endid = id + num;
72
73 GrfMsg(6, "FeatureNewName: About to rename engines {}..{} (feature 0x{:02X}) in language 0x{:02X}",
74 id, endid, feature, lang);
75
76 /* Feature overlay to make non-generic strings unique in their feature. We use feature + 1 so that generic strings stay as they are. */
77 uint32_t feature_overlay = generic ? 0 : ((feature + 1) << 16);
78
79 for (; id < endid && buf.HasData(); id++) {
80 std::string_view name = buf.ReadString();
81 GrfMsg(8, "FeatureNewName: 0x{:04X} <- {}", id, StrMakeValid(name));
82
83 switch (feature) {
84 case GSF_TRAINS:
85 case GSF_ROADVEHICLES:
86 case GSF_SHIPS:
87 case GSF_AIRCRAFT:
88 if (!generic) {
89 Engine *e = GetNewEngine(_cur_gps.grffile, (VehicleType)feature, id, _cur_gps.grfconfig->flags.Test(GRFConfigFlag::Static));
90 if (e == nullptr) break;
91 StringID string = AddGRFString(_cur_gps.grffile->grfid, GRFStringID{feature_overlay | e->index.base()}, lang, new_scheme, false, name, e->info.string_id);
92 e->info.string_id = string;
93 } else {
94 AddGRFString(_cur_gps.grffile->grfid, GRFStringID{id}, lang, new_scheme, true, name, STR_UNDEFINED);
95 }
96 break;
97
98 case GSF_BADGES: {
99 if (!generic) {
100 auto found = _cur_gps.grffile->badge_map.find(id);
101 if (found == std::end(_cur_gps.grffile->badge_map)) {
102 GrfMsg(1, "FeatureNewName: Attempt to name undefined badge 0x{:X}, ignoring", id);
103 } else {
104 Badge &badge = *GetBadge(found->second);
105 badge.name = AddGRFString(_cur_gps.grffile->grfid, GRFStringID{feature_overlay | id}, lang, true, false, name, STR_UNDEFINED);
106 }
107 } else {
108 AddGRFString(_cur_gps.grffile->grfid, GRFStringID{id}, lang, new_scheme, true, name, STR_UNDEFINED);
109 }
110 break;
111 }
112
113 default:
114 if (IsInsideMM(id, 0xD000, 0xD400) || IsInsideMM(id, 0xD800, 0x10000)) {
115 AddGRFString(_cur_gps.grffile->grfid, GRFStringID{id}, lang, new_scheme, true, name, STR_UNDEFINED);
116 break;
117 }
118
119 switch (GB(id, 8, 8)) {
120 case 0xC4: // Station class name
121 if (GB(id, 0, 8) >= _cur_gps.grffile->stations.size() || _cur_gps.grffile->stations[GB(id, 0, 8)] == nullptr) {
122 GrfMsg(1, "FeatureNewName: Attempt to name undefined station 0x{:X}, ignoring", GB(id, 0, 8));
123 } else {
124 StationClassID class_index = _cur_gps.grffile->stations[GB(id, 0, 8)]->class_index;
125 StationClass::Get(class_index)->name = AddGRFString(_cur_gps.grffile->grfid, GRFStringID{id}, lang, new_scheme, false, name, STR_UNDEFINED);
126 }
127 break;
128
129 case 0xC5: // Station name
130 if (GB(id, 0, 8) >= _cur_gps.grffile->stations.size() || _cur_gps.grffile->stations[GB(id, 0, 8)] == nullptr) {
131 GrfMsg(1, "FeatureNewName: Attempt to name undefined station 0x{:X}, ignoring", GB(id, 0, 8));
132 } else {
133 _cur_gps.grffile->stations[GB(id, 0, 8)]->name = AddGRFString(_cur_gps.grffile->grfid, GRFStringID{id}, lang, new_scheme, false, name, STR_UNDEFINED);
134 }
135 break;
136
137 case 0xC7: // Airporttile name
138 if (GB(id, 0, 8) >= _cur_gps.grffile->airtspec.size() || _cur_gps.grffile->airtspec[GB(id, 0, 8)] == nullptr) {
139 GrfMsg(1, "FeatureNewName: Attempt to name undefined airport tile 0x{:X}, ignoring", GB(id, 0, 8));
140 } else {
141 _cur_gps.grffile->airtspec[GB(id, 0, 8)]->name = AddGRFString(_cur_gps.grffile->grfid, GRFStringID{id}, lang, new_scheme, false, name, STR_UNDEFINED);
142 }
143 break;
144
145 case 0xC9: // House name
146 if (GB(id, 0, 8) >= _cur_gps.grffile->housespec.size() || _cur_gps.grffile->housespec[GB(id, 0, 8)] == nullptr) {
147 GrfMsg(1, "FeatureNewName: Attempt to name undefined house 0x{:X}, ignoring.", GB(id, 0, 8));
148 } else {
149 _cur_gps.grffile->housespec[GB(id, 0, 8)]->building_name = AddGRFString(_cur_gps.grffile->grfid, GRFStringID{id}, lang, new_scheme, false, name, STR_UNDEFINED);
150 }
151 break;
152
153 default:
154 GrfMsg(7, "FeatureNewName: Unsupported ID (0x{:04X})", id);
155 break;
156 }
157 break;
158 }
159 }
160}
161
162template <> void GrfActionHandler<0x04>::FileScan(ByteReader &) { }
163template <> void GrfActionHandler<0x04>::SafetyScan(ByteReader &) { }
164template <> void GrfActionHandler<0x04>::LabelScan(ByteReader &) { }
165template <> void GrfActionHandler<0x04>::Init(ByteReader &) { }
166template <> void GrfActionHandler<0x04>::Reserve(ByteReader &) { }
167template <> void GrfActionHandler<0x04>::Activation(ByteReader &buf) { FeatureNewName(buf); }
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T ClrBit(T &x, const uint8_t y)
Clears a bit in a variable.
StringID name
Short name.
Class to read from a NewGRF file.
uint16_t ReadWord()
Read a single Word (16 bits).
std::string_view ReadString()
Read a NUL-terminated string.
uint16_t ReadExtendedByte()
Read a single Extended Byte (8 or 16 bits).
uint8_t ReadByte()
Read a single byte (8 bits).
StringID name
Name of this class.
static NewGRFClass * Get(StationClassID class_index)
Functions related to debugging.
Base class for engines.
Definition of HouseSpec and accessors.
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
Engine * GetNewEngine(const GRFFile *file, VehicleType type, uint16_t internal_id, bool static_access)
Returns the engine associated to a certain internal_id, resp.
Definition newgrf.cpp:215
GrfSpecFeature
Definition newgrf.h:71
NewGRF handling of airport tiles.
Badge * GetBadge(BadgeID index)
Get a badge if it exists.
Functions related to NewGRF badges.
Types related to NewGRF badges.
NewGRF buffer reader definition.
Cargo support for NewGRFs.
@ Static
GRF file is used statically (can be used in any MP game).
Functions for NewGRF engines.
NewGRF internal processing state.
NewGRF internal processing state for vehicles.
Header file for NewGRF stations.
StationClassID
StringID AddGRFString(uint32_t grfid, GRFStringID stringid, uint8_t langid_to_add, bool new_scheme, bool allow_newlines, std::string_view text_to_add, StringID def_string)
Add the new read string into our structure.
Header of Action 04 "universal holder" structure and functions.
StrongType::Typedef< uint32_t, struct GRFStringIDTag, StrongType::Compare, StrongType::Integer > GRFStringID
Type for GRF-internal string IDs.
A number of safeguards to prevent using unsafe methods.
Definition of base types and functions in a cross-platform compatible way.
static void StrMakeValid(Builder &builder, StringConsumer &consumer, StringValidationSettings settings)
Copies the valid (UTF-8) characters from consumer to the builder.
Definition string.cpp:119
Functions related to low-level strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
StringID string_id
Default name of engine.
VehicleType
Available vehicle types.