1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-18 19:01:45 +02:00

add multi-language support: english (subs+audio), french (subs+audio), german (subs+audio), russian (audio), japanese (audio)

This commit is contained in:
XProger
2019-02-17 06:44:19 +03:00
parent 288c166c77
commit 87a54197d4
10 changed files with 1163 additions and 454 deletions

View File

@@ -202,7 +202,7 @@ namespace Core {
#endif #endif
} support; } support;
#define SETTINGS_VERSION 4 #define SETTINGS_VERSION 5
#define SETTINGS_READING 0xFF #define SETTINGS_READING 0xFF
struct Settings { struct Settings {
@@ -222,7 +222,6 @@ namespace Core {
uint8 quality[4]; uint8 quality[4];
}; };
uint8 simple; uint8 simple;
uint8 subtitles;
uint8 vsync; uint8 vsync;
uint8 stereo; uint8 stereo;
void setFilter(Quality value) { void setFilter(Quality value) {
@@ -262,6 +261,8 @@ namespace Core {
uint8 music; uint8 music;
uint8 sound; uint8 sound;
uint8 reverb; uint8 reverb;
uint8 subtitles;
uint8 language;
} audio; } audio;
struct Controls { struct Controls {
@@ -607,6 +608,7 @@ namespace Core {
namespace Core { namespace Core {
static const char *version = __DATE__; static const char *version = __DATE__;
static int defLang = 0;
void readPerlinAsync(Stream *stream, void *userData) { void readPerlinAsync(Stream *stream, void *userData) {
int size = PERLIN_TEX_SIZE * PERLIN_TEX_SIZE * PERLIN_TEX_SIZE; int size = PERLIN_TEX_SIZE * PERLIN_TEX_SIZE * PERLIN_TEX_SIZE;
@@ -729,12 +731,13 @@ namespace Core {
settings.detail.setShadows (Core::Settings::HIGH); settings.detail.setShadows (Core::Settings::HIGH);
settings.detail.setWater (Core::Settings::HIGH); settings.detail.setWater (Core::Settings::HIGH);
settings.detail.simple = false; settings.detail.simple = false;
settings.detail.subtitles = true;
settings.detail.vsync = true; settings.detail.vsync = true;
settings.detail.stereo = Settings::STEREO_OFF; settings.detail.stereo = Settings::STEREO_OFF;
settings.audio.music = 14; settings.audio.music = 14;
settings.audio.sound = 14; settings.audio.sound = 14;
settings.audio.reverb = true; settings.audio.reverb = true;
settings.audio.subtitles = true;
settings.audio.language = defLang;
// player 1 // player 1
{ {

View File

@@ -2,6 +2,7 @@
#define H_GAMEFLOW #define H_GAMEFLOW
#include "utils.h" #include "utils.h"
#include "lang.h"
#define CHECK_FILE(name) if (Stream::existsContent(name)) return name #define CHECK_FILE(name) if (Stream::existsContent(name)) return name
@@ -190,97 +191,100 @@ namespace TR {
TRACK_TR3_CUT_12 = 66, TRACK_TR3_CUT_12 = 66,
}; };
// #define LEVEL (version,name,track) { #name, STR_##version##_##name, TRACK_##version##track },
// #define CUT (version,id) { #CUT_#id, STR_##version##_##name, TRACK_##version##track },
struct LevelInfo { struct LevelInfo {
const char *name; const char *name;
const char *title; StringID title;
int track; int track;
} LEVEL_INFO[LVL_MAX] = { } LEVEL_INFO[LVL_MAX] = {
{ "" , STR_EMPTY , TRACK_TR1_CAVES },
// TR1 // TR1
{ "" , "Custom Level", TRACK_TR1_CAVES }, { "TITLE" , STR_EMPTY , TRACK_TR1_TITLE },
{ "TITLE" , "", TRACK_TR1_TITLE }, { "GYM" , STR_TR1_GYM , NO_TRACK },
{ "GYM" , "Lara's Home", NO_TRACK }, { "LEVEL1" , STR_TR1_LEVEL1 , TRACK_TR1_CAVES },
{ "LEVEL1" , "Caves", TRACK_TR1_CAVES }, { "LEVEL2" , STR_TR1_LEVEL2 , TRACK_TR1_CAVES },
{ "LEVEL2" , "City of Vilcabamba", TRACK_TR1_CAVES }, { "LEVEL3A" , STR_TR1_LEVEL3A , TRACK_TR1_CAVES },
{ "LEVEL3A" , "Lost Valley", TRACK_TR1_CAVES }, { "LEVEL3B" , STR_TR1_LEVEL3B , TRACK_TR1_CAVES },
{ "LEVEL3B" , "Tomb of Qualopec", TRACK_TR1_CAVES }, { "CUT1" , STR_EMPTY , TRACK_TR1_CUT_1 },
{ "CUT1" , "", TRACK_TR1_CUT_1 }, { "LEVEL4" , STR_TR1_LEVEL4 , TRACK_TR1_CAVES },
{ "LEVEL4" , "St. Francis' Folly", TRACK_TR1_CAVES }, { "LEVEL5" , STR_TR1_LEVEL5 , TRACK_TR1_CAVES },
{ "LEVEL5" , "Colosseum", TRACK_TR1_CAVES }, { "LEVEL6" , STR_TR1_LEVEL6 , TRACK_TR1_CAVES },
{ "LEVEL6" , "Palace Midas", TRACK_TR1_CAVES }, { "LEVEL7A" , STR_TR1_LEVEL7A , TRACK_TR1_CISTERN },
{ "LEVEL7A" , "The Cistern", TRACK_TR1_CISTERN }, { "LEVEL7B" , STR_TR1_LEVEL7B , TRACK_TR1_CISTERN },
{ "LEVEL7B" , "Tomb of Tihocan", TRACK_TR1_CISTERN }, { "CUT2" , STR_EMPTY , TRACK_TR1_CUT_2 },
{ "CUT2" , "", TRACK_TR1_CUT_2 }, { "LEVEL8A" , STR_TR1_LEVEL8A , TRACK_TR1_EGYPT },
{ "LEVEL8A" , "City of Khamoon", TRACK_TR1_EGYPT }, { "LEVEL8B" , STR_TR1_LEVEL8B , TRACK_TR1_EGYPT },
{ "LEVEL8B" , "Obelisk of Khamoon", TRACK_TR1_EGYPT }, { "LEVEL8C" , STR_TR1_LEVEL8C , TRACK_TR1_EGYPT },
{ "LEVEL8C" , "Sanctuary of the Scion", TRACK_TR1_EGYPT }, { "LEVEL10A" , STR_TR1_LEVEL10A , TRACK_TR1_MINE },
{ "LEVEL10A" , "Natla's Mines", TRACK_TR1_MINE }, { "CUT3" , STR_EMPTY , TRACK_TR1_CUT_3 },
{ "CUT3" , "", TRACK_TR1_CUT_3 }, { "LEVEL10B" , STR_TR1_LEVEL10B , TRACK_TR1_MINE },
{ "LEVEL10B" , "Atlantis", TRACK_TR1_MINE }, { "CUT4" , STR_EMPTY , TRACK_TR1_CUT_4 },
{ "CUT4" , "", TRACK_TR1_CUT_4 }, { "LEVEL10C" , STR_TR1_LEVEL10C , TRACK_TR1_MINE },
{ "LEVEL10C" , "The Great Pyramid", TRACK_TR1_MINE }, { "EGYPT" , STR_TR1_EGYPT , TRACK_TR1_EGYPT },
{ "EGYPT" , "Return to Egypt", TRACK_TR1_EGYPT }, { "CAT" , STR_TR1_CAT , TRACK_TR1_EGYPT },
{ "CAT" , "Temple of the Cat", TRACK_TR1_EGYPT }, { "END" , STR_TR1_END , TRACK_TR1_EGYPT },
{ "END" , "Atlantean Stronghold", TRACK_TR1_EGYPT }, { "END2" , STR_TR1_END2 , TRACK_TR1_EGYPT },
{ "END2" , "The Hive", TRACK_TR1_EGYPT },
// TR2 // TR2
{ "TITLE" , "", TRACK_TR2_TITLE }, { "TITLE" , STR_EMPTY , TRACK_TR2_TITLE },
{ "ASSAULT" , "Lara's Home", NO_TRACK }, { "ASSAULT" , STR_TR2_ASSAULT , NO_TRACK },
{ "WALL" , "The Great Wall", TRACK_TR2_CHINA_1 }, { "WALL" , STR_TR2_WALL , TRACK_TR2_CHINA_1 },
{ "CUT1" , "", TRACK_TR2_CUT_1 }, { "CUT1" , STR_EMPTY , TRACK_TR2_CUT_1 },
{ "BOAT" , "Venice", NO_TRACK }, { "BOAT" , STR_TR2_BOAT , NO_TRACK },
{ "VENICE" , "Bartoli's Hideout", NO_TRACK }, { "VENICE" , STR_TR2_VENICE , NO_TRACK },
{ "OPERA" , "Opera House", TRACK_TR2_ITALY }, { "OPERA" , STR_TR2_OPERA , TRACK_TR2_ITALY },
{ "CUT2" , "", TRACK_TR2_CUT_2 }, { "CUT2" , STR_EMPTY , TRACK_TR2_CUT_2 },
{ "RIG" , "Offshore Rig", TRACK_TR2_RIG }, { "RIG" , STR_TR2_RIG , TRACK_TR2_RIG },
{ "PLATFORM" , "Diving Area", TRACK_TR2_RIG }, { "PLATFORM" , STR_TR2_PLATFORM , TRACK_TR2_RIG },
{ "CUT3" , "", TRACK_TR2_CUT_3 }, { "CUT3" , STR_EMPTY , TRACK_TR2_CUT_3 },
{ "UNWATER" , "40 Fathoms", TRACK_TR2_UNWATER_1 }, { "UNWATER" , STR_TR2_UNWATER , TRACK_TR2_UNWATER_1 },
{ "KEEL" , "Wreck of the Maria Doria", TRACK_TR2_UNWATER_2 }, { "KEEL" , STR_TR2_KEEL , TRACK_TR2_UNWATER_2 },
{ "LIVING" , "Living Quarters", TRACK_TR2_UNWATER_1 }, { "LIVING" , STR_TR2_LIVING , TRACK_TR2_UNWATER_1 },
{ "DECK" , "The Deck", TRACK_TR2_UNWATER_2 }, { "DECK" , STR_TR2_DECK , TRACK_TR2_UNWATER_2 },
{ "SKIDOO" , "Tibetan Foothills", TRACK_TR2_TIBET_1 }, { "SKIDOO" , STR_TR2_SKIDOO , TRACK_TR2_TIBET_1 },
{ "MONASTRY" , "Barkhang Monastery", NO_TRACK }, { "MONASTRY" , STR_TR2_MONASTRY , NO_TRACK },
{ "CATACOMB" , "Catacombs of the Talion", TRACK_TR2_TIBET_2 }, { "CATACOMB" , STR_TR2_CATACOMB , TRACK_TR2_TIBET_2 },
{ "ICECAVE" , "Ice Palace", TRACK_TR2_TIBET_2 }, { "ICECAVE" , STR_TR2_ICECAVE , TRACK_TR2_TIBET_2 },
{ "EMPRTOMB" , "Temple of Xian", TRACK_TR2_CHINA_2 }, { "EMPRTOMB" , STR_TR2_EMPRTOMB , TRACK_TR2_CHINA_2 },
{ "CUT4" , "", TRACK_TR2_CUT_4 }, { "CUT4" , STR_EMPTY , TRACK_TR2_CUT_4 },
{ "FLOATING" , "Floating Islands", TRACK_TR2_CHINA_2 }, { "FLOATING" , STR_TR2_FLOATING , TRACK_TR2_CHINA_2 },
{ "XIAN" , "The Dragon's Lair", TRACK_TR2_CHINA_2 }, { "XIAN" , STR_TR2_XIAN , TRACK_TR2_CHINA_2 },
{ "HOUSE" , "Home Sweet Home", NO_TRACK }, { "HOUSE" , STR_TR2_HOUSE , NO_TRACK },
// TR3 // TR3
{ "TITLE", "", TRACK_TR3_TITLE }, { "TITLE" , STR_EMPTY , TRACK_TR3_TITLE },
{ "HOUSE", "Lara's House", NO_TRACK }, { "HOUSE" , STR_TR3_HOUSE , NO_TRACK },
{ "JUNGLE", "Jungle", TRACK_TR3_INDIA_1 }, { "JUNGLE" , STR_TR3_JUNGLE , TRACK_TR3_INDIA_1 },
{ "CUT6", "", TRACK_TR3_CUT_6 }, { "CUT6" , STR_EMPTY , TRACK_TR3_CUT_6 },
{ "TEMPLE", "Temple Ruins", TRACK_TR3_INDIA_1 }, { "TEMPLE" , STR_TR3_TEMPLE , TRACK_TR3_INDIA_1 },
{ "CUT9", "", TRACK_TR3_CUT_9 }, { "CUT9" , STR_EMPTY , TRACK_TR3_CUT_9 },
{ "QUADCHAS", "The River Ganges", TRACK_TR3_INDIA_1 }, { "QUADCHAS" , STR_TR3_QUADCHAS , TRACK_TR3_INDIA_1 },
{ "TONYBOSS", "Caves Of Kaliya", TRACK_TR3_INDIA_2 }, { "TONYBOSS" , STR_TR3_TONYBOSS , TRACK_TR3_INDIA_2 },
{ "SHORE", "Coastal Village", TRACK_TR3_SOUTH_1 }, { "SHORE" , STR_TR3_SHORE , TRACK_TR3_SOUTH_1 },
{ "CUT1", "", TRACK_TR3_CUT_1 }, { "CUT1" , STR_EMPTY , TRACK_TR3_CUT_1 },
{ "CRASH", "Crash Site", TRACK_TR3_SOUTH_2 }, { "CRASH" , STR_TR3_CRASH , TRACK_TR3_SOUTH_2 },
{ "CUT4", "", TRACK_TR3_CUT_4 }, { "CUT4" , STR_EMPTY , TRACK_TR3_CUT_4 },
{ "RAPIDS", "Madubu Gorge", TRACK_TR3_SOUTH_3 }, { "RAPIDS" , STR_TR3_RAPIDS , TRACK_TR3_SOUTH_3 },
{ "TRIBOSS", "Temple Of Puna", TRACK_TR3_CAVES }, { "TRIBOSS" , STR_TR3_TRIBOSS , TRACK_TR3_CAVES },
{ "ROOFS", "Thames Wharf", TRACK_TR3_LONDON_1 }, { "ROOFS" , STR_TR3_ROOFS , TRACK_TR3_LONDON_1 },
{ "CUT2", "", TRACK_TR3_CUT_2 }, { "CUT2" , STR_EMPTY , TRACK_TR3_CUT_2 },
{ "SEWER", "Aldwych", TRACK_TR3_LONDON_2 }, { "SEWER" , STR_TR3_SEWER , TRACK_TR3_LONDON_2 },
{ "CUT5", "", TRACK_TR3_CUT_5 }, { "CUT5" , STR_EMPTY , TRACK_TR3_CUT_5 },
{ "TOWER", "Lud's Gate", TRACK_TR3_LONDON_3 }, { "TOWER" , STR_TR3_TOWER , TRACK_TR3_LONDON_3 },
{ "CUT11", "", TRACK_TR3_CUT_11 }, { "CUT11" , STR_EMPTY , TRACK_TR3_CUT_11 },
{ "OFFICE", "City", TRACK_TR3_LONDON_4 }, { "OFFICE" , STR_TR3_OFFICE , TRACK_TR3_LONDON_4 },
{ "NEVADA", "Nevada Desert", TRACK_TR3_NEVADA_1 }, { "NEVADA" , STR_TR3_NEVADA , TRACK_TR3_NEVADA_1 },
{ "CUT7", "", TRACK_TR3_CUT_7 }, { "CUT7" , STR_EMPTY , TRACK_TR3_CUT_7 },
{ "COMPOUND", "High Security Compound", TRACK_TR3_NEVADA_2 }, { "COMPOUND" , STR_TR3_COMPOUND , TRACK_TR3_NEVADA_2 },
{ "CUT8", "", TRACK_TR3_CUT_8 }, { "CUT8" , STR_EMPTY , TRACK_TR3_CUT_8 },
{ "AREA51", "Area 51", TRACK_TR3_NEVADA_2 }, { "AREA51" , STR_TR3_AREA51 , TRACK_TR3_NEVADA_2 },
{ "ANTARC", "Antarctica", TRACK_TR3_ANTARC_1 }, { "ANTARC" , STR_TR3_ANTARC , TRACK_TR3_ANTARC_1 },
{ "CUT3", "", TRACK_TR3_CUT_3 }, { "CUT3" , STR_EMPTY , TRACK_TR3_CUT_3 },
{ "MINES", "RX-Tech Mines", TRACK_TR3_ANTARC_2 }, { "MINES" , STR_TR3_MINES , TRACK_TR3_ANTARC_2 },
{ "CITY", "Lost City Of Tinnos", TRACK_TR3_ANTARC_3 }, { "CITY" , STR_TR3_CITY , TRACK_TR3_ANTARC_3 },
{ "CUT12", "", TRACK_TR3_CUT_12 }, { "CUT12" , STR_EMPTY , TRACK_TR3_CUT_12 },
{ "CHAMBER", "Meteorite Cavern", TRACK_TR3_ANTARC_3 }, { "CHAMBER" , STR_TR3_CHAMBER , TRACK_TR3_ANTARC_3 },
{ "STPAUL", "All Hallows", TRACK_TR3_CAVES }, { "STPAUL" , STR_TR3_STPAUL , TRACK_TR3_CAVES },
}; };
LevelID getLevelID(int size, const char *name, Version &version, bool &isDemoLevel) { LevelID getLevelID(int size, const char *name, Version &version, bool &isDemoLevel) {
@@ -918,11 +922,17 @@ namespace TR {
bool checkTrack(const char *pre, char *name) { bool checkTrack(const char *pre, char *name) {
static const char *fmt[] = { ".ogg", ".mp3", ".wav" }; static const char *fmt[] = { ".ogg", ".mp3", ".wav" };
static const char *lng[] = { "", "_EN", "_DE", "_FR", "_IT", "_JA", "_RU" }; const char *lng[] = { "", "", "_EN", "_FR", "_DE", "_ES", "_IT", "_RU", "_JA" };
int start = 1;
if (Core::settings.audio.language != 0) {
start = 0;
lng[start] = lng[Core::settings.audio.language + 2];
}
char buf[32]; char buf[32];
for (int f = 0; f < COUNT(fmt); f++) for (int f = 0; f < COUNT(fmt); f++)
for (int l = 0; l < COUNT(lng); l++) { for (int l = start; l < COUNT(lng); l++) {
strcpy(buf, pre); strcpy(buf, pre);
strcat(buf, name); strcat(buf, name);
strcat(buf, lng[l]); strcat(buf, lng[l]);
@@ -978,7 +988,12 @@ namespace TR {
case VER_TR1_SAT : case VER_TR1_SAT :
case VER_TR1_PC : case VER_TR1_PC :
case VER_TR1_PSX : case VER_TR1_PSX :
sprintf(title, "audio/1/track_%02d.ogg", track); if (track != 24 && track >= 22 && track <= 56 && Core::settings.audio.language != LANG_ES && Core::settings.audio.language != LANG_IT) { // es, it isn't implemented yet
const char *lng[] = { "_EN", "_FR", "_DE", "_ES", "_IT", "_RU", "_JA" };
sprintf(title, "audio/1/track_%02d%s.ogg", track, lng[Core::settings.audio.language]);
} else {
sprintf(title, "audio/1/track_%02d.ogg", track);
}
#ifndef _OS_WEB #ifndef _OS_WEB
if (Stream::existsContent(title)) if (Stream::existsContent(title))
break; break;

View File

@@ -35,7 +35,7 @@ struct OptionItem {
uint8 maxValue; uint8 maxValue;
bool bar; bool bar;
OptionItem(Type type = TYPE_EMPTY, int title = STR_NOT_IMPLEMENTED, intptr_t offset = 0, uint32 color = 0xFFFFFFFF, int icon = 0, uint8 maxValue = 0, bool bar = false) : type(type), title(StringID(title)), offset(offset), color(color), icon(icon), maxValue(maxValue), bar(bar) {} OptionItem(Type type = TYPE_EMPTY, int title = STR_EMPTY, intptr_t offset = 0, uint32 color = 0xFFFFFFFF, int icon = 0, uint8 maxValue = 0, bool bar = false) : type(type), title(StringID(title)), offset(offset), color(color), icon(icon), maxValue(maxValue), bar(bar) {}
void setValue(uint8 value, Core::Settings *settings) const { void setValue(uint8 value, Core::Settings *settings) const {
*(uint8*)(intptr_t(settings) + offset) = value; *(uint8*)(intptr_t(settings) + offset) = value;
@@ -54,7 +54,7 @@ struct OptionItem {
} }
float drawParam(float x, float y, float w, StringID oStr, bool active, uint8 value) const { float drawParam(float x, float y, float w, StringID oStr, bool active, uint8 value) const {
if (oStr != STR_NOT_IMPLEMENTED) { if (oStr != STR_EMPTY) {
UI::textOut(vec2(x + 32.0f, y), oStr); UI::textOut(vec2(x + 32.0f, y), oStr);
x = x + w * 0.5f; x = x + w * 0.5f;
w = w * 0.5f - 32.0f; w = w * 0.5f - 32.0f;
@@ -104,7 +104,7 @@ struct OptionItem {
UI::textOut(vec2(x, y), title, UI::aCenter, w, 255, UI::SHADE_GRAY); UI::textOut(vec2(x, y), title, UI::aCenter, w, 255, UI::SHADE_GRAY);
case TYPE_EMPTY : break; case TYPE_EMPTY : break;
case TYPE_BUTTON : { case TYPE_BUTTON : {
const char *caption = offset ? (char*)offset : STR[title]; const char *caption = STR[offset ? StringID(offset) : title];
UI::textOut(vec2(x, y), caption, UI::aCenter, w); UI::textOut(vec2(x, y), caption, UI::aCenter, w);
break; break;
} }
@@ -127,7 +127,6 @@ static const OptionItem optDetail[] = {
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_DETAIL_SHADOWS, SETTINGS( detail.shadows ), STR_QUALITY_LOW, 0, 2 ), OptionItem( OptionItem::TYPE_PARAM, STR_OPT_DETAIL_SHADOWS, SETTINGS( detail.shadows ), STR_QUALITY_LOW, 0, 2 ),
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_DETAIL_WATER, SETTINGS( detail.water ), STR_QUALITY_LOW, 0, 2 ), OptionItem( OptionItem::TYPE_PARAM, STR_OPT_DETAIL_WATER, SETTINGS( detail.water ), STR_QUALITY_LOW, 0, 2 ),
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_SIMPLE_ITEMS, SETTINGS( detail.simple ), STR_OFF, 0, 1 ), OptionItem( OptionItem::TYPE_PARAM, STR_OPT_SIMPLE_ITEMS, SETTINGS( detail.simple ), STR_OFF, 0, 1 ),
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_SUBTITLES, SETTINGS( detail.subtitles ), STR_OFF, 0, 1 ),
#if defined(_OS_WIN) || defined(_OS_LINUX) || defined(_OS_PSP) || defined(_OS_RPI) || defined(_OS_PSV) #if defined(_OS_WIN) || defined(_OS_LINUX) || defined(_OS_PSP) || defined(_OS_RPI) || defined(_OS_PSV)
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_DETAIL_VSYNC, SETTINGS( detail.vsync ), STR_OFF, 0, 1 ), OptionItem( OptionItem::TYPE_PARAM, STR_OPT_DETAIL_VSYNC, SETTINGS( detail.vsync ), STR_OFF, 0, 1 ),
#endif #endif
@@ -147,24 +146,26 @@ static const OptionItem optDetail[] = {
static const OptionItem optSound[] = { static const OptionItem optSound[] = {
OptionItem( OptionItem::TYPE_TITLE, STR_SET_VOLUMES ), OptionItem( OptionItem::TYPE_TITLE, STR_SET_VOLUMES ),
OptionItem( ), OptionItem( ),
OptionItem( OptionItem::TYPE_PARAM, STR_NOT_IMPLEMENTED, SETTINGS( audio.music ), 0xFF0080FF, 101, SND_MAX_VOLUME, true ), OptionItem( OptionItem::TYPE_PARAM, STR_EMPTY, SETTINGS( audio.music ), 0xFF0080FF, 101, SND_MAX_VOLUME, true ),
OptionItem( OptionItem::TYPE_PARAM, STR_NOT_IMPLEMENTED, SETTINGS( audio.sound ), 0xFFFF8000, 102, SND_MAX_VOLUME, true ), OptionItem( OptionItem::TYPE_PARAM, STR_EMPTY, SETTINGS( audio.sound ), 0xFFFF8000, 102, SND_MAX_VOLUME, true ),
OptionItem( OptionItem::TYPE_PARAM, STR_REVERBERATION, SETTINGS( audio.reverb ), STR_OFF, 0, 1 ), OptionItem( OptionItem::TYPE_PARAM, STR_REVERBERATION, SETTINGS( audio.reverb ), STR_OFF, 0, 1 ),
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_SUBTITLES, SETTINGS( audio.subtitles ), STR_OFF, 0, 1 ),
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_LANGUAGE, SETTINGS( audio.language ), STR_LANG_EN, 0, 6 ),
}; };
static const OptionItem optControls[] = { static const OptionItem optControls[] = {
OptionItem( OptionItem::TYPE_TITLE, STR_SET_CONTROLS ), OptionItem( OptionItem::TYPE_TITLE, STR_SET_CONTROLS ),
OptionItem( ), OptionItem( ),
OptionItem( OptionItem::TYPE_PARAM, STR_NOT_IMPLEMENTED , SETTINGS( playerIndex ), STR_PLAYER_1, 0, 1 ), OptionItem( OptionItem::TYPE_PARAM, STR_EMPTY, SETTINGS( playerIndex ), STR_PLAYER_1, 0, 1 ),
#ifndef _OS_CLOVER #ifndef _OS_CLOVER
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_CONTROLS_GAMEPAD , SETTINGS( controls[0].joyIndex ), STR_GAMEPAD_1, 0, 3 ), OptionItem( OptionItem::TYPE_PARAM, STR_OPT_CONTROLS_GAMEPAD, SETTINGS( controls[0].joyIndex ), STR_GAMEPAD_1, 0, 3 ),
#endif #endif
#if defined(_OS_WIN) || defined(_OS_LINUX) || defined(_OS_RPI) #if defined(_OS_WIN) || defined(_OS_LINUX) || defined(_OS_RPI)
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_CONTROLS_VIBRATION , SETTINGS( controls[0].vibration ), STR_OFF, 0, 1 ), OptionItem( OptionItem::TYPE_PARAM, STR_OPT_CONTROLS_VIBRATION , SETTINGS( controls[0].vibration ), STR_OFF, 0, 1 ),
#endif #endif
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_CONTROLS_RETARGET , SETTINGS( controls[0].retarget ), STR_OFF, 0, 1 ), OptionItem( OptionItem::TYPE_PARAM, STR_OPT_CONTROLS_RETARGET , SETTINGS( controls[0].retarget ), STR_OFF, 0, 1 ),
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_CONTROLS_MULTIAIM , SETTINGS( controls[0].multiaim ), STR_OFF, 0, 1 ), OptionItem( OptionItem::TYPE_PARAM, STR_OPT_CONTROLS_MULTIAIM , SETTINGS( controls[0].multiaim ), STR_OFF, 0, 1 ),
OptionItem( OptionItem::TYPE_PARAM, STR_NOT_IMPLEMENTED , SETTINGS( ctrlIndex ), STR_OPT_CONTROLS_KEYBOARD, 0, 1 ), OptionItem( OptionItem::TYPE_PARAM, STR_EMPTY , SETTINGS( ctrlIndex ), STR_OPT_CONTROLS_KEYBOARD, 0, 1 ),
OptionItem( OptionItem::TYPE_KEY, STR_CTRL_FIRST + cUp , SETTINGS( controls[0].keys[ cUp ] ), STR_KEY_FIRST ), OptionItem( OptionItem::TYPE_KEY, STR_CTRL_FIRST + cUp , SETTINGS( controls[0].keys[ cUp ] ), STR_KEY_FIRST ),
OptionItem( OptionItem::TYPE_KEY, STR_CTRL_FIRST + cDown , SETTINGS( controls[0].keys[ cDown ] ), STR_KEY_FIRST ), OptionItem( OptionItem::TYPE_KEY, STR_CTRL_FIRST + cDown , SETTINGS( controls[0].keys[ cDown ] ), STR_KEY_FIRST ),
OptionItem( OptionItem::TYPE_KEY, STR_CTRL_FIRST + cRight , SETTINGS( controls[0].keys[ cRight ] ), STR_KEY_FIRST ), OptionItem( OptionItem::TYPE_KEY, STR_CTRL_FIRST + cRight , SETTINGS( controls[0].keys[ cRight ] ), STR_KEY_FIRST ),
@@ -322,7 +323,7 @@ struct Inventory {
OptionItem item; OptionItem item;
item.type = OptionItem::TYPE_BUTTON; item.type = OptionItem::TYPE_BUTTON;
item.offset = slot.isCheckpoint() ? intptr_t(STR[STR_CURRENT_POSITION]) : intptr_t(TR::LEVEL_INFO[id].title); // offset as int pointer to level title string item.offset = slot.isCheckpoint() ? STR_CURRENT_POSITION : TR::LEVEL_INFO[id].title;
item.color = i; // color as slot index item.color = i; // color as slot index
optLoadSlots.push(item); optLoadSlots.push(item);
} }
@@ -1572,7 +1573,7 @@ struct Inventory {
case TR::Entity::INV_GAMMA : case TR::Entity::INV_GAMMA :
case TR::Entity::INV_STOPWATCH : case TR::Entity::INV_STOPWATCH :
case TR::Entity::INV_MAP : case TR::Entity::INV_MAP :
UI::textOut(vec2(-eye, 240), STR_NOT_IMPLEMENTED, UI::aCenter, UI::width); UI::textOut(vec2(-eye, 240), STR_EMPTY, UI::aCenter, UI::width);
break; break;
default : ; default : ;
} }
@@ -1915,7 +1916,7 @@ struct Inventory {
sprintf(time, "%d:%02d", m, s); sprintf(time, "%d:%02d", m, s);
sprintf(buf, STR[STR_LEVEL_STATS], sprintf(buf, STR[STR_LEVEL_STATS],
TR::LEVEL_INFO[saveStats.level].title, STR[TR::LEVEL_INFO[saveStats.level].title],
saveStats.kills, saveStats.kills,
saveStats.pickups, saveStats.pickups,
secrets, secretsMax, time); secrets, secretsMax, time);

962
src/lang.h Normal file
View File

@@ -0,0 +1,962 @@
#ifndef H_LANG
#define H_LANG
enum StringID {
STR_EMPTY
// common
, STR_LOADING
, STR_HELP_PRESS
, STR_HELP_TEXT
, STR_LEVEL_STATS
, STR_HINT_SAVING
, STR_HINT_SAVING_DONE
, STR_HINT_SAVING_ERROR
, STR_YES
, STR_NO
, STR_OFF
, STR_ON
, STR_SPLIT
, STR_VR
, STR_QUALITY_LOW
, STR_QUALITY_MEDIUM
, STR_QUALITY_HIGH
, STR_LANG_EN
, STR_LANG_FR
, STR_LANG_DE
, STR_LANG_ES
, STR_LANG_IT
, STR_LANG_RU
, STR_LANG_JA
, STR_APPLY
, STR_GAMEPAD_1
, STR_GAMEPAD_2
, STR_GAMEPAD_3
, STR_GAMEPAD_4
, STR_NOT_READY
, STR_PLAYER_1
, STR_PLAYER_2
, STR_PRESS_ANY_KEY
, STR_HELP_SELECT
, STR_HELP_BACK
// inventory pages
, STR_OPTION
, STR_INVENTORY
, STR_ITEMS
// save game page
, STR_SAVEGAME
, STR_CURRENT_POSITION
// inventory option
, STR_GAME
, STR_MAP
, STR_COMPASS
, STR_STOPWATCH
, STR_HOME
, STR_DETAIL
, STR_SOUND
, STR_CONTROLS
, STR_GAMMA
// passport menu
, STR_LOAD_GAME
, STR_START_GAME
, STR_RESTART_LEVEL
, STR_EXIT_TO_TITLE
, STR_EXIT_GAME
, STR_SELECT_LEVEL
// detail options
, STR_SELECT_DETAIL
, STR_OPT_DETAIL_FILTER
, STR_OPT_DETAIL_LIGHTING
, STR_OPT_DETAIL_SHADOWS
, STR_OPT_DETAIL_WATER
, STR_OPT_DETAIL_VSYNC
, STR_OPT_DETAIL_STEREO
, STR_OPT_SIMPLE_ITEMS
// sound options
, STR_SET_VOLUMES
, STR_REVERBERATION
, STR_OPT_SUBTITLES
, STR_OPT_LANGUAGE
// controls options
, STR_SET_CONTROLS
, STR_OPT_CONTROLS_KEYBOARD
, STR_OPT_CONTROLS_GAMEPAD
, STR_OPT_CONTROLS_VIBRATION
, STR_OPT_CONTROLS_RETARGET
, STR_OPT_CONTROLS_MULTIAIM
// controls
, STR_CTRL_FIRST
, STR_CTRL_LAST = STR_CTRL_FIRST + cMAX - 1
// keys
, STR_KEY_FIRST
, STR_KEY_LAST = STR_KEY_FIRST + ikZ
// gamepad
, STR_JOY_FIRST
, STR_JOY_LAST = STR_JOY_FIRST + jkMAX - 1
// inventory items
, STR_UNKNOWN
, STR_EXPLOSIVE
, STR_PISTOLS
, STR_SHOTGUN
, STR_MAGNUMS
, STR_UZIS
, STR_AMMO_PISTOLS
, STR_AMMO_SHOTGUN
, STR_AMMO_MAGNUMS
, STR_AMMO_UZIS
, STR_MEDI_SMALL
, STR_MEDI_BIG
, STR_LEAD_BAR
, STR_SCION
// keys
, STR_KEY
, STR_KEY_SILVER
, STR_KEY_RUSTY
, STR_KEY_GOLD
, STR_KEY_SAPPHIRE
, STR_KEY_NEPTUNE
, STR_KEY_ATLAS
, STR_KEY_DAMOCLES
, STR_KEY_THOR
, STR_KEY_ORNATE
// puzzles
, STR_PUZZLE
, STR_PUZZLE_GOLD_IDOL
, STR_PUZZLE_GOLD_BAR
, STR_PUZZLE_COG
, STR_PUZZLE_FUSE
, STR_PUZZLE_ANKH
, STR_PUZZLE_HORUS
, STR_PUZZLE_ANUBIS
, STR_PUZZLE_SCARAB
, STR_PUZZLE_PYRAMID
// TR1 subtitles
, STR_TR1_SUB_26
, STR_TR1_SUB_27
, STR_TR1_SUB_28
, STR_TR1_SUB_29
, STR_TR1_SUB_30
, STR_TR1_SUB_31
, STR_TR1_SUB_32
, STR_TR1_SUB_33
, STR_TR1_SUB_34
, STR_TR1_SUB_35
, STR_TR1_SUB_36
, STR_TR1_SUB_37
, STR_TR1_SUB_38
, STR_TR1_SUB_39
, STR_TR1_SUB_40
, STR_TR1_SUB_41
, STR_TR1_SUB_42
, STR_TR1_SUB_43
, STR_TR1_SUB_44
, STR_TR1_SUB_45
, STR_TR1_SUB_46
, STR_TR1_SUB_47
, STR_TR1_SUB_48
, STR_TR1_SUB_49
, STR_TR1_SUB_50
, STR_TR1_SUB_51
, STR_TR1_SUB_52
, STR_TR1_SUB_53
, STR_TR1_SUB_54
, STR_TR1_SUB_55
, STR_TR1_SUB_56
// TR1 levels
, STR_TR1_GYM
, STR_TR1_LEVEL1
, STR_TR1_LEVEL2
, STR_TR1_LEVEL3A
, STR_TR1_LEVEL3B
, STR_TR1_LEVEL4
, STR_TR1_LEVEL5
, STR_TR1_LEVEL6
, STR_TR1_LEVEL7A
, STR_TR1_LEVEL7B
, STR_TR1_LEVEL8A
, STR_TR1_LEVEL8B
, STR_TR1_LEVEL8C
, STR_TR1_LEVEL10A
, STR_TR1_LEVEL10B
, STR_TR1_LEVEL10C
, STR_TR1_EGYPT
, STR_TR1_CAT
, STR_TR1_END
, STR_TR1_END2
// TR2 levels
, STR_TR2_ASSAULT
, STR_TR2_WALL
, STR_TR2_BOAT
, STR_TR2_VENICE
, STR_TR2_OPERA
, STR_TR2_RIG
, STR_TR2_PLATFORM
, STR_TR2_UNWATER
, STR_TR2_KEEL
, STR_TR2_LIVING
, STR_TR2_DECK
, STR_TR2_SKIDOO
, STR_TR2_MONASTRY
, STR_TR2_CATACOMB
, STR_TR2_ICECAVE
, STR_TR2_EMPRTOMB
, STR_TR2_FLOATING
, STR_TR2_XIAN
, STR_TR2_HOUSE
// TR3 levels
, STR_TR3_HOUSE
, STR_TR3_JUNGLE
, STR_TR3_TEMPLE
, STR_TR3_QUADCHAS
, STR_TR3_TONYBOSS
, STR_TR3_SHORE
, STR_TR3_CRASH
, STR_TR3_RAPIDS
, STR_TR3_TRIBOSS
, STR_TR3_ROOFS
, STR_TR3_SEWER
, STR_TR3_TOWER
, STR_TR3_OFFICE
, STR_TR3_NEVADA
, STR_TR3_COMPOUND
, STR_TR3_AREA51
, STR_TR3_ANTARC
, STR_TR3_MINES
, STR_TR3_CITY
, STR_TR3_CHAMBER
, STR_TR3_STPAUL
, STR_MAX
};
const char *helpText =
"Start - add second player or restore Lara@"
"H - Show or hide this help@"
"ALT + ENTER - Fullscreen@"
"5 - Save Game@"
"9 - Load Game@"
"C - Look@"
"R - Slow motion@"
"T - Fast motion@"
"Roll - Up + Down@"
"Step Left - Walk + Left@"
"Step Right - Walk + Right@"
"Out of water - Up + Action@"
"Handstand - Up + Walk@"
"Swan dive - Up + Walk + Jump@"
"First Person View - Look + Action@"
"DOZY on - Look + Duck + Action + Jump@"
"DOZY off - Walk";
const char *STR_EN[] = { ""
// help
, "Loading..."
, "Press H for help"
, helpText
, "%s@@@"
"KILLS %d@@"
"PICKUPS %d@@"
"SECRETS %d of %d@@"
"TIME TAKEN %s"
, "Saving game..."
, "Saving done!"
, "SAVING ERROR!"
, "YES"
, "NO"
, "Off"
, "On"
, "Split Screen"
, "VR"
, "Low"
, "Medium"
, "High"
, "English"
, "French"
, "German"
, "Spanish"
, "Italian"
, "Russian"
, "Japanese"
, "Apply"
, "Gamepad 1"
, "Gamepad 2"
, "Gamepad 3"
, "Gamepad 4"
, "Not Ready"
, "Player 1"
, "Player 2"
, "Press Any Key"
, "%s - Select"
, "%s - Go Back"
// inventory pages
, "OPTIONS"
, "INVENTORY"
, "ITEMS"
// save game page
, "Save Game?"
, "Current Position"
// inventory option
, "Game"
, "Map"
, "Compass"
, "Statistics"
, "Lara's Home"
, "Detail Levels"
, "Sound"
, "Controls"
, "Gamma"
// passport menu
, "Load Game"
, "Start Game"
, "Restart Level"
, "Exit to Title"
, "Exit Game"
, "Select Level"
// detail options
, "Select Detail"
, "Filtering"
, "Lighting"
, "Shadows"
, "Water"
, "VSync"
, "Stereo"
, "Simple Items"
// sound options
, "Set Volumes"
, "Reverberation"
, "Subtitles"
, "Language"
// controls options
, "Set Controls"
, "Keyboard"
, "Gamepad"
, "Vibration"
, "Retargeting"
, "Multi-aiming"
// controls
, "Left", "Right", "Run", "Back", "Jump", "Walk", "Action", "Draw Weapon", "Look", "Duck", "Dash", "Roll", "Inventory", "Start"
// keys
, "NONE", "LEFT", "RIGHT", "UP", "DOWN", "SPACE", "TAB", "ENTER", "ESCAPE", "SHIFT", "CTRL", "ALT"
, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
, "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M"
, "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
// gamepad
, "NONE", "A", "B", "X", "Y", "L BUMPER", "R BUMPER", "SELECT", "START", "L STICK", "R STICK", "L TRIGGER", "R TRIGGER", "D-LEFT", "D-RIGHT", "D-UP", "D-DOWN"
// inventory items
, "Unknown"
, "Explosive"
, "Pistols"
, "Shotgun"
, "Magnums"
, "Uzis"
, "Pistol Clips"
, "Shotgun Shells"
, "Magnum Clips"
, "Uzi Clips"
, "Small Medi Pack"
, "Large Medi Pack"
, "Lead Bar"
, "Scion"
// keys
, "Key"
, "Silver Key"
, "Rusty Key"
, "Gold Key"
, "Sapphire Key"
, "Neptune Key"
, "Atlas Key"
, "Damocles Key"
, "Thor Key"
, "Ornate Key"
// puzzles
, "Puzzle"
, "Gold Idol"
, "Gold Bar"
, "Machine Cog"
, "Fuse"
, "Ankh"
, "Eye of Horus"
, "Seal of Anubis"
, "Scarab"
, "Pyramid Key"
// TR1 subtitles
/* 26 */ , "Welcome to my home!@I'll take you on a guided tour."
/* 27 */ , "Use the directional buttons to go into the music room."
/* 28 */ , "OK. Let's do some tumbling.@Press the jump button."
/* 29 */ , "Now press it again and press one of@the directions and I'll jump that way."
/* 30 */ , "Ah, the main hall.@Sorry about the crates, I'm having some things put@ into storage and the delivery people haven't been yet."
/* 31 */ , "Run up to a crate, and while still pressing forwards@press action, and I'll vault up onto it."
/* 32 */ , "This used to be the ballroom, but I've converted it into my own personal gym.@What do you think?@Well, let's do some exercises."
/* 33 */ , "I don't actually run everywhere.@When I want to be careful, I walk.@Hold down the walk button, and walk to the white line."
/* 34 */ , "With the walk button down, I won't fall off even if you try to make me.@Go on, try it."
/* 35 */ , "If you want look around, press and hold the look button.@Then press in the direction you want to look."
/* 36 */ , "If a jump is too far for me, I can grab the ledge and save myself from a nasty fall.@Walk to the edge with the white line until I won't go any further.@Then press jump immediately followed by forwards then while @I'm in the air press and hold the action button."
/* 37 */ , "Press forward and I'll climb up."
/* 38 */ , "If I do a running jump, I can make a jump like that, no problem."
/* 39 */ , "Walk to the edge with the white line until I stop.@Then let go of walk and tap backwards to give me a run up.@Press forward, and almost immediately press and hold the jump button.@I won't actually jump until the last minute."
/* 40 */ , "Right. This is a really big one.@So do a running jump exactly as before except while I'm in the air@press and hold the action button to make me grab the ledge."
/* 41 */ , "Nice."
/* 42 */ , "Try to vault up here.@Press forwards and hold action."
/* 43 */ , "I can't climb up because the gap is too small.@But press right and I'll shimmy sideways@until there is room, then press forward."
/* 44 */ , "Great!@If there is a long drop and I don't want to@hurt myself jumping off I can let myself down carefully."
/* 45 */ , "Tap backwards, and I'll jump off backwards.@Immediately press and hold the action button,@and I'll grab the ledge on the way down."
/* 46 */ , "Then let go."
/* 47 */ , "Let's go for a swim."
/* 48 */ , "The jump button and the directions@move me around underwater."
/* 49 */ , "Ah! Air!@Just use forward and left and right@to manoeuvre around on the surface.@Press jump to dive down for another swim about.@Or go to the edge and press action to climb out."
/* 50 */ , "Right. Now I'd better take off these wet clothes."
/* 51 */ , "Say cheese!"
/* 52 */ , "Ain't nothin' personal."
/* 53 */ , "I still git a pain in my brain from ye.@An' it's tellin' me funny ideas now.@Like to shoot you to hell!"
/* 54 */ , "You can't bump off me and my brood so easy, Lara."
/* 55 */ , "A leetle late for the prize giving - non?@Still, it is the taking-part wheech counts."
/* 56 */ , "You firin' at me?@You firin' at me, huh?@Ain't nobody else, so you must be firin' at me!"
// TR1 levels
, "Lara's Home"
, "Caves"
, "City of Vilcabamba"
, "Lost Valley"
, "Tomb of Qualopec"
, "St. Francis' Folly"
, "Colosseum"
, "Palace Midas"
, "The Cistern"
, "Tomb of Tihocan"
, "City of Khamoon"
, "Obelisk of Khamoon"
, "Sanctuary of the Scion"
, "Natla's Mines"
, "Atlantis"
, "The Great Pyramid"
, "Return to Egypt"
, "Temple of the Cat"
, "Atlantean Stronghold"
, "The Hive"
// TR2 levels
, "Lara's Home"
, "The Great Wall"
, "Venice"
, "Bartoli's Hideout"
, "Opera House"
, "Offshore Rig"
, "Diving Area"
, "40 Fathoms"
, "Wreck of the Maria Doria"
, "Living Quarters"
, "The Deck"
, "Tibetan Foothills"
, "Barkhang Monastery"
, "Catacombs of the Talion"
, "Ice Palace"
, "Temple of Xian"
, "Floating Islands"
, "The Dragon's Lair"
, "Home Sweet Home"
// TR3 levels
, "Lara's House"
, "Jungle"
, "Temple Ruins"
, "The River Ganges"
, "Caves Of Kaliya"
, "Coastal Village"
, "Crash Site"
, "Madubu Gorge"
, "Temple Of Puna"
, "Thames Wharf"
, "Aldwych"
, "Lud's Gate"
, "City"
, "Nevada Desert"
, "High Security Compound"
, "Area 51"
, "Antarctica"
, "RX-Tech Mines"
, "Lost City Of Tinnos"
, "Meteorite Cavern"
, "All Hallows"
};
const char *STR_FR[] = { ""
// help
, "Chargement..."
, "Press H for help"
, helpText
, "%s@@@"
"ENNEMIS TU)ES %d@@"
"OBJETS TROUVES %d@@"
"SECRETS %d / %d@@"
"TEMPS %s"
, "Sauvegarde..."
, "Sauvegarde achev)ee !"
, "SAUVER ERREUR !"
, "OUI"
, "NON"
, "Arret"
, "Marche"
, ")Ecran Divis)e"
, "VR"
, "Bas"
, "Moyen"
, "Haut"
, "English"
, "French"
, "German"
, "Spanish"
, "Italian"
, "Russian"
, "Japanese"
, "Appliquer"
, "Gamepad 1"
, "Gamepad 2"
, "Gamepad 3"
, "Gamepad 4"
, "Not Ready"
, "Joueur 1"
, "Joueur 2"
, "Press Any Key"
, "%s - Choisir"
, "%s - Arri$ere"
// inventory pages
, "OPTIONS"
, "INVENTAIRE"
, "OBJETS"
// save game page
, "Sauver le jeu ?"
, "Charger Partie"
// inventory option
, "Jeu"
, "Carte"
, "Boussole"
, "Statistiques"
, "Manoir de Lara"
, "Niveau des D)etails"
, "Sons"
, "Controles"
, "Gamma"
// passport menu
, "Charger"
, "Commencer"
, "Rejouer Niveau"
, "Sortie vers titre"
, "Quitter"
, "Choisir Niveau"
// detail options
, "Niveau de D)etail"
, "Filtration"
, ")Eclairage"
, "Ombres"
, "Eau"
, "VSync"
, "St)er)eo"
, "Objets Simples"
// sound options
, "R)egler Volume"
, "R)everb)eration"
, "Sous-titres"
, "Langue"
// controls options
, "R)egler Controles"
, "Clavier"
, "Gamepad"
, "Vibration"
, "Reciblage"
, "Multi-vis)ee"
// controls
, "Gauche", "Droite", "Courir", "Arri$ere", "Sauter", "Marcher", "Action", "D)egainer", "Regarder", "Duck", "Dash", "Roulade", "Inventaire", "Start"
// keys
, "NONE", "LEFT", "RIGHT", "UP", "DOWN", "SPACE", "TAB", "ENTER", "ESCAPE", "SHIFT", "CTRL", "ALT"
, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
, "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M"
, "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
// gamepad
, "NONE", "A", "B", "X", "Y", "L BUMPER", "R BUMPER", "SELECT", "START", "L STICK", "R STICK", "L TRIGGER", "R TRIGGER", "D-LEFT", "D-RIGHT", "D-UP", "D-DOWN"
// inventory items
, "Inconnu"
, "Explosif"
, "Pistolets"
, "Fusil $a pompe"
, "Magnums"
, "Uzis"
, "Balles de pistolet"
, "Cartouches de fusil"
, "Balles de magnum"
, "Balles d'uzi"
, "Mini m)edikit"
, "Grand m)edikit"
, "Barre en plomb"
, "Scion"
// keys
, "Cl)e"
, "Cl)e d'argent"
, "Cl)e rouill)ee"
, "Cl)e en or"
, "Cl)e de saphir"
, "Cl)e Neptune"
, "Cl)e d'Atlas"
, "Cl)e Damocl$es"
, "Cl)e de Thor"
, "Cl)e Ornement)ee"
// puzzles
, "Puzzle"
, "Idole d'or"
, "Lingot d'or"
, "Engrenage"
, "Fusible"
, "Ankh"
, "Oeil d'Horus"
, "Sceau d'Anubis"
, "Scarab)ee"
, "Cl)e pyramide"
// TR1 subtitles
/* 26 */ , "Bienvenue chez moi !"
/* 27 */ , "Utilisez le bouton multidirectionnel pour@aller dans le salon de musique."
/* 28 */ , "OK. On va bouger un peu.@Appuyez sur la touche de saut."
/* 29 */ , "Recommencez en appuyant sur le bouton multidirectionnel@et je sauterai dans cette direction."
/* 30 */ , "Voici le grand hall.@Excusez le d)esordre, je dois tout envoyer au garde-meuble@et les d)em)enageurs ne sont pas encore arriv)es."
/* 31 */ , "Approchez-vous d'une caisse, puis appuyez@en m(eme temps sur la touche d'action et vers@le haut pour que je grimpe dessus."
/* 32 */ , "C')etait autrefois la salle de bal, mais je l'ai transform)ee en salle de gym personnelle.@C'est chouette, non ?@Allez, un peu d'exercice."
/* 33 */ , "Je ne cours pas sans arr(et, en fait.@S'il faut (etre prudente, je peux aussi marcher.@Appuyez sur la touche de marche et avancez@jusqu'$a la ligne blanche."
/* 34 */ , "Tant que vous garderez la touche de marche enfonc)ee,@je ne tomberai pas, m(eme si vous insistez.@Allez-y, essayez !"
/* 35 */ , "Si vous voulez examiner les environs, gardez la touche Observer enfonc)ee.@Puis utilisez le bouton multidirectionnel."
/* 36 */ , "Si je ne peux pas sauter assez loin, je peux me rattraper@de justesse pour ne pas tomber. Approchez-vous du bord au maximum,@en marchant pour que je ne tombe pas. Appuyez sur la touche de saut@puis vers le haut, et maintenez la touche@d'action enfonc)ee pendant que je saute."
/* 37 */ , "Appuyez vers le haut pour me faire grimper."
/* 38 */ , "Avec de l')elan, je peux m'en sortir sans probl$eme."
/* 39 */ , "Avancez en marchant jusqu'$a la ligne blanche, bien au bord.@L(achez la touche de marche et reculez@d'un cran pour que je prenne de l')elan.@Appuyez vers le haut et enfoncez tout de suite la touche de saut.@En fait, je ne sauterai qu'au dernier moment."
/* 40 */ , "L$a, c'est plus difficile.@Nous allons faire exactement le m(eme saut, mais@vous maintiendrez la touche d'action enfonc)ee pour que je me rattrape."
/* 41 */ , "Tr$es bien."
/* 42 */ , "Nous allons grimper ici.@Avancez en appuyant sur la touche d'action."
/* 43 */ , "Je n'ai pas assez de place pour monter, mais je peux longer la corniche.@Appuyez vers la droite jusqu'$a ce qu'il y ait assez d'espace,@puis appuyez vers le haut."
/* 44 */ , "Bien !@Pour )eviter de me blesser en sautant de si haut,@je peux redescendre tout en douceur."
/* 45 */ , "Appuyez vers le bas pour que je me laisse tomber et maintenez@la touche d'action enfonc)ee pour que@je me rattrape dans ma chute."
/* 46 */ , "Vous pouvez ensuite l(acher la touche d'action."
/* 47 */ , "Allons nager un peu."
/* 48 */ , "La touche de saut et le bouton multidirectionnel@me permettent d')evoluer sous l'eau."
/* 49 */ , "Ah ! De l'air !@Utilisez le bouton multidirectionnel pour me faire nager en surface.@Appuyez sur la touche de saut pour me faire nager sous l'eau.@Pour sortir, allez vers le bord et@appuyez sur la touche d'action."
/* 50 */ , "Bon. Je ferais mieux d'aller mettre des v(etements secs."
/* 51 */ , "Souris un peu !"
/* 52 */ , "J'fais que mon boulot."
/* 53 */ , "J'ai encore mal au cr(ane suite $a notre derni$ere rencontre.@Ca me donne des envies )etranges@Cette fois-ci, pas de cadeaux !"
/* 54 */ , "Vous ne pourrez pas vous d)ebarrasser@aussi facilement de moi, Lara."
/* 55 */ , "Vous arrivez un peu tard pour la remise des prix.@Mais l'important, c'est de participer, non ?"
/* 56 */ , "ON ME TIRE DESSUS !@ON ME TIRE DESSUS, LA !@IL N'Y A PAS DE DOUTE, ON ME TIRE DESSUS !"
// TR1 levels
, "Manoir de Lara"
, "Cavernes"
, "Cit)ee de Vilcabamba"
, "Vall)ee Perdue"
, "Tombe de Qualopec"
, "Monument St. Francis"
, "Colosseum"
, "Palais de Midas"
, "La Citerne"
, "Tombe de Tihocan"
, "Cit)ee de Khamoon"
, "Ob)elisque de Khamoon"
, "Sanctuaire du Scion"
, "Mines de Natla"
, "Atlantide"
, "La Grande Pyramide"
, "Retour en Egypte"
, "Temple du Chat"
, "La Forteresse Atlantique"
, "La Ruche"
// TR2 levels
, "Lara's Home"
, "The Great Wall"
, "Venice"
, "Bartoli's Hideout"
, "Opera House"
, "Offshore Rig"
, "Diving Area"
, "40 Fathoms"
, "Wreck of the Maria Doria"
, "Living Quarters"
, "The Deck"
, "Tibetan Foothills"
, "Barkhang Monastery"
, "Catacombs of the Talion"
, "Ice Palace"
, "Temple of Xian"
, "Floating Islands"
, "The Dragon's Lair"
, "Home Sweet Home"
// TR3 levels
, "Lara's House"
, "Jungle"
, "Temple Ruins"
, "The River Ganges"
, "Caves Of Kaliya"
, "Coastal Village"
, "Crash Site"
, "Madubu Gorge"
, "Temple Of Puna"
, "Thames Wharf"
, "Aldwych"
, "Lud's Gate"
, "City"
, "Nevada Desert"
, "High Security Compound"
, "Area 51"
, "Antarctica"
, "RX-Tech Mines"
, "Lost City Of Tinnos"
, "Meteorite Cavern"
, "All Hallows"
};
const char *STR_DE[] = { ""
// help
, "Wird geladen..."
, "Press H for help"
, helpText
, "%s@@@"
"Besiegte Gegner %d@@"
"Gegenst~ande %d@@"
"Geheimnisse %d von %d@@"
"Ben~otigte Zeit %s"
, "Spiel sicherung..."
, "Spielstand gesichert!"
, "Sicherung FEHLER!"
, "JA"
, "NEIN"
, "Aus"
, "An"
, "Geteilter Bildschirm"
, "VR"
, "Niedrig"
, "Mittel"
, "Hoch"
, "English"
, "French"
, "German"
, "Spanish"
, "Italian"
, "Russian"
, "Japanese"
, "Anwenden"
, "Gamepad 1"
, "Gamepad 2"
, "Gamepad 3"
, "Gamepad 4"
, "Not Ready"
, "Spieler 1"
, "Spieler 2"
, "Press Any Key"
, "%s - W~ahlen"
, "%s - Zur~uck"
// inventory pages
, "OPTIONEN"
, "INVENTAR"
, "GEGENST~ANDE"
// save game page
, "Spiel sichern?"
, "Aktuelle Position"
// inventory option
, "Spiel"
, "Karte"
, "Kompa="
, "Statistiken"
, "Laras Haus"
, "Detail-Stufe"
, "Ton"
, "Kontrollen"
, "Gamma"
// passport menu
, "Spiel Laden"
, "Spiel Starten"
, "Level neu starten"
, "Zur~uck zum Hauptmen~u"
, "Spiel Beenden"
, "Level W~ahlen"
// detail options
, "Detailstufe W~ahlen"
, "Filterung"
, "Beleuchtung"
, "Schatten"
, "Wasser"
, "VSync"
, "Stereo"
, "Einfache Gegenst~ande"
// sound options
, "Lautst~arke Einstellen"
, "Nachhall"
, "Untertitel"
, "Sprache"
// controls options
, "Kontrollen Einstellen"
, "Tastatur"
, "Gamepad"
, "Vibration"
, "Retargeting"
, "Multi-Zielen"
// controls
, "Links", "Rechts", "Laufen", "R~uckw~arts", "Springen", "Gehen", "Handlung", "Waffe ziehen", "Umsehen", "Duck", "Dash", "Rolle", "Inventory", "Start"
// keys
, "NONE", "LEFT", "RIGHT", "UP", "DOWN", "SPACE", "TAB", "ENTER", "ESCAPE", "SHIFT", "CTRL", "ALT"
, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
, "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M"
, "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
// gamepad
, "NONE", "A", "B", "X", "Y", "L BUMPER", "R BUMPER", "SELECT", "START", "L STICK", "R STICK", "L TRIGGER", "R TRIGGER", "D-LEFT", "D-RIGHT", "D-UP", "D-DOWN"
// inventory items
, "Unbekannte"
, "Explosiv"
, "Pistolen"
, "Schrotflinte"
, "Magnums"
, "Uzis"
, "Pistolen-Munition"
, "Schrot-Munition"
, "Magnum-Munition"
, "Uzi-Ladestreifen"
, "Kleines Medi-Pack"
, "Gro=es Medi-Pack"
, "Bleibarren"
, "Scion"
// keys
, "Schl~ussel"
, "Silberner Schl~ussel"
, "Rostiger Schl~ussel"
, "Goldener Schl~ussel"
, "Saphir-Schl~ussel"
, "Schl~ussel des Neptun"
, "Schl~ussel des Atlas"
, "Schl~ussel des Damokles"
, "Schl~ussel des Thor"
, "Der antike Schl~ussel"
// puzzles
, "R~atsel"
, "Goldener G~otze"
, "Goldbarren"
, "Zahnrad"
, "Sicherung"
, "Ankh-Kreuz"
, "Auge des Horus"
, "Siegel des Anubis"
, "Skarab~aus"
, "Schl~ussel der Pyramide"
// TR1 subtitles
/* 26 */ , "Willkommen in meinem Haus."
/* 27 */ , "Mit dem Steuerkreuz kommen Sie ins Musikzimmer."
/* 28 */ , "OK, ~uben wir ein paar Spr~unge.@Dr~ucken Sie die Sprungtaste."
/* 29 */ , "Nochmal Sprungtaste, dann das Steuerkreuz dr~ucken,@und ich springe in diese Richtung."
/* 30 */ , "Ah, die Haupthalle.@Sorry wegen der Kisten: Ich will einige Sachen einlagern@und sie sind noch nicht abgeholt worden."
/* 31 */ , "So springe ich auf eine Kiste: Vorw~artstaste gedr~uckt halten,@w~ahrend ich darauf zurenne und Handlungstaste dr~ucken."
/* 32 */ , "Fr~uher war das der Ballsaal.@Jetzt nutze ich ihn als Turnhalle.@Nicht ~ubel, was?@Dann wollen wir mal."
/* 33 */ , "~Ubrigens renne ich nicht immer:@Wenn Vorsicht geboten ist, gehe ich langsam.@Halten Sie die Gehen-Taste gedr~uckt@und gehen Sie bis zur weissen Linie."
/* 34 */ , "Ist die Gehen-Taste gedr~uckt,@kann ich nicht hinunterfallen - auch nicht, wenn Sie das m~ochten.@Los, versuchen Sie's mal."
/* 35 */ , "Dr~ucken und halten Sie die Umsehen-Taste, um sich umzusehen.@Dr~ucken Sie dann die Richtung, in die Sie blicken m~ochten."
/* 36 */ , "Ist ein Sprung zu weit f~ur mich, kann ich nach einem@Vorsprung greifen, um nicht abzust~urzen.@Gehen Sie zum Rand mit der weissen Linie, bis ich stehen bleibe.@Dr~ucken Sie dann Springen und gleich danach Vorw~arts.@Dr~ucken und halten Sie die Handlungstaste,@w~ahrend ich in der Luft bin."
/* 37 */ , "Dr~ucken Sie Vorw~arts, klettere ich nach oben."
/* 38 */ , "Wenn ich mit Anlauf springe, kann ich das problemlos schaffen."
/* 39 */ , "Gehen Sie zur weissen Linie am Rand, bis ich stehen bleibe.@Lassen Sie dann die Gehen-Taste los und dr~ucken@Sie kurz R~uckw~arts, damit ich Anlauf nehmen kann.@Dr~ucken Sie Vorw~arts. Dr~ucken und halten Sie dann fast gleichzeitig die Sprungtaste.@Ich springe erst im letzten Moment."
/* 40 */ , "OK. Jetzt geht's richtig zur Sache.@Machen Sie also wie vorhin einen Sprung mit Anlauf.@Aber wenn ich in der Luft bin dr~ucken und halten@Sie die Handlungstaste, damit ich den Vorsprung greifen kann."
/* 41 */ , "Sehr sch~on."
/* 42 */ , "Versuchen Sie mal, hier drauf zu springen:@Dr~ucken Sie Vorw~arts und halten Sie die Handlungstaste."
/* 43 */ , "Ich kann nicht hinaufklettern: Nicht genug Platz.@Dr~ucken Sie also Rechts, und ich bewege mich seitw~arts,@bis genug Platz ist. Dr~ucken Sie dann Vorw~arts."
/* 44 */ , "Prima!@Bei einem Sprung aus grosser H~ohe k~onnte ich mich verletzen:@Hier ist es besser, sich vorsichtig hinunter zu lassen."
/* 45 */ , "Dr~ucken Sie kurz R~uckw~arts,@damit ich r~uckw~arts abspringe.@Dr~ucken und halten Sie dann sofort die Handlungstaste,@halte ich mich an der Kante fest."
/* 46 */ , "Lassen Sie dann los."
/* 47 */ , "Gehen wir schwimmen."
/* 48 */ , "Mit der Sprungtaste und dem Steuerkreuz steuern@Sie mich unter Wasser."
/* 49 */ , "Ah! Luft!@Benutzen Sie einfach Vorw~arts, Links und Rechts,@um an der Oberfl~ache herumzuschwimmen.@Dr~ucken Sie die Sprungtaste, um noch mal abzutauchen und weiter zu schwimmen.@Oder schwimmen Sie zum Rand und dr~ucken Sie@die Handlungstaste, um heraus zu klettern."
/* 50 */ , "So. Die nassen Sachen sollte ich wohl besser ausziehen."
/* 51 */ , "Sag 'Cheese'!"
/* 52 */ , "Nimm's nicht pers~onlich."
/* 53 */ , "Es ist gef~ahrlich, Leuten auf den Kopf zu hauen.@Davon kriegt man ganz komische Ideen@wie zum Beispiel, Sie wegzupusten!"
/* 54 */ , "Mich und meine Brut werden Sie nicht so leicht los, Lara."
/* 55 */ , "Zu sp~at f~ur die Preisverleihung - non?@Aber dabei sein ist alles, nicht wahr?"
/* 56 */ , "Schiessen Sie auf mich?@He, ob Sie auf mich schiessen?@Ist ja sonst keiner da, Sie m~ussen wohl mich meinen!"
// TR1 levels
, "Laras Haus"
, "Die Kavernen"
, "Die Stadt Vilcabamba"
, "Das Verlorene Tal"
, "Das Grab von Qualopec"
, "St. Francis' Folly"
, "Das Kolosseum"
, "Der Palast des Midas"
, "Die Zisterne"
, "Das Grab des Tihocan"
, "Die Stadt Khamoon"
, "Der Obelisk von Khamoon"
, "Das Heiligtum des Scion"
, "Natlas Katakomben"
, "Atlantis"
, "Die Gro=e Pyramide"
, "Zuruck nach Agypten"
, "Tempel der Katze"
, "Atlantischen Stronghold"
, "Der Bienenstock"
// TR2 levels
, "Lara's Home"
, "The Great Wall"
, "Venice"
, "Bartoli's Hideout"
, "Opera House"
, "Offshore Rig"
, "Diving Area"
, "40 Fathoms"
, "Wreck of the Maria Doria"
, "Living Quarters"
, "The Deck"
, "Tibetan Foothills"
, "Barkhang Monastery"
, "Catacombs of the Talion"
, "Ice Palace"
, "Temple of Xian"
, "Floating Islands"
, "The Dragon's Lair"
, "Home Sweet Home"
// TR3 levels
, "Lara's House"
, "Jungle"
, "Temple Ruins"
, "The River Ganges"
, "Caves Of Kaliya"
, "Coastal Village"
, "Crash Site"
, "Madubu Gorge"
, "Temple Of Puna"
, "Thames Wharf"
, "Aldwych"
, "Lud's Gate"
, "City"
, "Nevada Desert"
, "High Security Compound"
, "Area 51"
, "Antarctica"
, "RX-Tech Mines"
, "Lost City Of Tinnos"
, "Meteorite Cavern"
, "All Hallows"
};
char **STR = NULL;
enum LangID {
LANG_EN ,
LANG_FR ,
LANG_DE ,
LANG_ES ,
LANG_IT ,
LANG_RU ,
LANG_JA ,
};
void ensureLanguage(LangID lang) {
ASSERT(COUNT(STR_EN) == STR_MAX);
ASSERT(COUNT(STR_FR) == STR_MAX);
ASSERT(COUNT(STR_DE) == STR_MAX);
switch (lang) {
case LANG_FR : STR = (char**)STR_FR; break;
case LANG_DE : STR = (char**)STR_DE; break;
case LANG_ES : STR = (char**)STR_EN; break;
case LANG_IT : STR = (char**)STR_EN; break;
case LANG_RU : STR = (char**)STR_EN; break;
case LANG_JA : STR = (char**)STR_EN; break;
default : STR = (char**)STR_EN; break;
}
}
#endif

View File

@@ -8,11 +8,11 @@
} }
body { body {
margin: 0px; margin: 0px;
font-size: 1.0em; font-size: 1.0em;
overflow: hidden; overflow: hidden;
} }
.game_fs { .game_fs {
position: fixed; position: fixed;
top: 0px; top: 0px;
left: 0px; left: 0px;
margin: 0px; margin: 0px;
@@ -111,7 +111,26 @@
} }
proc.connect(audioContext.destination); proc.connect(audioContext.destination);
} }
function getLanguage() {
var lang = navigator.languages && navigator.languages[0] || navigator.language || navigator.userLanguage;
var id = 0;
if (lang.startsWith("fr")) {
id = 1;
} else if (lang.startsWith("de")) {
id = 2;
} else if (lang.startsWith("es")) {
id = 3;
} else if (lang.startsWith("it")) {
id = 4;
} else if (lang.startsWith("ru") || lang.startsWith("be") || lang.startsWith("uk")) {
id = 5;
} else if (lang.startsWith("it")) {
id = 6;
}
Module.ccall('set_def_lang', 'null', ['number'], [id]);
}
// unlock audio context after user interaction // unlock audio context after user interaction
var userAction = function() { var userAction = function() {
if (audioContext && audioContext.state == "suspended") { if (audioContext && audioContext.state == "suspended") {
@@ -147,7 +166,9 @@
OpenLara on <a target="_blank" href="https://github.com/XProger/OpenLara">github</a> & <a target="_blank" href="https://www.facebook.com/OpenLaraTR">facebook</a><br> OpenLara on <a target="_blank" href="https://github.com/XProger/OpenLara">github</a> & <a target="_blank" href="https://www.facebook.com/OpenLaraTR">facebook</a><br>
<div id="latest_changes" style="margin:8px"> <div id="latest_changes" style="margin:8px">
<br><i>last update: 14.02.2019</i><br> <br><i>last update: <?php
echo date("d.m.Y", filemtime("./OpenLara.js.gz"));
?></i><br>
<input type="button" value="Latest changes" onclick="getLatestChanges()" /> <input type="button" value="Latest changes" onclick="getLatestChanges()" />
</div> </div>
</p> </p>

View File

@@ -236,6 +236,10 @@ bool isFullScreen() {
} }
extern "C" { extern "C" {
void EMSCRIPTEN_KEEPALIVE set_def_lang(int id) {
Core::defLang = id;
}
void EMSCRIPTEN_KEEPALIVE snd_fill(Sound::Frame *frames, int count) { void EMSCRIPTEN_KEEPALIVE snd_fill(Sound::Frame *frames, int count) {
Sound::fill(frames, count); Sound::fill(frames, count);
} }
@@ -338,6 +342,7 @@ int main() {
emscripten_set_mouseup_callback(0, 0, 1, mouseCallback); emscripten_set_mouseup_callback(0, 0, 1, mouseCallback);
emscripten_set_mousemove_callback(0, 0, 1, mouseCallback); emscripten_set_mousemove_callback(0, 0, 1, mouseCallback);
emscripten_run_script("getLanguage()");
Game::init(); Game::init();
emscripten_run_script("snd_init()"); emscripten_run_script("snd_init()");
resize(); resize();

View File

@@ -211,6 +211,7 @@
<ClInclude Include="..\..\frustum.h" /> <ClInclude Include="..\..\frustum.h" />
<ClInclude Include="..\..\game.h" /> <ClInclude Include="..\..\game.h" />
<ClInclude Include="..\..\gameflow.h" /> <ClInclude Include="..\..\gameflow.h" />
<ClInclude Include="..\..\lang.h" />
<ClInclude Include="..\..\napi_dummy.h" /> <ClInclude Include="..\..\napi_dummy.h" />
<ClInclude Include="..\..\napi_socket.h" /> <ClInclude Include="..\..\napi_socket.h" />
<ClInclude Include="..\..\network.h" /> <ClInclude Include="..\..\network.h" />

View File

@@ -58,6 +58,7 @@
<ClInclude Include="..\..\napi_socket.h" /> <ClInclude Include="..\..\napi_socket.h" />
<ClInclude Include="..\..\napi_dummy.h" /> <ClInclude Include="..\..\napi_dummy.h" />
<ClInclude Include="..\..\gapi_gxm.h" /> <ClInclude Include="..\..\gapi_gxm.h" />
<ClInclude Include="..\..\lang.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="..\..\shaders\filter.glsl"> <None Include="..\..\shaders\filter.glsl">

View File

@@ -489,6 +489,22 @@ void parseCommand(char *cmd) {
} }
#endif #endif
LangID checkLanguage() {
LANGID id = GetUserDefaultUILanguage() & 0xFF;
switch (id) {
case LANG_ENGLISH : return LANG_EN;
case LANG_FRENCH : return LANG_FR;
case LANG_GERMAN : return LANG_DE;
case LANG_SPANISH : return LANG_ES;
case LANG_ITALIAN : return LANG_IT;
case LANG_RUSSIAN :
case LANG_UKRAINIAN :
case LANG_BELARUSIAN : return LANG_RU;
case LANG_JAPANESE : return LANG_JA;
}
return LANG_EN;
}
static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) { switch (msg) {
// window // window
@@ -848,6 +864,8 @@ int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
joyInit(); joyInit();
sndInit(hWnd); sndInit(hWnd);
Core::defLang = checkLanguage();
Game::init(argc > 1 ? argv[1] : NULL); Game::init(argc > 1 ? argv[1] : NULL);
#ifdef VR_SUPPORT #ifdef VR_SUPPORT

374
src/ui.h
View File

@@ -12,343 +12,7 @@
#define UI_SHOW_FPS #define UI_SHOW_FPS
#endif #endif
enum StringID { #include "lang.h"
STR_NOT_IMPLEMENTED
// common
, STR_LOADING
, STR_HELP_PRESS
, STR_HELP_TEXT
, STR_LEVEL_STATS
, STR_HINT_SAVING
, STR_HINT_SAVING_DONE
, STR_HINT_SAVING_ERROR
, STR_YES
, STR_NO
, STR_OFF
, STR_ON
, STR_SPLIT
, STR_VR
, STR_QUALITY_LOW
, STR_QUALITY_MEDIUM
, STR_QUALITY_HIGH
, STR_APPLY
, STR_GAMEPAD_1
, STR_GAMEPAD_2
, STR_GAMEPAD_3
, STR_GAMEPAD_4
, STR_NOT_READY
, STR_PLAYER_1
, STR_PLAYER_2
, STR_PRESS_ANY_KEY
, STR_HELP_SELECT
, STR_HELP_BACK
// inventory pages
, STR_OPTION
, STR_INVENTORY
, STR_ITEMS
// save game page
, STR_SAVEGAME
, STR_CURRENT_POSITION
// inventory option
, STR_GAME
, STR_MAP
, STR_COMPASS
, STR_STOPWATCH
, STR_HOME
, STR_DETAIL
, STR_SOUND
, STR_CONTROLS
, STR_GAMMA
// passport menu
, STR_AUTOSAVE
, STR_LOAD_GAME
, STR_START_GAME
, STR_RESTART_LEVEL
, STR_EXIT_TO_TITLE
, STR_EXIT_GAME
, STR_SELECT_LEVEL
// detail options
, STR_SELECT_DETAIL
, STR_OPT_DETAIL_FILTER
, STR_OPT_DETAIL_LIGHTING
, STR_OPT_DETAIL_SHADOWS
, STR_OPT_DETAIL_WATER
, STR_OPT_DETAIL_VSYNC
, STR_OPT_DETAIL_STEREO
, STR_OPT_SIMPLE_ITEMS
, STR_OPT_SUBTITLES
// sound options
, STR_SET_VOLUMES
, STR_REVERBERATION
// controls options
, STR_SET_CONTROLS
, STR_OPT_CONTROLS_KEYBOARD
, STR_OPT_CONTROLS_GAMEPAD
, STR_OPT_CONTROLS_VIBRATION
, STR_OPT_CONTROLS_RETARGET
, STR_OPT_CONTROLS_MULTIAIM
// controls
, STR_CTRL_FIRST
, STR_CTRL_LAST = STR_CTRL_FIRST + cMAX - 1
// keys
, STR_KEY_FIRST
, STR_KEY_LAST = STR_KEY_FIRST + ikZ
// gamepad
, STR_JOY_FIRST
, STR_JOY_LAST = STR_JOY_FIRST + jkMAX - 1
// inventory items
, STR_UNKNOWN
, STR_EXPLOSIVE
, STR_PISTOLS
, STR_SHOTGUN
, STR_MAGNUMS
, STR_UZIS
, STR_AMMO_PISTOLS
, STR_AMMO_SHOTGUN
, STR_AMMO_MAGNUMS
, STR_AMMO_UZIS
, STR_MEDI_SMALL
, STR_MEDI_BIG
, STR_LEAD_BAR
, STR_SCION
// keys
, STR_KEY
, STR_KEY_SILVER
, STR_KEY_RUSTY
, STR_KEY_GOLD
, STR_KEY_SAPPHIRE
, STR_KEY_NEPTUNE
, STR_KEY_ATLAS
, STR_KEY_DAMOCLES
, STR_KEY_THOR
, STR_KEY_ORNATE
// puzzles
, STR_PUZZLE
, STR_PUZZLE_GOLD_IDOL
, STR_PUZZLE_GOLD_BAR
, STR_PUZZLE_COG
, STR_PUZZLE_FUSE
, STR_PUZZLE_ANKH
, STR_PUZZLE_HORUS
, STR_PUZZLE_ANUBIS
, STR_PUZZLE_SCARAB
, STR_PUZZLE_PYRAMID
// TR1 subtitles
, STR_TR1_SUB_26
, STR_TR1_SUB_27
, STR_TR1_SUB_28
, STR_TR1_SUB_29
, STR_TR1_SUB_30
, STR_TR1_SUB_31
, STR_TR1_SUB_32
, STR_TR1_SUB_33
, STR_TR1_SUB_34
, STR_TR1_SUB_35
, STR_TR1_SUB_36
, STR_TR1_SUB_37
, STR_TR1_SUB_38
, STR_TR1_SUB_39
, STR_TR1_SUB_40
, STR_TR1_SUB_41
, STR_TR1_SUB_42
, STR_TR1_SUB_43
, STR_TR1_SUB_44
, STR_TR1_SUB_45
, STR_TR1_SUB_46
, STR_TR1_SUB_47
, STR_TR1_SUB_48
, STR_TR1_SUB_49
, STR_TR1_SUB_50
, STR_TR1_SUB_51
, STR_TR1_SUB_52
, STR_TR1_SUB_53
, STR_TR1_SUB_54
, STR_TR1_SUB_55
, STR_TR1_SUB_56
, STR_MAX
};
const char *helpText =
"Start - add second player or restore Lara@"
"H - Show or hide this help@"
"ALT + ENTER - Fullscreen@"
"5 - Save Game@"
"9 - Load Game@"
"C - Look@"
"R - Slow motion@"
"T - Fast motion@"
"Roll - Up + Down@"
"Step Left - Walk + Left@"
"Step Right - Walk + Right@"
"Out of water - Up + Action@"
"Handstand - Up + Walk@"
"Swan dive - Up + Walk + Jump@"
"First Person View - Look + Action@"
"DOZY on - Look + Duck + Action + Jump@"
"DOZY off - Walk";
const char *levelStats =
"%s@@@"
"KILLS %d@@"
"PICKUPS %d@@"
"SECRETS %d of %d@@"
"TIME TAKEN %s";
const char *STR[STR_MAX] = {
"Not implemented yet!"
// help
, "Loading..."
, "Press H for help"
, helpText
, levelStats
, "Saving game..."
, "Saving done!"
, "SAVING ERROR!"
, "YES"
, "NO"
, "Off"
, "On"
, "Split Screen"
, "VR"
, "Low"
, "Medium"
, "High"
, "Apply"
, "Gamepad 1"
, "Gamepad 2"
, "Gamepad 3"
, "Gamepad 4"
, "Not Ready"
, "Player 1"
, "Player 2"
, "Press Any Key"
, "%s - Select"
, "%s - Go Back"
// inventory pages
, "OPTION"
, "INVENTORY"
, "ITEMS"
// save game page
, "Save Game?"
, "Current Position"
// inventory option
, "Game"
, "Map"
, "Compass"
, "Statistics"
, "Lara's Home"
, "Detail Levels"
, "Sound"
, "Controls"
, "Gamma"
// passport menu
, "Autosave"
, "Load Game"
, "Start Game"
, "Restart Level"
, "Exit to Title"
, "Exit Game"
, "Load Game"
// detail options
, "Select Detail"
, "Filtering"
, "Lighting"
, "Shadows"
, "Water"
, "VSync"
, "Stereo"
, "Simple Items"
, "Subtitles"
// sound options
, "Set Volumes"
, "Reverberation"
// controls options
, "Set Controls"
, "Keyboard"
, "Gamepad"
, "Vibration"
, "Retargeting"
, "Multi-aiming"
// controls
, "Left", "Right", "Up", "Down", "Jump", "Walk", "Action", "Draw Weapon", "Look", "Duck", "Dash", "Roll", "Inventory", "Start"
// keys
, "NONE", "LEFT", "RIGHT", "UP", "DOWN", "SPACE", "TAB", "ENTER", "ESCAPE", "SHIFT", "CTRL", "ALT"
, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
, "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M"
, "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
// gamepad
, "NONE", "A", "B", "X", "Y", "L BUMPER", "R BUMPER", "SELECT", "START", "L STICK", "R STICK", "L TRIGGER", "R TRIGGER", "D-LEFT", "D-RIGHT", "D-UP", "D-DOWN"
// inventory items
, "Unknown"
, "Explosive"
, "Pistols"
, "Shotgun"
, "Magnums"
, "Uzis"
, "Pistol Clips"
, "Shotgun Shells"
, "Magnum Clips"
, "Uzi Clips"
, "Small Medi Pack"
, "Large Medi Pack"
, "Lead Bar"
, "Scion"
// keys
, "Key"
, "Silver Key"
, "Rusty Key"
, "Gold Key"
, "Sapphire Key"
, "Neptune Key"
, "Atlas Key"
, "Damocles Key"
, "Thor Key"
, "Ornate Key"
// puzzles
, "Puzzle"
, "Gold Idol"
, "Gold Bar"
, "Machine Cog"
, "Fuse"
, "Ankh"
, "Eye of Horus"
, "Seal of Anubis"
, "Scarab"
, "Pyramid Key"
// TR1 subtitles
/* 26 */ , "Welcome to my home.@I'll take you on a guided tour."
/* 27 */ , "Use the directional buttons to go into the music room."
/* 28 */ , "OK. Let's do some tumbling.@Press the jump button."
/* 29 */ , "Now press it again and press one of@the directions and I'll jump that way."
/* 30 */ , "Ah, the main hall.@Sorry about the crates, I'm having some things put@ into storage and the delivery people haven't been yet."
/* 31 */ , "Run up to a crate, and while still pressing forwards@press action, and I'll vault up onto it."
/* 32 */ , "This used to be the ballroom, but I've converted it into my own personal gym.@What do you think?@Well, let's do some exercises."
/* 33 */ , "I don't actually run everywhere.@When I want to be careful, I walk.@Hold down the walk button, and walk to the white line."
/* 34 */ , "With the walk button down, I won't fall off even if you try to make me.@Go on, try it."
/* 35 */ , "If you want look around, press and hold the look button.@Then press in the direction you want to look."
/* 36 */ , "If a jump is too far for me, I can grab the ledge and save myself from a nasty fall.@Walk to the edge with the white line until I won't go any further.@Then press jump immediately followed by forwards then while @I'm in the air press and hold the action button."
/* 37 */ , "Press forward and I'll climb up."
/* 38 */ , "If I do a running jump, I can make a jump like that, no problem."
/* 39 */ , "Walk to the edge with the white line until I stop.@Then let go of walk and tap backwards to give me a run up.@Press forward, and almost immediately press and hold the jump button.@I won't actually jump until the last minute."
/* 40 */ , "Right. This is a really big one.@So do a running jump exactly as before except while I'm in the air@press and hold the action button to make me grab the ledge."
/* 41 */ , "Nice."
/* 42 */ , "Try to vault up here.@Press forwards and hold action."
/* 43 */ , "I can't climb up because the gap is too small.@But press right and I'll shimmy sideways@until there is room, then press forward."
/* 44 */ , "Great!@If there is a long drop and I don't want to@hurt myself jumping off I can let myself down carefully."
/* 45 */ , "Tap backwards, and I'll jump off backwards.@Immediately press and hold the action button,@and I'll grab the ledge on the way down."
/* 46 */ , "Then let go."
/* 47 */ , "Let's go for a swim."
/* 48 */ , "The jump button and the directions@move me around underwater."
/* 49 */ , "Ah! Air!@Just use forward and left and right@to manoeuvre around on the surface.@Press jump to dive down for another swim about.@Or go to the edge and press action to climb out."
/* 50 */ , "Right. Now I'd better take off these wet clothes."
/* 51 */ , "Say cheese!"
/* 52 */ , "Ain't nothin' personal."
/* 53 */ , "I still git a pain in my brain from ye.@An' it's tellin' me funny ideas now.@Like to shoot you to hell!"
/* 54 */ , "You can't bump off me and my brood so easy, Lara."
/* 55 */ , "A leetle late for the prize giving - non?@Still, it is the taking-part wheech counts."
/* 56 */ , "You firin' at me?@You firin' at me, huh?@Ain't nobody else, so you must be firin' at me!"
};
#ifdef _NAPI_SOCKET #ifdef _NAPI_SOCKET
extern char command[256]; extern char command[256];
@@ -380,7 +44,7 @@ namespace UI {
14, 11, 11, 11, 11, 11, 11, 13, 8, 11, 12, 11, 13, 13, 12, 11, 12, 12, 11, 12, 13, 13, 13, 12, 12, 11, // A-Z 14, 11, 11, 11, 11, 11, 11, 13, 8, 11, 12, 11, 13, 13, 12, 11, 12, 12, 11, 12, 13, 13, 13, 12, 12, 11, // A-Z
9, 9, 9, 9, 9, 9, 9, 9, 5, 9, 9, 5, 12, 10, 9, 9, 9, 8, 9, 8, 9, 9, 11, 9, 9, 9, // a-z 9, 9, 9, 9, 9, 9, 9, 9, 5, 9, 9, 5, 12, 10, 9, 9, 9, 8, 9, 8, 9, 9, 11, 9, 9, 9, // a-z
12, 8, 10, 10, 10, 10, 10, 9, 10, 10, // 0-9 12, 8, 10, 10, 10, 10, 10, 9, 10, 10, // 0-9
5, 5, 5, 11, 9, 10, 8, 6, 6, 7, 7, 3, 11, 8, 13, 16, 9, 4, 12, 12, 5, 5, 5, 11, 9, 10, 8, 6, 6, 7, 7, 3, 8, 8, 13, 16, 9, 4, 12, 12,
7, 5, 7, 7, 7, 7, 7, 7, 7, 7, 16, 14, 14, 14, 16, 16, 16, 16, 16, 12, 14, 8, 8, 8, 8, 8, 8, 8 }; 7, 5, 7, 7, 7, 7, 7, 7, 7, 7, 16, 14, 14, 14, 16, 16, 16, 16, 16, 12, 14, 8, 8, 8, 8, 8, 8, 8 };
static const uint8 char_map[102] = { static const uint8 char_map[102] = {
@@ -405,12 +69,18 @@ namespace UI {
int x = 0; int x = 0;
while (char c = *text++) { while (char c = *text++) {
if (c == ' ' || c == '_') { //if (c == '<27>') c = '?';
//if (c == '<27>') c = '!';
if (c == '~' || c == '$' || c == ')') { // umlauts
//
} else if (c == ' ' || c == '_') {
x += 6; x += 6;
} else if (c == '@') { } else if (c == '@') {
break; break;
} else } else {
x += char_width[charRemap(c)] + 1; x += char_width[charRemap(c)] + 1;
}
} }
return short2(x, 16); return short2(x, 16);
} }
@@ -419,13 +89,18 @@ namespace UI {
int x = 0, w = 0, h = 16; int x = 0, w = 0, h = 16;
while (char c = *text++) { while (char c = *text++) {
if (c == ' ' || c == '_') { //if (c == '<27>') c = '?';
//if (c == '<27>') c = '!';
if (c == '~' || c == '$' || c == ')') { // umlauts
//
} else if (c == ' ' || c == '_') {
x += 6; x += 6;
} else if (c == '@') { } else if (c == '@') {
w = max(w, x); w = max(w, x);
h += 16; h += 16;
x = 0; x = 0;
} else } else
x += char_width[charRemap(c)] + 1; x += char_width[charRemap(c)] + 1;
} }
w = max(w, x); w = max(w, x);
@@ -455,6 +130,8 @@ namespace UI {
} }
void begin() { void begin() {
ensureLanguage(LangID(Core::settings.audio.language));
Core::setDepthTest(false); Core::setDepthTest(false);
Core::setBlendMode(bmPremult); Core::setBlendMode(bmPremult);
Core::setCullMode(cmNone); Core::setCullMode(cmNone);
@@ -517,6 +194,8 @@ namespace UI {
} }
while (char c = *text++) { while (char c = *text++) {
//if (c == '<27>') c = '?';
//if (c == '<27>') c = '!';
if (c == '@') { if (c == '@') {
x = int(pos.x) + getLeftOffset(text, align, int(width)); x = int(pos.x) + getLeftOffset(text, align, int(width));
@@ -554,7 +233,9 @@ namespace UI {
mesh->addDynSprite(level->spriteSequences[seq].sStart + frame, short3(x, y, 0), tColor, bColor, true); mesh->addDynSprite(level->spriteSequences[seq].sStart + frame, short3(x, y, 0), tColor, bColor, true);
x += char_width[frame] + 1; if (c != '~' && c != '$' && c != ')') { // umlauts
x += char_width[frame] + 1;
}
} }
} }
@@ -577,6 +258,7 @@ namespace UI {
#undef MAX_CHARS #undef MAX_CHARS
void init(IGame *game) { void init(IGame *game) {
ensureLanguage(LangID(Core::settings.audio.language));
UI::game = game; UI::game = game;
showHelp = false; showHelp = false;
helpTipTime = 5.0f; helpTipTime = 5.0f;
@@ -688,7 +370,7 @@ namespace UI {
} }
void showSubs(StringID str) { void showSubs(StringID str) {
if (str == STR_NOT_IMPLEMENTED || !Core::settings.detail.subtitles) if (str == STR_EMPTY || !Core::settings.audio.subtitles)
return; return;
subsStr = str; subsStr = str;
subsTime = strlen(STR[str]) * SUBTITLES_SPEED; subsTime = strlen(STR[str]) * SUBTITLES_SPEED;
@@ -697,7 +379,7 @@ namespace UI {
StringID getSubs(int track) { StringID getSubs(int track) {
if (game && (game->getLevel()->version & TR::VER_TR1) && track >= 26 && track <= 56) if (game && (game->getLevel()->version & TR::VER_TR1) && track >= 26 && track <= 56)
return StringID(STR_TR1_SUB_26 + (track - 26)); return StringID(STR_TR1_SUB_26 + (track - 26));
return STR_NOT_IMPLEMENTED; return STR_EMPTY;
} }
void renderHelp() { void renderHelp() {
@@ -838,4 +520,4 @@ namespace UI {
} }
}; };
#endif #endif