35 static char *GetSpecialPlayerNameString(char *buff, int ind, const int32 *argv, const char* last); |
37 static char *GetSpecialPlayerNameString(char *buff, int ind, const int32 *argv, const char* last); |
36 |
38 |
37 static char *FormatString(char *buff, const char *str, const int32 *argv, uint casei, const char* last); |
39 static char *FormatString(char *buff, const char *str, const int32 *argv, uint casei, const char* last); |
38 |
40 |
39 struct LanguagePack { |
41 struct LanguagePack { |
40 uint32 ident; |
42 uint32 ident; // 32-bits identifier |
41 uint32 version; // 32-bits of auto generated version info which is basically a hash of strings.h |
43 uint32 version; // 32-bits of auto generated version info which is basically a hash of strings.h |
42 char name[32]; // the international name of this language |
44 char name[32]; // the international name of this language |
43 char own_name[32]; // the localized name of this language |
45 char own_name[32]; // the localized name of this language |
44 char isocode[16]; // the ISO code for the language (not country code) |
46 char isocode[16]; // the ISO code for the language (not country code) |
45 uint16 offsets[32]; // the offsets |
47 uint16 offsets[32]; // the offsets |
46 byte plural_form; // how to compute plural forms |
48 byte plural_form; // how to compute plural forms |
47 byte pad[3]; // pad header to be a multiple of 4 |
49 byte pad[3]; // pad header to be a multiple of 4 |
48 char data[VARARRAY_SIZE]; |
50 char data[VARARRAY_SIZE]; // list of strings |
49 }; |
51 }; |
50 |
52 |
51 static char **_langpack_offs; |
53 static char **_langpack_offs; |
52 static LanguagePack *_langpack; |
54 static LanguagePack *_langpack; |
53 static uint _langtab_num[32]; // Offset into langpack offs |
55 static uint _langtab_num[32]; // Offset into langpack offs |
54 static uint _langtab_start[32]; // Offset into langpack offs |
56 static uint _langtab_start[32]; // Offset into langpack offs |
55 |
57 |
56 |
58 |
57 // Read an int64 from the argv array. |
59 /** Read an int64 from the argv array. */ |
58 static inline int64 GetInt64(const int32 **argv) |
60 static inline int64 GetInt64(const int32 **argv) |
59 { |
61 { |
60 int64 result; |
62 int64 result; |
61 |
63 |
62 assert(argv); |
64 assert(argv); |
63 result = (uint32)(*argv)[0] + ((uint64)(uint32)(*argv)[1] << 32); |
65 result = (uint32)(*argv)[0] + ((uint64)(uint32)(*argv)[1] << 32); |
64 (*argv)+=2; |
66 (*argv)+=2; |
65 return result; |
67 return result; |
66 } |
68 } |
67 |
69 |
68 // Read an int32 from the argv array. |
70 /** Read an int32 from the argv array. */ |
69 static inline int32 GetInt32(const int32 **argv) |
71 static inline int32 GetInt32(const int32 **argv) |
70 { |
72 { |
71 assert(argv); |
73 assert(argv); |
72 return *(*argv)++; |
74 return *(*argv)++; |
73 } |
75 } |
74 |
76 |
75 // Read an array from the argv array. |
77 /** Read an array from the argv array. */ |
76 static inline const int32 *GetArgvPtr(const int32 **argv, int n) |
78 static inline const int32 *GetArgvPtr(const int32 **argv, int n) |
77 { |
79 { |
78 const int32 *result; |
80 const int32 *result; |
79 assert(*argv); |
81 assert(*argv); |
80 result = *argv; |
82 result = *argv; |
83 } |
85 } |
84 |
86 |
85 |
87 |
86 #define NUM_BOUND_STRINGS 8 |
88 #define NUM_BOUND_STRINGS 8 |
87 |
89 |
88 // Array to hold the bound strings. |
90 /* Array to hold the bound strings. */ |
89 static const char *_bound_strings[NUM_BOUND_STRINGS]; |
91 static const char *_bound_strings[NUM_BOUND_STRINGS]; |
90 |
92 |
91 // This index is used to implement a "round-robin" allocating of |
93 /* This index is used to implement a "round-robin" allocating of |
92 // slots for BindCString. NUM_BOUND_STRINGS slots are reserved. |
94 * slots for BindCString. NUM_BOUND_STRINGS slots are reserved. |
93 // Which means that after NUM_BOUND_STRINGS calls to BindCString, |
95 * Which means that after NUM_BOUND_STRINGS calls to BindCString, |
94 // the indices will be reused. |
96 * the indices will be reused. */ |
95 static int _bind_index; |
97 static int _bind_index; |
96 |
98 |
97 static const char *GetStringPtr(StringID string) |
99 static const char *GetStringPtr(StringID string) |
98 { |
100 { |
99 return _langpack_offs[_langtab_start[string >> 11] + (string & 0x7FF)]; |
101 return _langpack_offs[_langtab_start[string >> 11] + (string & 0x7FF)]; |
100 } |
102 } |
101 |
103 |
102 // The highest 8 bits of string contain the "case index". |
104 /** The highest 8 bits of string contain the "case index". |
103 // These 8 bits will only be set when FormatString wants to print |
105 * These 8 bits will only be set when FormatString wants to print |
104 // the string in a different case. No one else except FormatString |
106 * the string in a different case. No one else except FormatString |
105 // should set those bits, therefore string CANNOT be StringID, but uint32. |
107 * should set those bits, therefore string CANNOT be StringID, but uint32. |
|
108 * @param buffr |
|
109 * @param string |
|
110 * @param argv |
|
111 * @param last |
|
112 * @return a formatted string of char |
|
113 */ |
106 static char *GetStringWithArgs(char *buffr, uint string, const int32 *argv, const char* last) |
114 static char *GetStringWithArgs(char *buffr, uint string, const int32 *argv, const char* last) |
107 { |
115 { |
108 uint index = GB(string, 0, 11); |
116 uint index = GB(string, 0, 11); |
109 uint tab = GB(string, 11, 5); |
117 uint tab = GB(string, 11, 5); |
110 char buff[512]; |
118 char buff[512]; |
145 case 30: |
153 case 30: |
146 GetGRFString(buff, index + 0x1000, lastof(buff)); |
154 GetGRFString(buff, index + 0x1000, lastof(buff)); |
147 return FormatString(buffr, buff, argv, 0, last); |
155 return FormatString(buffr, buff, argv, 0, last); |
148 |
156 |
149 case 31: |
157 case 31: |
150 // dynamic strings. These are NOT to be passed through the formatter, |
158 /* dynamic strings. These are NOT to be passed through the formatter, |
151 // but passed through verbatim. |
159 * but passed through verbatim. */ |
152 if (index < (STR_SPEC_USERSTRING & 0x7FF)) { |
160 if (index < (STR_SPEC_USERSTRING & 0x7FF)) { |
153 return strecpy(buffr, _bound_strings[index], last); |
161 return strecpy(buffr, _bound_strings[index], last); |
154 } |
162 } |
155 |
163 |
156 return FormatString(buffr, _userstring, NULL, 0, last); |
164 return FormatString(buffr, _userstring, NULL, 0, last); |
182 |
190 |
183 /** |
191 /** |
184 * This function takes a C-string and allocates a temporary string ID. |
192 * This function takes a C-string and allocates a temporary string ID. |
185 * The StringID of the bound string is valid until BindCString is called |
193 * The StringID of the bound string is valid until BindCString is called |
186 * another NUM_BOUND_STRINGS times. So be careful when using it. |
194 * another NUM_BOUND_STRINGS times. So be careful when using it. |
187 * |
195 * @param str temp string to add |
|
196 * @return the id of that temp string |
188 * @note formatting a DATE_TINY calls BindCString twice, thus reduces the |
197 * @note formatting a DATE_TINY calls BindCString twice, thus reduces the |
189 * amount of 'user' bound strings by 2. |
198 * amount of 'user' bound strings by 2. |
190 * @todo rewrite the BindCString system to make the limit flexible and |
199 * @todo rewrite the BindCString system to make the limit flexible and |
191 * non-round-robin. For example by using smart pointers that free |
200 * non-round-robin. For example by using smart pointers that free |
192 * the allocated StringID when they go out-of-scope/are freed. |
201 * the allocated StringID when they go out-of-scope/are freed. |
196 int idx = (++_bind_index) & (NUM_BOUND_STRINGS - 1); |
205 int idx = (++_bind_index) & (NUM_BOUND_STRINGS - 1); |
197 _bound_strings[idx] = str; |
206 _bound_strings[idx] = str; |
198 return idx + STR_SPEC_DYNSTRING; |
207 return idx + STR_SPEC_DYNSTRING; |
199 } |
208 } |
200 |
209 |
201 // This function is used to "bind" a C string to a OpenTTD dparam slot. |
210 /** This function is used to "bind" a C string to a OpenTTD dparam slot. |
|
211 * @param n slot of the string |
|
212 * @param str string to bind |
|
213 */ |
202 void SetDParamStr(uint n, const char *str) |
214 void SetDParamStr(uint n, const char *str) |
203 { |
215 { |
204 SetDParam(n, BindCString(str)); |
216 SetDParam(n, BindCString(str)); |
205 } |
217 } |
206 |
218 |
329 const char* multiplier = ""; |
341 const char* multiplier = ""; |
330 char buf[40]; |
342 char buf[40]; |
331 char* p; |
343 char* p; |
332 int j; |
344 int j; |
333 |
345 |
334 // multiply by exchange rate |
346 /* multiply by exchange rate */ |
335 number *= spec->rate; |
347 number *= spec->rate; |
336 |
348 |
337 // convert from negative |
349 /* convert from negative */ |
338 if (number < 0) { |
350 if (number < 0) { |
339 buff = strecpy(buff, "-", last); |
351 buff = strecpy(buff, "-", last); |
340 number = -number; |
352 number = -number; |
341 } |
353 } |
342 |
354 |
343 /* Add prefix part, folowing symbol_pos specification. |
355 /* Add prefix part, folowing symbol_pos specification. |
344 * Here, it can can be either 0 (prefix) or 2 (both prefix anf suffix). |
356 * Here, it can can be either 0 (prefix) or 2 (both prefix anf suffix). |
345 * The only remaining value is 1 (suffix), so everything that is not 1 */ |
357 * The only remaining value is 1 (suffix), so everything that is not 1 */ |
346 if (spec->symbol_pos != 1) buff = strecpy(buff, spec->prefix, last); |
358 if (spec->symbol_pos != 1) buff = strecpy(buff, spec->prefix, last); |
347 |
359 |
348 // for huge numbers, compact the number into k or M |
360 /* for huge numbers, compact the number into k or M */ |
349 if (compact) { |
361 if (compact) { |
350 if (number >= 1000000000) { |
362 if (number >= 1000000000) { |
351 number = (number + 500000) / 1000000; |
363 number = (number + 500000) / 1000000; |
352 multiplier = "M"; |
364 multiplier = "M"; |
353 } else if (number >= 1000000) { |
365 } else if (number >= 1000000) { |
354 number = (number + 500) / 1000; |
366 number = (number + 500) / 1000; |
355 multiplier = "k"; |
367 multiplier = "k"; |
356 } |
368 } |
357 } |
369 } |
358 |
370 |
359 // convert to ascii number and add commas |
371 /* convert to ascii number and add commas */ |
360 p = endof(buf); |
372 p = endof(buf); |
361 *--p = '\0'; |
373 *--p = '\0'; |
362 j = 4; |
374 j = 4; |
363 do { |
375 do { |
364 if (--j == 0) { |
376 if (--j == 0) { |
379 return buff; |
391 return buff; |
380 } |
392 } |
381 |
393 |
382 static int DeterminePluralForm(int32 n) |
394 static int DeterminePluralForm(int32 n) |
383 { |
395 { |
384 // The absolute value determines plurality |
396 /* The absolute value determines plurality */ |
385 if (n < 0) n = -n; |
397 if (n < 0) n = -n; |
386 |
398 |
387 switch (_langpack->plural_form) { |
399 switch (_langpack->plural_form) { |
388 // Two forms, singular used for one only |
400 /* Two forms, singular used for one only |
389 // Used in: |
401 * Used in: |
390 // Danish, Dutch, English, German, Norwegian, Swedish, Estonian, Finnish, |
402 * Danish, Dutch, English, German, Norwegian, Swedish, Estonian, Finnish, |
391 // Greek, Hebrew, Italian, Portuguese, Spanish, Esperanto |
403 * Greek, Hebrew, Italian, Portuguese, Spanish, Esperanto */ |
392 case 0: |
404 case 0: |
393 default: |
405 default: |
394 return n != 1; |
406 return n != 1; |
395 |
407 |
396 // Only one form |
408 /* Only one form |
397 // Used in: |
409 * Used in: |
398 // Hungarian, Japanese, Korean, Turkish |
410 * Hungarian, Japanese, Korean, Turkish */ |
399 case 1: |
411 case 1: |
400 return 0; |
412 return 0; |
401 |
413 |
402 // Two forms, singular used for zero and one |
414 /* Two forms, singular used for zero and one |
403 // Used in: |
415 * Used in: |
404 // French, Brazilian Portuguese |
416 * French, Brazilian Portuguese */ |
405 case 2: |
417 case 2: |
406 return n > 1; |
418 return n > 1; |
407 |
419 |
408 // Three forms, special case for zero |
420 /* Three forms, special case for zero |
409 // Used in: |
421 * Used in: |
410 // Latvian |
422 * Latvian */ |
411 case 3: |
423 case 3: |
412 return n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2; |
424 return n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2; |
413 |
425 |
414 // Three forms, special case for one and two |
426 /* Three forms, special case for one and two |
415 // Used in: |
427 * Used in: |
416 // Gaelige (Irish) |
428 * Gaelige (Irish) */ |
417 case 4: |
429 case 4: |
418 return n==1 ? 0 : n==2 ? 1 : 2; |
430 return n==1 ? 0 : n==2 ? 1 : 2; |
419 |
431 |
420 // Three forms, special case for numbers ending in 1[2-9] |
432 /* Three forms, special case for numbers ending in 1[2-9] |
421 // Used in: |
433 * Used in: |
422 // Lithuanian |
434 * Lithuanian */ |
423 case 5: |
435 case 5: |
424 return n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2; |
436 return n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2; |
425 |
437 |
426 // Three forms, special cases for numbers ending in 1 and 2, 3, 4, except those ending in 1[1-4] |
438 /* Three forms, special cases for numbers ending in 1 and 2, 3, 4, except those ending in 1[1-4] |
427 // Used in: |
439 * Used in: |
428 // Croatian, Czech, Russian, Slovak, Ukrainian |
440 * Croatian, Czech, Russian, Slovak, Ukrainian */ |
429 case 6: |
441 case 6: |
430 return n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; |
442 return n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; |
431 |
443 |
432 // Three forms, special case for one and some numbers ending in 2, 3, or 4 |
444 /* Three forms, special case for one and some numbers ending in 2, 3, or 4 |
433 // Used in: |
445 * Used in: |
434 // Polish |
446 * Polish */ |
435 case 7: |
447 case 7: |
436 return n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; |
448 return n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; |
437 |
449 |
438 // Four forms, special case for one and all numbers ending in 02, 03, or 04 |
450 /* Four forms, special case for one and all numbers ending in 02, 03, or 04 |
439 // Used in: |
451 * Used in: |
440 // Slovenian |
452 * Slovenian */ |
441 case 8: |
453 case 8: |
442 return n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3; |
454 return n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3; |
443 } |
455 } |
444 } |
456 } |
445 |
457 |
559 case SCC_REVISION: /* {REV} */ |
571 case SCC_REVISION: /* {REV} */ |
560 buff = strecpy(buff, _openttd_revision, last); |
572 buff = strecpy(buff, _openttd_revision, last); |
561 break; |
573 break; |
562 |
574 |
563 case SCC_CARGO_SHORT: { /* {SHORTCARGO} */ |
575 case SCC_CARGO_SHORT: { /* {SHORTCARGO} */ |
564 // Short description of cargotypes. Layout: |
576 /* Short description of cargotypes. Layout: |
565 // 8-bit = cargo type |
577 * 8-bit = cargo type |
566 // 16-bit = cargo count |
578 * 16-bit = cargo count */ |
567 StringID cargo_str = GetCargo(GetInt32(&argv))->units_volume; |
579 StringID cargo_str = GetCargo(GetInt32(&argv))->units_volume; |
568 switch (cargo_str) { |
580 switch (cargo_str) { |
569 case STR_TONS: { |
581 case STR_TONS: { |
570 int32 args[1]; |
582 int32 args[1]; |
571 assert(_opt_ptr->units < lengthof(units)); |
583 assert(_opt_ptr->units < lengthof(units)); |
597 break; |
609 break; |
598 } |
610 } |
599 } break; |
611 } break; |
600 |
612 |
601 case SCC_CURRENCY_COMPACT_64: { /* {CURRCOMPACT64} */ |
613 case SCC_CURRENCY_COMPACT_64: { /* {CURRCOMPACT64} */ |
602 // 64 bit compact currency-unit |
614 /* 64 bit compact currency-unit */ |
603 buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), true, last); |
615 buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), true, last); |
604 break; |
616 break; |
605 } |
617 } |
606 |
618 |
607 case SCC_STRING1: { /* {STRING1} */ |
619 case SCC_STRING1: { /* {STRING1} */ |
608 // String that consumes ONE argument |
620 /* String that consumes ONE argument */ |
609 uint str = modifier + GetInt32(&argv); |
621 uint str = modifier + GetInt32(&argv); |
610 buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 1), last); |
622 buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 1), last); |
611 modifier = 0; |
623 modifier = 0; |
612 break; |
624 break; |
613 } |
625 } |
614 |
626 |
615 case SCC_STRING2: { /* {STRING2} */ |
627 case SCC_STRING2: { /* {STRING2} */ |
616 // String that consumes TWO arguments |
628 /* String that consumes TWO arguments */ |
617 uint str = modifier + GetInt32(&argv); |
629 uint str = modifier + GetInt32(&argv); |
618 buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 2), last); |
630 buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 2), last); |
619 modifier = 0; |
631 modifier = 0; |
620 break; |
632 break; |
621 } |
633 } |
622 |
634 |
623 case SCC_STRING3: { /* {STRING3} */ |
635 case SCC_STRING3: { /* {STRING3} */ |
624 // String that consumes THREE arguments |
636 /* String that consumes THREE arguments */ |
625 uint str = modifier + GetInt32(&argv); |
637 uint str = modifier + GetInt32(&argv); |
626 buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 3), last); |
638 buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 3), last); |
627 modifier = 0; |
639 modifier = 0; |
628 break; |
640 break; |
629 } |
641 } |
630 |
642 |
631 case SCC_STRING4: { /* {STRING4} */ |
643 case SCC_STRING4: { /* {STRING4} */ |
632 // String that consumes FOUR arguments |
644 /* String that consumes FOUR arguments */ |
633 uint str = modifier + GetInt32(&argv); |
645 uint str = modifier + GetInt32(&argv); |
634 buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 4), last); |
646 buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 4), last); |
635 modifier = 0; |
647 modifier = 0; |
636 break; |
648 break; |
637 } |
649 } |
638 |
650 |
639 case SCC_STRING5: { /* {STRING5} */ |
651 case SCC_STRING5: { /* {STRING5} */ |
640 // String that consumes FIVE arguments |
652 /* String that consumes FIVE arguments */ |
641 uint str = modifier + GetInt32(&argv); |
653 uint str = modifier + GetInt32(&argv); |
642 buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 5), last); |
654 buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 5), last); |
643 modifier = 0; |
655 modifier = 0; |
644 break; |
656 break; |
645 } |
657 } |
651 |
663 |
652 case SCC_INDUSTRY_NAME: { /* {INDUSTRY} */ |
664 case SCC_INDUSTRY_NAME: { /* {INDUSTRY} */ |
653 const Industry* i = GetIndustry(GetInt32(&argv)); |
665 const Industry* i = GetIndustry(GetInt32(&argv)); |
654 int32 args[2]; |
666 int32 args[2]; |
655 |
667 |
656 // industry not valid anymore? |
668 /* industry not valid anymore? */ |
657 if (!IsValidIndustry(i)) break; |
669 if (!IsValidIndustry(i)) break; |
658 |
670 |
659 // First print the town name and the industry type name |
671 /* First print the town name and the industry type name |
660 // The string STR_INDUSTRY_PATTERN controls the formatting |
672 * The string STR_INDUSTRY_PATTERN controls the formatting */ |
661 args[0] = i->town->index; |
673 args[0] = i->town->index; |
662 args[1] = GetIndustrySpec(i->type)->name; |
674 args[1] = GetIndustrySpec(i->type)->name; |
663 buff = FormatString(buff, GetStringPtr(STR_INDUSTRY_FORMAT), args, modifier >> 24, last); |
675 buff = FormatString(buff, GetStringPtr(STR_INDUSTRY_FORMAT), args, modifier >> 24, last); |
664 modifier = 0; |
676 modifier = 0; |
665 break; |
677 break; |
688 buff = FormatTinyDate(buff, GetInt32(&argv), last); |
700 buff = FormatTinyDate(buff, GetInt32(&argv), last); |
689 break; |
701 break; |
690 } |
702 } |
691 |
703 |
692 case SCC_CARGO: { // {CARGO} |
704 case SCC_CARGO: { // {CARGO} |
693 // Layout now is: |
705 /* Layout now is: |
694 // 8bit - cargo type |
706 * 8bit - cargo type |
695 // 16-bit - cargo count |
707 * 16-bit - cargo count */ |
696 CargoID cargo = GetInt32(&argv); |
708 CargoID cargo = GetInt32(&argv); |
697 StringID cargo_str = (cargo == CT_INVALID) ? (StringID)STR_8838_N_A : GetCargo(cargo)->quantifier; |
709 StringID cargo_str = (cargo == CT_INVALID) ? (StringID)STR_8838_N_A : GetCargo(cargo)->quantifier; |
698 buff = GetStringWithArgs(buff, cargo_str, argv++, last); |
710 buff = GetStringWithArgs(buff, cargo_str, argv++, last); |
699 break; |
711 break; |
700 } |
712 } |
746 |
758 |
747 case SCC_SKIP: // {SKIP} |
759 case SCC_SKIP: // {SKIP} |
748 argv++; |
760 argv++; |
749 break; |
761 break; |
750 |
762 |
751 // This sets up the gender for the string. |
763 /* This sets up the gender for the string. |
752 // We just ignore this one. It's used in {G 0 Der Die Das} to determine the case. |
764 * We just ignore this one. It's used in {G 0 Der Die Das} to determine the case. */ |
753 case SCC_GENDER_INDEX: // {GENDER 0} |
765 case SCC_GENDER_INDEX: // {GENDER 0} |
754 str++; |
766 str++; |
755 break; |
767 break; |
756 |
768 |
757 case SCC_STRING: {// {STRING} |
769 case SCC_STRING: {// {STRING} |
758 uint str = modifier + GetInt32(&argv); |
770 uint str = modifier + GetInt32(&argv); |
759 // WARNING. It's prohibited for the included string to consume any arguments. |
771 /* WARNING. It's prohibited for the included string to consume any arguments. |
760 // For included strings that consume argument, you should use STRING1, STRING2 etc. |
772 * For included strings that consume argument, you should use STRING1, STRING2 etc. |
761 // To debug stuff you can set argv to NULL and it will tell you |
773 * To debug stuff you can set argv to NULL and it will tell you */ |
762 buff = GetStringWithArgs(buff, str, argv, last); |
774 buff = GetStringWithArgs(buff, str, argv, last); |
763 modifier = 0; |
775 modifier = 0; |
764 break; |
776 break; |
765 } |
777 } |
766 |
778 |
832 buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), false, last); |
844 buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), false, last); |
833 break; |
845 break; |
834 } |
846 } |
835 |
847 |
836 case SCC_SETCASE: { // {SETCASE} |
848 case SCC_SETCASE: { // {SETCASE} |
837 // This is a pseudo command, it's outputted when someone does {STRING.ack} |
849 /* This is a pseudo command, it's outputted when someone does {STRING.ack} |
838 // The modifier is added to all subsequent GetStringWithArgs that accept the modifier. |
850 * The modifier is added to all subsequent GetStringWithArgs that accept the modifier. */ |
839 modifier = (byte)*str++ << 24; |
851 modifier = (byte)*str++ << 24; |
840 break; |
852 break; |
841 } |
853 } |
842 |
854 |
843 case SCC_SWITCH_CASE: { // {Used to implement case switching} |
855 case SCC_SWITCH_CASE: { // {Used to implement case switching} |
844 // <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT> |
856 /* <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT> |
845 // Each LEN is printed using 2 bytes in big endian order. |
857 * Each LEN is printed using 2 bytes in big endian order. */ |
846 uint num = (byte)*str++; |
858 uint num = (byte)*str++; |
847 while (num) { |
859 while (num) { |
848 if ((byte)str[0] == casei) { |
860 if ((byte)str[0] == casei) { |
849 // Found the case, adjust str pointer and continue |
861 /* Found the case, adjust str pointer and continue */ |
850 str += 3; |
862 str += 3; |
851 break; |
863 break; |
852 } |
864 } |
853 // Otherwise skip to the next case |
865 /* Otherwise skip to the next case */ |
854 str += 3 + (str[1] << 8) + str[2]; |
866 str += 3 + (str[1] << 8) + str[2]; |
855 num--; |
867 num--; |
856 } |
868 } |
857 break; |
869 break; |
858 } |
870 } |
1016 |
1028 |
1017 case 4: // song names |
1029 case 4: // song names |
1018 return strecpy(buff, origin_songs_specs[GetInt32(&argv) - 1].song_name, last); |
1030 return strecpy(buff, origin_songs_specs[GetInt32(&argv) - 1].song_name, last); |
1019 } |
1031 } |
1020 |
1032 |
1021 // town name? |
1033 /* town name? */ |
1022 if (IS_INT_INSIDE(ind - 6, 0, SPECSTR_TOWNNAME_LAST-SPECSTR_TOWNNAME_START + 1)) { |
1034 if (IS_INT_INSIDE(ind - 6, 0, SPECSTR_TOWNNAME_LAST-SPECSTR_TOWNNAME_START + 1)) { |
1023 buff = GetSpecialTownNameString(buff, ind - 6, GetInt32(&argv), last); |
1035 buff = GetSpecialTownNameString(buff, ind - 6, GetInt32(&argv), last); |
1024 return strecpy(buff, " Transport", last); |
1036 return strecpy(buff, " Transport", last); |
1025 } |
1037 } |
1026 |
1038 |
1027 // language name? |
1039 /* language name? */ |
1028 if (IS_INT_INSIDE(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) { |
1040 if (IS_INT_INSIDE(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) { |
1029 int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4); |
1041 int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4); |
1030 return strecpy(buff, |
1042 return strecpy(buff, |
1031 i == _dynlang.curr ? _langpack->own_name : _dynlang.ent[i].name, last); |
1043 i == _dynlang.curr ? _langpack->own_name : _dynlang.ent[i].name, last); |
1032 } |
1044 } |
1033 |
1045 |
1034 // resolution size? |
1046 /* resolution size? */ |
1035 if (IS_INT_INSIDE(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) { |
1047 if (IS_INT_INSIDE(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) { |
1036 int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4); |
1048 int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4); |
1037 buff += snprintf( |
1049 buff += snprintf( |
1038 buff, last - buff + 1, "%dx%d", _resolutions[i][0], _resolutions[i][1] |
1050 buff, last - buff + 1, "%dx%d", _resolutions[i][0], _resolutions[i][1] |
1039 ); |
1051 ); |
1040 return buff; |
1052 return buff; |
1041 } |
1053 } |
1042 |
1054 |
1043 // screenshot format name? |
1055 /* screenshot format name? */ |
1044 if (IS_INT_INSIDE(ind, (SPECSTR_SCREENSHOT_START - 0x70E4), (SPECSTR_SCREENSHOT_END - 0x70E4) + 1)) { |
1056 if (IS_INT_INSIDE(ind, (SPECSTR_SCREENSHOT_START - 0x70E4), (SPECSTR_SCREENSHOT_END - 0x70E4) + 1)) { |
1045 int i = ind - (SPECSTR_SCREENSHOT_START - 0x70E4); |
1057 int i = ind - (SPECSTR_SCREENSHOT_START - 0x70E4); |
1046 return strecpy(buff, GetScreenshotFormatDesc(i), last); |
1058 return strecpy(buff, GetScreenshotFormatDesc(i), last); |
1047 } |
1059 } |
1048 |
1060 |
1049 assert(0); |
1061 assert(0); |
1050 return NULL; |
1062 return NULL; |
1051 } |
1063 } |
1052 |
1064 |
1053 // remap a string ID from the old format to the new format |
1065 /** |
|
1066 * remap a string ID from the old format to the new format |
|
1067 * @param s StringID that requires remapping |
|
1068 * @return translated ID*/ |
1054 StringID RemapOldStringID(StringID s) |
1069 StringID RemapOldStringID(StringID s) |
1055 { |
1070 { |
1056 switch (s) { |
1071 switch (s) { |
1057 case 0x0006: return STR_SV_EMPTY; |
1072 case 0x0006: return STR_SV_EMPTY; |
1058 case 0x7000: return STR_SV_UNNAMED; |
1073 case 0x7000: return STR_SV_UNNAMED; |
1131 } |
1146 } |
1132 |
1147 |
1133 /** Determine the current charset based on the environment |
1148 /** Determine the current charset based on the environment |
1134 * First check some default values, after this one we passed ourselves |
1149 * First check some default values, after this one we passed ourselves |
1135 * and if none exist return the value for $LANG |
1150 * and if none exist return the value for $LANG |
1136 * @param environment variable to check conditionally if default ones are not |
1151 * @param param environment variable to check conditionally if default ones are not |
1137 * set. Pass NULL if you don't want additional checks. |
1152 * set. Pass NULL if you don't want additional checks. |
1138 * @return return string containing current charset, or NULL if not-determinable */ |
1153 * @return return string containing current charset, or NULL if not-determinable */ |
1139 const char *GetCurrentLocale(const char *param) |
1154 const char *GetCurrentLocale(const char *param) |
1140 { |
1155 { |
1141 const char *env; |
1156 const char *env; |