mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2025-12-21 23:03:04 +01:00
add ability to change language
This commit is contained in:
@@ -2774,9 +2774,9 @@ STR_2772 :Hogere spelsnelheid
|
|||||||
STR_2773 :???
|
STR_2773 :???
|
||||||
STR_2774 :???
|
STR_2774 :???
|
||||||
STR_2775 :???
|
STR_2775 :???
|
||||||
STR_2776 :???
|
STR_2776 :Language
|
||||||
STR_2777 :???
|
STR_2777 :{MOVE_X}{SMALLFONT}{STRING}
|
||||||
STR_2778 :???
|
STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING}
|
||||||
STR_2779 :???
|
STR_2779 :???
|
||||||
STR_2780 :???
|
STR_2780 :???
|
||||||
STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID}
|
STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID}
|
||||||
|
|||||||
3447
data/language/english_uk.txt
Normal file
3447
data/language/english_uk.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2774,9 +2774,9 @@ STR_2772 :Faster Gamespeed
|
|||||||
STR_2773 :???
|
STR_2773 :???
|
||||||
STR_2774 :???
|
STR_2774 :???
|
||||||
STR_2775 :???
|
STR_2775 :???
|
||||||
STR_2776 :???
|
STR_2776 :Language
|
||||||
STR_2777 :???
|
STR_2777 :{MOVE_X}{SMALLFONT}{STRING}
|
||||||
STR_2778 :???
|
STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING}
|
||||||
STR_2779 :???
|
STR_2779 :???
|
||||||
STR_2780 :???
|
STR_2780 :???
|
||||||
STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID}
|
STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID}
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
<ClInclude Include="..\src\gfx.h" />
|
<ClInclude Include="..\src\gfx.h" />
|
||||||
<ClInclude Include="..\src\graph.h" />
|
<ClInclude Include="..\src\graph.h" />
|
||||||
<ClInclude Include="..\src\intro.h" />
|
<ClInclude Include="..\src\intro.h" />
|
||||||
|
<ClInclude Include="..\src\language.h" />
|
||||||
<ClInclude Include="..\src\map.h" />
|
<ClInclude Include="..\src\map.h" />
|
||||||
<ClInclude Include="..\src\marketing.h" />
|
<ClInclude Include="..\src\marketing.h" />
|
||||||
<ClInclude Include="..\src\news_item.h" />
|
<ClInclude Include="..\src\news_item.h" />
|
||||||
@@ -73,6 +74,7 @@
|
|||||||
<ClCompile Include="..\src\gfx.c" />
|
<ClCompile Include="..\src\gfx.c" />
|
||||||
<ClCompile Include="..\src\graph.c" />
|
<ClCompile Include="..\src\graph.c" />
|
||||||
<ClCompile Include="..\src\intro.c" />
|
<ClCompile Include="..\src\intro.c" />
|
||||||
|
<ClCompile Include="..\src\language.c" />
|
||||||
<ClCompile Include="..\src\map.c" />
|
<ClCompile Include="..\src\map.c" />
|
||||||
<ClCompile Include="..\src\marketing.c" />
|
<ClCompile Include="..\src\marketing.c" />
|
||||||
<ClCompile Include="..\src\news_item.c" />
|
<ClCompile Include="..\src\news_item.c" />
|
||||||
|
|||||||
@@ -153,6 +153,9 @@
|
|||||||
<ClInclude Include="..\src\graph.h">
|
<ClInclude Include="..\src\graph.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\src\language.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\src\game.c">
|
<ClCompile Include="..\src\game.c">
|
||||||
@@ -359,6 +362,9 @@
|
|||||||
<ClCompile Include="..\src\window_new_campaign.c">
|
<ClCompile Include="..\src\window_new_campaign.c">
|
||||||
<Filter>Windows</Filter>
|
<Filter>Windows</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\src\language.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\openrct2.exe">
|
<None Include="..\openrct2.exe">
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include "addresses.h"
|
#include "addresses.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "language.h"
|
||||||
#include "rct2.h"
|
#include "rct2.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -90,6 +91,7 @@ general_configuration_t gGeneral_config_default = {
|
|||||||
0, // show_height_as_units
|
0, // show_height_as_units
|
||||||
1, // save_plugin_data
|
1, // save_plugin_data
|
||||||
0, // fullscreen mode (default: windowed)
|
0, // fullscreen mode (default: windowed)
|
||||||
|
LANGUAGE_ENGLISH_UK
|
||||||
};
|
};
|
||||||
sound_configuration_t gSound_config;
|
sound_configuration_t gSound_config;
|
||||||
|
|
||||||
@@ -381,6 +383,8 @@ void config_write_ini_general(FILE *fp)
|
|||||||
fprintf(fp, "fullscreen_mode = fullscreen\n");
|
fprintf(fp, "fullscreen_mode = fullscreen\n");
|
||||||
else
|
else
|
||||||
fprintf(fp, "fullscreen_mode = borderless_fullscreen\n");
|
fprintf(fp, "fullscreen_mode = borderless_fullscreen\n");
|
||||||
|
|
||||||
|
fprintf(fp, "language = %d\n", gGeneral_config.language);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -621,6 +625,9 @@ static void config_general(char *setting, char *value){
|
|||||||
else
|
else
|
||||||
gGeneral_config.fullscreen_mode = 2;
|
gGeneral_config.fullscreen_mode = 2;
|
||||||
}
|
}
|
||||||
|
else if (strcmp(setting, "language") == 0) {
|
||||||
|
gGeneral_config.language = atoi(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ typedef struct general_configuration {
|
|||||||
|
|
||||||
//new
|
//new
|
||||||
uint8 fullscreen_mode;
|
uint8 fullscreen_mode;
|
||||||
|
uint16 language;
|
||||||
} general_configuration_t;
|
} general_configuration_t;
|
||||||
|
|
||||||
static const struct { char *key; int value; } _currencyLookupTable[] = {
|
static const struct { char *key; int value; } _currencyLookupTable[] = {
|
||||||
|
|||||||
165
src/language.c
Normal file
165
src/language.c
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014 Ted John
|
||||||
|
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
||||||
|
*
|
||||||
|
* This file is part of OpenRCT2.
|
||||||
|
*
|
||||||
|
* OpenRCT2 is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "addresses.h"
|
||||||
|
#include "language.h"
|
||||||
|
#include "string_ids.h"
|
||||||
|
|
||||||
|
const char *language_names[LANGUAGE_COUNT] = {
|
||||||
|
"", // LANGUAGE_UNDEFINED
|
||||||
|
"English (UK)", // LANGUAGE_ENGLISH_UK
|
||||||
|
"English (US)", // LANGUAGE_ENGLISH_US
|
||||||
|
"Nederlands" // LANGUAGE_DUTCH
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *language_filenames[LANGUAGE_COUNT] = {
|
||||||
|
"", // LANGUAGE_UNDEFINED
|
||||||
|
"english_uk", // LANGUAGE_ENGLISH_UK
|
||||||
|
"english_us", // LANGUAGE_ENGLISH_US
|
||||||
|
"dutch" // LANGUAGE_DUTCH
|
||||||
|
};
|
||||||
|
|
||||||
|
int gCurrentLanguage = LANGUAGE_UNDEFINED;
|
||||||
|
|
||||||
|
// Buffer storing all the string data
|
||||||
|
long language_buffer_size = 0;
|
||||||
|
char *language_buffer = NULL;
|
||||||
|
|
||||||
|
// List of string pointers into the string data
|
||||||
|
int language_num_strings = 0;
|
||||||
|
char **language_strings = NULL;
|
||||||
|
|
||||||
|
static int language_open_file(const char *filename);
|
||||||
|
|
||||||
|
const char *language_get_string(rct_string_id 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int language_open(int id)
|
||||||
|
{
|
||||||
|
char filename[_MAX_PATH];
|
||||||
|
|
||||||
|
language_close();
|
||||||
|
if (id == LANGUAGE_UNDEFINED)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
sprintf(filename, "data/language/%s.txt", language_filenames[id]);
|
||||||
|
if (language_open_file(filename)) {
|
||||||
|
gCurrentLanguage = id;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
static int language_open_file(const char *filename)
|
||||||
|
{
|
||||||
|
FILE *f = fopen(filename, "rb");
|
||||||
|
if (f == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
language_buffer_size = ftell(f);
|
||||||
|
language_buffer = calloc(1, language_buffer_size);
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
fread(language_buffer, language_buffer_size, 1, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
language_strings = calloc(STR_COUNT, sizeof(char*));
|
||||||
|
|
||||||
|
char *dst, *token;
|
||||||
|
char tokenBuffer[64];
|
||||||
|
int i, stringIndex = 0, mode = 0;
|
||||||
|
for (i = 0; i < language_buffer_size; i++) {
|
||||||
|
char *src = &language_buffer[i];
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case 0:
|
||||||
|
// Search for colon
|
||||||
|
if (*src == ':') {
|
||||||
|
dst = src + 1;
|
||||||
|
language_strings[stringIndex++] = dst;
|
||||||
|
mode = 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;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void language_close()
|
||||||
|
{
|
||||||
|
if (language_buffer != NULL)
|
||||||
|
free(language_buffer);
|
||||||
|
language_buffer_size = 0;
|
||||||
|
|
||||||
|
if (language_strings != NULL)
|
||||||
|
free(language_strings);
|
||||||
|
language_num_strings = 0;
|
||||||
|
|
||||||
|
gCurrentLanguage = LANGUAGE_UNDEFINED;
|
||||||
|
}
|
||||||
42
src/language.h
Normal file
42
src/language.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014 Ted John
|
||||||
|
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
||||||
|
*
|
||||||
|
* This file is part of OpenRCT2.
|
||||||
|
*
|
||||||
|
* OpenRCT2 is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _LANGUAGE_H_
|
||||||
|
#define _LANGUAGE_H_
|
||||||
|
|
||||||
|
#include "rct2.h"
|
||||||
|
#include "string_ids.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
LANGUAGE_UNDEFINED,
|
||||||
|
LANGUAGE_ENGLISH_UK,
|
||||||
|
LANGUAGE_ENGLISH_US,
|
||||||
|
LANGUAGE_DUTCH,
|
||||||
|
LANGUAGE_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const char *language_names[LANGUAGE_COUNT];
|
||||||
|
extern int gCurrentLanguage;
|
||||||
|
|
||||||
|
const char *language_get_string(rct_string_id id);
|
||||||
|
int language_open(int id);
|
||||||
|
void language_close();
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -37,6 +37,7 @@
|
|||||||
#include "game.h"
|
#include "game.h"
|
||||||
#include "gfx.h"
|
#include "gfx.h"
|
||||||
#include "intro.h"
|
#include "intro.h"
|
||||||
|
#include "language.h"
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "news_item.h"
|
#include "news_item.h"
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
@@ -76,9 +77,6 @@ __declspec(dllexport) int StartOpenRCT(HINSTANCE hInstance, HINSTANCE hPrevInsta
|
|||||||
{
|
{
|
||||||
print_launch_information();
|
print_launch_information();
|
||||||
|
|
||||||
// OpenRCT2 initialisation
|
|
||||||
language_open("data/language/english.txt");
|
|
||||||
|
|
||||||
// Begin RCT2
|
// Begin RCT2
|
||||||
RCT2_GLOBAL(RCT2_ADDRESS_HINSTANCE, HINSTANCE) = hInstance;
|
RCT2_GLOBAL(RCT2_ADDRESS_HINSTANCE, HINSTANCE) = hInstance;
|
||||||
RCT2_GLOBAL(RCT2_ADDRESS_CMDLINE, LPSTR) = lpCmdLine;
|
RCT2_GLOBAL(RCT2_ADDRESS_CMDLINE, LPSTR) = lpCmdLine;
|
||||||
@@ -88,6 +86,7 @@ __declspec(dllexport) int StartOpenRCT(HINSTANCE hInstance, HINSTANCE hPrevInsta
|
|||||||
audio_get_devices();
|
audio_get_devices();
|
||||||
RCT2_CALLPROC(0x0040502E); // get_dsound_devices()
|
RCT2_CALLPROC(0x0040502E); // get_dsound_devices()
|
||||||
config_init();
|
config_init();
|
||||||
|
language_open(gGeneral_config.language);
|
||||||
rct2_init();
|
rct2_init();
|
||||||
rct2_loop();
|
rct2_loop();
|
||||||
osinterface_free();
|
osinterface_free();
|
||||||
|
|||||||
109
src/string_ids.c
109
src/string_ids.c
@@ -25,6 +25,7 @@
|
|||||||
#include "currency.h"
|
#include "currency.h"
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
#include "date.h"
|
#include "date.h"
|
||||||
|
#include "language.h"
|
||||||
#include "rct2.h"
|
#include "rct2.h"
|
||||||
#include "string_ids.h"
|
#include "string_ids.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@@ -1471,7 +1472,7 @@ void format_string_code(unsigned char format_code, char **dest, char **args)
|
|||||||
value = *((uint16*)*args);
|
value = *((uint16*)*args);
|
||||||
*args += 2;
|
*args += 2;
|
||||||
|
|
||||||
strcpy(*dest, get_string(STR_MONTH_MARCH + date_get_month(value)));
|
strcpy(*dest, language_get_string(STR_MONTH_MARCH + date_get_month(value)));
|
||||||
*dest += strlen(*dest);
|
*dest += strlen(*dest);
|
||||||
break;
|
break;
|
||||||
case FORMAT_VELOCITY:
|
case FORMAT_VELOCITY:
|
||||||
@@ -1591,7 +1592,7 @@ void format_string_part(char **dest, rct_string_id format, char **args)
|
|||||||
{
|
{
|
||||||
if (format < 0x8000) {
|
if (format < 0x8000) {
|
||||||
// Language string
|
// Language string
|
||||||
format_string_part_from_raw(dest, get_string(format), args);
|
format_string_part_from_raw(dest, language_get_string(format), args);
|
||||||
} else if (format < 0x9000) {
|
} else if (format < 0x9000) {
|
||||||
// Custom string
|
// Custom string
|
||||||
format -= 0x8000;
|
format -= 0x8000;
|
||||||
@@ -1690,108 +1691,4 @@ void reset_saved_strings() {
|
|||||||
for (int i = 0; i < 1024; i++) {
|
for (int i = 0; i < 1024; i++) {
|
||||||
RCT2_ADDRESS(0x135A8F4, uint8)[i * 32] = 0;
|
RCT2_ADDRESS(0x135A8F4, uint8)[i * 32] = 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Buffer storing all the string data
|
|
||||||
long language_buffer_size = 0;
|
|
||||||
char *language_buffer = NULL;
|
|
||||||
|
|
||||||
// List of string pointers into the string data
|
|
||||||
int language_num_strings = 0;
|
|
||||||
char **language_strings = NULL;
|
|
||||||
|
|
||||||
const char *get_string(rct_string_id 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)
|
|
||||||
{
|
|
||||||
FILE *f = fopen(filename, "rb");
|
|
||||||
if (f == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
fseek(f, 0, SEEK_END);
|
|
||||||
language_buffer_size = ftell(f);
|
|
||||||
language_buffer = calloc(1, language_buffer_size);
|
|
||||||
fseek(f, 0, SEEK_SET);
|
|
||||||
fread(language_buffer, language_buffer_size, 1, f);
|
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
language_strings = calloc(STR_COUNT, sizeof(char*));
|
|
||||||
|
|
||||||
char *dst, *token;
|
|
||||||
char tokenBuffer[64];
|
|
||||||
int i, stringIndex = 0, mode = 0;
|
|
||||||
for (i = 0; i < language_buffer_size; i++) {
|
|
||||||
char *src = &language_buffer[i];
|
|
||||||
|
|
||||||
switch (mode) {
|
|
||||||
case 0:
|
|
||||||
// Search for colon
|
|
||||||
if (*src == ':') {
|
|
||||||
dst = src + 1;
|
|
||||||
language_strings[stringIndex++] = dst;
|
|
||||||
mode = 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;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void language_close()
|
|
||||||
{
|
|
||||||
if (language_buffer != NULL)
|
|
||||||
free(language_buffer);
|
|
||||||
language_buffer_size = 0;
|
|
||||||
|
|
||||||
if (language_strings != NULL)
|
|
||||||
free(language_strings);
|
|
||||||
language_num_strings = 0;
|
|
||||||
}
|
}
|
||||||
@@ -28,9 +28,8 @@ void generate_string_file();
|
|||||||
void reset_saved_strings();
|
void reset_saved_strings();
|
||||||
void error_string_quit(int error, rct_string_id format);
|
void error_string_quit(int error, rct_string_id format);
|
||||||
|
|
||||||
const char *get_string(rct_string_id id);
|
char format_get_code(const char *token);
|
||||||
int language_open(const char *filename);
|
const char *format_get_token(char code);
|
||||||
void language_close();
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
// Font format codes
|
// Font format codes
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "gfx.h"
|
#include "gfx.h"
|
||||||
|
#include "language.h"
|
||||||
#include "osinterface.h"
|
#include "osinterface.h"
|
||||||
#include "string_ids.h"
|
#include "string_ids.h"
|
||||||
#include "viewport.h"
|
#include "viewport.h"
|
||||||
@@ -67,11 +68,14 @@ enum WINDOW_OPTIONS_WIDGET_IDX {
|
|||||||
WIDX_HOTKEY_DROPDOWN,
|
WIDX_HOTKEY_DROPDOWN,
|
||||||
WIDX_GENERAL_GROUP,
|
WIDX_GENERAL_GROUP,
|
||||||
WIDX_REAL_NAME_CHECKBOX,
|
WIDX_REAL_NAME_CHECKBOX,
|
||||||
WIDX_SAVE_PLUGIN_DATA_CHECKBOX
|
WIDX_SAVE_PLUGIN_DATA_CHECKBOX,
|
||||||
|
WIDX_LANGUAGE_GROUP,
|
||||||
|
WIDX_LANGUAGE_DROPDOWN,
|
||||||
|
WIDX_LANGUAGE_DROPDOWN_BUTTON
|
||||||
};
|
};
|
||||||
|
|
||||||
#define WW 310
|
#define WW 310
|
||||||
#define WH 399
|
#define WH 437
|
||||||
|
|
||||||
static rct_widget window_options_widgets[] = {
|
static rct_widget window_options_widgets[] = {
|
||||||
{ WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, STR_NONE, STR_NONE },
|
{ WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, STR_NONE, STR_NONE },
|
||||||
@@ -110,6 +114,9 @@ static rct_widget window_options_widgets[] = {
|
|||||||
{ WWT_GROUPBOX, 0, 3, 306, 344, 392, STR_GENERAL, STR_NONE },
|
{ WWT_GROUPBOX, 0, 3, 306, 344, 392, STR_GENERAL, STR_NONE },
|
||||||
{ WWT_CHECKBOX, 2, 10, 299, 358, 369, STR_REAL_NAME, STR_REAL_NAME_TIP },
|
{ WWT_CHECKBOX, 2, 10, 299, 358, 369, STR_REAL_NAME, STR_REAL_NAME_TIP },
|
||||||
{ WWT_CHECKBOX, 2, 10, 299, 372, 384, STR_SAVE_PLUGIN_DATA, STR_SAVE_PLUGIN_DATA_TIP },
|
{ WWT_CHECKBOX, 2, 10, 299, 372, 384, STR_SAVE_PLUGIN_DATA, STR_SAVE_PLUGIN_DATA_TIP },
|
||||||
|
{ WWT_GROUPBOX, 0, 3, 306, 399, 430, 2776, STR_NONE },
|
||||||
|
{ WWT_DROPDOWN, 0, 10, 299, 413, 424, STR_NONE, STR_NONE }, // language
|
||||||
|
{ WWT_DROPDOWN_BUTTON, 0, 288, 298, 414, 423, 0x36C, STR_NONE },
|
||||||
{ WIDGETS_END },
|
{ WIDGETS_END },
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -119,7 +126,7 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget*
|
|||||||
static void window_options_dropdown();
|
static void window_options_dropdown();
|
||||||
static void window_options_invalidate();
|
static void window_options_invalidate();
|
||||||
static void window_options_paint();
|
static void window_options_paint();
|
||||||
static void window_options_draw_dropdown_box(rct_window *w, rct_widget *widget, int num_items);
|
static void window_options_show_dropdown(rct_window *w, rct_widget *widget, int num_items);
|
||||||
static void window_options_update_height_markers();
|
static void window_options_update_height_markers();
|
||||||
|
|
||||||
static void* window_options_events[] = {
|
static void* window_options_events[] = {
|
||||||
@@ -326,7 +333,7 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget*
|
|||||||
gDropdownItemsArgs[i] = 1170 | ((uint64)(intptr_t)gAudioDevices[i].name << 16);
|
gDropdownItemsArgs[i] = 1170 | ((uint64)(intptr_t)gAudioDevices[i].name << 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
window_options_draw_dropdown_box(w, widget, gAudioDeviceCount);
|
window_options_show_dropdown(w, widget, gAudioDeviceCount);
|
||||||
|
|
||||||
gDropdownItemsChecked |= (1 << RCT2_GLOBAL(0x9AF280, uint32));
|
gDropdownItemsChecked |= (1 << RCT2_GLOBAL(0x9AF280, uint32));
|
||||||
break;
|
break;
|
||||||
@@ -336,7 +343,7 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget*
|
|||||||
gDropdownItemsArgs[0] = STR_UNITS;
|
gDropdownItemsArgs[0] = STR_UNITS;
|
||||||
gDropdownItemsArgs[1] = STR_REAL_VALUES;
|
gDropdownItemsArgs[1] = STR_REAL_VALUES;
|
||||||
|
|
||||||
window_options_draw_dropdown_box(w, widget, 2);
|
window_options_show_dropdown(w, widget, 2);
|
||||||
|
|
||||||
gDropdownItemsChecked =
|
gDropdownItemsChecked =
|
||||||
(RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) &
|
(RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) &
|
||||||
@@ -348,7 +355,7 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget*
|
|||||||
gDropdownItemsArgs[0] = STR_OFF;
|
gDropdownItemsArgs[0] = STR_OFF;
|
||||||
gDropdownItemsArgs[1] = STR_ON;
|
gDropdownItemsArgs[1] = STR_ON;
|
||||||
|
|
||||||
window_options_draw_dropdown_box(w, widget, 2);
|
window_options_show_dropdown(w, widget, 2);
|
||||||
|
|
||||||
gDropdownItemsChecked = 1 << RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8);
|
gDropdownItemsChecked = 1 << RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8);
|
||||||
break;
|
break;
|
||||||
@@ -360,7 +367,7 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget*
|
|||||||
gDropdownItemsArgs[i] = STR_SOUND_LOW + i; // low, medium, high
|
gDropdownItemsArgs[i] = STR_SOUND_LOW + i; // low, medium, high
|
||||||
}
|
}
|
||||||
|
|
||||||
window_options_draw_dropdown_box(w, widget, num_items);
|
window_options_show_dropdown(w, widget, num_items);
|
||||||
|
|
||||||
gDropdownItemsChecked = 1 << RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_QUALITY, uint8);
|
gDropdownItemsChecked = 1 << RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_QUALITY, uint8);
|
||||||
break;
|
break;
|
||||||
@@ -372,7 +379,7 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget*
|
|||||||
gDropdownItemsArgs[i] = STR_POUNDS + i; // all different currencies
|
gDropdownItemsArgs[i] = STR_POUNDS + i; // all different currencies
|
||||||
}
|
}
|
||||||
|
|
||||||
window_options_draw_dropdown_box(w, widget, num_items);
|
window_options_show_dropdown(w, widget, num_items);
|
||||||
|
|
||||||
gDropdownItemsChecked = 1 << (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_CURRENCY, uint8) & 0x3F);
|
gDropdownItemsChecked = 1 << (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_CURRENCY, uint8) & 0x3F);
|
||||||
break;
|
break;
|
||||||
@@ -382,7 +389,7 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget*
|
|||||||
gDropdownItemsArgs[0] = STR_IMPERIAL;
|
gDropdownItemsArgs[0] = STR_IMPERIAL;
|
||||||
gDropdownItemsArgs[1] = STR_METRIC;
|
gDropdownItemsArgs[1] = STR_METRIC;
|
||||||
|
|
||||||
window_options_draw_dropdown_box(w, widget, 2);
|
window_options_show_dropdown(w, widget, 2);
|
||||||
|
|
||||||
gDropdownItemsChecked = 1 << RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_METRIC, uint8);
|
gDropdownItemsChecked = 1 << RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_METRIC, uint8);
|
||||||
break;
|
break;
|
||||||
@@ -397,7 +404,7 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget*
|
|||||||
gDropdownItemsArgs[1] = STR_FAHRENHEIT;
|
gDropdownItemsArgs[1] = STR_FAHRENHEIT;
|
||||||
gDropdownItemsArgs[2] = STR_METRIC;
|
gDropdownItemsArgs[2] = STR_METRIC;
|
||||||
|
|
||||||
window_options_draw_dropdown_box(w, widget, 3);
|
window_options_show_dropdown(w, widget, 3);
|
||||||
|
|
||||||
gDropdownItemsChecked = 1 << gGeneral_config.fullscreen_mode;
|
gDropdownItemsChecked = 1 << gGeneral_config.fullscreen_mode;
|
||||||
break;
|
break;
|
||||||
@@ -407,7 +414,7 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget*
|
|||||||
gDropdownItemsArgs[0] = STR_CELSIUS;
|
gDropdownItemsArgs[0] = STR_CELSIUS;
|
||||||
gDropdownItemsArgs[1] = STR_FAHRENHEIT;
|
gDropdownItemsArgs[1] = STR_FAHRENHEIT;
|
||||||
|
|
||||||
window_options_draw_dropdown_box(w, widget, 2);
|
window_options_show_dropdown(w, widget, 2);
|
||||||
|
|
||||||
gDropdownItemsChecked = 1 << RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_TEMPERATURE, uint8);
|
gDropdownItemsChecked = 1 << RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_TEMPERATURE, uint8);
|
||||||
break;
|
break;
|
||||||
@@ -417,10 +424,18 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget*
|
|||||||
gDropdownItemsArgs[0] = STR_WHITE;
|
gDropdownItemsArgs[0] = STR_WHITE;
|
||||||
gDropdownItemsArgs[1] = STR_TRANSLUCENT;
|
gDropdownItemsArgs[1] = STR_TRANSLUCENT;
|
||||||
|
|
||||||
window_options_draw_dropdown_box(w, widget, 2);
|
window_options_show_dropdown(w, widget, 2);
|
||||||
|
|
||||||
gDropdownItemsChecked = 1 << RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_CONSTRUCTION_MARKER, uint8);
|
gDropdownItemsChecked = 1 << RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_CONSTRUCTION_MARKER, uint8);
|
||||||
break;
|
break;
|
||||||
|
case WIDX_LANGUAGE_DROPDOWN_BUTTON:
|
||||||
|
for (i = 1; i < LANGUAGE_COUNT; i++) {
|
||||||
|
gDropdownItemsFormat[i - 1] = 2777;
|
||||||
|
gDropdownItemsArgs[i - 1] = (sint64)language_names[i];
|
||||||
|
}
|
||||||
|
window_options_show_dropdown(w, widget, LANGUAGE_COUNT - 1);
|
||||||
|
gDropdownItemsChecked = 1 << (gCurrentLanguage - 1);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -544,6 +559,14 @@ static void window_options_dropdown()
|
|||||||
gfx_invalidate_screen();
|
gfx_invalidate_screen();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case WIDX_LANGUAGE_DROPDOWN_BUTTON:
|
||||||
|
if (dropdownIndex != gCurrentLanguage - 1) {
|
||||||
|
language_open(dropdownIndex + 1);
|
||||||
|
gGeneral_config.language = dropdownIndex + 1;
|
||||||
|
config_save();
|
||||||
|
gfx_invalidate_screen();
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -708,10 +731,19 @@ static void window_options_paint()
|
|||||||
w->y + window_options_widgets[WIDX_MUSIC].top + 1);
|
w->y + window_options_widgets[WIDX_MUSIC].top + 1);
|
||||||
gfx_draw_string_left(dpi, STR_SOUND_QUALITY, w, 0, w->x + 10,
|
gfx_draw_string_left(dpi, STR_SOUND_QUALITY, w, 0, w->x + 10,
|
||||||
w->y + window_options_widgets[WIDX_SOUND_QUALITY].top + 1);
|
w->y + window_options_widgets[WIDX_SOUND_QUALITY].top + 1);
|
||||||
|
|
||||||
|
// language
|
||||||
|
gfx_draw_string(
|
||||||
|
dpi,
|
||||||
|
(char*)language_names[gCurrentLanguage],
|
||||||
|
12,
|
||||||
|
w->x + window_options_widgets[WIDX_LANGUAGE_DROPDOWN].left + 1,
|
||||||
|
w->y + window_options_widgets[WIDX_LANGUAGE_DROPDOWN].top
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper function, all dropdown boxes have similar properties
|
// helper function, all dropdown boxes have similar properties
|
||||||
static void window_options_draw_dropdown_box(rct_window *w, rct_widget *widget, int num_items)
|
static void window_options_show_dropdown(rct_window *w, rct_widget *widget, int num_items)
|
||||||
{
|
{
|
||||||
window_dropdown_show_text_custom_width(
|
window_dropdown_show_text_custom_width(
|
||||||
w->x + widget->left,
|
w->x + widget->left,
|
||||||
@@ -721,7 +753,7 @@ static void window_options_draw_dropdown_box(rct_window *w, rct_widget *widget,
|
|||||||
0x80,
|
0x80,
|
||||||
num_items,
|
num_items,
|
||||||
widget->right - widget->left - 3
|
widget->right - widget->left - 3
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void window_options_update_height_markers()
|
static void window_options_update_height_markers()
|
||||||
|
|||||||
Reference in New Issue
Block a user