src/newgrf_text.cpp
branchNewGRF_ports
changeset 6870 ca3fd1fbe311
parent 6868 7eb395287b3d
child 6871 5a9dc001e1ad
equal deleted inserted replaced
6869:76282d3b748d 6870:ca3fd1fbe311
    19 #include "table/strings.h"
    19 #include "table/strings.h"
    20 #include "newgrf.h"
    20 #include "newgrf.h"
    21 #include "newgrf_text.h"
    21 #include "newgrf_text.h"
    22 #include "table/control_codes.h"
    22 #include "table/control_codes.h"
    23 #include "helpers.hpp"
    23 #include "helpers.hpp"
       
    24 #include "date.h"
    24 
    25 
    25 #define GRFTAB  28
    26 #define GRFTAB  28
    26 #define TABSIZE 11
    27 #define TABSIZE 11
    27 
    28 
    28 /**
    29 /**
   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 }