OpenTTD

newgrf_text.cpp
Go to the documentation of this file.
1 /* $Id: newgrf_text.cpp 27851 2017-04-09 21:58:07Z peter1138 $ */
2
3 /*
4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
8 */
9
20 #include "stdafx.h"
21 #include "newgrf.h"
22 #include "strings_func.h"
23 #include "newgrf_storage.h"
24 #include "newgrf_text.h"
25 #include "newgrf_cargo.h"
26 #include "string_func.h"
27 #include "date_type.h"
28 #include "debug.h"
29 #include "core/alloc_type.hpp"
30 #include "core/smallmap_type.hpp"
31 #include "language.h"
32
33 #include "table/strings.h"
34 #include "table/control_codes.h"
35
36 #include "safeguards.h"
37
43 enum GRFBaseLanguages {
44 GRFLB_AMERICAN = 0x01,
45 GRFLB_ENGLISH = 0x02,
46 GRFLB_GERMAN = 0x04,
47 GRFLB_FRENCH = 0x08,
48 GRFLB_SPANISH = 0x10,
49 GRFLB_GENERIC = 0x80,
50 };
51
52 enum GRFExtendedLanguages {
53 GRFLX_AMERICAN = 0x00,
54 GRFLX_ENGLISH = 0x01,
55 GRFLX_GERMAN = 0x02,
56 GRFLX_FRENCH = 0x03,
57 GRFLX_SPANISH = 0x04,
58 GRFLX_UNSPECIFIED = 0x7F,
59 };
60
66 struct GRFText {
67 public:
78 static GRFText *New(byte langid, const char *text, size_t len)
79 {
80 return new (len) GRFText(langid, text, len);
81 }
82
88 static GRFText *Copy(GRFText *orig)
89 {
90 return GRFText::New(orig->langid, orig->text, orig->len);
91 }
92
98 void *operator new(size_t size)
99 {
100 NOT_REACHED();
101 }
102
107 void operator delete(void *p)
108 {
109 free(p);
110 }
111 private:
118 GRFText(byte langid_, const char *text_, size_t len_) : next(NULL), len(len_), langid(langid_)
119 {
120 /* We need to use memcpy instead of strcpy due to
121 * the possibility of "choice lists" and therefore
122 * intermediate string terminators. */
123 memcpy(this->text, text_, len);
124 }
125
132 void *operator new(size_t size, size_t extra)
133 {
134 return MallocT<byte>(size + extra);
135 }
136
137 public:
138 GRFText *next;
139 size_t len;
140 byte langid;
141 char text[];
142 };
143
144
150 struct GRFTextEntry {
151 uint32 grfid;
152 uint16 stringid;
153 StringID def_string;
154 GRFText *textholder;
155 };
156
157
158 static uint _num_grf_texts = 0;
159 static GRFTextEntry _grf_text[TAB_SIZE_NEWGRF];
160 static byte _currentLangID = GRFLX_ENGLISH;
161
168 int LanguageMap::GetMapping(int newgrf_id, bool gender) const
169 {
170 const SmallVector<Mapping, 1> &map = gender ? this->gender_map : this->case_map;
171 for (const Mapping *m = map.Begin(); m != map.End(); m++) {
172 if (m->newgrf_id == newgrf_id) return m->openttd_id;
173 }
174 return -1;
175 }
176
183 int LanguageMap::GetReverseMapping(int openttd_id, bool gender) const
184 {
185 const SmallVector<Mapping, 1> &map = gender ? this->gender_map : this->case_map;
186 for (const Mapping *m = map.Begin(); m != map.End(); m++) {
187 if (m->openttd_id == openttd_id) return m->newgrf_id;
188 }
189 return -1;
190 }
191
193 struct UnmappedChoiceList : ZeroedMemoryAllocator {
195 ~UnmappedChoiceList()
196 {
197 for (SmallPair<byte, char *> *p = this->strings.Begin(); p < this->strings.End(); p++) {
198 free(p->second);
199 }
200 }
201
208 UnmappedChoiceList(StringControlCode type, char *old_d, int offset) :
209 type(type), old_d(old_d), offset(offset)
210 {
211 }
212
213 StringControlCode type;
214 char *old_d;
215 int offset;
216
218 SmallMap<byte, char *> strings;
219
225 char *Flush(const LanguageMap *lm)
226 {
227 if (!this->strings.Contains(0)) {
228 /* In case of a (broken) NewGRF without a default,
229 * assume an empty string. */
230 grfmsg(1, "choice list misses default value");
231 this->strings[0] = stredup("");
232 }
233
234 char *d = old_d;
235 if (lm == NULL) {
236 /* In case there is no mapping, just ignore everything but the default.
237 * A probable cause for this happening is when the language file has
238 * been removed by the user and as such no mapping could be made. */
239 size_t len = strlen(this->strings[0]);
240 memcpy(d, this->strings[0], len);
241 return d + len;
242 }
243
244 d += Utf8Encode(d, this->type);
245
246 if (this->type == SCC_SWITCH_CASE) {
247 /*
248 * Format for case switch:
249 * <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
250 * Each LEN is printed using 2 bytes in big endian order.
251 */
252
253 /* "<NUM CASES>" */
254 int count = 0;
255 for (uint8 i = 0; i < _current_language->num_cases; i++) {
256 /* Count the ones we have a mapped string for. */
257 if (this->strings.Contains(lm->GetReverseMapping(i, false))) count++;
258 }
259 *d++ = count;
260
261 for (uint8 i = 0; i < _current_language->num_cases; i++) {
262 /* Resolve the string we're looking for. */
263 int idx = lm->GetReverseMapping(i, false);
264 if (!this->strings.Contains(idx)) continue;
265 char *str = this->strings[idx];
266
267 /* "<CASEn>" */
268 *d++ = i + 1;
269
270 /* "<LENn>" */
271 size_t len = strlen(str) + 1;
272 *d++ = GB(len, 8, 8);
273 *d++ = GB(len, 0, 8);
274
275 /* "<STRINGn>" */
276 memcpy(d, str, len);
277 d += len;
278 }
279
280 /* "<STRINGDEFAULT>" */
281 size_t len = strlen(this->strings[0]) + 1;
282 memcpy(d, this->strings[0], len);
283 d += len;
284 } else {
285 if (this->type == SCC_PLURAL_LIST) {
286 *d++ = lm->plural_form;
287 }
288
289 /*
290 * Format for choice list:
291 * <OFFSET> <NUM CHOICES> <LENs> <STRINGs>
292 */
293
294 /* "<OFFSET>" */
295 *d++ = this->offset - 0x80;
296
297 /* "<NUM CHOICES>" */
298 int count = (this->type == SCC_GENDER_LIST ? _current_language->num_genders : LANGUAGE_MAX_PLURAL_FORMS);
299 *d++ = count;
300
301 /* "<LENs>" */
302 for (int i = 0; i < count; i++) {
303 int idx = (this->type == SCC_GENDER_LIST ? lm->GetReverseMapping(i, true) : i + 1);
304 const char *str = this->strings[this->strings.Contains(idx) ? idx : 0];
305 size_t len = strlen(str) + 1;
306 if (len > 0xFF) grfmsg(1, "choice list string is too long");
307 *d++ = GB(len, 0, 8);
308 }
309
310 /* "<STRINGs>" */
311 for (int i = 0; i < count; i++) {
312 int idx = (this->type == SCC_GENDER_LIST ? lm->GetReverseMapping(i, true) : i + 1);
313 const char *str = this->strings[this->strings.Contains(idx) ? idx : 0];
314 /* Limit the length of the string we copy to 0xFE. The length is written above
315 * as a byte and we need room for the final '\0'. */
316 size_t len = min<size_t>(0xFE, strlen(str));
317 memcpy(d, str, len);
318 d += len;
319 *d++ = '\0';
320 }
321 }
322 return d;
323 }
324 };
325
336 char *TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newlines, const char *str, int *olen, StringControlCode byte80)
337 {
338 char *tmp = MallocT<char>(strlen(str) * 10 + 1); // Allocate space to allow for expansion
339 char *d = tmp;
340 bool unicode = false;
341 WChar c;
342 size_t len = Utf8Decode(&c, str);
343
344 /* Helper variable for a possible (string) mapping. */
345 UnmappedChoiceList *mapping = NULL;
346
347 if (c == NFO_UTF8_IDENTIFIER) {
348 unicode = true;
349 str += len;
350 }
351
352 for (;;) {
353 if (unicode && Utf8EncodedCharLen(*str) != 0) {
354 c = Utf8Consume(&str);
355 /* 'Magic' range of control codes. */
356 if (GB(c, 8, 8) == 0xE0) {
357 c = GB(c, 0, 8);
358 } else if (c >= 0x20) {
359 if (!IsValidChar(c, CS_ALPHANUMERAL)) c = '?';
360 d += Utf8Encode(d, c);
361 continue;
362 }
363 } else {
364 c = (byte)*str++;
365 }
366 if (c == '\0') break;
367
368 switch (c) {
369 case 0x01:
370 if (str[0] == '\0') goto string_end;
371 d += Utf8Encode(d, ' ');
372 str++;
373 break;
374 case 0x0A: break;
375 case 0x0D:
376 if (allow_newlines) {
377 *d++ = 0x0A;
378 } else {
379 grfmsg(1, "Detected newline in string that does not allow one");
380 }
381 break;
382 case 0x0E: d += Utf8Encode(d, SCC_TINYFONT); break;
383 case 0x0F: d += Utf8Encode(d, SCC_BIGFONT); break;
384 case 0x1F:
385 if (str[0] == '\0' || str[1] == '\0') goto string_end;
386 d += Utf8Encode(d, ' ');
387 str += 2;
388 break;
389 case 0x7B:
390 case 0x7C:
391 case 0x7D:
392 case 0x7E:
393 case 0x7F: d += Utf8Encode(d, SCC_NEWGRF_PRINT_DWORD_SIGNED + c - 0x7B); break;
394 case 0x80: d += Utf8Encode(d, byte80); break;
395 case 0x81: {
396 if (str[0] == '\0' || str[1] == '\0') goto string_end;
397 StringID string;
398 string = ((uint8)*str++);
399 string |= ((uint8)*str++) << 8;
400 d += Utf8Encode(d, SCC_NEWGRF_STRINL);
401 d += Utf8Encode(d, MapGRFStringID(grfid, string));
402 break;
403 }
404 case 0x82:
405 case 0x83:
406 case 0x84: d += Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_DATE_LONG + c - 0x82); break;
407 case 0x85: d += Utf8Encode(d, SCC_NEWGRF_DISCARD_WORD); break;
408 case 0x86: d += Utf8Encode(d, SCC_NEWGRF_ROTATE_TOP_4_WORDS); break;
409 case 0x87: d += Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_VOLUME_LONG); break;
410 case 0x88: d += Utf8Encode(d, SCC_BLUE); break;
411 case 0x89: d += Utf8Encode(d, SCC_SILVER); break;
412 case 0x8A: d += Utf8Encode(d, SCC_GOLD); break;
413 case 0x8B: d += Utf8Encode(d, SCC_RED); break;
414 case 0x8C: d += Utf8Encode(d, SCC_PURPLE); break;
415 case 0x8D: d += Utf8Encode(d, SCC_LTBROWN); break;
416 case 0x8E: d += Utf8Encode(d, SCC_ORANGE); break;
417 case 0x8F: d += Utf8Encode(d, SCC_GREEN); break;
418 case 0x90: d += Utf8Encode(d, SCC_YELLOW); break;
419 case 0x91: d += Utf8Encode(d, SCC_DKGREEN); break;
420 case 0x92: d += Utf8Encode(d, SCC_CREAM); break;
421 case 0x93: d += Utf8Encode(d, SCC_BROWN); break;
422 case 0x94: d += Utf8Encode(d, SCC_WHITE); break;
423 case 0x95: d += Utf8Encode(d, SCC_LTBLUE); break;
424 case 0x96: d += Utf8Encode(d, SCC_GRAY); break;
425 case 0x97: d += Utf8Encode(d, SCC_DKBLUE); break;
426 case 0x98: d += Utf8Encode(d, SCC_BLACK); break;
427 case 0x9A: {
428 int code = *str++;
429 switch (code) {
430 case 0x00: goto string_end;
431 case 0x01: d += Utf8Encode(d, SCC_NEWGRF_PRINT_QWORD_CURRENCY); break;
432 /* 0x02: ignore next colour byte is not supported. It works on the final
433 * string and as such hooks into the string drawing routine. At that
434 * point many things already happened, such as splitting up of strings
435 * when drawn over multiple lines or right-to-left translations, which
436 * make the behaviour peculiar, e.g. only happening at specific width
437 * of windows. Or we need to add another pass over the string to just
438 * support this. As such it is not implemented in OpenTTD. */
439 case 0x03: {
440 if (str[0] == '\0' || str[1] == '\0') goto string_end;
441 uint16 tmp = ((uint8)*str++);
442 tmp |= ((uint8)*str++) << 8;
443 d += Utf8Encode(d, SCC_NEWGRF_PUSH_WORD);
444 d += Utf8Encode(d, tmp);
445 break;
446 }
447 case 0x04:
448 if (str[0] == '\0') goto string_end;
449 d += Utf8Encode(d, SCC_NEWGRF_UNPRINT);
450 d += Utf8Encode(d, *str++);
451 break;
452 case 0x06: d += Utf8Encode(d, SCC_NEWGRF_PRINT_BYTE_HEX); break;
453 case 0x07: d += Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_HEX); break;
454 case 0x08: d += Utf8Encode(d, SCC_NEWGRF_PRINT_DWORD_HEX); break;
455 /* 0x09, 0x0A are TTDPatch internal use only string codes. */
456 case 0x0B: d += Utf8Encode(d, SCC_NEWGRF_PRINT_QWORD_HEX); break;
457 case 0x0C: d += Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_STATION_NAME); break;
458 case 0x0D: d += Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG); break;
459 case 0x0E:
460 case 0x0F: {
461 if (str[0] == '\0') goto string_end;
462 const LanguageMap *lm = LanguageMap::GetLanguageMap(grfid, language_id);
463 int index = *str++;
464 int mapped = lm != NULL ? lm->GetMapping(index, code == 0x0E) : -1;
465 if (mapped >= 0) {
466 d += Utf8Encode(d, code == 0x0E ? SCC_GENDER_INDEX : SCC_SET_CASE);
467 d += Utf8Encode(d, code == 0x0E ? mapped : mapped + 1);
468 }
469 break;
470 }
471
472 case 0x10:
473 case 0x11:
474 if (str[0] == '\0') goto string_end;
475 if (mapping == NULL) {
476 if (code == 0x10) str++; // Skip the index
477 grfmsg(1, "choice list %s marker found when not expected", code == 0x10 ? "next" : "default");
478 break;
479 } else {
480 /* Terminate the previous string. */
481 *d = '\0';
482 int index = (code == 0x10 ? *str++ : 0);
483 if (mapping->strings.Contains(index)) {
484 grfmsg(1, "duplicate choice list string, ignoring");
485 d++;
486 } else {
487 d = mapping->strings[index] = MallocT<char>(strlen(str) * 10 + 1);
488 }
489 }
490 break;
491
492 case 0x12:
493 if (mapping == NULL) {
494 grfmsg(1, "choice list end marker found when not expected");
495 } else {
496 /* Terminate the previous string. */
497 *d = '\0';
498
499 /* Now we can start flushing everything and clean everything up. */
500 d = mapping->Flush(LanguageMap::GetLanguageMap(grfid, language_id));
501 delete mapping;
502 mapping = NULL;
503 }
504 break;
505
506 case 0x13:
507 case 0x14:
508 case 0x15:
509 if (str[0] == '\0') goto string_end;
510 if (mapping != NULL) {
511 grfmsg(1, "choice lists can't be stacked, it's going to get messy now...");
512 if (code != 0x14) str++;
513 } else {
514 static const StringControlCode mp[] = { SCC_GENDER_LIST, SCC_SWITCH_CASE, SCC_PLURAL_LIST };
515 mapping = new UnmappedChoiceList(mp[code - 0x13], d, code == 0x14 ? 0 : *str++);
516 }
517 break;
518
519 case 0x16:
520 case 0x17:
521 case 0x18:
522 case 0x19:
523 case 0x1A:
524 case 0x1B:
525 case 0x1C:
526 case 0x1D:
527 case 0x1E:
528 d += Utf8Encode(d, SCC_NEWGRF_PRINT_DWORD_DATE_LONG + code - 0x16);
529 break;
530
531 default:
532 grfmsg(1, "missing handler for extended format code");
533 break;
534 }
535 break;
536 }
537
538 case 0x9E: d += Utf8Encode(d, 0x20AC); break; // Euro
539 case 0x9F: d += Utf8Encode(d, 0x0178); break; // Y with diaeresis
540 case 0xA0: d += Utf8Encode(d, SCC_UP_ARROW); break;
541 case 0xAA: d += Utf8Encode(d, SCC_DOWN_ARROW); break;
542 case 0xAC: d += Utf8Encode(d, SCC_CHECKMARK); break;
543 case 0xAD: d += Utf8Encode(d, SCC_CROSS); break;
544 case 0xAF: d += Utf8Encode(d, SCC_RIGHT_ARROW); break;
545 case 0xB4: d += Utf8Encode(d, SCC_TRAIN); break;
546 case 0xB5: d += Utf8Encode(d, SCC_LORRY); break;
547 case 0xB6: d += Utf8Encode(d, SCC_BUS); break;
548 case 0xB7: d += Utf8Encode(d, SCC_PLANE); break;
549 case 0xB8: d += Utf8Encode(d, SCC_SHIP); break;
550 case 0xB9: d += Utf8Encode(d, SCC_SUPERSCRIPT_M1); break;
551 case 0xBC: d += Utf8Encode(d, SCC_SMALL_UP_ARROW); break;
552 case 0xBD: d += Utf8Encode(d, SCC_SMALL_DOWN_ARROW); break;
553 default:
554 /* Validate any unhandled character */
555 if (!IsValidChar(c, CS_ALPHANUMERAL)) c = '?';
556 d += Utf8Encode(d, c);
557 break;
558 }
559 }
560
561 string_end:
562 if (mapping != NULL) {
563 grfmsg(1, "choice list was incomplete, the whole list is ignored");
564 delete mapping;
565 }
566
567 *d = '\0';
568 if (olen != NULL) *olen = d - tmp + 1;
569 tmp = ReallocT(tmp, d - tmp + 1);
570 return tmp;
571 }
572
578 void AddGRFTextToList(GRFText **list, GRFText *text_to_add)
579 {
580 GRFText **ptext, *text;
581
582 /* Loop through all languages and see if we can replace a string */
583 for (ptext = list; (text = *ptext) != NULL; ptext = &text->next) {
584 if (text->langid == text_to_add->langid) {
585 text_to_add->next = text->next;
586 *ptext = text_to_add;
587 delete text;
588 return;
589 }
590 }
591
592 /* If a string wasn't replaced, then we must append the new string */
593 *ptext = text_to_add;
594 }
595
605 void AddGRFTextToList(struct GRFText **list, byte langid, uint32 grfid, bool allow_newlines, const char *text_to_add)
606 {
607 int len;
608 char *translatedtext = TranslateTTDPatchCodes(grfid, langid, allow_newlines, text_to_add, &len);
609 GRFText *newtext = GRFText::New(langid, translatedtext, len);
610 free(translatedtext);
611
612 AddGRFTextToList(list, newtext);
613 }
614
621 void AddGRFTextToList(struct GRFText **list, const char *text_to_add)
622 {
623 AddGRFTextToList(list, GRFText::New(0x7F, text_to_add, strlen(text_to_add) + 1));
624 }
625
631 GRFText *DuplicateGRFText(GRFText *orig)
632 {
633 GRFText *newtext = NULL;
634 GRFText **ptext = &newtext;
635 for (; orig != NULL; orig = orig->next) {
636 *ptext = GRFText::Copy(orig);
637 ptext = &(*ptext)->next;
638 }
639 return newtext;
640 }
641
645 StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid_to_add, bool new_scheme, bool allow_newlines, const char *text_to_add, StringID def_string)
646 {
647 char *translatedtext;
648 uint id;
649
650 /* When working with the old language scheme (grf_version is less than 7) and
651 * English or American is among the set bits, simply add it as English in
652 * the new scheme, i.e. as langid = 1.
653 * If English is set, it is pretty safe to assume the translations are not
654 * actually translated.
655 */
656 if (!new_scheme) {
657 if (langid_to_add & (GRFLB_AMERICAN | GRFLB_ENGLISH)) {
658 langid_to_add = GRFLX_ENGLISH;
659 } else {
660 StringID ret = STR_EMPTY;
661 if (langid_to_add & GRFLB_GERMAN) ret = AddGRFString(grfid, stringid, GRFLX_GERMAN, true, allow_newlines, text_to_add, def_string);
662 if (langid_to_add & GRFLB_FRENCH) ret = AddGRFString(grfid, stringid, GRFLX_FRENCH, true, allow_newlines, text_to_add, def_string);
663 if (langid_to_add & GRFLB_SPANISH) ret = AddGRFString(grfid, stringid, GRFLX_SPANISH, true, allow_newlines, text_to_add, def_string);
664 return ret;
665 }
666 }
667
668 for (id = 0; id < _num_grf_texts; id++) {
669 if (_grf_text[id].grfid == grfid && _grf_text[id].stringid == stringid) {
670 break;
671 }
672 }
673
674 /* Too many strings allocated, return empty */
675 if (id == lengthof(_grf_text)) return STR_EMPTY;
676
677 int len;
678 translatedtext = TranslateTTDPatchCodes(grfid, langid_to_add, allow_newlines, text_to_add, &len);
679
680 GRFText *newtext = GRFText::New(langid_to_add, translatedtext, len);
681
682 free(translatedtext);
683
684 /* If we didn't find our stringid and grfid in the list, allocate a new id */
685 if (id == _num_grf_texts) _num_grf_texts++;
686
687 if (_grf_text[id].textholder == NULL) {
688 _grf_text[id].grfid = grfid;
689 _grf_text[id].stringid = stringid;
690 _grf_text[id].def_string = def_string;
691 }
692 AddGRFTextToList(&_grf_text[id].textholder, newtext);
693
694 grfmsg(3, "Added 0x%X: grfid %08X string 0x%X lang 0x%X string '%s' (%X)", id, grfid, stringid, newtext->langid, newtext->text, MakeStringID(TEXT_TAB_NEWGRF_START, id));
695
696 return MakeStringID(TEXT_TAB_NEWGRF_START, id);
697 }
698
702 StringID GetGRFStringID(uint32 grfid, StringID stringid)
703 {
704 for (uint id = 0; id < _num_grf_texts; id++) {
705 if (_grf_text[id].grfid == grfid && _grf_text[id].stringid == stringid) {
706 return MakeStringID(TEXT_TAB_NEWGRF_START, id);
707 }
708 }
709
710 return STR_UNDEFINED;
711 }
712
713
721 const char *GetGRFStringFromGRFText(const GRFText *text)
722 {
723 const char *default_text = NULL;
724
725 /* Search the list of lang-strings of this stringid for current lang */
726 for (; text != NULL; text = text->next) {
727 if (text->langid == _currentLangID) return text->text;
728
729 /* If the current string is English or American, set it as the
730 * fallback language if the specific language isn't available. */
731 if (text->langid == GRFLX_UNSPECIFIED || (default_text == NULL && (text->langid == GRFLX_ENGLISH || text->langid == GRFLX_AMERICAN))) {
732 default_text = text->text;
733 }
734 }
735
736 return default_text;
737 }
738
742 const char *GetGRFStringPtr(uint16 stringid)
743 {
744 assert(_grf_text[stringid].grfid != 0);
745
746 const char *str = GetGRFStringFromGRFText(_grf_text[stringid].textholder);
747 if (str != NULL) return str;
748
749 /* Use the default string ID if the fallback string isn't available */
750 return GetStringPtr(_grf_text[stringid].def_string);
751 }
752
761 void SetCurrentGrfLangID(byte language_id)
762 {
763 _currentLangID = language_id;
764 }
765
766 bool CheckGrfLangID(byte lang_id, byte grf_version)
767 {
768 if (grf_version < 7) {
769 switch (_currentLangID) {
770 case GRFLX_GERMAN: return (lang_id & GRFLB_GERMAN) != 0;
771 case GRFLX_FRENCH: return (lang_id & GRFLB_FRENCH) != 0;
772 case GRFLX_SPANISH: return (lang_id & GRFLB_SPANISH) != 0;
773 default: return (lang_id & (GRFLB_ENGLISH | GRFLB_AMERICAN)) != 0;
774 }
775 }
776
777 return (lang_id == _currentLangID || lang_id == GRFLX_UNSPECIFIED);
778 }
779
784 void CleanUpGRFText(GRFText *grftext)
785 {
786 while (grftext != NULL) {
787 GRFText *grftext2 = grftext->next;
788 delete grftext;
789 grftext = grftext2;
790 }
791 }
792
797 void CleanUpStrings()
798 {
799 uint id;
800
801 for (id = 0; id < _num_grf_texts; id++) {
802 CleanUpGRFText(_grf_text[id].textholder);
803 _grf_text[id].grfid = 0;
804 _grf_text[id].stringid = 0;
805 _grf_text[id].textholder = NULL;
806 }
807
808 _num_grf_texts = 0;
809 }
810
811 struct TextRefStack {
812 byte stack[0x30];
813 byte position;
814 const GRFFile *grffile;
815 bool used;
816
817 TextRefStack() : position(0), grffile(NULL), used(false) {}
818
819 TextRefStack(const TextRefStack &stack) :
820 position(stack.position),
821 grffile(stack.grffile),
822 used(stack.used)
823 {
824 memcpy(this->stack, stack.stack, sizeof(this->stack));
825 }
826
827 uint8 PopUnsignedByte() { assert(this->position < lengthof(this->stack)); return this->stack[this->position++]; }
828 int8 PopSignedByte() { return (int8)this->PopUnsignedByte(); }
829
830 uint16 PopUnsignedWord()
831 {
832 uint16 val = this->PopUnsignedByte();
833 return val | (this->PopUnsignedByte() << 8);
834 }
835 int16 PopSignedWord() { return (int32)this->PopUnsignedWord(); }
836
837 uint32 PopUnsignedDWord()
838 {
839 uint32 val = this->PopUnsignedWord();
840 return val | (this->PopUnsignedWord() << 16);
841 }
842 int32 PopSignedDWord() { return (int32)this->PopUnsignedDWord(); }
843
844 uint64 PopUnsignedQWord()
845 {
846 uint64 val = this->PopUnsignedDWord();
847 return val | (((uint64)this->PopUnsignedDWord()) << 32);
848 }
849 int64 PopSignedQWord() { return (int64)this->PopUnsignedQWord(); }
850
852 void RotateTop4Words()
853 {
854 byte tmp[2];
855 for (int i = 0; i < 2; i++) tmp[i] = this->stack[this->position + i + 6];
856 for (int i = 5; i >= 0; i--) this->stack[this->position + i + 2] = this->stack[this->position + i];
857 for (int i = 0; i < 2; i++) this->stack[this->position + i] = tmp[i];
858 }
859
860 void PushWord(uint16 word)
861 {
862 if (this->position >= 2) {
863 this->position -= 2;
864 } else {
865 for (int i = lengthof(stack) - 1; i >= this->position + 2; i--) {
866 this->stack[i] = this->stack[i - 2];
867 }
868 }
869 this->stack[this->position] = GB(word, 0, 8);
870 this->stack[this->position + 1] = GB(word, 8, 8);
871 }
872
873 void ResetStack(const GRFFile *grffile)
874 {
875 assert(grffile != NULL);
876 this->position = 0;
877 this->grffile = grffile;
878 this->used = true;
879 }
880
881 void RewindStack() { this->position = 0; }
882 };
883
885 static TextRefStack _newgrf_textrefstack;
886
891 bool UsingNewGRFTextStack()
892 {
893 return _newgrf_textrefstack.used;
894 }
895
900 struct TextRefStack *CreateTextRefStackBackup()
901 {
902 return new TextRefStack(_newgrf_textrefstack);
903 }
904
909 void RestoreTextRefStackBackup(struct TextRefStack *backup)
910 {
911 _newgrf_textrefstack = *backup;
912 delete backup;
913 }
914
933 void StartTextRefStackUsage(const GRFFile *grffile, byte numEntries, const uint32 *values)
934 {
935 extern TemporaryStorageArray<int32, 0x110> _temp_store;
936
937 _newgrf_textrefstack.ResetStack(grffile);
938
939 byte *p = _newgrf_textrefstack.stack;
940 for (uint i = 0; i < numEntries; i++) {
941 uint32 value = values != NULL ? values[i] : _temp_store.GetValue(0x100 + i);
942 for (uint j = 0; j < 32; j += 8) {
943 *p = GB(value, j, 8);
944 p++;
945 }
946 }
947 }
948
950 void StopTextRefStackUsage()
951 {
952 _newgrf_textrefstack.used = false;
953 }
954
955 void RewindTextRefStack()
956 {
957 _newgrf_textrefstack.RewindStack();
958 }
959
970 uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const char **str, int64 *argv, uint argv_size, bool modify_argv)
971 {
972 switch (scc) {
973 default: break;
974
975 case SCC_NEWGRF_PRINT_DWORD_SIGNED:
976 case SCC_NEWGRF_PRINT_WORD_SIGNED:
977 case SCC_NEWGRF_PRINT_BYTE_SIGNED:
978 case SCC_NEWGRF_PRINT_WORD_UNSIGNED:
979 case SCC_NEWGRF_PRINT_BYTE_HEX:
980 case SCC_NEWGRF_PRINT_WORD_HEX:
981 case SCC_NEWGRF_PRINT_DWORD_HEX:
982 case SCC_NEWGRF_PRINT_QWORD_HEX:
983 case SCC_NEWGRF_PRINT_DWORD_CURRENCY:
984 case SCC_NEWGRF_PRINT_QWORD_CURRENCY:
985 case SCC_NEWGRF_PRINT_WORD_STRING_ID:
986 case SCC_NEWGRF_PRINT_WORD_DATE_LONG:
987 case SCC_NEWGRF_PRINT_DWORD_DATE_LONG:
988 case SCC_NEWGRF_PRINT_WORD_DATE_SHORT:
989 case SCC_NEWGRF_PRINT_DWORD_DATE_SHORT:
990 case SCC_NEWGRF_PRINT_WORD_SPEED:
991 case SCC_NEWGRF_PRINT_WORD_VOLUME_LONG:
992 case SCC_NEWGRF_PRINT_WORD_VOLUME_SHORT:
993 case SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG:
994 case SCC_NEWGRF_PRINT_WORD_WEIGHT_SHORT:
995 case SCC_NEWGRF_PRINT_WORD_POWER:
996 case SCC_NEWGRF_PRINT_WORD_STATION_NAME:
997 case SCC_NEWGRF_PRINT_WORD_CARGO_NAME:
998 if (argv_size < 1) {
999 DEBUG(misc, 0, "Too many NewGRF string parameters.");
1000 return 0;
1001 }
1002 break;
1003
1004 case SCC_NEWGRF_PRINT_WORD_CARGO_LONG:
1005 case SCC_NEWGRF_PRINT_WORD_CARGO_SHORT:
1006 case SCC_NEWGRF_PRINT_WORD_CARGO_TINY:
1007 if (argv_size < 2) {
1008 DEBUG(misc, 0, "Too many NewGRF string parameters.");
1009 return 0;
1010 }
1011 break;
1012 }
1013
1014 if (_newgrf_textrefstack.used && modify_argv) {
1015 switch (scc) {
1016 default: NOT_REACHED();
1017 case SCC_NEWGRF_PRINT_BYTE_SIGNED: *argv = _newgrf_textrefstack.PopSignedByte(); break;
1018 case SCC_NEWGRF_PRINT_QWORD_CURRENCY: *argv = _newgrf_textrefstack.PopSignedQWord(); break;
1019
1020 case SCC_NEWGRF_PRINT_DWORD_CURRENCY:
1021 case SCC_NEWGRF_PRINT_DWORD_SIGNED: *argv = _newgrf_textrefstack.PopSignedDWord(); break;
1022
1023 case SCC_NEWGRF_PRINT_BYTE_HEX: *argv = _newgrf_textrefstack.PopUnsignedByte(); break;
1024 case SCC_NEWGRF_PRINT_QWORD_HEX: *argv = _newgrf_textrefstack.PopUnsignedQWord(); break;
1025
1026 case SCC_NEWGRF_PRINT_WORD_SPEED:
1027 case SCC_NEWGRF_PRINT_WORD_VOLUME_LONG:
1028 case SCC_NEWGRF_PRINT_WORD_VOLUME_SHORT:
1029 case SCC_NEWGRF_PRINT_WORD_SIGNED: *argv = _newgrf_textrefstack.PopSignedWord(); break;
1030
1031 case SCC_NEWGRF_PRINT_WORD_HEX:
1032 case SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG:
1033 case SCC_NEWGRF_PRINT_WORD_WEIGHT_SHORT:
1034 case SCC_NEWGRF_PRINT_WORD_POWER:
1035 case SCC_NEWGRF_PRINT_WORD_STATION_NAME:
1036 case SCC_NEWGRF_PRINT_WORD_UNSIGNED: *argv = _newgrf_textrefstack.PopUnsignedWord(); break;
1037
1038 case SCC_NEWGRF_PRINT_DWORD_DATE_LONG:
1039 case SCC_NEWGRF_PRINT_DWORD_DATE_SHORT:
1040 case SCC_NEWGRF_PRINT_DWORD_HEX: *argv = _newgrf_textrefstack.PopUnsignedDWord(); break;
1041
1042 case SCC_NEWGRF_PRINT_WORD_DATE_LONG:
1043 case SCC_NEWGRF_PRINT_WORD_DATE_SHORT: *argv = _newgrf_textrefstack.PopUnsignedWord() + DAYS_TILL_ORIGINAL_BASE_YEAR; break;
1044
1045 case SCC_NEWGRF_DISCARD_WORD: _newgrf_textrefstack.PopUnsignedWord(); break;
1046
1047 case SCC_NEWGRF_ROTATE_TOP_4_WORDS: _newgrf_textrefstack.RotateTop4Words(); break;
1048 case SCC_NEWGRF_PUSH_WORD: _newgrf_textrefstack.PushWord(Utf8Consume(str)); break;
1049 case SCC_NEWGRF_UNPRINT: *buff = max(*buff - Utf8Consume(str), buf_start); break;
1050
1051 case SCC_NEWGRF_PRINT_WORD_CARGO_LONG:
1052 case SCC_NEWGRF_PRINT_WORD_CARGO_SHORT:
1053 case SCC_NEWGRF_PRINT_WORD_CARGO_TINY:
1054 argv[0] = GetCargoTranslation(_newgrf_textrefstack.PopUnsignedWord(), _newgrf_textrefstack.grffile);
1055 argv[1] = _newgrf_textrefstack.PopUnsignedWord();
1056 break;
1057
1058 case SCC_NEWGRF_PRINT_WORD_STRING_ID:
1059 *argv = MapGRFStringID(_newgrf_textrefstack.grffile->grfid, _newgrf_textrefstack.PopUnsignedWord());
1060 break;
1061
1062 case SCC_NEWGRF_PRINT_WORD_CARGO_NAME: {
1063 CargoID cargo = GetCargoTranslation(_newgrf_textrefstack.PopUnsignedWord(), _newgrf_textrefstack.grffile);
1064 *argv = cargo < NUM_CARGO ? 1 << cargo : 0;
1065 break;
1066 }
1067 }
1068 } else {
1069 /* Consume additional parameter characters */
1070 switch (scc) {
1071 default: break;
1072
1073 case SCC_NEWGRF_PUSH_WORD:
1074 case SCC_NEWGRF_UNPRINT:
1075 Utf8Consume(str);
1076 break;
1077 }
1078 }
1079
1080 switch (scc) {
1081 default: NOT_REACHED();
1082 case SCC_NEWGRF_PRINT_DWORD_SIGNED:
1083 case SCC_NEWGRF_PRINT_WORD_SIGNED:
1084 case SCC_NEWGRF_PRINT_BYTE_SIGNED:
1085 case SCC_NEWGRF_PRINT_WORD_UNSIGNED:
1086 return SCC_COMMA;
1087
1088 case SCC_NEWGRF_PRINT_BYTE_HEX:
1089 case SCC_NEWGRF_PRINT_WORD_HEX:
1090 case SCC_NEWGRF_PRINT_DWORD_HEX:
1091 case SCC_NEWGRF_PRINT_QWORD_HEX:
1092 return SCC_HEX;
1093
1094 case SCC_NEWGRF_PRINT_DWORD_CURRENCY:
1095 case SCC_NEWGRF_PRINT_QWORD_CURRENCY:
1096 return SCC_CURRENCY_LONG;
1097
1098 case SCC_NEWGRF_PRINT_WORD_STRING_ID:
1099 return SCC_NEWGRF_PRINT_WORD_STRING_ID;
1100
1101 case SCC_NEWGRF_PRINT_WORD_DATE_LONG:
1102 case SCC_NEWGRF_PRINT_DWORD_DATE_LONG:
1103 return SCC_DATE_LONG;
1104
1105 case SCC_NEWGRF_PRINT_WORD_DATE_SHORT:
1106 case SCC_NEWGRF_PRINT_DWORD_DATE_SHORT:
1107 return SCC_DATE_SHORT;
1108
1109 case SCC_NEWGRF_PRINT_WORD_SPEED:
1110 return SCC_VELOCITY;
1111
1112 case SCC_NEWGRF_PRINT_WORD_VOLUME_LONG:
1113 return SCC_VOLUME_LONG;
1114
1115 case SCC_NEWGRF_PRINT_WORD_VOLUME_SHORT:
1116 return SCC_VOLUME_SHORT;
1117
1118 case SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG:
1119 return SCC_WEIGHT_LONG;
1120
1121 case SCC_NEWGRF_PRINT_WORD_WEIGHT_SHORT:
1122 return SCC_WEIGHT_SHORT;
1123
1124 case SCC_NEWGRF_PRINT_WORD_POWER:
1125 return SCC_POWER;
1126
1127 case SCC_NEWGRF_PRINT_WORD_CARGO_LONG:
1128 return SCC_CARGO_LONG;
1129
1130 case SCC_NEWGRF_PRINT_WORD_CARGO_SHORT:
1131 return SCC_CARGO_SHORT;
1132
1133 case SCC_NEWGRF_PRINT_WORD_CARGO_TINY:
1134 return SCC_CARGO_TINY;
1135
1136 case SCC_NEWGRF_PRINT_WORD_CARGO_NAME:
1137 return SCC_CARGO_LIST;
1138
1139 case SCC_NEWGRF_PRINT_WORD_STATION_NAME:
1140 return SCC_STATION_NAME;
1141
1142 case SCC_NEWGRF_DISCARD_WORD:
1143 case SCC_NEWGRF_ROTATE_TOP_4_WORDS:
1144 case SCC_NEWGRF_PUSH_WORD:
1145 case SCC_NEWGRF_UNPRINT:
1146 return 0;
1147 }
1148 }
strings_func.h
Functions related to OTTD&#39;s strings.
SCC_NEWGRF_PRINT_DWORD_DATE_SHORT
9A 17: Read 4 bytes from the stack as base 0 date
Definition: control_codes.h:139
SCC_NEWGRF_PUSH_WORD
9A 03: Pushes 2 bytes onto the stack
Definition: control_codes.h:147
SCC_NEWGRF_STRINL
Inline another string at the current position, StringID is encoded in the string. ...
Definition: control_codes.h:153
UnmappedChoiceList::offset
int offset
The offset for the plural/gender form.
Definition: newgrf_text.cpp:215
AddGRFString
StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid_to_add, bool new_scheme, bool allow_newlines, const char *text_to_add, StringID def_string)
Add the new read string into our structure.
Definition: newgrf_text.cpp:645
SmallMap::Contains
bool Contains(const T &key) const
Tests whether a key is assigned in this map.
Definition: smallmap_type.hpp:83
control_codes.h
Control codes that are embedded in the translation strings.
UsingNewGRFTextStack
bool UsingNewGRFTextStack()
Check whether the NewGRF text stack is in use.
Definition: newgrf_text.cpp:891
LanguageMap::plural_form
int plural_form
The plural form used for this language.
Definition: newgrf_text.h:62
DAYS_TILL_ORIGINAL_BASE_YEAR
#define DAYS_TILL_ORIGINAL_BASE_YEAR
The offset in days from the &#39;_date == 0&#39; till &#39;ConvertYMDToDate(ORIGINAL_BASE_YEAR, 0, 1)&#39;.
Definition: date_type.h:82
newgrf_storage.h
Functionality related to the temporary and persistent storage arrays for NewGRFs. ...
StringControlCode
StringControlCode
List of string control codes used for string formatting, displaying, and by strgen to generate the la...
Definition: control_codes.h:19
debug.h
Functions related to debugging.
SetCurrentGrfLangID
void SetCurrentGrfLangID(byte language_id)
Equivalence Setter function between game and newgrf langID.
Definition: newgrf_text.cpp:761
GetCargoTranslation
CargoID GetCargoTranslation(uint8 cargo, const GRFFile *grffile, bool usebit)
Translate a GRF-local cargo slot/bitnum into a CargoID.
Definition: newgrf_cargo.cpp:78
TemporaryStorageArray
Class for temporary storage of data.
Definition: newgrf_storage.h:152
TranslateTTDPatchCodes
char * TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newlines, const char *str, int *olen, StringControlCode byte80)
Translate TTDPatch string codes into something OpenTTD can handle (better).
Definition: newgrf_text.cpp:336
_currentLangID
static byte _currentLangID
by default, english is used.
Definition: newgrf_text.cpp:160
GRFText::next
GRFText * next
The next GRFText in this chain.
Definition: newgrf_text.cpp:138
_current_language
const LanguageMetadata * _current_language
The currently loaded language.
Definition: strings.cpp:50
SmallMap
Implementation of simple mapping class.
Definition: smallmap_type.hpp:42
SCC_NEWGRF_PRINT_WORD_DATE_SHORT
83: Read 2 bytes from the stack as base 1920 date
Definition: control_codes.h:128
SCC_NEWGRF_ROTATE_TOP_4_WORDS
86: Rotate the top 4 words of the stack (W4 W1 W2 W3)
Definition: control_codes.h:150
SCC_BIGFONT
Switch to large font.
Definition: control_codes.h:31
SmallVector::Begin
const T * Begin() const
Get the pointer to the first item (const)
Definition: smallvec_type.hpp:272
SCC_NEWGRF_PRINT_WORD_DATE_LONG
82: Read 2 bytes from the stack as base 1920 date
Definition: control_codes.h:127
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:144
MakeStringID
static StringID MakeStringID(StringTab tab, uint index)
Create a StringID.
Definition: strings_func.h:49
Utf8Decode
size_t Utf8Decode(WChar *c, const char *s)
Decode and consume the next UTF-8 encoded character.
Definition: string.cpp:437
SCC_NEWGRF_UNPRINT
9A 04: "Unprints" the given number of bytes from the string
Definition: control_codes.h:148
SmallVector
Simple vector template class.
Definition: smallvec_type.hpp:29
GetGRFStringID
StringID GetGRFStringID(uint32 grfid, StringID stringid)
Returns the index for this stringid associated with its grfID.
Definition: newgrf_text.cpp:702
alloc_type.hpp
Helper types related to the allocation of memory.
max
static T max(const T a, const T b)
Returns the maximum of two values.
Definition: math_func.hpp:26
SmallVector::End
const T * End() const
Get the pointer behind the last valid item (const)
Definition: smallvec_type.hpp:292
LanguageMap::GetLanguageMap
static const LanguageMap * GetLanguageMap(uint32 grfid, uint8 language_id)
Get the language map associated with a given NewGRF and language.
Definition: newgrf.cpp:2543
smallmap_type.hpp
Simple mapping class targeted for small sets of data.
LanguagePackHeader::num_cases
uint8 num_cases
the number of cases of this language
Definition: language.h:56
RemapNewGRFStringControlCode
uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const char **str, int64 *argv, uint argv_size, bool modify_argv)
FormatString for NewGRF specific "magic" string control codes.
Definition: newgrf_text.cpp:970
LanguageMap::Mapping
Mapping between NewGRF and OpenTTD IDs.
Definition: newgrf_text.h:49
Utf8EncodedCharLen
static int8 Utf8EncodedCharLen(char c)
Return the length of an UTF-8 encoded value based on a single char.
Definition: string_func.h:118
newgrf_text.h
Header of Action 04 "universal holder" structure and functions.
GRFText::len
size_t len
The length of the stored string, used for copying.
Definition: newgrf_text.cpp:139
SCC_NEWGRF_PRINT_WORD_STATION_NAME
9A 0C: Read 2 bytes from the stack as station name
Definition: control_codes.h:132
string_func.h
Functions related to low-level strings.
IsValidChar
bool IsValidChar(WChar key, CharSetFilter afilter)
Only allow certain keys.
Definition: string.cpp:338
SCC_NEWGRF_PRINT_WORD_HEX
9A 07: Read 2 bytes from the stack and print it as hex
Definition: control_codes.h:135
GRFText::New
static GRFText * New(byte langid, const char *text, size_t len)
Allocate, and assign a new GRFText with the given text.
Definition: newgrf_text.cpp:78
UnmappedChoiceList::~UnmappedChoiceList
~UnmappedChoiceList()
Clean everything up.
Definition: newgrf_text.cpp:195
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:143
AddGRFTextToList
void AddGRFTextToList(GRFText **list, GRFText *text_to_add)
Add a GRFText to a GRFText list.
Definition: newgrf_text.cpp:578
SmallPair< byte, char * >
SCC_NEWGRF_PRINT_WORD_POWER
9A 18: Read 2 bytes from the stack as unsigned power
Definition: control_codes.h:140
UnmappedChoiceList::type
StringControlCode type
The type of choice list.
Definition: newgrf_text.cpp:213
SCC_NEWGRF_PRINT_WORD_WEIGHT_SHORT
9A 1A: Read 2 bytes from the stack as short unsigned weight
Definition: control_codes.h:142
SCC_NEWGRF_PRINT_WORD_STRING_ID
81: Read 2 bytes from the stack as String ID
Definition: control_codes.h:126
TAB_SIZE_NEWGRF
static const uint TAB_SIZE_NEWGRF
Number of strings for NewGRFs.
Definition: strings_type.h:54
SCC_NEWGRF_PRINT_WORD_VOLUME_LONG
87: Read 2 bytes from the stack as long signed volume
Definition: control_codes.h:130
CleanUpGRFText
void CleanUpGRFText(GRFText *grftext)
Delete all items of a linked GRFText list.
Definition: newgrf_text.cpp:784
LanguageMap
Mapping of language data between a NewGRF and OpenTTD.
Definition: newgrf_text.h:47
stdafx.h
Definition of base types and functions in a cross-platform compatible way.
safeguards.h
A number of safeguards to prevent using unsafe methods.
UnmappedChoiceList::old_d
char * old_d
The old/original location of the "d" local variable.
Definition: newgrf_text.cpp:214
TextRefStack::RotateTop4Words
void RotateTop4Words()
Rotate the top four words down: W1, W2, W3, W4 -> W4, W1, W2, W3.
Definition: newgrf_text.cpp:852
MapGRFStringID
StringID MapGRFStringID(uint32 grfid, StringID str)
Used when setting an object&#39;s property to map to the GRF&#39;s strings while taking in consideration the ...
Definition: newgrf.cpp:552
SCC_NEWGRF_PRINT_DWORD_HEX
9A 08: Read 4 bytes from the stack and print it as hex
Definition: control_codes.h:136
SCC_NEWGRF_PRINT_QWORD_HEX
9A 0B: Read 8 bytes from the stack and print it as hex
Definition: control_codes.h:137
CleanUpStrings
void CleanUpStrings()
House cleaning.
Definition: newgrf_text.cpp:797
language.h
Information about languages and their files.
SCC_NEWGRF_PRINT_WORD_CARGO_NAME
9A 1E: Read 2 bytes from the stack as cargo name
Definition: control_codes.h:146
ReallocT
static T * ReallocT(T *t_ptr, size_t num_elements)
Simplified reallocation function that allocates the specified number of elements of the given type...
Definition: alloc_func.hpp:113
stredup
char * stredup(const char *s, const char *last)
Create a duplicate of the given string.
Definition: string.cpp:126
GRFText::langid
byte langid
The language associated with this GRFText.
Definition: newgrf_text.cpp:140
GRFBaseLanguages
GRFBaseLanguages
Explains the newgrf shift bit positioning.
Definition: newgrf_text.cpp:43
lengthof
#define lengthof(x)
Return the length of an fixed size array.
Definition: depend.cpp:42
_newgrf_textrefstack
static TextRefStack _newgrf_textrefstack
The stack that is used for TTDP compatible string code parsing.
Definition: newgrf_text.cpp:885
GRFText
Element of the linked list.
Definition: newgrf_text.cpp:66
StartTextRefStackUsage
void StartTextRefStackUsage(const GRFFile *grffile, byte numEntries, const uint32 *values)
Start using the TTDP compatible string code parsing.
Definition: newgrf_text.cpp:933
ZeroedMemoryAllocator
Base class that provides memory initialization on dynamically created objects.
Definition: alloc_type.hpp:150
StringID
uint32 StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:18
LanguageMap::GetReverseMapping
int GetReverseMapping(int openttd_id, bool gender) const
Get the mapping from OpenTTD&#39;s internal ID to the NewGRF supplied ID.
Definition: newgrf_text.cpp:183
UnmappedChoiceList::Flush
char * Flush(const LanguageMap *lm)
Flush this choice list into the old d variable.
Definition: newgrf_text.cpp:225
GRFText::text
char text[]
The actual (translated) text.
Definition: newgrf_text.cpp:141
UnmappedChoiceList
Helper structure for mapping choice lists.
Definition: newgrf_text.cpp:193
DEBUG
#define DEBUG(name, level,...)
Output a line of debugging information.
Definition: debug.h:39
NUM_CARGO
Maximal number of cargo types in a game.
Definition: cargo_type.h:66
DuplicateGRFText
GRFText * DuplicateGRFText(GRFText *orig)
Create a copy of this GRFText list.
Definition: newgrf_text.cpp:631
LanguagePackHeader::num_genders
uint8 num_genders
the number of genders of this language
Definition: language.h:55
SCC_NEWGRF_PRINT_WORD_SIGNED
7C: Read 2 bytes from the stack as signed value
Definition: control_codes.h:122
GetGRFStringFromGRFText
const char * GetGRFStringFromGRFText(const GRFText *text)
Get a C-string from a GRFText-list.
Definition: newgrf_text.cpp:721
GRFTextEntry
Holder of the above structure.
Definition: newgrf_text.cpp:150
SCC_NEWGRF_DISCARD_WORD
85: Discard the next two bytes
Definition: control_codes.h:149
CS_ALPHANUMERAL
Both numeric and alphabetic and spaces and stuff.
Definition: string_type.h:27
NFO_UTF8_IDENTIFIER
static const WChar NFO_UTF8_IDENTIFIER
This character, the thorn (&#39;þ&#39;), indicates a unicode string to NFO.
Definition: newgrf_text.h:21
SCC_NEWGRF_PRINT_DWORD_DATE_LONG
9A 16: Read 4 bytes from the stack as base 0 date
Definition: control_codes.h:138
SCC_NEWGRF_PRINT_BYTE_SIGNED
7D: Read 1 byte from the stack as signed value
Definition: control_codes.h:123
newgrf_cargo.h
Cargo support for NewGRFs.
SCC_NEWGRF_PRINT_DWORD_SIGNED
7B: Read 4 bytes from the stack
Definition: control_codes.h:121
LanguageMap::GetMapping
int GetMapping(int newgrf_id, bool gender) const
Get the mapping from the NewGRF supplied ID to OpenTTD&#39;s internal ID.
Definition: newgrf_text.cpp:168
grfmsg
void CDECL grfmsg(int severity, const char *str,...)
DEBUG() function dedicated to newGRF debugging messages Function is essentially the same as DEBUG(grf...
Definition: newgrf.cpp:375
GB
static uint GB(const T x, const uint8 s, const uint8 n)
Fetch n bits from x, started at bit s.
Definition: bitmath_func.hpp:34
GRFText::GRFText
GRFText(byte langid_, const char *text_, size_t len_)
Actually construct the GRFText.
Definition: newgrf_text.cpp:118
RestoreTextRefStackBackup
void RestoreTextRefStackBackup(struct TextRefStack *backup)
Restore a copy of the text stack to the used stack.
Definition: newgrf_text.cpp:909
UnmappedChoiceList::UnmappedChoiceList
UnmappedChoiceList(StringControlCode type, char *old_d, int offset)
Initialise the mapping.
Definition: newgrf_text.cpp:208
GetGRFStringPtr
const char * GetGRFStringPtr(uint16 stringid)
Get a C-string from a stringid set by a newgrf.
Definition: newgrf_text.cpp:742
TEXT_TAB_NEWGRF_START
Start of NewGRF supplied strings.
Definition: strings_type.h:42
SCC_NEWGRF_PRINT_DWORD_CURRENCY
8F: Read 4 bytes from the stack as currency
Definition: control_codes.h:125
SCC_NEWGRF_PRINT_QWORD_CURRENCY
9A 01: Read 8 bytes from the stack as currency
Definition: control_codes.h:133
CreateTextRefStackBackup
struct TextRefStack * CreateTextRefStackBackup()
Create a backup of the current NewGRF text stack.
Definition: newgrf_text.cpp:900
SCC_NEWGRF_PRINT_WORD_SPEED
84: Read 2 bytes from the stack as signed speed
Definition: control_codes.h:129
SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG
9A 0D: Read 2 bytes from the stack as long unsigned weight
Definition: control_codes.h:131
date_type.h
Types related to the dates in OpenTTD.
Utf8Encode
size_t Utf8Encode(char *buf, WChar c)
Encode a unicode character and place it in the buffer.
Definition: string.cpp:477
free
static void free(const void *ptr)
Version of the standard free that accepts const pointers.
Definition: depend.cpp:114
SCC_NEWGRF_PRINT_BYTE_HEX
9A 06: Read 1 byte from the stack and print it as hex
Definition: control_codes.h:134
TemporaryStorageArray::GetValue
TYPE GetValue(uint pos) const
Gets the value from a given position.
Definition: newgrf_storage.h:184
CargoID
byte CargoID
Cargo slots to indicate a cargo type within a game.
Definition: cargo_type.h:22
SCC_NEWGRF_PRINT_WORD_UNSIGNED
7E: Read 2 bytes from the stack as unsigned value
Definition: control_codes.h:124
SCC_NEWGRF_PRINT_WORD_VOLUME_SHORT
9A 19: Read 2 bytes from the stack as short signed volume
Definition: control_codes.h:141
WChar
uint32 WChar
Type for wide characters, i.e.
Definition: string_type.h:35
UnmappedChoiceList::strings
SmallMap< byte, char * > strings
Mapping of NewGRF supplied ID to the different strings in the choice list.
Definition: newgrf_text.cpp:218
SCC_TINYFONT
Switch to small font.
Definition: control_codes.h:30
GRFText::Copy
static GRFText * Copy(GRFText *orig)
Create a copy of this GRFText.
Definition: newgrf_text.cpp:88
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:145
TextRefStack
Definition: newgrf_text.cpp:811
StopTextRefStackUsage
void StopTextRefStackUsage()
Stop using the TTDP compatible string code parsing.
Definition: newgrf_text.cpp:950
GRFFile
Dynamic data of a loaded NewGRF.
Definition: newgrf.h:104
newgrf.h
Base for the NewGRF implementation.