Add translations (#153)

* Add translations from v1

* Add font configuration (to be able to use non-latin languages)

* translations: remove includes that are already in pch.h

* translations: rename enums and avoid macros

* Fix crash when the font file doesn't exist

* translations: avoid u8 to avoid reencoding by MSVC

MSVC will read the file as ASCII and reconvert characters as UTF-8, this will corrupt characters as the file is in fact already in UTF-8.

* translations: remove NUMBER in enums

* translations: handle non existing translations gracefuly (don't crash)

Fallback to english if available, else return empty string

* Testing pull collaboration.

* Rollback: remove NUMBER in enums.

* Get rid of namespace, use header instead.

* Collapsed translated text struct and array.

* Fixed build errors and warnings.

* Simplified language list.

* All new types, locals and globals should use CamelCase.

* Removed unnecessary ImGui patch.

* Rearranged TTextBox immediate mode draw.

* Final touches: removed unused declaration in gdrv.
Removed unused Msg entries and added new check.

* Remove placeholder english texts from missing translations

Co-authored-by: Muzychenko Andrey <33288308+k4zmu2a@users.noreply.github.com>
This commit is contained in:
Alexis Murzeau 2022-08-31 06:58:03 +02:00 committed by GitHub
parent c1c74878df
commit 66a868083a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 7957 additions and 461 deletions

View File

@ -38,6 +38,8 @@ set(SOURCE_FILES
SpaceCadetPinball/control.h
SpaceCadetPinball/EmbeddedData.cpp
SpaceCadetPinball/EmbeddedData.h
SpaceCadetPinball/font_selection.cpp
SpaceCadetPinball/font_selection.h
SpaceCadetPinball/fullscrn.cpp
SpaceCadetPinball/fullscrn.h
SpaceCadetPinball/gdrv.cpp
@ -131,6 +133,8 @@ set(SOURCE_FILES
SpaceCadetPinball/TPopupTarget.h
SpaceCadetPinball/TRamp.cpp
SpaceCadetPinball/TRamp.h
SpaceCadetPinball/translations.cpp
SpaceCadetPinball/translations.h
SpaceCadetPinball/TRollover.cpp
SpaceCadetPinball/TRollover.h
SpaceCadetPinball/TSink.cpp
@ -177,7 +181,7 @@ set(SOURCE_FILES
# On Windows, include resource file with the icon
if(WIN32)
set_source_files_properties(SpaceCadetPinball/SpaceCadetPinball.rc LANGUAGE RC)
list(APPEND SOURCE_FILES SpaceCadetPinball/SpaceCadetPinball.rc)
list(APPEND SOURCE_FILES SpaceCadetPinball/SpaceCadetPinball.rc)
endif(WIN32)
add_executable(SpaceCadetPinball ${SOURCE_FILES})

View File

@ -290,7 +290,7 @@ void TPinballTable::tilt(float time)
{
pinball::InfoTextBox->Clear();
pinball::MissTextBox->Clear();
pinball::InfoTextBox->Display(pinball::get_rc_string(35, 0), -1.0);
pinball::InfoTextBox->Display(pinball::get_rc_string(Msg::STRING136), -1.0);
loader::play_sound(SoundIndex3, nullptr, "TPinballTable1");
TiltTimeoutTimer = timer::set(30.0, this, tilt_timeout);
@ -315,7 +315,7 @@ void TPinballTable::port_draw()
int TPinballTable::Message(int code, float value)
{
LPSTR rc_text;
const char* rc_text;
switch (code)
{
case 1000:
@ -369,9 +369,9 @@ int TPinballTable::Message(int code, float value)
LightGroup->Message(20, 0.0);
Plunger->Message(1016, 0.0);
if (Demo && Demo->ActiveFlag)
rc_text = pinball::get_rc_string(30, 0);
rc_text = pinball::get_rc_string(Msg::STRING131);
else
rc_text = pinball::get_rc_string(26, 0);
rc_text = pinball::get_rc_string(Msg::STRING127);
pinball::InfoTextBox->Display(rc_text, -1.0);
if (Demo)
Demo->Message(1014, 0.0);
@ -466,11 +466,11 @@ int TPinballTable::Message(int code, float value)
{
if (PlayerCount <= 1)
{
char* textboxText;
const char* textboxText;
if (Demo->ActiveFlag)
textboxText = pinball::get_rc_string(30, 0);
textboxText = pinball::get_rc_string(Msg::STRING131);
else
textboxText = pinball::get_rc_string(26, 0);
textboxText = pinball::get_rc_string(Msg::STRING127);
pinball::InfoTextBox->Display(textboxText, -1.0);
break;
}
@ -507,32 +507,32 @@ int TPinballTable::Message(int code, float value)
component->Message(1020, static_cast<float>(nextPlayer));
}
char* textboxText = nullptr;
const char* textboxText = nullptr;
switch (nextPlayer)
{
case 0:
if (Demo->ActiveFlag)
textboxText = pinball::get_rc_string(30, 0);
textboxText = pinball::get_rc_string(Msg::STRING131);
else
textboxText = pinball::get_rc_string(26, 0);
textboxText = pinball::get_rc_string(Msg::STRING127);
break;
case 1:
if (Demo->ActiveFlag)
textboxText = pinball::get_rc_string(31, 0);
textboxText = pinball::get_rc_string(Msg::STRING132);
else
textboxText = pinball::get_rc_string(27, 0);
textboxText = pinball::get_rc_string(Msg::STRING128);
break;
case 2:
if (Demo->ActiveFlag)
textboxText = pinball::get_rc_string(32, 0);
textboxText = pinball::get_rc_string(Msg::STRING133);
else
textboxText = pinball::get_rc_string(28, 0);
textboxText = pinball::get_rc_string(Msg::STRING129);
break;
case 3:
if (Demo->ActiveFlag)
textboxText = pinball::get_rc_string(33, 0);
textboxText = pinball::get_rc_string(Msg::STRING134);
else
textboxText = pinball::get_rc_string(29, 0);
textboxText = pinball::get_rc_string(Msg::STRING130);
break;
default:
break;
@ -549,7 +549,7 @@ int TPinballTable::Message(int code, float value)
case 1022:
loader::play_sound(SoundIndex2, nullptr, "TPinballTable3");
pinball::MissTextBox->Clear();
pinball::InfoTextBox->Display(pinball::get_rc_string(34, 0), -1.0);
pinball::InfoTextBox->Display(pinball::get_rc_string(Msg::STRING135), -1.0);
EndGameTimeoutTimer = timer::set(3.0, this, EndGame_timeout);
break;
case 1024:
@ -661,7 +661,7 @@ void TPinballTable::EndGame_timeout(int timerId, void* caller)
if (table->Demo)
table->Demo->Message(1022, 0.0);
control::handler(67, pinball::MissTextBox);
pinball::InfoTextBox->Display(pinball::get_rc_string(24, 0), -1.0);
pinball::InfoTextBox->Display(pinball::get_rc_string(Msg::STRING125), -1.0);
}
void TPinballTable::LightShow_timeout(int timerId, void* caller)

View File

@ -145,6 +145,43 @@ void TTextBox::Display(const char* text, float time)
}
}
void TTextBox::DrawImGui()
{
// Do nothing when using a font (the text will be rendered to VScreen in TTextBox::Draw)
if (Font || !Message1)
return;
char windowName[64];
SDL_Rect rect;
ImGuiWindowFlags window_flags =
ImGuiWindowFlags_NoBackground |
ImGuiWindowFlags_NoDecoration |
ImGuiWindowFlags_NoSavedSettings |
ImGuiWindowFlags_NoFocusOnAppearing |
ImGuiWindowFlags_NoInputs;
rect.x = OffsetX;
rect.y = OffsetY;
rect.w = Width;
rect.h = Height;
rect = fullscrn::GetScreenRectFromPinballRect(rect);
ImGui::SetNextWindowPos(ImVec2(rect.x, rect.y));
ImGui::SetNextWindowSize(ImVec2(rect.w, rect.h));
// Use the pointer to generate a window unique name per text box
snprintf(windowName, sizeof(windowName), "TTextBox_%p", this);
if (ImGui::Begin(windowName, nullptr, window_flags))
{
ImGui::SetWindowFontScale(fullscrn::GetScreenToPinballRatio());
// ToDo: centered text in FT
ImGui::TextWrapped("%s", Message1->Text);
}
ImGui::End();
}
void TTextBox::Draw()
{
auto bmp = BgBmp;
@ -189,13 +226,7 @@ void TTextBox::Draw()
{
if (!Font)
{
gdrv::grtext_draw_ttext_in_box(
Message1->Text,
render::vscreen->XPosition + OffsetX,
render::vscreen->YPosition + OffsetY,
Width,
Height,
255);
// Immediate mode drawing using system font is handled by TTextBox::DrawImGui
return;
}

View File

@ -22,6 +22,7 @@ public:
int Message(int code, float value) override;
void Clear();
void Display(const char* text, float time);
void DrawImGui();
private:
struct LayoutResult

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,7 @@
#pragma once
#include "translations.h"
class TLight;
class TSound;
class TPinballTable;
@ -66,7 +68,8 @@ public:
static component_tag_base* simple_components[145];
static int waiting_deployment_flag;
static bool table_unlimited_balls;
static int RankRcArray[9], MissionRcArray[17], mission_select_scores[17];
static Msg RankRcArray[9], MissionRcArray[17];
static int mission_select_scores[17];
static component_tag_base *wormhole_tag_array1[3], *wormhole_tag_array2[3], *wormhole_tag_array3[3];
static void make_links(TPinballTable* table);

View File

@ -0,0 +1,50 @@
#include "pch.h"
#include "font_selection.h"
#include "options.h"
#include "pinball.h"
#include "score.h"
#include "winmain.h"
static const char* popupName = "Font Selection";
bool font_selection::ShowDialogFlag = false;
char font_selection::DialogInputBuffer[512];
void font_selection::ShowDialog()
{
ShowDialogFlag = true;
}
void font_selection::RenderDialog()
{
if (ShowDialogFlag == true)
{
strncpy(DialogInputBuffer, options::Options.FontFileName.c_str(), sizeof(DialogInputBuffer));
ShowDialogFlag = false;
if (!ImGui::IsPopupOpen(popupName))
{
ImGui::OpenPopup(popupName);
}
}
bool unused_open = true;
if (ImGui::BeginPopupModal(popupName, &unused_open, ImGuiWindowFlags_AlwaysAutoResize))
{
ImGui::Text("Font file to use: ");
ImGui::SameLine();
ImGui::InputText("", DialogInputBuffer, IM_ARRAYSIZE(DialogInputBuffer));
if (ImGui::Button(pinball::get_rc_string(Msg::HIGHSCORES_Ok)))
{
options::Options.FontFileName = DialogInputBuffer;
ImGui::CloseCurrentPopup();
winmain::Restart();
}
ImGui::SameLine();
if (ImGui::Button(pinball::get_rc_string(Msg::HIGHSCORES_Cancel)))
ImGui::CloseCurrentPopup();
ImGui::EndPopup();
}
}

View File

@ -0,0 +1,11 @@
#pragma once
class font_selection
{
public:
static void ShowDialog();
static void RenderDialog();
private:
static bool ShowDialogFlag;
static char DialogInputBuffer[512];
};

View File

@ -140,3 +140,21 @@ void fullscrn::window_size_changed()
width - offset2X, height - offset2Y
};
}
SDL_Rect fullscrn::GetScreenRectFromPinballRect(SDL_Rect rect)
{
SDL_Rect converted_rect;
converted_rect.x = rect.x * render::DestinationRect.w / render::vscreen->Width + render::DestinationRect.x;
converted_rect.y = rect.y * render::DestinationRect.h / render::vscreen->Height + render::DestinationRect.y;
converted_rect.w = rect.w * render::DestinationRect.w / render::vscreen->Width;
converted_rect.h = rect.h * render::DestinationRect.h / render::vscreen->Height;
return converted_rect;
}
float fullscrn::GetScreenToPinballRatio()
{
return (float) render::DestinationRect.w / render::vscreen->Width;
}

View File

@ -28,6 +28,8 @@ public:
static void SetResolution(int value);
static int GetMaxResolution();
static void window_size_changed();
static SDL_Rect GetScreenRectFromPinballRect(SDL_Rect rect);
static float GetScreenToPinballRatio();
private :
static int resolution;

View File

@ -6,6 +6,9 @@
#include "pb.h"
#include "score.h"
#include "winmain.h"
#include "TTextBox.h"
#include "fullscrn.h"
#include "pinball.h"
ColorRgba gdrv::current_palette[256]{};
@ -269,8 +272,15 @@ void gdrv::ScrollBitmapHorizontal(gdrv_bitmap8* bmp, int xStart)
}
void gdrv::grtext_draw_ttext_in_box(LPCSTR text, int xOff, int yOff, int width, int height, int a6)
void gdrv::grtext_draw_ttext_in_box()
{
for (const auto textBox : { pinball::InfoTextBox, pinball::MissTextBox })
{
if (textBox)
{
textBox->DrawImGui();
}
}
}
void gdrv::ApplyPalette(gdrv_bitmap8& bmp)

View File

@ -80,7 +80,7 @@ public:
static void copy_bitmap_w_transparency(gdrv_bitmap8* dstBmp, int width, int height, int xOff, int yOff,
gdrv_bitmap8* srcBmp, int srcXOff, int srcYOff);
static void ScrollBitmapHorizontal(gdrv_bitmap8* bmp, int xStart);
static void grtext_draw_ttext_in_box(LPCSTR text, int xOff, int yOff, int width, int height, int a6);
static void grtext_draw_ttext_in_box();
static void ApplyPalette(gdrv_bitmap8& bmp);
static void CreatePreview(gdrv_bitmap8& bmp);
private:

View File

@ -121,7 +121,7 @@ void high_score::RenderHighScoreDialog()
if (ShowDialog == true)
{
ShowDialog = false;
if (!ImGui::IsPopupOpen("High Scores"))
if (!ImGui::IsPopupOpen(pinball::get_rc_string(Msg::HIGHSCORES_Caption)))
{
dlg_enter_name = false;
while (!ScoreQueue.empty())
@ -140,19 +140,19 @@ void high_score::RenderHighScoreDialog()
}
}
ImGui::OpenPopup("High Scores");
ImGui::OpenPopup(pinball::get_rc_string(Msg::HIGHSCORES_Caption));
}
}
bool unused_open = true;
if (ImGui::BeginPopupModal("High Scores", &unused_open, ImGuiWindowFlags_AlwaysAutoResize))
if (ImGui::BeginPopupModal(pinball::get_rc_string(Msg::HIGHSCORES_Caption), &unused_open, ImGuiWindowFlags_AlwaysAutoResize))
{
if (ImGui::BeginTable("table1", 3, ImGuiTableFlags_Borders))
{
char buf[36];
ImGui::TableSetupColumn("Rank");
ImGui::TableSetupColumn("Name");
ImGui::TableSetupColumn("Score");
ImGui::TableSetupColumn(pinball::get_rc_string(Msg::HIGHSCORES_Rank));
ImGui::TableSetupColumn(pinball::get_rc_string(Msg::HIGHSCORES_Name));
ImGui::TableSetupColumn(pinball::get_rc_string(Msg::HIGHSCORES_Score));
ImGui::TableHeadersRow();
for (int offset = 0, row = 0; row < 5; row++)
@ -184,7 +184,7 @@ void high_score::RenderHighScoreDialog()
ImGui::EndTable();
}
if (ImGui::Button("Ok"))
if (ImGui::Button(pinball::get_rc_string(Msg::HIGHSCORES_Ok)))
{
if (dlg_enter_name)
{
@ -194,23 +194,23 @@ void high_score::RenderHighScoreDialog()
}
ImGui::SameLine();
if (ImGui::Button("Cancel"))
if (ImGui::Button(pinball::get_rc_string(Msg::HIGHSCORES_Cancel)))
ImGui::CloseCurrentPopup();
ImGui::SameLine();
if (ImGui::Button("Clear"))
if (ImGui::Button(pinball::get_rc_string(Msg::HIGHSCORES_Clear)))
ImGui::OpenPopup("Confirm");
if (ImGui::BeginPopupModal("Confirm", nullptr, ImGuiWindowFlags_MenuBar))
{
ImGui::TextUnformatted(pinball::get_rc_string(40, 0));
if (ImGui::Button("OK", ImVec2(120, 0)))
ImGui::TextUnformatted(pinball::get_rc_string(Msg::STRING141));
if (ImGui::Button(pinball::get_rc_string(Msg::HIGHSCORES_Ok), ImVec2(120, 0)))
{
clear_table();
ImGui::CloseCurrentPopup();
}
ImGui::SetItemDefaultFocus();
ImGui::SameLine();
if (ImGui::Button("Cancel", ImVec2(120, 0)))
if (ImGui::Button(pinball::get_rc_string(Msg::HIGHSCORES_Cancel), ImVec2(120, 0)))
{
ImGui::CloseCurrentPopup();
}
@ -220,7 +220,7 @@ void high_score::RenderHighScoreDialog()
ImGui::EndPopup();
// Reenter dialog for the next score in the queue
if (!ImGui::IsPopupOpen("High Scores") && !ScoreQueue.empty())
if (!ImGui::IsPopupOpen(pinball::get_rc_string(Msg::HIGHSCORES_Caption)) && !ScoreQueue.empty())
{
ShowDialog = true;
}

View File

@ -3,6 +3,7 @@
#include "fullscrn.h"
#include "midi.h"
#include "pinball.h"
#include "render.h"
#include "Sound.h"
#include "winmain.h"
@ -18,12 +19,12 @@ bool options::ShowDialog = false;
GameInput* options::ControlWaitingForInput = nullptr;
const ControlRef options::Controls[6]
{
{"Left Flipper", RebindControls.LeftFlipper},
{"Right Flipper", RebindControls.RightFlipper},
{"Left Table Bump", RebindControls.LeftTableBump},
{"Right Table Bump", RebindControls.RightTableBump},
{"Bottom Table Bump", RebindControls.BottomTableBump},
{"Plunger", RebindControls.Plunger},
{Msg::KEYMAPPER_FlipperL, RebindControls.LeftFlipper},
{Msg::KEYMAPPER_FlipperR, RebindControls.RightFlipper},
{Msg::KEYMAPPER_BumpLeft, RebindControls.LeftTableBump},
{Msg::KEYMAPPER_BumpRight, RebindControls.RightTableBump},
{Msg::KEYMAPPER_BumpBottom, RebindControls.BottomTableBump},
{Msg::KEYMAPPER_Plunger, RebindControls.Plunger},
};
@ -113,6 +114,8 @@ void options::InitPrimary()
Options.DebugOverlayCollisionMask = get_int("Debug Overlay Collision Mask", true);
Options.DebugOverlaySprites = get_int("Debug Overlay Sprites", true);
Options.DebugOverlaySounds = get_int("Debug Overlay Sounds", true);
translations::SetCurrentLanguage(get_string("Language", translations::GetCurrentLanguage()->ShortName).c_str());
Options.FontFileName = get_string("FontFileName", "");
}
void options::InitSecondary()
@ -160,7 +163,9 @@ void options::uninit()
set_int("Debug Overlay Ball Edges", Options.DebugOverlayBallEdges);
set_int("Debug Overlay Collision Mask", Options.DebugOverlayCollisionMask);
set_int("Debug Overlay Sprites", Options.DebugOverlaySprites);
get_int("Debug Overlay Sounds", Options.DebugOverlaySounds);
set_int("Debug Overlay Sounds", Options.DebugOverlaySounds);
set_string("Language", translations::GetCurrentLanguage()->ShortName);
set_string("FontFileName", Options.FontFileName.c_str());
}
@ -339,18 +344,16 @@ void options::RenderControlDialog()
return;
ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2{550, 450});
if (ImGui::Begin("3D Pinball: Player Controls", &ShowDialog))
if (ImGui::Begin(pinball::get_rc_string(Msg::KEYMAPPER_Caption), &ShowDialog))
{
ImGui::TextUnformatted("Instructions");
ImGui::TextUnformatted(pinball::get_rc_string(Msg::KEYMAPPER_Groupbox2));
ImGui::Separator();
ImGui::TextWrapped(
"To change game controls, click the control button, press the new key, and then choose OK.");
ImGui::TextWrapped(
"To restore 3D Pinball to its original settings, choose Default, and then choose OK.");
ImGui::TextWrapped("%s", pinball::get_rc_string(Msg::KEYMAPPER_Help1));
ImGui::TextWrapped("%s", pinball::get_rc_string(Msg::KEYMAPPER_Help2));
ImGui::Spacing();
ImGui::TextUnformatted("Control Options");
ImGui::TextUnformatted(pinball::get_rc_string(Msg::KEYMAPPER_Groupbox1));
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{5, 10});
if (ImGui::BeginTable("Controls", 4, ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders))
@ -366,7 +369,7 @@ void options::RenderControlDialog()
{
ImGui::TableNextColumn();
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{0.5, 0, 0, 1});
if (ImGui::Button(row.Name))
if (ImGui::Button(pinball::get_rc_string(row.NameStringId)))
{
for (auto i = 0u; i <= 2; i++)
row.Option[i] = {};
@ -419,20 +422,20 @@ void options::RenderControlDialog()
ImGui::PopStyleVar();
ImGui::Spacing();
if (ImGui::Button("OK"))
if (ImGui::Button(pinball::get_rc_string(Msg::KEYMAPPER_Ok)))
{
Options.Key = RebindControls;
ShowDialog = false;
}
ImGui::SameLine();
if (ImGui::Button("Cancel"))
if (ImGui::Button(pinball::get_rc_string(Msg::KEYMAPPER_Cancel)))
{
ShowDialog = false;
}
ImGui::SameLine();
if (ImGui::Button("Default"))
if (ImGui::Button(pinball::get_rc_string(Msg::KEYMAPPER_Default)))
{
RebindControls = Options.KeyDft;
ControlWaitingForInput = nullptr;

View File

@ -1,5 +1,7 @@
#pragma once
#include "translations.h"
enum class Menu1:int
{
New_Game = 101,
@ -90,11 +92,12 @@ struct optionsStruct
bool DebugOverlayCollisionMask;
bool DebugOverlaySprites;
bool DebugOverlaySounds;
std::string FontFileName;
};
struct ControlRef
{
const char* Name;
Msg NameStringId;
GameInput (&Option)[3];
};

View File

@ -47,7 +47,7 @@ int pb::init()
record_table = partman::load_records(dataFilePath.c_str(), FullTiltMode);
auto useBmpFont = 0;
pinball::get_rc_int(158, &useBmpFont);
pinball::get_rc_int(Msg::STRING258, &useBmpFont);
if (useBmpFont)
score::load_msg_font("pbmsg_ft");
@ -124,7 +124,7 @@ void pb::SelectDatFile(const std::vector<const char*>& dataSearchPaths)
std::string datFileNames[3]
{
"CADET.DAT",
options::get_string("Pinball Data", pinball::get_rc_string(168, 0)),
options::get_string("Pinball Data", pinball::get_rc_string(Msg::STRING268)),
"DEMO.DAT",
};
@ -219,7 +219,7 @@ void pb::toggle_demo()
MainTable->Message(1024, 0.0);
mode_change(GameModes::GameOver);
pinball::MissTextBox->Clear();
auto text = pinball::get_rc_string(24, 0);
auto text = pinball::get_rc_string(Msg::STRING125);
pinball::InfoTextBox->Display(text, -1.0);
}
else
@ -288,7 +288,7 @@ void pb::frame(float dtMilliSec)
{
if (nudge::nudge_count > 0.5f)
{
pinball::InfoTextBox->Display(pinball::get_rc_string(25, 0), 2.0);
pinball::InfoTextBox->Display(pinball::get_rc_string(Msg::STRING126), 2.0);
}
if (nudge::nudge_count > 1.0f)
MainTable->tilt(time_now);
@ -366,7 +366,7 @@ void pb::pause_continue()
{
if (MainTable)
MainTable->Message(1008, time_now);
pinball::InfoTextBox->Display(pinball::get_rc_string(22, 0), -1.0);
pinball::InfoTextBox->Display(pinball::get_rc_string(Msg::STRING123), -1.0);
midi::music_stop();
Sound::Deactivate();
}
@ -376,17 +376,17 @@ void pb::pause_continue()
MainTable->Message(1009, 0.0);
if (!demo_mode)
{
char* text;
const char* text;
float textTime;
if (game_mode == GameModes::GameOver)
{
textTime = -1.0;
text = pinball::get_rc_string(24, 0);
text = pinball::get_rc_string(Msg::STRING125);
}
else
{
textTime = 5.0;
text = pinball::get_rc_string(23, 0);
text = pinball::get_rc_string(Msg::STRING124);
}
pinball::InfoTextBox->Display(text, textTime);
}
@ -481,7 +481,7 @@ void pb::InputDown(GameInput input)
case 'h':
{
high_score_struct entry{ {0}, 1000000000 };
strncpy(entry.Name, pinball::get_rc_string(26, 0), sizeof entry.Name - 1);
strncpy(entry.Name, pinball::get_rc_string(Msg::STRING127), sizeof entry.Name - 1);
high_score::show_and_set_high_score_dialog({ entry, 1 });
break;
}
@ -550,7 +550,16 @@ void pb::end_game()
if (position >= 0)
{
high_score_struct entry{ {0}, scores[i] };
strncpy(entry.Name, pinball::get_rc_string(scoreIndex[i] + 26, 0), sizeof entry.Name - 1);
const char* playerName = "Player";
switch(scoreIndex[i]) {
case 0: playerName = pinball::get_rc_string(Msg::STRING127); break;
case 1: playerName = pinball::get_rc_string(Msg::STRING128); break;
case 2: playerName = pinball::get_rc_string(Msg::STRING129); break;
case 3: playerName = pinball::get_rc_string(Msg::STRING130); break;
}
strncpy(entry.Name, playerName, sizeof entry.Name - 1);
high_score::show_and_set_high_score_dialog({ entry, -1 });
}
}

View File

@ -29,6 +29,7 @@
#include <string>
#include <thread>
#include <map>
#include <initializer_list>
//#include <array>
#define SDL_MAIN_HANDLED

View File

@ -1,219 +1,13 @@
#include "pch.h"
#include "pinball.h"
#include "translations.h"
#include "winmain.h"
// Todo: load translations from file
std::map<uint32_t, LPCSTR> rc_strings
int LoadStringAlt(Msg uID, LPSTR lpBuffer, int cchBufferMax)
{
{0, "Replay Awarded"},
{1, "Ball Locked"},
{2, "Center Post\n%ld"},
{3, "Bonus Awarded\n%ld"},
{4, "Bonus Activated"},
{5, "Weapons Upgraded"},
{6, "Engine Upgraded"},
{7, "Bonus up 1 Million"},
{8, "Extra Ball Available\n%ld"},
{9, "Extra Ball"},
{10, "Reflex Shot Award\n%ld"},
{11, "Final Battle Won"},
{12, "Hyperspace Bonus\n%ld"},
{13, "Hyperspace Bonus Available"},
{14, "Jackpot Awarded\n%ld"},
{15, "Jackpot Activated"},
{16, "Multiball"},
{17, "Ramp Bonus Awarded"},
{18, "Light Added"},
{19, "Ramp Bonus On"},
{20, "Light Reset Off"},
{21, "Skill Shot\n%ld"},
{22, "Game Paused\nF3 to Resume"},
{23, "Continue Play"},
{24, "F2 Starts New Game"},
{25, "Careful..."},
{26, "Player 1"},
{27, "Player 2"},
{28, "Player 3"},
{29, "Player 4"},
{30, "Demo\nPlayer 1"},
{31, "Demo\nPlayer 2"},
{32, "Demo\nPlayer 3"},
{33, "Demo\nPlayer 4"},
{34, "Game Over"},
{35, "TILT!"},
{36, "This program requires an 80386 or later CPU."},
{37, "80386 Required"},
{38, "3D Pinball for Windows - Space Cadet"},
{
39,
"One or more of the player controls is set to the same key,\nfor best performance use unique keys for each control."
},
{40, "Clear High Scores?"},
{41, "Confirm"},
{42, "WAVEMIX.INF is missing - it must be in the pinball directory!"},
{43, "Warning:"},
{44, "Ship Re-Fueled"},
{45, "Gravity Well"},
{46, "Time Warp Forward"},
{47, "Time Warp Backward"},
{48, "Maelstrom!"},
{49, "Wormhole"},
{50, "Awaiting Deployment"},
{51, "Flags Upgraded"},
{52, "Bonus Hold"},
{53, "Level One Commendation"},
{54, "Level Two Commendation"},
{55, "Level Three Commendation"},
{56, "Field Multiplier 2x"},
{57, "Field Multiplier 3x"},
{58, "Field Multiplier 5x"},
{59, "Field Multiplier 10x"},
{60, "Target Practice"},
{61, "Launch Training"},
{62, "Re-Entry Training"},
{63, "Science"},
{64, "Stray Comet"},
{65, "Black Hole"},
{66, "Space Radiation"},
{67, "Bug Hunt"},
{68, "Alien Menace"},
{69, "Rescue"},
{70, "Satellite Retrieval"},
{71, "Recon"},
{72, "Doomsday Machine"},
{73, "Cosmic Plague"},
{74, "Secret"},
{75, "Time Warp"},
{76, "Maelstrom"},
{77, "Mission Accepted\n%ld"},
{78, "Mission Completed\n%ld"},
{79, "%s Mission Selected"},
{80, "Black Hole\n%ld"},
{81, "Gravity Normalized\n%ld"},
{82, "Gravity Well\n%ld"},
{83, "Promotion to %s"},
{84, "Cadet"},
{85, "Ensign"},
{86, "Lieutenant"},
{87, "Captain"},
{88, "Lt Commander"},
{89, "Commander"},
{90, "Commodore"},
{91, "Admiral"},
{92, "Fleet Admiral"},
{93, "Wormhole Opened"},
{94, "Crash Bonus\n%ld"},
{95, "Replay Ball"},
{96, "Re-Deploy"},
{97, "Player 1 Shoot Again"},
{98, "Player 2 Shoot Again"},
{99, "Player 3 Shoot Again"},
{100, "Player 4 Shoot Again"},
{
101,
"This 3D Pinball Table was created for Microsoft by Maxis.\nFor more information call (800)-336-2947\n(US and Canadian customers only).\nCopyright (c) 1995 Maxis."
},
{102, "3D Pinball Table created for Microsoft by Maxis. Copyright (c) 1995 Maxis."},
{103, "About 3D Pinball"},
{104, "Hit Mission Targets To Select Mission"},
{105, "Re-Fuel Ship"},
{106, "Launch Ramp To Accept %s Mission"},
{107, "Attack Bumpers Hits\nLeft: %d"},
{108, "Target Training Passed"},
{109, "Mission Aborted"},
{110, "Launches Left: %d"},
{111, "Launch Training Passed"},
{112, "Re-Entries Left: %d"},
{113, "Re-Entry Training Passed"},
{114, "Drop Targets\nLeft: %d"},
{115, "Science Mission Completed"},
{116, "Warning -- Low Fuel"},
{117, "Fill Right Hazard Banks"},
{118, "Hyperspace Launch"},
{119, "Comet Destroyed"},
{120, "Enter Wormhole"},
{121, "Radiation Eliminated"},
{122, "Upgrade Launch Bumpers"},
{123, "Enter Black Hole"},
{124, "Black Hole Eliminated"},
{125, "Targets\nLeft: %d"},
{126, "Xenomorphs Destroyed"},
{127, "Upgrade Flags"},
{128, "Hyperspace Launch"},
{129, "Survivors Rescued"},
{130, "Aliens Repelled"},
{131, "Hit Fuel Targets"},
{132, "Remote Attack Bumper Hits\nLeft: %d"},
{133, "Satellite Repaired"},
{134, "Lane Passes\nLeft: %d"},
{135, "Shoot Ball Up Fuel Chute"},
{136, "Survey Complete"},
{137, "Out Lane Passes\nLeft: %d"},
{138, "Doomsday Machine Destroyed"},
{139, "Roll Flags: %d"},
{140, "Hit Space Warp Rollover"},
{141, "Plague Eliminated"},
{142, "Hit Yellow Wormhole"},
{143, "Hit Red Wormhole"},
{144, "Hit Green Wormhole"},
{145, "Plans Recovered"},
{146, "Rebound Hits\nLeft: %d"},
{147, "Hit Hyperspace Chute or Launch Ramp"},
{148, "Drop Target Hits\nLeft: %d"},
{149, "Spot Target Hits\nLeft: %d"},
{150, "Lanes Passes\nLeft: %d"},
{151, "Shoot Ball Up Fuel Chute"},
{152, "Hit Launch Ramp"},
{153, "Hit Flags"},
{154, "Hit Worm Hole"},
{155, "Hyperspace Chute to Maelstrom"},
{156, "pinball.mid"},
{158, "1 UseBitmapFont"},
{159, "90 Left Flipper Key"},
{160, "191 Right Flipper Key"},
{161, "32 Plunger Key"},
{162, "88 Bump Left Key"},
{163, "190 Bump Right Key"},
{164, "38 Bump Bottom Key"},
{165, "Software\\Microsoft\\Plus!\\Pinball"},
{166, "SpaceCadet"},
{167, "1c7c22a0-9576-11ce-bf80-444553540000"},
{168, "PINBALL.DAT"},
{169, "Space Cadet"},
{170, "Error:"},
{171, "Unable to find other tables."},
{172, "3D Pinball\nSpace Cadet"},
{173, "Promotion to %s"},
{174, "Demotion to %s"},
{175, "Upgrade Attack Bumpers"},
{176, "Fill Left Hazard Banks"},
{177, "HIGH SCORE"},
{178, "pinball.chm"},
{179, "Not enough memory to run 3D Pinball."},
{180, "Player 1's Score\n%ld"},
{181, "Player 2's Score\n%ld"},
{182, "Player 3's Score\n%ld"},
{183, "Player 4's Score\n%ld"},
{184, "High Score 1\n%ld"},
{185, "High Score 2\n%ld"},
{186, "High Score 3\n%ld"},
{187, "High Score 4\n%ld"},
{188, "High Score 5\n%ld"},
{189, "255 255 255 (R G B default font color)"},
{2030, "Use Maximum Resolution (640 x 480)"},
{2031, "Use Maximum Resolution (800 x 600)"},
{2032, "Use Maximum Resolution (1024 x 768)"}
};
const char* text = translations::GetTranslation(uID);
int LoadStringAlt(uint32_t uID, LPSTR lpBuffer, int cchBufferMax)
{
auto str = rc_strings.find(uID);
if (str == rc_strings.end())
{
return 0;
}
strncpy(lpBuffer, str->second, cchBufferMax);
strncpy(lpBuffer, text, cchBufferMax);
return 1;
}
@ -226,17 +20,18 @@ int pinball::LeftShift = -1;
int pinball::RightShift = -1;
std::string pinball::BasePath;
char* pinball::get_rc_string(int uID, int a2)
char* pinball::get_rc_string(Msg uID)
{
char* result = &getRcBuffer[256 * rc_string_slot];
if (!LoadStringAlt(uID, &getRcBuffer[256 * rc_string_slot], 255))
*result = 0;
if (++rc_string_slot >= 6)
rc_string_slot = 0;
return result;
}
int pinball::get_rc_int(int uID, int* dst)
int pinball::get_rc_int(Msg uID, int* dst)
{
char buffer[255];
int result = LoadStringAlt(uID, buffer, 255);

View File

@ -1,5 +1,7 @@
#pragma once
#include "translations.h"
class TTextBox;
class pinball
@ -12,8 +14,8 @@ public:
static int LeftShift;
static std::string BasePath;
static char* get_rc_string(int uID, int a2);
static int get_rc_int(int uID, int* dst);
static char* get_rc_string(Msg uID);
static int get_rc_int(Msg uID, int* dst);
static std::string make_path_name(const std::string& fileName);
private:
static char getRcBuffer[256 * 6];

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,361 @@
#pragma once
enum class Msg : int
{
Min = 0,
STRING101 = 0,
STRING102,
STRING103,
STRING104,
STRING105,
STRING106,
STRING107,
STRING108,
STRING109,
STRING110,
STRING111,
STRING112,
STRING113,
STRING114,
STRING115,
STRING116,
STRING117,
STRING118,
STRING119,
STRING120,
STRING121,
STRING122,
STRING123,
STRING124,
STRING125,
STRING126,
STRING127,
STRING128,
STRING129,
STRING130,
STRING131,
STRING132,
STRING133,
STRING134,
STRING135,
STRING136,
STRING137,
STRING138,
STRING139,
STRING140,
STRING141,
STRING142,
STRING143,
STRING144,
STRING145,
STRING146,
STRING147,
STRING148,
STRING149,
STRING150,
STRING151,
STRING152,
STRING153,
STRING154,
STRING155,
STRING156,
STRING157,
STRING158,
STRING159,
STRING160,
STRING161,
STRING162,
STRING163,
STRING164,
STRING165,
STRING166,
STRING167,
STRING168,
STRING169,
STRING170,
STRING171,
STRING172,
STRING173,
STRING174,
STRING175,
STRING176,
STRING177,
STRING178,
STRING179,
STRING180,
STRING181,
STRING182,
STRING183,
STRING184,
STRING185,
STRING186,
STRING187,
STRING188,
STRING189,
STRING190,
STRING191,
STRING192,
STRING193,
STRING194,
STRING195,
STRING196,
STRING197,
STRING198,
STRING199,
STRING200,
STRING201,
STRING202,
STRING203,
STRING204,
STRING205,
STRING206,
STRING207,
STRING208,
STRING209,
STRING210,
STRING211,
STRING212,
STRING213,
STRING214,
STRING215,
STRING216,
STRING217,
STRING218,
STRING219,
STRING220,
STRING221,
STRING222,
STRING223,
STRING224,
STRING225,
STRING226,
STRING227,
STRING228,
STRING229,
STRING230,
STRING231,
STRING232,
STRING233,
STRING234,
STRING235,
STRING236,
STRING237,
STRING238,
STRING239,
STRING240,
STRING241,
STRING242,
STRING243,
STRING244,
STRING245,
STRING246,
STRING247,
STRING248,
STRING249,
STRING250,
STRING251,
STRING252,
STRING253,
STRING254,
STRING255,
STRING256,
STRING257,
STRING258,
STRING259,
STRING260,
STRING261,
STRING262,
STRING263,
STRING264,
STRING265,
STRING266,
STRING267,
STRING268,
STRING269,
STRING270,
STRING271,
STRING272,
STRING273,
STRING274,
STRING275,
STRING276,
STRING277,
STRING278,
STRING279,
STRING280,
STRING281,
STRING282,
STRING283,
STRING284,
STRING285,
STRING286,
STRING287,
STRING288,
STRING289,
HIGHSCORES_Caption,
HIGHSCORES_Ok,
HIGHSCORES_Cancel,
HIGHSCORES_Clear,
HIGHSCORES_Name,
HIGHSCORES_Score,
HIGHSCORES_Rank,
HIGHSCORES_Rank1,
HIGHSCORES_Rank2,
HIGHSCORES_Rank3,
HIGHSCORES_Rank4,
HIGHSCORES_Rank5,
KEYMAPPER_Caption,
KEYMAPPER_Ok,
KEYMAPPER_Cancel,
KEYMAPPER_FlipperL,
KEYMAPPER_FlipperR,
KEYMAPPER_Plunger,
KEYMAPPER_BumpLeft,
KEYMAPPER_BumpRight,
KEYMAPPER_BumpBottom,
KEYMAPPER_Default,
KEYMAPPER_Help1,
KEYMAPPER_Help2,
KEYMAPPER_Groupbox1,
KEYMAPPER_Groupbox2,
Menu1_New_Game,
Menu1_About_Pinball,
Menu1_High_Scores,
Menu1_Exit,
Menu1_Sounds,
Menu1_Music,
Menu1_Help_Topics,
Menu1_Launch_Ball,
Menu1_Pause_Resume_Game,
Menu1_Full_Screen,
Menu1_Demo,
Menu1_Select_Table,
Menu1_Player_Controls,
Menu1_1Player,
Menu1_2Players,
Menu1_3Players,
Menu1_4Players,
Menu1_MaximumResolution,
Menu1_640x480,
Menu1_800x600,
Menu1_1024x768,
Menu1_WindowUniformScale,
Menu1_AlternativeRender,
Menu1_Game,
Menu1_Options,
Menu1_Select_Players,
Menu1_Table_Resolution,
Menu1_Window,
Menu1_Help,
Menu1_UseMaxResolution_640x480,
Menu1_UseMaxResolution_800x600,
Menu1_UseMaxResolution_1024x768,
Max,
};
enum class Lang : int
{
Min = 0,
Arabic = 0,
Czech,
Danish,
German,
Greek,
English,
Spanish,
Finnish,
French,
Hebrew,
Hungarian,
Italian,
Japanese,
Korean,
Norwegian,
Dutch,
Polish,
BrazilianPortuguese,
Portuguese,
Russian,
Swedish,
Turkish,
SimplifiedChinese,
TraditionalChinese,
Max
};
struct TextArray
{
TextArray(const std::initializer_list<std::pair<Msg, std::initializer_list<std::pair<Lang, LPCSTR>>>>& iList)
{
for (const auto& msgPair : iList)
{
for (const auto& languagePair : msgPair.second)
{
assertm(!contains(msgPair.first, languagePair.first), "Key redefinition");
Set(msgPair.first, languagePair.first, languagePair.second);
}
}
for (auto i = Msg::Min; i < Msg::Max; i = static_cast<Msg>(static_cast<int>(i) + 1))
{
assertm(contains(i, Lang::English), "English text is mandatory for all keys");
}
}
LPCSTR Get(Msg msgId, Lang langId) const
{
assertm(TextArray::contains(msgId), "Message Id out of bounds");
assertm(TextArray::contains(langId), "Language Id out of bounds");
return Store[static_cast<int>(msgId)][static_cast<int>(langId)];
}
bool contains(Msg msgId, Lang langId) const
{
return contains(msgId) && Get(msgId, langId) != nullptr;
}
static bool contains(Msg msgId)
{
return msgId >= Msg::Min && msgId < Msg::Max;
}
static bool contains(Lang langId)
{
return langId >= Lang::Min && langId < Lang::Max;
}
private:
LPCSTR Store[static_cast<int>(Msg::Max )][static_cast<int>(Lang::Max)]{ nullptr };
void Set(Msg msgId, Lang langId, LPCSTR value)
{
assertm(TextArray::contains(msgId), "Message Id out of bounds");
assertm(TextArray::contains(langId), "Language Id out of bounds");
Store[static_cast<int>(msgId)][static_cast<int>(langId)] = value;
}
};
struct LanguageInfo
{
const Lang Language;
const char* ShortName;
const char* DisplayName;
};
class translations
{
public:
static const LanguageInfo Languages[static_cast<int>(Lang::Max)];
static const char* GetTranslation(Msg id);
static void SetCurrentLanguage(const char* short_name);
static const LanguageInfo* GetCurrentLanguage();
static void GetGlyphRange(ImVector<ImWchar>* ranges);
private:
static const TextArray Translations;
static Lang CurrentLanguage;
};

View File

@ -9,6 +9,8 @@
#include "pb.h"
#include "render.h"
#include "Sound.h"
#include "translations.h"
#include "font_selection.h"
SDL_Window* winmain::MainWindow = nullptr;
SDL_Renderer* winmain::Renderer = nullptr;
@ -64,7 +66,7 @@ int winmain::WinMain(LPCSTR lpCmdLine)
// SDL window
SDL_Window* window = SDL_CreateWindow
(
pinball::get_rc_string(38, 0),
pinball::get_rc_string(Msg::STRING139),
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
800, 556,
SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE
@ -106,9 +108,6 @@ int winmain::WinMain(LPCSTR lpCmdLine)
ImGui::StyleColorsDark();
ImGuiIO& io = ImGui::GetIO();
ImIO = &io;
// ImGui_ImplSDL2_Init is private, we are not actually using ImGui OpenGl backend
ImGui_ImplSDL2_InitForOpenGL(window, nullptr);
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard | ImGuiConfigFlags_NavEnableGamepad;
auto prefPath = SDL_GetPrefPath(nullptr, "SpaceCadetPinball");
auto iniPath = std::string(prefPath) + "imgui_pb.ini";
@ -117,6 +116,40 @@ int winmain::WinMain(LPCSTR lpCmdLine)
// First step: just load the options
options::InitPrimary();
if(!Options.FontFileName.empty())
{
ImGuiSDL::Deinitialize();
io.Fonts->Clear();
ImVector<ImWchar> ranges;
translations::GetGlyphRange(&ranges);
ImFontConfig fontConfig{};
// ToDo: further tweak font options, maybe try imgui_freetype
fontConfig.OversampleV = 2;
fontConfig.OversampleH = 4;
// ToDo: improve font file test, checking if file exists is not enough
auto fileName = Options.FontFileName.c_str();
auto fileHandle = fopenu(fileName, "rb");
if (fileHandle)
{
fclose(fileHandle);
// ToDo: Bind font size to UI scale
if (!io.Fonts->AddFontFromFileTTF(fileName, 13.f, &fontConfig, ranges.Data))
io.Fonts->AddFontDefault();
}
else
io.Fonts->AddFontDefault();
io.Fonts->Build();
ImGuiSDL::Initialize(renderer, 0, 0);
}
// ImGui_ImplSDL2_Init is private, we are not actually using ImGui OpenGl backend
ImGui_ImplSDL2_InitForOpenGL(window, nullptr);
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard | ImGuiConfigFlags_NavEnableGamepad;
// Data search order: WD, executable path, user pref path, platform specific paths.
auto basePath = SDL_GetBasePath();
std::vector<const char*> searchPaths
@ -372,34 +405,34 @@ void winmain::RenderUi()
fullscrn::window_size_changed();
}
if (ImGui::BeginMenu("Game"))
if (ImGui::BeginMenu(pinball::get_rc_string(Msg::Menu1_Game)))
{
if (ImGui::MenuItem("New Game", "F2"))
if (ImGui::MenuItem(pinball::get_rc_string(Msg::Menu1_New_Game), "F2"))
{
new_game();
}
if (ImGui::MenuItem("Launch Ball", nullptr, false, LaunchBallEnabled))
if (ImGui::MenuItem(pinball::get_rc_string(Msg::Menu1_Launch_Ball), nullptr, false, LaunchBallEnabled))
{
end_pause();
pb::launch_ball();
}
if (ImGui::MenuItem("Pause/Resume Game", "F3"))
if (ImGui::MenuItem(pinball::get_rc_string(Msg::Menu1_Pause_Resume_Game), "F3"))
{
pause();
}
ImGui::Separator();
if (ImGui::MenuItem("High Scores...", nullptr, false, HighScoresEnabled))
if (ImGui::MenuItem(pinball::get_rc_string(Msg::Menu1_High_Scores), nullptr, false, HighScoresEnabled))
{
pause(false);
pb::high_scores();
}
if (ImGui::MenuItem("Demo", nullptr, DemoActive))
if (ImGui::MenuItem(pinball::get_rc_string(Msg::Menu1_Demo), nullptr, DemoActive))
{
end_pause();
pb::toggle_demo();
}
if (ImGui::MenuItem("Exit"))
if (ImGui::MenuItem(pinball::get_rc_string(Msg::Menu1_Exit)))
{
SDL_Event event{SDL_QUIT};
SDL_PushEvent(&event);
@ -407,45 +440,58 @@ void winmain::RenderUi()
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Options"))
if (ImGui::BeginMenu(pinball::get_rc_string(Msg::Menu1_Options)))
{
if (ImGui::MenuItem("Show Menu", "F9", Options.ShowMenu))
{
options::toggle(Menu1::Show_Menu);
}
if (ImGui::MenuItem("Full Screen", "F4", Options.FullScreen))
if (ImGui::MenuItem(pinball::get_rc_string(Msg::Menu1_Full_Screen), "F4", Options.FullScreen))
{
options::toggle(Menu1::Full_Screen);
}
if (ImGui::BeginMenu("Select Players"))
if (ImGui::BeginMenu(pinball::get_rc_string(Msg::Menu1_Select_Players)))
{
if (ImGui::MenuItem("1 Player", nullptr, Options.Players == 1))
if (ImGui::MenuItem(pinball::get_rc_string(Msg::Menu1_1Player), nullptr, Options.Players == 1))
{
options::toggle(Menu1::OnePlayer);
new_game();
}
if (ImGui::MenuItem("2 Players", nullptr, Options.Players == 2))
if (ImGui::MenuItem(pinball::get_rc_string(Msg::Menu1_2Players), nullptr, Options.Players == 2))
{
options::toggle(Menu1::TwoPlayers);
new_game();
}
if (ImGui::MenuItem("3 Players", nullptr, Options.Players == 3))
if (ImGui::MenuItem(pinball::get_rc_string(Msg::Menu1_3Players), nullptr, Options.Players == 3))
{
options::toggle(Menu1::ThreePlayers);
new_game();
}
if (ImGui::MenuItem("4 Players", nullptr, Options.Players == 4))
if (ImGui::MenuItem(pinball::get_rc_string(Msg::Menu1_4Players), nullptr, Options.Players == 4))
{
options::toggle(Menu1::FourPlayers);
new_game();
}
ImGui::EndMenu();
}
if (ImGui::MenuItem("Player Controls...", "F8"))
if (ImGui::MenuItem(pinball::get_rc_string(Msg::Menu1_Player_Controls), "F8"))
{
pause(false);
options::ShowControlDialog();
}
if (ImGui::BeginMenu("Language"))
{
auto currentLanguage = translations::GetCurrentLanguage();
for (auto &item : translations::Languages)
{
if (ImGui::MenuItem(item.DisplayName, nullptr, currentLanguage->Language == item.Language))
{
translations::SetCurrentLanguage(item.ShortName);
winmain::Restart();
}
}
ImGui::EndMenu();
}
ImGui::Separator();
if (ImGui::BeginMenu("Audio"))
@ -472,7 +518,7 @@ void winmain::RenderUi()
}
ImGui::Separator();
if (ImGui::MenuItem("Music", "F6", Options.Music))
if (ImGui::MenuItem(pinball::get_rc_string(Msg::Menu1_Music), "F6", Options.Music))
{
options::toggle(Menu1::Music);
}
@ -487,6 +533,10 @@ void winmain::RenderUi()
if (ImGui::BeginMenu("Graphics"))
{
if (ImGui::MenuItem("Change Font"))
{
font_selection::ShowDialog();
}
if (ImGui::MenuItem("Uniform Scaling", nullptr, Options.UniformScaling))
{
options::toggle(Menu1::WindowUniformScale);
@ -543,10 +593,18 @@ void winmain::RenderUi()
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Table Resolution"))
if (ImGui::BeginMenu(pinball::get_rc_string(Msg::Menu1_Table_Resolution)))
{
char buffer[20]{};
auto maxResText = pinball::get_rc_string(fullscrn::GetMaxResolution() + 2030, 0);
Msg resolutionStringId = Msg::Menu1_UseMaxResolution_640x480;
switch(fullscrn::GetMaxResolution()) {
case 0: resolutionStringId = Msg::Menu1_UseMaxResolution_640x480; break;
case 1: resolutionStringId = Msg::Menu1_UseMaxResolution_800x600; break;
case 2: resolutionStringId = Msg::Menu1_UseMaxResolution_1024x768; break;
}
auto maxResText = pinball::get_rc_string(resolutionStringId);
if (ImGui::MenuItem(maxResText, nullptr, Options.Resolution == -1))
{
options::toggle(Menu1::MaximumResolution);
@ -574,7 +632,7 @@ void winmain::RenderUi()
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Help"))
if (ImGui::BeginMenu(pinball::get_rc_string(Msg::Menu1_Help)))
{
#ifndef NDEBUG
if (ImGui::MenuItem("ImGui Demo", nullptr, ShowImGuiDemo))
@ -633,7 +691,7 @@ void winmain::RenderUi()
}
ImGui::Separator();
if (ImGui::MenuItem("About Pinball"))
if (ImGui::MenuItem(pinball::get_rc_string(Msg::Menu1_About_Pinball)))
{
pause(false);
ShowAboutDialog = true;
@ -648,11 +706,15 @@ void winmain::RenderUi()
a_dialog();
high_score::RenderHighScoreDialog();
font_selection::RenderDialog();
if (ShowSpriteViewer)
render::SpriteViewer(&ShowSpriteViewer);
options::RenderControlDialog();
if (DispGRhistory)
RenderFrameTimeDialog();
// Print game texts on the sidebar
gdrv::grtext_draw_ttext_in_box();
}
int winmain::event_handler(const SDL_Event* event)
@ -924,8 +986,8 @@ void winmain::memalloc_failure()
{
midi::music_stop();
Sound::Close();
char* caption = pinball::get_rc_string(170, 0);
char* text = pinball::get_rc_string(179, 0);
const char* caption = pinball::get_rc_string(Msg::STRING270);
const char* text = pinball::get_rc_string(Msg::STRING279);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, caption, text, MainWindow);
std::exit(1);
}
@ -935,13 +997,13 @@ void winmain::a_dialog()
if (ShowAboutDialog == true)
{
ShowAboutDialog = false;
ImGui::OpenPopup("About");
ImGui::OpenPopup(pinball::get_rc_string(Msg::STRING204));
}
bool unused_open = true;
if (ImGui::BeginPopupModal("About", &unused_open, ImGuiWindowFlags_AlwaysAutoResize))
if (ImGui::BeginPopupModal(pinball::get_rc_string(Msg::STRING204), &unused_open, ImGuiWindowFlags_AlwaysAutoResize))
{
ImGui::TextUnformatted("3D Pinball for Windows - Space Cadet");
ImGui::TextUnformatted(pinball::get_rc_string(Msg::STRING139));
ImGui::TextUnformatted("Original game by Cinematronics, Microsoft");
ImGui::Separator();