OpenTTD Source: src/newgrf_text.cpp Source File

OpenTTD Source 15.0-beta1

newgrf_text.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
18#include "stdafx.h"
19
20#include "newgrf.h"
21#include "strings_internal.h"
22#include "newgrf_storage.h"
23#include "newgrf_text.h"
24#include "newgrf_cargo.h"
25#include "string_func.h"
26#include "timer/timer_game_calendar.h"
27#include "debug.h"
28#include "core/alloc_type.hpp"
29#include "language.h"
30#include <sstream>
31
32#include "table/strings.h"
33#include "table/control_codes.h"
34
35#include "safeguards.h"
36
42 enum GRFBaseLanguages {
43 GRFLB_AMERICAN = 0x01,
44 GRFLB_ENGLISH = 0x02,
45 GRFLB_GERMAN = 0x04,
46 GRFLB_FRENCH = 0x08,
47 GRFLB_SPANISH = 0x10,
48 GRFLB_GENERIC = 0x80,
49};
50
51enum GRFExtendedLanguages {
52 GRFLX_AMERICAN = 0x00,
53 GRFLX_ENGLISH = 0x01,
54 GRFLX_GERMAN = 0x02,
55 GRFLX_FRENCH = 0x03,
56 GRFLX_SPANISH = 0x04,
57 GRFLX_UNSPECIFIED = 0x7F,
58};
59
60
66 struct GRFTextEntry {
67 GRFTextList textholder;
68 StringID def_string;
69 uint32_t grfid;
70 uint16_t stringid;
71};
72
73
74static std::vector<GRFTextEntry> _grf_text;
75 static uint8_t _currentLangID = GRFLX_ENGLISH;
76
83 int LanguageMap::GetMapping(int newgrf_id, bool gender) const
84{
85 const std::vector<Mapping> &map = gender ? this->gender_map : this->case_map;
86 for (const Mapping &m : map) {
87 if (m.newgrf_id == newgrf_id) return m.openttd_id;
88 }
89 return -1;
90}
91
98 int LanguageMap::GetReverseMapping(int openttd_id, bool gender) const
99{
100 const std::vector<Mapping> &map = gender ? this->gender_map : this->case_map;
101 for (const Mapping &m : map) {
102 if (m.openttd_id == openttd_id) return m.newgrf_id;
103 }
104 return -1;
105}
106
108 struct UnmappedChoiceList {
114 UnmappedChoiceList(StringControlCode type, int offset) :
115 type(type), offset(offset)
116 {
117 }
118
119 StringControlCode type;
120 int offset;
121
123 std::map<uint8_t, std::stringstream> strings;
124
130 void Flush(const LanguageMap *lm, std::ostringstream &dest)
131 {
132 if (this->strings.find(0) == this->strings.end()) {
133 /* In case of a (broken) NewGRF without a default,
134 * assume an empty string. */
135 GrfMsg(1, "choice list misses default value");
136 this->strings[0] = std::stringstream();
137 }
138
139 std::ostreambuf_iterator<char> d(dest);
140
141 if (lm == nullptr) {
142 /* In case there is no mapping, just ignore everything but the default.
143 * A probable cause for this happening is when the language file has
144 * been removed by the user and as such no mapping could be made. */
145 dest << this->strings[0].rdbuf();
146 return;
147 }
148
149 Utf8Encode(d, this->type);
150
151 if (this->type == SCC_SWITCH_CASE) {
152 /*
153 * Format for case switch:
154 * <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
155 * Each LEN is printed using 2 bytes in big endian order.
156 */
157
158 /* "<NUM CASES>" */
159 int count = 0;
160 for (uint8_t i = 0; i < _current_language->num_cases; i++) {
161 /* Count the ones we have a mapped string for. */
162 if (this->strings.find(lm->GetReverseMapping(i, false)) != this->strings.end()) count++;
163 }
164 *d++ = count;
165
166 for (uint8_t i = 0; i < _current_language->num_cases; i++) {
167 /* Resolve the string we're looking for. */
168 int idx = lm->GetReverseMapping(i, false);
169 if (this->strings.find(idx) == this->strings.end()) continue;
170 auto str = this->strings[idx].str();
171
172 /* "<CASEn>" */
173 *d++ = i + 1;
174
175 /* "<LENn>": Limit the length of the string to 0xFFFE to leave space for the '\0'. */
176 size_t len = std::min<size_t>(0xFFFE, str.size());
177 *d++ = GB(len + 1, 8, 8);
178 *d++ = GB(len + 1, 0, 8);
179
180 /* "<STRINGn>" */
181 dest.write(str.c_str(), len);
182 *d++ = '\0';
183 }
184
185 /* "<STRINGDEFAULT>" */
186 dest << this->strings[0].rdbuf() << '\0';
187 } else {
188 if (this->type == SCC_PLURAL_LIST) {
189 *d++ = lm->plural_form;
190 }
191
192 /*
193 * Format for choice list:
194 * <OFFSET> <NUM CHOICES> <LENs> <STRINGs>
195 */
196
197 /* "<OFFSET>" */
198 *d++ = this->offset - 0x80;
199
200 /* "<NUM CHOICES>" */
201 int count = (this->type == SCC_GENDER_LIST ? _current_language->num_genders : LANGUAGE_MAX_PLURAL_FORMS);
202 *d++ = count;
203
204 /* "<LENs>" */
205 for (int i = 0; i < count; i++) {
206 int idx = (this->type == SCC_GENDER_LIST ? lm->GetReverseMapping(i, true) : i + 1);
207 const auto &str = this->strings[this->strings.find(idx) != this->strings.end() ? idx : 0].str();
208 size_t len = str.size() + 1;
209 if (len > 0xFF) GrfMsg(1, "choice list string is too long");
210 *d++ = GB(len, 0, 8);
211 }
212
213 /* "<STRINGs>" */
214 for (int i = 0; i < count; i++) {
215 int idx = (this->type == SCC_GENDER_LIST ? lm->GetReverseMapping(i, true) : i + 1);
216 const auto &str = this->strings[this->strings.find(idx) != this->strings.end() ? idx : 0].str();
217 /* Limit the length of the string we copy to 0xFE. The length is written above
218 * as a byte and we need room for the final '\0'. */
219 size_t len = std::min<size_t>(0xFE, str.size());
220 dest.write(str.c_str(), len);
221 *d++ = '\0';
222 }
223 }
224 }
225};
226
236std::string TranslateTTDPatchCodes(uint32_t grfid, uint8_t language_id, bool allow_newlines, std::string_view str, StringControlCode byte80)
237{
238 /* Empty input string? Nothing to do here. */
239 if (str.empty()) return {};
240
241 std::string_view::const_iterator src = str.cbegin();
242
243 /* Is this an unicode string? */
244 bool unicode = false;
245 char32_t marker;
246 size_t len = Utf8Decode(&marker, &*src);
247
248 if (marker == NFO_UTF8_IDENTIFIER) {
249 unicode = true;
250 src += len;
251 }
252
253 /* Helper variable for a possible (string) mapping. */
254 UnmappedChoiceList *mapping = nullptr;
255
256 std::ostringstream dest;
257 std::ostreambuf_iterator<char> d(dest);
258 while (src != str.cend()) {
259 char32_t c;
260
261 if (unicode && Utf8EncodedCharLen(*src) != 0) {
262 c = Utf8Consume(src);
263 /* 'Magic' range of control codes. */
264 if (GB(c, 8, 8) == 0xE0) {
265 c = GB(c, 0, 8);
266 } else if (c >= 0x20) {
267 if (!IsValidChar(c, CS_ALPHANUMERAL)) c = '?';
268 Utf8Encode(d, c);
269 continue;
270 }
271 } else {
272 c = static_cast<uint8_t>(*src++);
273 }
274
275 if (c == '\0') break;
276
277 switch (c) {
278 case 0x01:
279 if (*src == '\0') goto string_end;
280 Utf8Encode(d, ' ');
281 src++;
282 break;
283 case 0x0A: break;
284 case 0x0D:
285 if (allow_newlines) {
286 *d++ = 0x0A;
287 } else {
288 GrfMsg(1, "Detected newline in string that does not allow one");
289 }
290 break;
291 case 0x0E: Utf8Encode(d, SCC_TINYFONT); break;
292 case 0x0F: Utf8Encode(d, SCC_BIGFONT); break;
293 case 0x1F:
294 if (src[0] == '\0' || src[1] == '\0') goto string_end;
295 Utf8Encode(d, ' ');
296 src += 2;
297 break;
298 case 0x7B:
299 case 0x7C:
300 case 0x7D:
301 case 0x7E:
302 case 0x7F: Utf8Encode(d, SCC_NEWGRF_PRINT_DWORD_SIGNED + c - 0x7B); break;
303 case 0x80: Utf8Encode(d, byte80); break;
304 case 0x81:
305 {
306 if (src[0] == '\0' || src[1] == '\0') goto string_end;
307 StringID string;
308 string = static_cast<uint8_t>(*src++);
309 string |= static_cast<uint8_t>(*src++) << 8;
310 Utf8Encode(d, SCC_NEWGRF_STRINL);
311 Utf8Encode(d, MapGRFStringID(grfid, string));
312 break;
313 }
314 case 0x82:
315 case 0x83:
316 case 0x84: Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_DATE_LONG + c - 0x82); break;
317 case 0x85: Utf8Encode(d, SCC_NEWGRF_DISCARD_WORD); break;
318 case 0x86: Utf8Encode(d, SCC_NEWGRF_ROTATE_TOP_4_WORDS); break;
319 case 0x87: Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_VOLUME_LONG); break;
320 case 0x88: Utf8Encode(d, SCC_BLUE); break;
321 case 0x89: Utf8Encode(d, SCC_SILVER); break;
322 case 0x8A: Utf8Encode(d, SCC_GOLD); break;
323 case 0x8B: Utf8Encode(d, SCC_RED); break;
324 case 0x8C: Utf8Encode(d, SCC_PURPLE); break;
325 case 0x8D: Utf8Encode(d, SCC_LTBROWN); break;
326 case 0x8E: Utf8Encode(d, SCC_ORANGE); break;
327 case 0x8F: Utf8Encode(d, SCC_GREEN); break;
328 case 0x90: Utf8Encode(d, SCC_YELLOW); break;
329 case 0x91: Utf8Encode(d, SCC_DKGREEN); break;
330 case 0x92: Utf8Encode(d, SCC_CREAM); break;
331 case 0x93: Utf8Encode(d, SCC_BROWN); break;
332 case 0x94: Utf8Encode(d, SCC_WHITE); break;
333 case 0x95: Utf8Encode(d, SCC_LTBLUE); break;
334 case 0x96: Utf8Encode(d, SCC_GRAY); break;
335 case 0x97: Utf8Encode(d, SCC_DKBLUE); break;
336 case 0x98: Utf8Encode(d, SCC_BLACK); break;
337 case 0x9A:
338 {
339 int code = *src++;
340 switch (code) {
341 case 0x00: goto string_end;
342 case 0x01: Utf8Encode(d, SCC_NEWGRF_PRINT_QWORD_CURRENCY); break;
343 /* 0x02: ignore next colour byte is not supported. It works on the final
344 * string and as such hooks into the string drawing routine. At that
345 * point many things already happened, such as splitting up of strings
346 * when drawn over multiple lines or right-to-left translations, which
347 * make the behaviour peculiar, e.g. only happening at specific width
348 * of windows. Or we need to add another pass over the string to just
349 * support this. As such it is not implemented in OpenTTD. */
350 case 0x03:
351 {
352 if (src[0] == '\0' || src[1] == '\0') goto string_end;
353 uint16_t tmp = static_cast<uint8_t>(*src++);
354 tmp |= static_cast<uint8_t>(*src++) << 8;
355 Utf8Encode(d, SCC_NEWGRF_PUSH_WORD);
356 Utf8Encode(d, tmp);
357 break;
358 }
359 case 0x06: Utf8Encode(d, SCC_NEWGRF_PRINT_BYTE_HEX); break;
360 case 0x07: Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_HEX); break;
361 case 0x08: Utf8Encode(d, SCC_NEWGRF_PRINT_DWORD_HEX); break;
362 /* 0x09, 0x0A are TTDPatch internal use only string codes. */
363 case 0x0B: Utf8Encode(d, SCC_NEWGRF_PRINT_QWORD_HEX); break;
364 case 0x0C: Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_STATION_NAME); break;
365 case 0x0D: Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG); break;
366 case 0x0E:
367 case 0x0F:
368 {
369 if (str[0] == '\0') goto string_end;
370 const LanguageMap *lm = LanguageMap::GetLanguageMap(grfid, language_id);
371 int index = *src++;
372 int mapped = lm != nullptr ? lm->GetMapping(index, code == 0x0E) : -1;
373 if (mapped >= 0) {
374 Utf8Encode(d, code == 0x0E ? SCC_GENDER_INDEX : SCC_SET_CASE);
375 Utf8Encode(d, code == 0x0E ? mapped : mapped + 1);
376 }
377 break;
378 }
379
380 case 0x10:
381 case 0x11:
382 if (str[0] == '\0') goto string_end;
383 if (mapping == nullptr) {
384 if (code == 0x10) src++; // Skip the index
385 GrfMsg(1, "choice list {} marker found when not expected", code == 0x10 ? "next" : "default");
386 break;
387 } else {
388 int index = (code == 0x10 ? *src++ : 0);
389 if (mapping->strings.find(index) != mapping->strings.end()) {
390 GrfMsg(1, "duplicate choice list string, ignoring");
391 } else {
392 d = std::ostreambuf_iterator<char>(mapping->strings[index]);
393 }
394 }
395 break;
396
397 case 0x12:
398 if (mapping == nullptr) {
399 GrfMsg(1, "choice list end marker found when not expected");
400 } else {
401 /* Now we can start flushing everything and clean everything up. */
402 mapping->Flush(LanguageMap::GetLanguageMap(grfid, language_id), dest);
403 delete mapping;
404 mapping = nullptr;
405
406 d = std::ostreambuf_iterator<char>(dest);
407 }
408 break;
409
410 case 0x13:
411 case 0x14:
412 case 0x15:
413 if (src[0] == '\0') goto string_end;
414 if (mapping != nullptr) {
415 GrfMsg(1, "choice lists can't be stacked, it's going to get messy now...");
416 if (code != 0x14) src++;
417 } else {
418 static const StringControlCode mp[] = { SCC_GENDER_LIST, SCC_SWITCH_CASE, SCC_PLURAL_LIST };
419 mapping = new UnmappedChoiceList(mp[code - 0x13], code == 0x14 ? 0 : *src++);
420 }
421 break;
422
423 case 0x16:
424 case 0x17:
425 case 0x18:
426 case 0x19:
427 case 0x1A:
428 case 0x1B:
429 case 0x1C:
430 case 0x1D:
431 case 0x1E:
432 Utf8Encode(d, SCC_NEWGRF_PRINT_DWORD_DATE_LONG + code - 0x16);
433 break;
434
435 case 0x1F: Utf8Encode(d, SCC_PUSH_COLOUR); break;
436 case 0x20: Utf8Encode(d, SCC_POP_COLOUR); break;
437
438 case 0x21: Utf8Encode(d, SCC_NEWGRF_PRINT_DWORD_FORCE); break;
439
440 default:
441 GrfMsg(1, "missing handler for extended format code");
442 break;
443 }
444 break;
445 }
446
447 case 0x9E: Utf8Encode(d, 0x20AC); break; // Euro
448 case 0x9F: Utf8Encode(d, 0x0178); break; // Y with diaeresis
449 case 0xA0: Utf8Encode(d, SCC_UP_ARROW); break;
450 case 0xAA: Utf8Encode(d, SCC_DOWN_ARROW); break;
451 case 0xAC: Utf8Encode(d, SCC_CHECKMARK); break;
452 case 0xAD: Utf8Encode(d, SCC_CROSS); break;
453 case 0xAF: Utf8Encode(d, SCC_RIGHT_ARROW); break;
454 case 0xB4: Utf8Encode(d, SCC_TRAIN); break;
455 case 0xB5: Utf8Encode(d, SCC_LORRY); break;
456 case 0xB6: Utf8Encode(d, SCC_BUS); break;
457 case 0xB7: Utf8Encode(d, SCC_PLANE); break;
458 case 0xB8: Utf8Encode(d, SCC_SHIP); break;
459 case 0xB9: Utf8Encode(d, SCC_SUPERSCRIPT_M1); break;
460 case 0xBC: Utf8Encode(d, SCC_SMALL_UP_ARROW); break;
461 case 0xBD: Utf8Encode(d, SCC_SMALL_DOWN_ARROW); break;
462 default:
463 /* Validate any unhandled character */
464 if (!IsValidChar(c, CS_ALPHANUMERAL)) c = '?';
465 Utf8Encode(d, c);
466 break;
467 }
468 }
469
470string_end:
471 if (mapping != nullptr) {
472 GrfMsg(1, "choice list was incomplete, the whole list is ignored");
473 delete mapping;
474 }
475
476 return dest.str();
477}
478
485 static void AddGRFTextToList(GRFTextList &list, uint8_t langid, std::string_view text_to_add)
486{
487 /* Loop through all languages and see if we can replace a string */
488 for (auto &text : list) {
489 if (text.langid == langid) {
490 text.text = text_to_add;
491 return;
492 }
493 }
494
495 /* If a string wasn't replaced, then we must append the new string */
496 list.push_back(GRFText{ langid, std::string(text_to_add) });
497}
498
508 void AddGRFTextToList(GRFTextList &list, uint8_t langid, uint32_t grfid, bool allow_newlines, std::string_view text_to_add)
509{
510 AddGRFTextToList(list, langid, TranslateTTDPatchCodes(grfid, langid, allow_newlines, text_to_add));
511}
512
522 void AddGRFTextToList(GRFTextWrapper &list, uint8_t langid, uint32_t grfid, bool allow_newlines, std::string_view text_to_add)
523{
524 if (list == nullptr) list = std::make_shared<GRFTextList>();
525 AddGRFTextToList(*list, langid, grfid, allow_newlines, text_to_add);
526}
527
534 void AddGRFTextToList(GRFTextWrapper &list, std::string_view text_to_add)
535{
536 if (list == nullptr) list = std::make_shared<GRFTextList>();
537 AddGRFTextToList(*list, GRFLX_UNSPECIFIED, text_to_add);
538}
539
543 StringID AddGRFString(uint32_t grfid, uint16_t stringid, uint8_t langid_to_add, bool new_scheme, bool allow_newlines, std::string_view text_to_add, StringID def_string)
544{
545 /* When working with the old language scheme (grf_version is less than 7) and
546 * English or American is among the set bits, simply add it as English in
547 * the new scheme, i.e. as langid = 1.
548 * If English is set, it is pretty safe to assume the translations are not
549 * actually translated.
550 */
551 if (!new_scheme) {
552 if (langid_to_add & (GRFLB_AMERICAN | GRFLB_ENGLISH)) {
553 langid_to_add = GRFLX_ENGLISH;
554 } else {
555 StringID ret = STR_EMPTY;
556 if (langid_to_add & GRFLB_GERMAN) ret = AddGRFString(grfid, stringid, GRFLX_GERMAN, true, allow_newlines, text_to_add, def_string);
557 if (langid_to_add & GRFLB_FRENCH) ret = AddGRFString(grfid, stringid, GRFLX_FRENCH, true, allow_newlines, text_to_add, def_string);
558 if (langid_to_add & GRFLB_SPANISH) ret = AddGRFString(grfid, stringid, GRFLX_SPANISH, true, allow_newlines, text_to_add, def_string);
559 return ret;
560 }
561 }
562
563 auto it = std::ranges::find_if(_grf_text, [&grfid, &stringid](const GRFTextEntry &grf_text) { return grf_text.grfid == grfid && grf_text.stringid == stringid; });
564 if (it == std::end(_grf_text)) {
565 /* Too many strings allocated, return empty. */
566 if (_grf_text.size() == TAB_SIZE_NEWGRF) return STR_EMPTY;
567
568 /* We didn't find our stringid and grfid in the list, allocate a new id. */
569 it = _grf_text.emplace(std::end(_grf_text));
570 it->grfid = grfid;
571 it->stringid = stringid;
572 it->def_string = def_string;
573 }
574 uint id = static_cast<uint>(it - std::begin(_grf_text));
575
576 std::string newtext = TranslateTTDPatchCodes(grfid, langid_to_add, allow_newlines, text_to_add);
577 AddGRFTextToList(it->textholder, langid_to_add, newtext);
578
579 GrfMsg(3, "Added 0x{:X} grfid {:08X} string 0x{:X} lang 0x{:X} string '{}' ({:X})", id, grfid, stringid, langid_to_add, newtext, MakeStringID(TEXT_TAB_NEWGRF_START, id));
580
581 return MakeStringID(TEXT_TAB_NEWGRF_START, id);
582}
583
587 StringID GetGRFStringID(uint32_t grfid, StringID stringid)
588{
589 auto it = std::ranges::find_if(_grf_text, [&grfid, &stringid](const GRFTextEntry &grf_text) { return grf_text.grfid == grfid && grf_text.stringid == stringid; });
590 if (it != std::end(_grf_text)) {
591 uint id = static_cast<uint>(it - std::begin(_grf_text));
592 return MakeStringID(TEXT_TAB_NEWGRF_START, id);
593 }
594
595 return STR_UNDEFINED;
596}
597
598
606 const char *GetGRFStringFromGRFText(const GRFTextList &text_list)
607{
608 const char *default_text = nullptr;
609
610 /* Search the list of lang-strings of this stringid for current lang */
611 for (const auto &text : text_list) {
612 if (text.langid == _currentLangID) return text.text.c_str();
613
614 /* If the current string is English or American, set it as the
615 * fallback language if the specific language isn't available. */
616 if (text.langid == GRFLX_UNSPECIFIED || (default_text == nullptr && (text.langid == GRFLX_ENGLISH || text.langid == GRFLX_AMERICAN))) {
617 default_text = text.text.c_str();
618 }
619 }
620
621 return default_text;
622}
623
631 const char *GetGRFStringFromGRFText(const GRFTextWrapper &text)
632{
633 return text ? GetGRFStringFromGRFText(*text) : nullptr;
634}
635
639 const char *GetGRFStringPtr(uint32_t stringid)
640{
641 assert(stringid < _grf_text.size());
642 assert(_grf_text[stringid].grfid != 0);
643
644 const char *str = GetGRFStringFromGRFText(_grf_text[stringid].textholder);
645 if (str != nullptr) return str;
646
647 /* Use the default string ID if the fallback string isn't available */
648 return GetStringPtr(_grf_text[stringid].def_string);
649}
650
659 void SetCurrentGrfLangID(uint8_t language_id)
660{
661 _currentLangID = language_id;
662}
663
664bool CheckGrfLangID(uint8_t lang_id, uint8_t grf_version)
665{
666 if (grf_version < 7) {
667 switch (_currentLangID) {
668 case GRFLX_GERMAN: return (lang_id & GRFLB_GERMAN) != 0;
669 case GRFLX_FRENCH: return (lang_id & GRFLB_FRENCH) != 0;
670 case GRFLX_SPANISH: return (lang_id & GRFLB_SPANISH) != 0;
671 default: return (lang_id & (GRFLB_ENGLISH | GRFLB_AMERICAN)) != 0;
672 }
673 }
674
675 return (lang_id == _currentLangID || lang_id == GRFLX_UNSPECIFIED);
676}
677
682 void CleanUpStrings()
683{
684 _grf_text.clear();
685}
686
687 struct TextRefStack {
688 std::array<uint8_t, 0x30> stack;
689 uint8_t position;
690 const GRFFile *grffile;
691 bool used;
692
693 TextRefStack() : position(0), grffile(nullptr), used(false) {}
694
695 uint8_t PopUnsignedByte() { assert(this->position < this->stack.size()); return this->stack[this->position++]; }
696 int8_t PopSignedByte() { return (int8_t)this->PopUnsignedByte(); }
697
698 uint16_t PopUnsignedWord()
699 {
700 uint16_t val = this->PopUnsignedByte();
701 return val | (this->PopUnsignedByte() << 8);
702 }
703 int16_t PopSignedWord() { return (int32_t)this->PopUnsignedWord(); }
704
705 uint32_t PopUnsignedDWord()
706 {
707 uint32_t val = this->PopUnsignedWord();
708 return val | (this->PopUnsignedWord() << 16);
709 }
710 int32_t PopSignedDWord() { return (int32_t)this->PopUnsignedDWord(); }
711
712 uint64_t PopUnsignedQWord()
713 {
714 uint64_t val = this->PopUnsignedDWord();
715 return val | (((uint64_t)this->PopUnsignedDWord()) << 32);
716 }
717 int64_t PopSignedQWord() { return (int64_t)this->PopUnsignedQWord(); }
718
720 void RotateTop4Words()
721 {
722 uint8_t tmp[2];
723 for (int i = 0; i < 2; i++) tmp[i] = this->stack[this->position + i + 6];
724 for (int i = 5; i >= 0; i--) this->stack[this->position + i + 2] = this->stack[this->position + i];
725 for (int i = 0; i < 2; i++) this->stack[this->position + i] = tmp[i];
726 }
727
728 void PushWord(uint16_t word)
729 {
730 if (this->position >= 2) {
731 this->position -= 2;
732 } else {
733 // Rotate right 2 positions
734 std::rotate(this->stack.rbegin(), this->stack.rbegin() + 2, this->stack.rend());
735 }
736 this->stack[this->position] = GB(word, 0, 8);
737 this->stack[this->position + 1] = GB(word, 8, 8);
738 }
739
740 void ResetStack(const GRFFile *grffile)
741 {
742 assert(grffile != nullptr);
743 this->position = 0;
744 this->grffile = grffile;
745 this->used = true;
746 }
747};
748
750 static TextRefStack _newgrf_textrefstack;
751
756 bool UsingNewGRFTextStack()
757{
758 return _newgrf_textrefstack.used;
759}
760
765 struct TextRefStack *CreateTextRefStackBackup()
766{
767 return new TextRefStack(_newgrf_textrefstack);
768}
769
774 void RestoreTextRefStackBackup(struct TextRefStack *backup)
775{
776 _newgrf_textrefstack = *backup;
777 delete backup;
778}
779
798 void StartTextRefStackUsage(const GRFFile *grffile, uint8_t numEntries, const uint32_t *values)
799{
800 extern TemporaryStorageArray<int32_t, 0x110> _temp_store;
801
802 _newgrf_textrefstack.ResetStack(grffile);
803
804 auto stack_it = _newgrf_textrefstack.stack.begin();
805 for (uint i = 0; i < numEntries; i++) {
806 uint32_t value = values != nullptr ? values[i] : _temp_store.GetValue(0x100 + i);
807 for (uint j = 0; j < 32; j += 8) {
808 *stack_it = GB(value, j, 8);
809 stack_it++;
810 }
811 }
812}
813
815 void StopTextRefStackUsage()
816{
817 _newgrf_textrefstack.used = false;
818}
819
828 char32_t RemapNewGRFStringControlCode(char32_t scc, const char **str, StringParameters &parameters, bool modify_parameters)
829{
830 switch (scc) {
831 default: break;
832
833 /* These control codes take one string parameter, check there are at least that many available. */
834 case SCC_NEWGRF_PRINT_DWORD_SIGNED:
835 case SCC_NEWGRF_PRINT_WORD_SIGNED:
836 case SCC_NEWGRF_PRINT_BYTE_SIGNED:
837 case SCC_NEWGRF_PRINT_WORD_UNSIGNED:
838 case SCC_NEWGRF_PRINT_BYTE_HEX:
839 case SCC_NEWGRF_PRINT_WORD_HEX:
840 case SCC_NEWGRF_PRINT_DWORD_HEX:
841 case SCC_NEWGRF_PRINT_QWORD_HEX:
842 case SCC_NEWGRF_PRINT_DWORD_CURRENCY:
843 case SCC_NEWGRF_PRINT_QWORD_CURRENCY:
844 case SCC_NEWGRF_PRINT_WORD_STRING_ID:
845 case SCC_NEWGRF_PRINT_WORD_DATE_LONG:
846 case SCC_NEWGRF_PRINT_DWORD_DATE_LONG:
847 case SCC_NEWGRF_PRINT_WORD_DATE_SHORT:
848 case SCC_NEWGRF_PRINT_DWORD_DATE_SHORT:
849 case SCC_NEWGRF_PRINT_WORD_SPEED:
850 case SCC_NEWGRF_PRINT_WORD_VOLUME_LONG:
851 case SCC_NEWGRF_PRINT_WORD_VOLUME_SHORT:
852 case SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG:
853 case SCC_NEWGRF_PRINT_WORD_WEIGHT_SHORT:
854 case SCC_NEWGRF_PRINT_WORD_POWER:
855 case SCC_NEWGRF_PRINT_DWORD_FORCE:
856 case SCC_NEWGRF_PRINT_WORD_STATION_NAME:
857 case SCC_NEWGRF_PRINT_WORD_CARGO_NAME:
858 if (parameters.GetDataLeft() < 1) {
859 Debug(misc, 0, "Too many NewGRF string parameters.");
860 return 0;
861 }
862 break;
863
864 /* These string code take two string parameters, check there are at least that many available. */
865 case SCC_NEWGRF_PRINT_WORD_CARGO_LONG:
866 case SCC_NEWGRF_PRINT_WORD_CARGO_SHORT:
867 case SCC_NEWGRF_PRINT_WORD_CARGO_TINY:
868 if (parameters.GetDataLeft() < 2) {
869 Debug(misc, 0, "Too many NewGRF string parameters.");
870 return 0;
871 }
872 break;
873 }
874
875 if (_newgrf_textrefstack.used && modify_parameters) {
876 /* There is data on the NewGRF text stack, and we want to move them to OpenTTD's string stack.
877 * After this call, a new call is made with `modify_parameters` set to false when the string is finally formatted. */
878 switch (scc) {
879 default: NOT_REACHED();
880 case SCC_NEWGRF_PRINT_BYTE_SIGNED: parameters.SetParam(0, _newgrf_textrefstack.PopSignedByte()); break;
881 case SCC_NEWGRF_PRINT_QWORD_CURRENCY: parameters.SetParam(0, _newgrf_textrefstack.PopSignedQWord()); break;
882
883 case SCC_NEWGRF_PRINT_DWORD_CURRENCY:
884 case SCC_NEWGRF_PRINT_DWORD_SIGNED: parameters.SetParam(0, _newgrf_textrefstack.PopSignedDWord()); break;
885
886 case SCC_NEWGRF_PRINT_BYTE_HEX: parameters.SetParam(0, _newgrf_textrefstack.PopUnsignedByte()); break;
887 case SCC_NEWGRF_PRINT_QWORD_HEX: parameters.SetParam(0, _newgrf_textrefstack.PopUnsignedQWord()); break;
888
889 case SCC_NEWGRF_PRINT_WORD_SPEED:
890 case SCC_NEWGRF_PRINT_WORD_VOLUME_LONG:
891 case SCC_NEWGRF_PRINT_WORD_VOLUME_SHORT:
892 case SCC_NEWGRF_PRINT_WORD_SIGNED: parameters.SetParam(0, _newgrf_textrefstack.PopSignedWord()); break;
893
894 case SCC_NEWGRF_PRINT_WORD_HEX:
895 case SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG:
896 case SCC_NEWGRF_PRINT_WORD_WEIGHT_SHORT:
897 case SCC_NEWGRF_PRINT_WORD_POWER:
898 case SCC_NEWGRF_PRINT_WORD_STATION_NAME:
899 case SCC_NEWGRF_PRINT_WORD_UNSIGNED: parameters.SetParam(0, _newgrf_textrefstack.PopUnsignedWord()); break;
900
901 case SCC_NEWGRF_PRINT_DWORD_FORCE:
902 case SCC_NEWGRF_PRINT_DWORD_DATE_LONG:
903 case SCC_NEWGRF_PRINT_DWORD_DATE_SHORT:
904 case SCC_NEWGRF_PRINT_DWORD_HEX: parameters.SetParam(0, _newgrf_textrefstack.PopUnsignedDWord()); break;
905
906 /* Dates from NewGRFs have 1920-01-01 as their zero point, convert it to OpenTTD's epoch. */
907 case SCC_NEWGRF_PRINT_WORD_DATE_LONG:
908 case SCC_NEWGRF_PRINT_WORD_DATE_SHORT: parameters.SetParam(0, _newgrf_textrefstack.PopUnsignedWord() + CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR); break;
909
910 case SCC_NEWGRF_DISCARD_WORD: _newgrf_textrefstack.PopUnsignedWord(); break;
911
912 case SCC_NEWGRF_ROTATE_TOP_4_WORDS: _newgrf_textrefstack.RotateTop4Words(); break;
913 case SCC_NEWGRF_PUSH_WORD: _newgrf_textrefstack.PushWord(Utf8Consume(str)); break;
914
915 case SCC_NEWGRF_PRINT_WORD_CARGO_LONG:
916 case SCC_NEWGRF_PRINT_WORD_CARGO_SHORT:
917 case SCC_NEWGRF_PRINT_WORD_CARGO_TINY:
918 parameters.SetParam(0, GetCargoTranslation(_newgrf_textrefstack.PopUnsignedWord(), _newgrf_textrefstack.grffile));
919 parameters.SetParam(1, _newgrf_textrefstack.PopUnsignedWord());
920 break;
921
922 case SCC_NEWGRF_PRINT_WORD_STRING_ID:
923 parameters.SetParam(0, MapGRFStringID(_newgrf_textrefstack.grffile->grfid, _newgrf_textrefstack.PopUnsignedWord()));
924 break;
925
926 case SCC_NEWGRF_PRINT_WORD_CARGO_NAME: {
927 CargoID cargo = GetCargoTranslation(_newgrf_textrefstack.PopUnsignedWord(), _newgrf_textrefstack.grffile);
928 parameters.SetParam(0, cargo < NUM_CARGO ? 1ULL << cargo : 0);
929 break;
930 }
931 }
932 } else {
933 /* Consume additional parameter characters that follow the NewGRF string code. */
934 switch (scc) {
935 default: break;
936
937 case SCC_NEWGRF_PUSH_WORD:
938 Utf8Consume(str);
939 break;
940 }
941 }
942
943 /* Emit OpenTTD's internal string code for the different NewGRF variants. */
944 switch (scc) {
945 default: NOT_REACHED();
946 case SCC_NEWGRF_PRINT_DWORD_SIGNED:
947 case SCC_NEWGRF_PRINT_WORD_SIGNED:
948 case SCC_NEWGRF_PRINT_BYTE_SIGNED:
949 case SCC_NEWGRF_PRINT_WORD_UNSIGNED:
950 return SCC_COMMA;
951
952 case SCC_NEWGRF_PRINT_BYTE_HEX:
953 case SCC_NEWGRF_PRINT_WORD_HEX:
954 case SCC_NEWGRF_PRINT_DWORD_HEX:
955 case SCC_NEWGRF_PRINT_QWORD_HEX:
956 return SCC_HEX;
957
958 case SCC_NEWGRF_PRINT_DWORD_CURRENCY:
959 case SCC_NEWGRF_PRINT_QWORD_CURRENCY:
960 return SCC_CURRENCY_LONG;
961
962 case SCC_NEWGRF_PRINT_WORD_STRING_ID:
963 return SCC_NEWGRF_PRINT_WORD_STRING_ID;
964
965 case SCC_NEWGRF_PRINT_WORD_DATE_LONG:
966 case SCC_NEWGRF_PRINT_DWORD_DATE_LONG:
967 return SCC_DATE_LONG;
968
969 case SCC_NEWGRF_PRINT_WORD_DATE_SHORT:
970 case SCC_NEWGRF_PRINT_DWORD_DATE_SHORT:
971 return SCC_DATE_SHORT;
972
973 case SCC_NEWGRF_PRINT_WORD_SPEED:
974 return SCC_VELOCITY;
975
976 case SCC_NEWGRF_PRINT_WORD_VOLUME_LONG:
977 return SCC_VOLUME_LONG;
978
979 case SCC_NEWGRF_PRINT_WORD_VOLUME_SHORT:
980 return SCC_VOLUME_SHORT;
981
982 case SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG:
983 return SCC_WEIGHT_LONG;
984
985 case SCC_NEWGRF_PRINT_WORD_WEIGHT_SHORT:
986 return SCC_WEIGHT_SHORT;
987
988 case SCC_NEWGRF_PRINT_WORD_POWER:
989 return SCC_POWER;
990
991 case SCC_NEWGRF_PRINT_DWORD_FORCE:
992 return SCC_FORCE;
993
994 case SCC_NEWGRF_PRINT_WORD_CARGO_LONG:
995 return SCC_CARGO_LONG;
996
997 case SCC_NEWGRF_PRINT_WORD_CARGO_SHORT:
998 return SCC_CARGO_SHORT;
999
1000 case SCC_NEWGRF_PRINT_WORD_CARGO_TINY:
1001 return SCC_CARGO_TINY;
1002
1003 case SCC_NEWGRF_PRINT_WORD_CARGO_NAME:
1004 return SCC_CARGO_LIST;
1005
1006 case SCC_NEWGRF_PRINT_WORD_STATION_NAME:
1007 return SCC_STATION_NAME;
1008
1009 /* These NewGRF string codes modify the NewGRF stack or otherwise do not map to OpenTTD string codes. */
1010 case SCC_NEWGRF_DISCARD_WORD:
1011 case SCC_NEWGRF_ROTATE_TOP_4_WORDS:
1012 case SCC_NEWGRF_PUSH_WORD:
1013 return 0;
1014 }
1015}
alloc_type.hpp
Helper types related to the allocation of memory.
GB
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.
Definition bitmath_func.hpp:32
CargoID
uint8_t CargoID
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:22
NUM_CARGO
static const CargoID NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:74
StringParameters
Definition strings_internal.h:22
StringParameters::GetDataLeft
size_t GetDataLeft() const
Return the amount of elements which can still be read.
Definition strings_internal.h:146
TimerGameConst< struct Calendar >::DAYS_TILL_ORIGINAL_BASE_YEAR
static constexpr TimerGame< struct Calendar >::Date DAYS_TILL_ORIGINAL_BASE_YEAR
The date of the first day of the original base year.
Definition timer_game_common.h:184
control_codes.h
Control codes that are embedded in the translation strings.
StringControlCode
StringControlCode
List of string control codes used for string formatting, displaying, and by strgen to generate the la...
Definition control_codes.h:17
SCC_NEWGRF_PRINT_WORD_VOLUME_SHORT
@ SCC_NEWGRF_PRINT_WORD_VOLUME_SHORT
9A 19: Read 2 bytes from the stack as short signed volume
Definition control_codes.h:151
SCC_NEWGRF_PRINT_DWORD_CURRENCY
@ SCC_NEWGRF_PRINT_DWORD_CURRENCY
8F: Read 4 bytes from the stack as currency
Definition control_codes.h:135
SCC_NEWGRF_PRINT_WORD_HEX
@ SCC_NEWGRF_PRINT_WORD_HEX
9A 07: Read 2 bytes from the stack and print it as hex
Definition control_codes.h:145
SCC_NEWGRF_PRINT_WORD_WEIGHT_SHORT
@ SCC_NEWGRF_PRINT_WORD_WEIGHT_SHORT
9A 1A: Read 2 bytes from the stack as short unsigned weight
Definition control_codes.h:152
SCC_NEWGRF_ROTATE_TOP_4_WORDS
@ SCC_NEWGRF_ROTATE_TOP_4_WORDS
86: Rotate the top 4 words of the stack (W4 W1 W2 W3)
Definition control_codes.h:160
SCC_TINYFONT
@ SCC_TINYFONT
Switch to small font.
Definition control_codes.h:30
SCC_NEWGRF_PRINT_DWORD_DATE_LONG
@ SCC_NEWGRF_PRINT_DWORD_DATE_LONG
9A 16: Read 4 bytes from the stack as base 0 date
Definition control_codes.h:148
SCC_NEWGRF_PRINT_DWORD_HEX
@ SCC_NEWGRF_PRINT_DWORD_HEX
9A 08: Read 4 bytes from the stack and print it as hex
Definition control_codes.h:146
SCC_NEWGRF_PRINT_WORD_DATE_SHORT
@ SCC_NEWGRF_PRINT_WORD_DATE_SHORT
83: Read 2 bytes from the stack as base 1920 date
Definition control_codes.h:138
SCC_BIGFONT
@ SCC_BIGFONT
Switch to large font.
Definition control_codes.h:31
SCC_NEWGRF_PRINT_BYTE_HEX
@ SCC_NEWGRF_PRINT_BYTE_HEX
9A 06: Read 1 byte from the stack and print it as hex
Definition control_codes.h:144
SCC_NEWGRF_PRINT_WORD_UNSIGNED
@ SCC_NEWGRF_PRINT_WORD_UNSIGNED
7E: Read 2 bytes from the stack as unsigned value
Definition control_codes.h:134
SCC_NEWGRF_PRINT_BYTE_SIGNED
@ SCC_NEWGRF_PRINT_BYTE_SIGNED
7D: Read 1 byte from the stack as signed value
Definition control_codes.h:133
SCC_NEWGRF_PRINT_WORD_CARGO_NAME
@ SCC_NEWGRF_PRINT_WORD_CARGO_NAME
9A 1E: Read 2 bytes from the stack as cargo name
Definition control_codes.h:156
SCC_NEWGRF_PRINT_DWORD_SIGNED
@ SCC_NEWGRF_PRINT_DWORD_SIGNED
7B: Read 4 bytes from the stack
Definition control_codes.h:131
SCC_NEWGRF_STRINL
@ SCC_NEWGRF_STRINL
Inline another string at the current position, StringID is encoded in the string.
Definition control_codes.h:163
SCC_NEWGRF_PRINT_WORD_CARGO_SHORT
@ SCC_NEWGRF_PRINT_WORD_CARGO_SHORT
9A 1C: Read 2 + 2 bytes from the stack as cargo type (translated) and unsigned cargo amount
Definition control_codes.h:154
SCC_NEWGRF_PRINT_WORD_STATION_NAME
@ SCC_NEWGRF_PRINT_WORD_STATION_NAME
9A 0C: Read 2 bytes from the stack as station name
Definition control_codes.h:142
SCC_NEWGRF_PRINT_WORD_DATE_LONG
@ SCC_NEWGRF_PRINT_WORD_DATE_LONG
82: Read 2 bytes from the stack as base 1920 date
Definition control_codes.h:137
SCC_NEWGRF_PRINT_WORD_SIGNED
@ SCC_NEWGRF_PRINT_WORD_SIGNED
7C: Read 2 bytes from the stack as signed value
Definition control_codes.h:132
SCC_NEWGRF_PRINT_WORD_POWER
@ SCC_NEWGRF_PRINT_WORD_POWER
9A 18: Read 2 bytes from the stack as unsigned power
Definition control_codes.h:150
SCC_NEWGRF_PUSH_WORD
@ SCC_NEWGRF_PUSH_WORD
9A 03: Pushes 2 bytes onto the stack
Definition control_codes.h:158
SCC_NEWGRF_PRINT_WORD_STRING_ID
@ SCC_NEWGRF_PRINT_WORD_STRING_ID
81: Read 2 bytes from the stack as String ID
Definition control_codes.h:136
SCC_NEWGRF_PRINT_WORD_VOLUME_LONG
@ SCC_NEWGRF_PRINT_WORD_VOLUME_LONG
87: Read 2 bytes from the stack as long signed volume
Definition control_codes.h:140
SCC_NEWGRF_DISCARD_WORD
@ SCC_NEWGRF_DISCARD_WORD
85: Discard the next two bytes
Definition control_codes.h:159
SCC_NEWGRF_PRINT_DWORD_FORCE
@ SCC_NEWGRF_PRINT_DWORD_FORCE
9A 21: Read 4 bytes from the stack as unsigned force
Definition control_codes.h:157
SCC_NEWGRF_PRINT_WORD_CARGO_TINY
@ SCC_NEWGRF_PRINT_WORD_CARGO_TINY
9A 1D: Read 2 + 2 bytes from the stack as cargo type (translated) and unsigned cargo amount
Definition control_codes.h:155
SCC_NEWGRF_PRINT_QWORD_HEX
@ SCC_NEWGRF_PRINT_QWORD_HEX
9A 0B: Read 8 bytes from the stack and print it as hex
Definition control_codes.h:147
SCC_NEWGRF_PRINT_WORD_CARGO_LONG
@ SCC_NEWGRF_PRINT_WORD_CARGO_LONG
9A 1B: Read 2 + 2 bytes from the stack as cargo type (translated) and unsigned cargo amount
Definition control_codes.h:153
SCC_NEWGRF_PRINT_WORD_SPEED
@ SCC_NEWGRF_PRINT_WORD_SPEED
84: Read 2 bytes from the stack as signed speed
Definition control_codes.h:139
SCC_NEWGRF_PRINT_DWORD_DATE_SHORT
@ SCC_NEWGRF_PRINT_DWORD_DATE_SHORT
9A 17: Read 4 bytes from the stack as base 0 date
Definition control_codes.h:149
SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG
@ SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG
9A 0D: Read 2 bytes from the stack as long unsigned weight
Definition control_codes.h:141
SCC_NEWGRF_PRINT_QWORD_CURRENCY
@ SCC_NEWGRF_PRINT_QWORD_CURRENCY
9A 01: Read 8 bytes from the stack as currency
Definition control_codes.h:143
debug.h
Functions related to debugging.
Debug
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition debug.h:37
language.h
Information about languages and their files.
_current_language
const LanguageMetadata * _current_language
The currently loaded language.
Definition strings.cpp:54
MapGRFStringID
StringID MapGRFStringID(uint32_t grfid, StringID str)
Used when setting an object's property to map to the GRF's strings while taking in consideration the ...
Definition newgrf.cpp:560
newgrf.h
Base for the NewGRF implementation.
GetCargoTranslation
CargoID GetCargoTranslation(uint8_t cargo, const GRFFile *grffile, bool usebit)
Translate a GRF-local cargo slot/bitnum into a CargoID.
Definition newgrf_cargo.cpp:80
newgrf_cargo.h
Cargo support for NewGRFs.
newgrf_storage.h
Functionality related to the temporary and persistent storage arrays for NewGRFs.
CreateTextRefStackBackup
struct TextRefStack * CreateTextRefStackBackup()
Create a backup of the current NewGRF text stack.
Definition newgrf_text.cpp:765
CleanUpStrings
void CleanUpStrings()
House cleaning.
Definition newgrf_text.cpp:682
_newgrf_textrefstack
static TextRefStack _newgrf_textrefstack
The stack that is used for TTDP compatible string code parsing.
Definition newgrf_text.cpp:750
AddGRFTextToList
static void AddGRFTextToList(GRFTextList &list, uint8_t langid, std::string_view text_to_add)
Add a new text to a GRFText list.
Definition newgrf_text.cpp:485
RemapNewGRFStringControlCode
char32_t RemapNewGRFStringControlCode(char32_t scc, const char **str, StringParameters &parameters, bool modify_parameters)
FormatString for NewGRF specific "magic" string control codes.
Definition newgrf_text.cpp:828
TranslateTTDPatchCodes
std::string TranslateTTDPatchCodes(uint32_t grfid, uint8_t language_id, bool allow_newlines, std::string_view str, StringControlCode byte80)
Translate TTDPatch string codes into something OpenTTD can handle (better).
Definition newgrf_text.cpp:236
SetCurrentGrfLangID
void SetCurrentGrfLangID(uint8_t language_id)
Equivalence Setter function between game and newgrf langID.
Definition newgrf_text.cpp:659
StartTextRefStackUsage
void StartTextRefStackUsage(const GRFFile *grffile, uint8_t numEntries, const uint32_t *values)
Start using the TTDP compatible string code parsing.
Definition newgrf_text.cpp:798
GetGRFStringPtr
const char * GetGRFStringPtr(uint32_t stringid)
Get a C-string from a stringid set by a newgrf.
Definition newgrf_text.cpp:639
GetGRFStringFromGRFText
const char * GetGRFStringFromGRFText(const GRFTextList &text_list)
Get a C-string from a GRFText-list.
Definition newgrf_text.cpp:606
_currentLangID
static uint8_t _currentLangID
by default, english is used.
Definition newgrf_text.cpp:75
RestoreTextRefStackBackup
void RestoreTextRefStackBackup(struct TextRefStack *backup)
Restore a copy of the text stack to the used stack.
Definition newgrf_text.cpp:774
UsingNewGRFTextStack
bool UsingNewGRFTextStack()
Check whether the NewGRF text stack is in use.
Definition newgrf_text.cpp:756
AddGRFString
StringID AddGRFString(uint32_t grfid, uint16_t 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.
Definition newgrf_text.cpp:543
GetGRFStringID
StringID GetGRFStringID(uint32_t grfid, StringID stringid)
Returns the index for this stringid associated with its grfID.
Definition newgrf_text.cpp:587
GRFBaseLanguages
GRFBaseLanguages
Explains the newgrf shift bit positioning.
Definition newgrf_text.cpp:42
StopTextRefStackUsage
void StopTextRefStackUsage()
Stop using the TTDP compatible string code parsing.
Definition newgrf_text.cpp:815
newgrf_text.h
Header of Action 04 "universal holder" structure and functions.
GRFTextWrapper
std::shared_ptr< GRFTextList > GRFTextWrapper
Reference counted wrapper around a GRFText pointer.
Definition newgrf_text_type.h:25
GRFTextList
std::vector< GRFText > GRFTextList
A GRF text with a list of translations.
Definition newgrf_text_type.h:23
NFO_UTF8_IDENTIFIER
static const char32_t NFO_UTF8_IDENTIFIER
This character (thorn) indicates a unicode string to NFO.
Definition newgrf_text_type.h:14
safeguards.h
A number of safeguards to prevent using unsafe methods.
stdafx.h
Definition of base types and functions in a cross-platform compatible way.
IsValidChar
bool IsValidChar(char32_t key, CharSetFilter afilter)
Only allow certain keys.
Definition string.cpp:396
Utf8Decode
size_t Utf8Decode(char32_t *c, const char *s)
Decode and consume the next UTF-8 encoded character.
Definition string.cpp:419
Utf8Encode
size_t Utf8Encode(T buf, char32_t c)
Encode a unicode character and place it in the buffer.
Definition string.cpp:460
string_func.h
Functions related to low-level strings.
Utf8EncodedCharLen
int8_t Utf8EncodedCharLen(char c)
Return the length of an UTF-8 encoded value based on a single char.
Definition string_func.h:124
CS_ALPHANUMERAL
@ CS_ALPHANUMERAL
Both numeric and alphabetic and spaces and stuff.
Definition string_type.h:25
MakeStringID
StringID MakeStringID(StringTab tab, uint index)
Create a StringID.
Definition strings_func.h:49
StringID
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition strings_type.h:16
TAB_SIZE_NEWGRF
static const uint TAB_SIZE_NEWGRF
Number of strings for NewGRFs.
Definition strings_type.h:52
TEXT_TAB_NEWGRF_START
@ TEXT_TAB_NEWGRF_START
Start of NewGRF supplied strings.
Definition strings_type.h:40
GRFFile
Dynamic data of a loaded NewGRF.
Definition newgrf.h:108
GRFTextEntry
Holder of the above structure.
Definition newgrf_text.cpp:66
GRFText
A GRF text with associated language ID.
Definition newgrf_text_type.h:17
LanguageMap::Mapping
Mapping between NewGRF and OpenTTD IDs.
Definition newgrf_text_type.h:30
LanguageMap
Mapping of language data between a NewGRF and OpenTTD.
Definition newgrf_text_type.h:28
LanguageMap::gender_map
std::vector< Mapping > gender_map
Mapping of NewGRF and OpenTTD IDs for genders.
Definition newgrf_text_type.h:41
LanguageMap::GetReverseMapping
int GetReverseMapping(int openttd_id, bool gender) const
Get the mapping from OpenTTD's internal ID to the NewGRF supplied ID.
Definition newgrf_text.cpp:98
LanguageMap::plural_form
int plural_form
The plural form used for this language.
Definition newgrf_text_type.h:43
LanguageMap::GetLanguageMap
static const LanguageMap * GetLanguageMap(uint32_t grfid, uint8_t language_id)
Get the language map associated with a given NewGRF and language.
Definition newgrf.cpp:2687
LanguageMap::case_map
std::vector< Mapping > case_map
Mapping of NewGRF and OpenTTD IDs for cases.
Definition newgrf_text_type.h:42
LanguageMap::GetMapping
int GetMapping(int newgrf_id, bool gender) const
Get the mapping from the NewGRF supplied ID to OpenTTD's internal ID.
Definition newgrf_text.cpp:83
LanguagePackHeader::num_genders
uint8_t num_genders
the number of genders of this language
Definition language.h:53
LanguagePackHeader::num_cases
uint8_t num_cases
the number of cases of this language
Definition language.h:54
TemporaryStorageArray
Class for temporary storage of data.
Definition newgrf_storage.h:133
TextRefStack
Definition newgrf_text.cpp:687
TextRefStack::RotateTop4Words
void RotateTop4Words()
Rotate the top four words down: W1, W2, W3, W4 -> W4, W1, W2, W3.
Definition newgrf_text.cpp:720
UnmappedChoiceList
Helper structure for mapping choice lists.
Definition newgrf_text.cpp:108
UnmappedChoiceList::strings
std::map< uint8_t, std::stringstream > strings
Mapping of NewGRF supplied ID to the different strings in the choice list.
Definition newgrf_text.cpp:123
UnmappedChoiceList::type
StringControlCode type
The type of choice list.
Definition newgrf_text.cpp:119
UnmappedChoiceList::offset
int offset
The offset for the plural/gender form.
Definition newgrf_text.cpp:120
UnmappedChoiceList::UnmappedChoiceList
UnmappedChoiceList(StringControlCode type, int offset)
Initialise the mapping.
Definition newgrf_text.cpp:114
UnmappedChoiceList::Flush
void Flush(const LanguageMap *lm, std::ostringstream &dest)
Flush this choice list into the destination string.
Definition newgrf_text.cpp:130
timer_game_calendar.h
Definition of the game-calendar-timer.