diff options
Diffstat (limited to 'src/newgrf_text.cpp')
-rw-r--r-- | src/newgrf_text.cpp | 172 |
1 files changed, 163 insertions, 9 deletions
diff --git a/src/newgrf_text.cpp b/src/newgrf_text.cpp index f9ef1ec5c..067e080c5 100644 --- a/src/newgrf_text.cpp +++ b/src/newgrf_text.cpp @@ -21,6 +21,7 @@ #include "newgrf_text.h" #include "table/control_codes.h" #include "helpers.hpp" +#include "date.h" #define GRFTAB 28 #define TABSIZE 11 @@ -228,9 +229,9 @@ char *TranslateTTDPatchCodes(const char *str) case 0x7B: case 0x7C: case 0x7D: - case 0x7E: d += Utf8Encode(d, SCC_NUM); break; - case 0x7F: d += Utf8Encode(d, SCC_CURRENCY); break; - case 0x80: d += Utf8Encode(d, SCC_STRING); break; + case 0x7E: + case 0x7F: + case 0x80: d += Utf8Encode(d, SCC_NEWGRF_PRINT_DWORD + c - 0x7B); break; case 0x81: { StringID string; string = *str++; @@ -239,12 +240,12 @@ char *TranslateTTDPatchCodes(const char *str) d += Utf8Encode(d, string); break; } - case 0x82: d += Utf8Encode(d, SCC_DATE_TINY); break; - case 0x83: d += Utf8Encode(d, SCC_DATE_SHORT); break; - case 0x84: d += Utf8Encode(d, SCC_VELOCITY); break; - case 0x85: d += Utf8Encode(d, SCC_SKIP); break; - case 0x86: /* "Rotate down top 4 words on stack" */ break; - case 0x87: d += Utf8Encode(d, SCC_VOLUME); break; + case 0x82: + case 0x83: + case 0x84: d += Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_SPEED + c - 0x82); break; + case 0x85: d += Utf8Encode(d, SCC_NEWGRF_DISCARD_WORD); break; + case 0x86: d += Utf8Encode(d, SCC_NEWGRF_ROTATE_TOP_4_WORDS); break; + case 0x87: d += Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_LITRES); break; case 0x88: d += Utf8Encode(d, SCC_BLUE); break; case 0x89: d += Utf8Encode(d, SCC_SILVER); break; case 0x8A: d += Utf8Encode(d, SCC_GOLD); break; @@ -262,6 +263,20 @@ char *TranslateTTDPatchCodes(const char *str) case 0x96: d += Utf8Encode(d, SCC_GRAY); break; case 0x97: d += Utf8Encode(d, SCC_DKBLUE); break; case 0x98: d += Utf8Encode(d, SCC_BLACK); break; + case 0x9A: + switch (*str++) { + case 0: /* FALL THROUGH */ + case 1: d += Utf8Encode(d, SCC_NEWGRF_PRINT_QWORD_CURRENCY); break; + case 3: { + uint16 tmp = *str++; + tmp |= (*str++) << 8; + d += Utf8Encode(d, SCC_NEWGRF_PUSH_WORD); d += Utf8Encode(d, tmp); + } break; + case 4: d += Utf8Encode(d, SCC_NEWGRF_UNPRINT); d += Utf8Encode(d, *str++); break; + default: grfmsg(1, "missing handler for extended format code"); break; + } + break; + case 0x9E: d += Utf8Encode(d, 0x20AC); break; // Euro case 0x9F: d += Utf8Encode(d, 0x0178); break; // Y with diaeresis case 0xA0: d += Utf8Encode(d, SCC_UPARROW); break; @@ -481,3 +496,142 @@ void CleanUpStrings() _num_grf_texts = 0; } + +struct TextRefStack { + byte stack[0x30]; + byte position; + bool used; + + TextRefStack() : used(false) {} + + uint8 PopUnsignedByte() { assert(this->position < lengthof(this->stack)); return this->stack[this->position++]; } + int8 PopSignedByte() { return (int8)this->PopUnsignedByte(); } + + uint16 PopUnsignedWord() { return this->PopUnsignedByte() | (((uint16)this->PopUnsignedByte()) << 8); } + int16 PopSignedWord() { return (int32)this->PopUnsignedWord(); } + + uint32 PopUnsignedDWord() { return this->PopUnsignedWord() | (((uint32)this->PopUnsignedWord()) << 16); } + int32 PopSignedDWord() { return (int32)this->PopUnsignedDWord(); } + + uint64 PopUnsignedQWord() { return this->PopUnsignedDWord() | (((uint64)this->PopUnsignedDWord()) << 32); } + int64 PopSignedQWord() { return (int64)this->PopUnsignedQWord(); } + + /** Rotate the top four words down: W1, W2, W3, W4 -> W4, W1, W2, W3 */ + void RotateTop4Words() + { + byte tmp[2]; + for (int i = 0; i < 2; i++) tmp[i] = this->stack[this->position + i + 6]; + for (int i = 5; i >= 0; i--) this->stack[this->position + i + 2] = this->stack[this->position + i]; + for (int i = 0; i < 2; i++) this->stack[this->position + i] = tmp[i]; + } + + void PushWord(uint16 word) + { + if (this->position >= 2) { + this->position -= 2; + } else { + for (uint i = lengthof(stack) - 3; i >= this->position; i--) { + this->stack[this->position + 2] = this->stack[this->position]; + } + } + this->stack[this->position] = GB(word, 0, 8); + this->stack[this->position + 1] = GB(word, 8, 8); + } + + void ResetStack() { this->used = true; this->position = 0; } +}; + +/** The stack that is used for TTDP compatible string code parsing */ +static TextRefStack _newgrf_textrefstack; + +/** Prepare the TTDP compatible string code parsing */ +void PrepareTextRefStackUsage() +{ + extern TemporaryStorageArray<uint32, 0x110> _temp_store; + + _newgrf_textrefstack.ResetStack(); + + byte *p = _newgrf_textrefstack.stack; + for (uint i = 0; i < 6; i++) { + for (uint j = 0; j < 32; j += 8) { + *p = GB(_temp_store.Get(0x100 + i), 32 - j, 8); + p++; + } + } +} + +/** Stop using the TTDP compatible string code parsing */ +void StopTextRefStackUsage() { _newgrf_textrefstack.used = false; } + +/** + * FormatString for NewGRF specific "magic" string control codes + * @param scc the string control code that has been read + * @param stack the current "stack" + * @return the string control code to "execute" now + */ +uint RemapNewGRFStringControlCode(uint scc, char **buff, const char **str, int64 *argv) +{ + if (_newgrf_textrefstack.used) { + switch (scc) { + default: NOT_REACHED(); + case SCC_NEWGRF_PRINT_SIGNED_BYTE: *argv = _newgrf_textrefstack.PopSignedByte(); break; + case SCC_NEWGRF_PRINT_SIGNED_WORD: *argv = _newgrf_textrefstack.PopSignedWord(); break; + case SCC_NEWGRF_PRINT_QWORD_CURRENCY: *argv = _newgrf_textrefstack.PopUnsignedQWord(); break; + + case SCC_NEWGRF_PRINT_DWORD_CURRENCY: + case SCC_NEWGRF_PRINT_DWORD: *argv = _newgrf_textrefstack.PopSignedDWord(); break; + + case SCC_NEWGRF_PRINT_WORD_SPEED: + case SCC_NEWGRF_PRINT_WORD_LITRES: + case SCC_NEWGRF_PRINT_UNSIGNED_WORD: *argv = _newgrf_textrefstack.PopUnsignedWord(); break; + + case SCC_NEWGRF_PRINT_DATE: + case SCC_NEWGRF_PRINT_MONTH_YEAR: *argv = _newgrf_textrefstack.PopSignedWord() + DAYS_TILL_ORIGINAL_BASE_YEAR; break; + + case SCC_NEWGRF_DISCARD_WORD: _newgrf_textrefstack.PopUnsignedWord(); break; + + case SCC_NEWGRF_ROTATE_TOP_4_WORDS: _newgrf_textrefstack.RotateTop4Words(); break; + case SCC_NEWGRF_PUSH_WORD: _newgrf_textrefstack.PushWord(Utf8Consume(str)); break; + case SCC_NEWGRF_UNPRINT: *buff -= Utf8Consume(str); break; + + case SCC_NEWGRF_PRINT_STRING_ID: + *argv = _newgrf_textrefstack.PopUnsignedWord(); + if (*argv == STR_NULL) *argv = STR_EMPTY; + break; + } + } + + switch (scc) { + default: NOT_REACHED(); + case SCC_NEWGRF_PRINT_DWORD: + case SCC_NEWGRF_PRINT_SIGNED_WORD: + case SCC_NEWGRF_PRINT_SIGNED_BYTE: + case SCC_NEWGRF_PRINT_UNSIGNED_WORD: + return SCC_NUM; + + case SCC_NEWGRF_PRINT_DWORD_CURRENCY: + case SCC_NEWGRF_PRINT_QWORD_CURRENCY: + return SCC_CURRENCY; + + case SCC_NEWGRF_PRINT_STRING_ID: + return SCC_STRING; + + case SCC_NEWGRF_PRINT_DATE: + return SCC_DATE_LONG; + + case SCC_NEWGRF_PRINT_MONTH_YEAR: + return SCC_DATE_TINY; + + case SCC_NEWGRF_PRINT_WORD_SPEED: + return SCC_VELOCITY; + + case SCC_NEWGRF_PRINT_WORD_LITRES: + return SCC_VOLUME; + + case SCC_NEWGRF_DISCARD_WORD: + case SCC_NEWGRF_ROTATE_TOP_4_WORDS: + case SCC_NEWGRF_PUSH_WORD: + case SCC_NEWGRF_UNPRINT: + return 0; + } +} |