226 *d++ = *str++; |
227 *d++ = *str++; |
227 break; |
228 break; |
228 case 0x7B: |
229 case 0x7B: |
229 case 0x7C: |
230 case 0x7C: |
230 case 0x7D: |
231 case 0x7D: |
231 case 0x7E: d += Utf8Encode(d, SCC_NUM); break; |
232 case 0x7E: |
232 case 0x7F: d += Utf8Encode(d, SCC_CURRENCY); break; |
233 case 0x7F: |
233 case 0x80: d += Utf8Encode(d, SCC_STRING); break; |
234 case 0x80: d += Utf8Encode(d, SCC_NEWGRF_PRINT_DWORD + c - 0x7B); break; |
234 case 0x81: { |
235 case 0x81: { |
235 StringID string; |
236 StringID string; |
236 string = *str++; |
237 string = *str++; |
237 string |= *str++ << 8; |
238 string |= *str++ << 8; |
238 d += Utf8Encode(d, SCC_STRING_ID); |
239 d += Utf8Encode(d, SCC_STRING_ID); |
239 d += Utf8Encode(d, string); |
240 d += Utf8Encode(d, string); |
240 break; |
241 break; |
241 } |
242 } |
242 case 0x82: d += Utf8Encode(d, SCC_DATE_TINY); break; |
243 case 0x82: |
243 case 0x83: d += Utf8Encode(d, SCC_DATE_SHORT); break; |
244 case 0x83: |
244 case 0x84: d += Utf8Encode(d, SCC_VELOCITY); break; |
245 case 0x84: d += Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_SPEED + c - 0x82); break; |
245 case 0x85: d += Utf8Encode(d, SCC_SKIP); break; |
246 case 0x85: d += Utf8Encode(d, SCC_NEWGRF_DISCARD_WORD); break; |
246 case 0x86: /* "Rotate down top 4 words on stack" */ break; |
247 case 0x86: d += Utf8Encode(d, SCC_NEWGRF_ROTATE_TOP_4_WORDS); break; |
247 case 0x87: d += Utf8Encode(d, SCC_VOLUME); break; |
248 case 0x87: d += Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_LITRES); break; |
248 case 0x88: d += Utf8Encode(d, SCC_BLUE); break; |
249 case 0x88: d += Utf8Encode(d, SCC_BLUE); break; |
249 case 0x89: d += Utf8Encode(d, SCC_SILVER); break; |
250 case 0x89: d += Utf8Encode(d, SCC_SILVER); break; |
250 case 0x8A: d += Utf8Encode(d, SCC_GOLD); break; |
251 case 0x8A: d += Utf8Encode(d, SCC_GOLD); break; |
251 case 0x8B: d += Utf8Encode(d, SCC_RED); break; |
252 case 0x8B: d += Utf8Encode(d, SCC_RED); break; |
252 case 0x8C: d += Utf8Encode(d, SCC_PURPLE); break; |
253 case 0x8C: d += Utf8Encode(d, SCC_PURPLE); break; |
260 case 0x94: d += Utf8Encode(d, SCC_WHITE); break; |
261 case 0x94: d += Utf8Encode(d, SCC_WHITE); break; |
261 case 0x95: d += Utf8Encode(d, SCC_LTBLUE); break; |
262 case 0x95: d += Utf8Encode(d, SCC_LTBLUE); break; |
262 case 0x96: d += Utf8Encode(d, SCC_GRAY); break; |
263 case 0x96: d += Utf8Encode(d, SCC_GRAY); break; |
263 case 0x97: d += Utf8Encode(d, SCC_DKBLUE); break; |
264 case 0x97: d += Utf8Encode(d, SCC_DKBLUE); break; |
264 case 0x98: d += Utf8Encode(d, SCC_BLACK); break; |
265 case 0x98: d += Utf8Encode(d, SCC_BLACK); break; |
|
266 case 0x9A: |
|
267 switch (*str++) { |
|
268 case 0: /* FALL THROUGH */ |
|
269 case 1: d += Utf8Encode(d, SCC_NEWGRF_PRINT_QWORD_CURRENCY); break; |
|
270 case 3: { |
|
271 uint16 tmp = *str++; |
|
272 tmp |= (*str++) << 8; |
|
273 d += Utf8Encode(d, SCC_NEWGRF_PUSH_WORD); d += Utf8Encode(d, tmp); |
|
274 } break; |
|
275 case 4: d += Utf8Encode(d, SCC_NEWGRF_UNPRINT); d += Utf8Encode(d, *str++); break; |
|
276 default: grfmsg(1, "missing handler for extended format code"); break; |
|
277 } |
|
278 break; |
|
279 |
265 case 0x9E: d += Utf8Encode(d, 0x20AC); break; // Euro |
280 case 0x9E: d += Utf8Encode(d, 0x20AC); break; // Euro |
266 case 0x9F: d += Utf8Encode(d, 0x0178); break; // Y with diaeresis |
281 case 0x9F: d += Utf8Encode(d, 0x0178); break; // Y with diaeresis |
267 case 0xA0: d += Utf8Encode(d, SCC_UPARROW); break; |
282 case 0xA0: d += Utf8Encode(d, SCC_UPARROW); break; |
268 case 0xAA: d += Utf8Encode(d, SCC_DOWNARROW); break; |
283 case 0xAA: d += Utf8Encode(d, SCC_DOWNARROW); break; |
269 case 0xAC: d += Utf8Encode(d, SCC_CHECKMARK); break; |
284 case 0xAC: d += Utf8Encode(d, SCC_CHECKMARK); break; |
479 _grf_text[id].textholder = NULL; |
494 _grf_text[id].textholder = NULL; |
480 } |
495 } |
481 |
496 |
482 _num_grf_texts = 0; |
497 _num_grf_texts = 0; |
483 } |
498 } |
|
499 |
|
500 struct TextRefStack { |
|
501 byte stack[0x30]; |
|
502 byte position; |
|
503 bool used; |
|
504 |
|
505 TextRefStack() : used(false) {} |
|
506 |
|
507 uint8 PopUnsignedByte() { assert(this->position < lengthof(this->stack)); return this->stack[this->position++]; } |
|
508 int8 PopSignedByte() { return (int8)this->PopUnsignedByte(); } |
|
509 |
|
510 uint16 PopUnsignedWord() { return this->PopUnsignedByte() | (((uint16)this->PopUnsignedByte()) << 8); } |
|
511 int16 PopSignedWord() { return (int32)this->PopUnsignedWord(); } |
|
512 |
|
513 uint32 PopUnsignedDWord() { return this->PopUnsignedWord() | (((uint32)this->PopUnsignedWord()) << 16); } |
|
514 int32 PopSignedDWord() { return (int32)this->PopUnsignedDWord(); } |
|
515 |
|
516 uint64 PopUnsignedQWord() { return this->PopUnsignedDWord() | (((uint64)this->PopUnsignedDWord()) << 32); } |
|
517 int64 PopSignedQWord() { return (int64)this->PopUnsignedQWord(); } |
|
518 |
|
519 /** Rotate the top four words down: W1, W2, W3, W4 -> W4, W1, W2, W3 */ |
|
520 void RotateTop4Words() |
|
521 { |
|
522 byte tmp[2]; |
|
523 for (int i = 0; i < 2; i++) tmp[i] = this->stack[this->position + i + 6]; |
|
524 for (int i = 5; i >= 0; i--) this->stack[this->position + i + 2] = this->stack[this->position + i]; |
|
525 for (int i = 0; i < 2; i++) this->stack[this->position + i] = tmp[i]; |
|
526 } |
|
527 |
|
528 void PushWord(uint16 word) |
|
529 { |
|
530 if (this->position >= 2) { |
|
531 this->position -= 2; |
|
532 } else { |
|
533 for (uint i = lengthof(stack) - 3; i >= this->position; i--) { |
|
534 this->stack[this->position + 2] = this->stack[this->position]; |
|
535 } |
|
536 } |
|
537 this->stack[this->position] = GB(word, 0, 8); |
|
538 this->stack[this->position + 1] = GB(word, 8, 8); |
|
539 } |
|
540 |
|
541 void ResetStack() { this->used = true; this->position = 0; } |
|
542 }; |
|
543 |
|
544 /** The stack that is used for TTDP compatible string code parsing */ |
|
545 static TextRefStack _newgrf_textrefstack; |
|
546 |
|
547 /** Prepare the TTDP compatible string code parsing */ |
|
548 void PrepareTextRefStackUsage() |
|
549 { |
|
550 extern TemporaryStorageArray<uint32, 0x110> _temp_store; |
|
551 |
|
552 _newgrf_textrefstack.ResetStack(); |
|
553 |
|
554 byte *p = _newgrf_textrefstack.stack; |
|
555 for (uint i = 0; i < 6; i++) { |
|
556 for (uint j = 0; j < 32; j += 8) { |
|
557 *p = GB(_temp_store.Get(0x100 + i), 32 - j, 8); |
|
558 p++; |
|
559 } |
|
560 } |
|
561 } |
|
562 |
|
563 /** Stop using the TTDP compatible string code parsing */ |
|
564 void StopTextRefStackUsage() { _newgrf_textrefstack.used = false; } |
|
565 |
|
566 /** |
|
567 * FormatString for NewGRF specific "magic" string control codes |
|
568 * @param scc the string control code that has been read |
|
569 * @param stack the current "stack" |
|
570 * @return the string control code to "execute" now |
|
571 */ |
|
572 uint RemapNewGRFStringControlCode(uint scc, char **buff, const char **str, int64 *argv) |
|
573 { |
|
574 if (_newgrf_textrefstack.used) { |
|
575 switch (scc) { |
|
576 default: NOT_REACHED(); |
|
577 case SCC_NEWGRF_PRINT_SIGNED_BYTE: *argv = _newgrf_textrefstack.PopSignedByte(); break; |
|
578 case SCC_NEWGRF_PRINT_SIGNED_WORD: *argv = _newgrf_textrefstack.PopSignedWord(); break; |
|
579 case SCC_NEWGRF_PRINT_QWORD_CURRENCY: *argv = _newgrf_textrefstack.PopUnsignedQWord(); break; |
|
580 |
|
581 case SCC_NEWGRF_PRINT_DWORD_CURRENCY: |
|
582 case SCC_NEWGRF_PRINT_DWORD: *argv = _newgrf_textrefstack.PopSignedDWord(); break; |
|
583 |
|
584 case SCC_NEWGRF_PRINT_WORD_SPEED: |
|
585 case SCC_NEWGRF_PRINT_WORD_LITRES: |
|
586 case SCC_NEWGRF_PRINT_UNSIGNED_WORD: *argv = _newgrf_textrefstack.PopUnsignedWord(); break; |
|
587 |
|
588 case SCC_NEWGRF_PRINT_DATE: |
|
589 case SCC_NEWGRF_PRINT_MONTH_YEAR: *argv = _newgrf_textrefstack.PopSignedWord() + DAYS_TILL_ORIGINAL_BASE_YEAR; break; |
|
590 |
|
591 case SCC_NEWGRF_DISCARD_WORD: _newgrf_textrefstack.PopUnsignedWord(); break; |
|
592 |
|
593 case SCC_NEWGRF_ROTATE_TOP_4_WORDS: _newgrf_textrefstack.RotateTop4Words(); break; |
|
594 case SCC_NEWGRF_PUSH_WORD: _newgrf_textrefstack.PushWord(Utf8Consume(str)); break; |
|
595 case SCC_NEWGRF_UNPRINT: *buff -= Utf8Consume(str); break; |
|
596 |
|
597 case SCC_NEWGRF_PRINT_STRING_ID: |
|
598 *argv = _newgrf_textrefstack.PopUnsignedWord(); |
|
599 if (*argv == STR_NULL) *argv = STR_EMPTY; |
|
600 break; |
|
601 } |
|
602 } |
|
603 |
|
604 switch (scc) { |
|
605 default: NOT_REACHED(); |
|
606 case SCC_NEWGRF_PRINT_DWORD: |
|
607 case SCC_NEWGRF_PRINT_SIGNED_WORD: |
|
608 case SCC_NEWGRF_PRINT_SIGNED_BYTE: |
|
609 case SCC_NEWGRF_PRINT_UNSIGNED_WORD: |
|
610 return SCC_NUM; |
|
611 |
|
612 case SCC_NEWGRF_PRINT_DWORD_CURRENCY: |
|
613 case SCC_NEWGRF_PRINT_QWORD_CURRENCY: |
|
614 return SCC_CURRENCY; |
|
615 |
|
616 case SCC_NEWGRF_PRINT_STRING_ID: |
|
617 return SCC_STRING; |
|
618 |
|
619 case SCC_NEWGRF_PRINT_DATE: |
|
620 return SCC_DATE_LONG; |
|
621 |
|
622 case SCC_NEWGRF_PRINT_MONTH_YEAR: |
|
623 return SCC_DATE_TINY; |
|
624 |
|
625 case SCC_NEWGRF_PRINT_WORD_SPEED: |
|
626 return SCC_VELOCITY; |
|
627 |
|
628 case SCC_NEWGRF_PRINT_WORD_LITRES: |
|
629 return SCC_VOLUME; |
|
630 |
|
631 case SCC_NEWGRF_DISCARD_WORD: |
|
632 case SCC_NEWGRF_ROTATE_TOP_4_WORDS: |
|
633 case SCC_NEWGRF_PUSH_WORD: |
|
634 case SCC_NEWGRF_UNPRINT: |
|
635 return 0; |
|
636 } |
|
637 } |