finish partial support for language loading... new string test in cheat window

This commit is contained in:
IntelOrca 2014-08-08 18:47:28 +01:00
parent 045cef2e0a
commit cc93e6b7db
3 changed files with 166 additions and 93 deletions

View File

@ -1065,6 +1065,110 @@ char real_name_initials[] = {
'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W'
};
#pragma region Format codes
typedef struct {
char code;
char *token;
} format_code_token;
format_code_token format_code_tokens[] = {
{ FORMAT_MOVE_X, "MOVE_X" },
{ FORMAT_ADJUST_PALETTE, "ADJUST_PALETTE" },
{ FORMAT_NEWLINE, "NEWLINE" },
{ FORMAT_NEWLINE_SMALLER, "NEWLINE_SMALLER" },
{ FORMAT_TINYFONT, "TINYFONT" },
{ FORMAT_BIGFONT, "BIGFONT" },
{ FORMAT_MEDIUMFONT, "MEDIUMFONT" },
{ FORMAT_SMALLFONT, "SMALLFONT" },
{ FORMAT_OUTLINE, "OUTLINE" },
{ FORMAT_OUTLINE_OFF, "OUTLINE_OFF" },
{ FORMAT_WINDOW_COLOUR_1, "WINDOW_COLOUR_1" },
{ FORMAT_WINDOW_COLOUR_2, "WINDOW_COLOUR_2" },
{ FORMAT_WINDOW_COLOUR_3, "WINDOW_COLOUR_3" },
{ FORMAT_NEWLINE_X_Y, "NEWLINE_X_Y" },
{ FORMAT_INLINE_SPRITE, "INLINE_SPRITE" },
{ FORMAT_ENDQUOTES, "ENDQUOTES" },
{ FORMAT_ARGUMENT_CODE_START, "ARGUMENT_CODE_START" },
{ FORMAT_COMMA32, "COMMA32" },
{ FORMAT_INT32, "INT32" },
{ FORMAT_COMMA2DP32, "COMMA2DP32" },
{ FORMAT_COMMA16, "COMMA16" },
{ FORMAT_UINT16, "UINT16" },
{ FORMAT_CURRENCY2DP, "CURRENCY2DP" },
{ FORMAT_CURRENCY, "CURRENCY" },
{ FORMAT_STRINGID, "STRINGID" },
{ FORMAT_STRINGID2, "STRINGID2" },
{ FORMAT_STRING, "STRING" },
{ FORMAT_MONTHYEAR, "MONTHYEAR" },
{ FORMAT_MONTH, "MONTH" },
{ FORMAT_VELOCITY, "VELOCITY" },
{ FORMAT_POP16, "POP16" },
{ FORMAT_PUSH16, "PUSH16" },
{ FORMAT_DURATION, "DURATION" },
{ FORMAT_REALTIME, "REALTIME" },
{ FORMAT_LENGTH, "LENGTH" },
{ FORMAT_SPRITE, "SPRITE" },
{ FORMAT_COLOUR_CODE_START, "COLOUR_CODE_START" },
{ FORMAT_BLACK, "BLACK" },
{ FORMAT_GREY, "GREY" },
{ FORMAT_WHITE, "WHITE" },
{ FORMAT_RED, "RED" },
{ FORMAT_GREEN, "GREEN" },
{ FORMAT_YELLOW, "YELLOW" },
{ FORMAT_TOPAZ, "TOPAZ" },
{ FORMAT_CELADON, "CELADON" },
{ FORMAT_BABYBLUE, "BABYBLUE" },
{ FORMAT_PALELAVENDER, "PALELAVENDER" },
{ FORMAT_PALEGOLD, "PALEGOLD" },
{ FORMAT_LIGHTPINK, "LIGHTPINK" },
{ FORMAT_PEARLAQUA, "PEARLAQUA" },
{ FORMAT_PALESILVER, "PALESILVER" },
{ FORMAT_COLOUR_CODE_END, "COLOUR_CODE_END" },
{ FORMAT_AMINUSCULE, "AMINUSCULE" },
{ FORMAT_UP, "UP" },
{ FORMAT_POUND, "POUND" },
{ FORMAT_YEN, "YEN" },
{ FORMAT_COPYRIGHT, "COPYRIGHT" },
{ FORMAT_DOWN, "DOWN" },
{ FORMAT_LEFTGUILLEMET, "LEFTGUILLEMET" },
{ FORMAT_TICK, "TICK" },
{ FORMAT_CROSS, "CROSS" },
{ FORMAT_RIGHT, "RIGHT" },
{ FORMAT_DEGREE, "DEGREE" },
{ FORMAT_SQUARED, "SQUARED" },
{ FORMAT_OPENQUOTES, "OPENQUOTES" },
{ FORMAT_EURO, "EURO" },
{ FORMAT_APPROX, "APPROX" },
{ FORMAT_POWERNEGATIVEONE, "POWERNEGATIVEONE" },
{ FORMAT_BULLET, "BULLET" },
{ FORMAT_RIGHTGUILLEMET, "RIGHTGUILLEMET" },
{ FORMAT_SMALLUP, "SMALLUP" },
{ FORMAT_SMALLDOWN, "SMALLDOWN" },
{ FORMAT_LEFT, "LEFT" },
{ FORMAT_INVERTEDQUESTION, "INVERTEDQUESTION" }
};
char format_get_code(const char *token)
{
int i;
for (i = 0; i < countof(format_code_tokens); i++)
if (strcmpi(token, format_code_tokens[i].token) == 0)
return format_code_tokens[i].code;
return 0;
}
const char *format_get_token(char code)
{
int i;
for (i = 0; i < countof(format_code_tokens); i++)
if (code == format_code_tokens[i].code)
return format_code_tokens[i].token;
return 0;
}
#pragma endregion
void format_string_part_from_raw(char **dest, const char *src, char **args);
void format_string_part(char **dest, rct_string_id format, char **args);
@ -1564,81 +1668,15 @@ void generate_string_file()
fprintf(f, "STR_%04d :", i);
while (*c != '\0') {
switch (*c) {
case 7: fputs("{TINYFONT}", f); break;
case 8: fputs("{BIGFONT}", f); break;
case 9: fputs("{MEDIUMFONT}", f); break;
case 10: fputs("{SMALLFONT}", f); break;
case 11: fputs("{OUTLINE}", f); break;
case 34: fputs("{ENDQUOTES}", f); break;
case 123: fputs("{COMMA32}", f); break;
case 124: fputs("{INT32}", f); break;
case 125: fputs("{COMMA2DP32}", f); break;
case 126: fputs("{COMMA16}", f); break;
case 127: fputs("{UINT16}", f); break;
case 128: fputs("{CURRENCY2DP}", f); break;
case 129: fputs("{CURRENCY}", f); break;
case 130: fputs("{STRINGID}", f); break;
case 131: fputs("{STRINGID2}", f); break;
case 132: fputs("{STRING}", f); break;
case 133: fputs("{MONTHYEAR}", f); break;
case 134: fputs("{MONTH}", f); break;
case 135: fputs("{VELOCITY}", f); break;
case 136: fputs("{POP16}", f); break;
case 137: fputs("{PUSH16}", f); break;
case 138: fputs("{DURATION}", f); break;
case 139: fputs("{REALTIME}", f); break;
case 140: fputs("{LENGTH}", f); break;
case 141: fputs("{SPRITE}", f); break;
case 142: fputs("{BLACK}", f); break;
case 143: fputs("{GREY}", f); break;
case 144: fputs("{WHITE}", f); break;
case 145: fputs("{RED}", f); break;
case 146: fputs("{GREEN}", f); break;
case 147: fputs("{YELLOW}", f); break;
case 148: fputs("{TOPAZ}", f); break;
case 149: fputs("{CELADON}", f); break;
case 150: fputs("{BABYBLUE}", f); break;
case 151: fputs("{PALELAVENDER}", f); break;
case 152: fputs("{PALEGOLD}", f); break;
case 153: fputs("{LIGHTPINK}", f); break;
case 154: fputs("{PEARLAQUA}", f); break;
case 155: fputs("{PALESILVER}", f); break;
case 159: fputs("{AMINUSCULE}", f); break;
case 160: fputs("{UP}", f); break;
case 163: fputs("{POUND}", f); break;
case 165: fputs("{YEN}", f); break;
case 169: fputs("{COPYRIGHT}", f); break;
case 170: fputs("{DOWN}", f); break;
case 171: fputs("{LEFTGUILLEMET}", f); break;
case 172: fputs("{TICK}", f); break;
case 173: fputs("{CROSS}", f); break;
case 175: fputs("{RIGHT}", f); break;
case 176: fputs("{DEGREE}", f); break;
case 178: fputs("{SQUARED}", f); break;
case 180: fputs("{OPENQUOTES}", f); break;
case 181: fputs("{EURO}", f); break;
case 184: fputs("{APPROX}", f); break;
case 185: fputs("{POWERNEGATIVEONE}", f); break;
case 186: fputs("{BULLET}", f); break;
case 187: fputs("{RIGHTGUILLEMET}", f); break;
case 188: fputs("{SMALLUP}", f); break;
case 189: fputs("{SMALLDOWN}", f); break;
case 190: fputs("{LEFT}", f); break;
case 191: fputs("{INVERTEDQUESTION}", f); break;
default:
const char *token = format_get_token(*c);
if (token != NULL) {
fprintf(f, "{%s}", token);
} else {
if (*c < 32 || *c > 127)
fprintf(f, "{%d}", *c);
else
fputc(*c, f);
break;
}
c++;
}
fputc('\n', f);
@ -1667,23 +1705,29 @@ char **language_strings = NULL;
const char *get_string(rct_string_id id)
{
const char *str = language_strings == NULL ?
RCT2_ADDRESS(0x009BF2D4, const char*)[id] :
language_strings[id];
const char *rct = RCT2_ADDRESS(0x009BF2D4, const char*)[id];
const char *openrct = language_strings == NULL ? NULL : language_strings[id];
const char *str = (openrct == NULL || strlen(openrct) == 0 ? rct : openrct);
return str == NULL ? "" : str;
}
/**
* Partial support to open a uncompiled language file which parses tokens and converts them to the corresponding character
* code. Due to resource strings (strings in scenarios and objects) being written to the original game's string table,
* get_string will use those if the same entry in the loaded language is empty.
*
* Unsure at how the original game decides which entries to write resource strings to, but this could affect adding new
* strings for the time being. Further investigation is required.
*
* Also note that all strings are currently still ASCII. It probably can't be converted to UTF-8 until all game functions that
* read / write strings in some way is decompiled. The original game used a DIY extended 8-bit extended ASCII set for special
* characters, format codes and accents.
*
* In terms of reading the language files, the STR_XXXX part is completely ignored at the moment. It just parses each line from
* the colon and thus not allowing gaps in the string indices.
*/
int language_open(const char *filename)
{
// WIP, file can be loaded in but not in a suitable state.
// Due to loading an uncompiled text language file, tokens surrounded with braces need to be converted to the correct
// format character code. Therefore the language can not stay in its raw form and must be re-written as the text file is
// parsed.
// get_string returns the original game string address if no language is loaded in.
return 0;
FILE *f = fopen(filename, "rb");
if (f == NULL)
return 0;
@ -1697,18 +1741,46 @@ int language_open(const char *filename)
language_strings = calloc(STR_COUNT, sizeof(char*));
int i, stringIndex = 0, searchForEndLine = 0;
char *dst, *token;
char tokenBuffer[64];
int i, stringIndex = 0, mode = 0;
for (i = 0; i < language_buffer_size; i++) {
char *c = &language_buffer[i];
char *src = &language_buffer[i];
if (searchForEndLine) {
if (*c == '\n' || *c == '\r') {
*c = 0;
searchForEndLine = 0;
switch (mode) {
case 0:
// Search for colon
if (*src == ':') {
dst = src + 1;
language_strings[stringIndex++] = dst;
mode = 1;
}
} else if (*c == ':') {
language_strings[stringIndex++] = c + 1;
searchForEndLine = 1;
break;
case 1:
// Copy string over, stop at line break
if (*src == '{') {
token = src + 1;
mode = 2;
} else if (*src == '\n' || *src == '\r') {
*dst = 0;
mode = 0;
} else {
*dst++ = *src;
}
break;
case 2:
// Read token, convert to code
if (*src == '}') {
int tokenLength = min(src - token, sizeof(tokenBuffer) - 1);
memcpy(tokenBuffer, token, tokenLength);
tokenBuffer[tokenLength] = 0;
char code = format_get_code(tokenBuffer);
if (code == 0)
code = atoi(tokenBuffer);
*dst++ = code;
mode = 1;
}
break;
}
}
language_num_strings = stringIndex;

View File

@ -760,7 +760,8 @@ enum {
STR_PAGE_4 = STR_PAGE_1 + 3,
STR_PAGE_5 = STR_PAGE_1 + 4,
STR_COUNT = 4000
// Have to include resource strings (from scenarios and objects) for the time being now that language is partially working
STR_COUNT = 32768
};
#endif

View File

@ -89,7 +89,7 @@ static rct_widget window_cheats_money_widgets[] = {
{ WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 2462}, // tab 1
{ WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, 2462}, // tab 2
{ WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 2462}, // tab 3
{ WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(1), HPL(1), STR_VERY_HIGH, STR_VERY_HIGH}, // high money
{ WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(1), HPL(1), 2760, STR_VERY_HIGH}, // high money
{ WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(3), HPL(3), STR_FREE, STR_FREE}, //Park Entrance Fee Toggle
{ WIDGETS_END },
};