diff --git a/Source/DiabloUI/diabloui.h b/Source/DiabloUI/diabloui.h index 0aa6ffc32..0b6a80ed0 100644 --- a/Source/DiabloUI/diabloui.h +++ b/Source/DiabloUI/diabloui.h @@ -102,7 +102,7 @@ void UiSelHeroSingDialog(bool (*fninfo)(bool (*fninfofunc)(_uiheroinfo *)), bool bool UiCreditsDialog(); bool UiSupportDialog(); bool UiMainMenuDialog(const char *name, _mainmenu_selections *pdwResult, void (*fnSound)(const char *file), int attractTimeOut); -bool UiProgressDialog(const char *msg, int (*fnfunc)()); +bool UiProgressDialog(int (*fnfunc)()); bool UiSelectGame(GameData *gameData, int *playerId); bool UiSelectProvider(GameData *gameData); void UiFadeIn(); diff --git a/Source/DiabloUI/dialogs.cpp b/Source/DiabloUI/dialogs.cpp index 77835af39..e56b091dd 100644 --- a/Source/DiabloUI/dialogs.cpp +++ b/Source/DiabloUI/dialogs.cpp @@ -14,6 +14,7 @@ #include "utils/display.h" #include "utils/language.h" #include "utils/log.hpp" +#include "utils/stdcompat/string_view.hpp" namespace devilution { @@ -159,7 +160,7 @@ void LoadFallbackPalette() BlackPalette(); } -void Init(const char *caption, const char *text, bool error, bool renderBehind) +void Init(string_view caption, string_view text, bool error, bool renderBehind) { if (!renderBehind) { ArtBackground.Unload(); @@ -171,7 +172,7 @@ void Init(const char *caption, const char *text, bool error, bool renderBehind) } } - if (caption == nullptr) { + if (caption.empty()) { LoadMaskedArt(error ? "ui_art\\srpopup.pcx" : "ui_art\\spopup.pcx", &dialogArt); } else if (error) { LoadArt(&dialogArt, PopupData, 385, 280); @@ -184,12 +185,12 @@ void Init(const char *caption, const char *text, bool error, bool renderBehind) wrappedText = WordWrapString(text, textWidth, FontSizeDialog); - if (caption == nullptr) { + if (caption.empty()) { SDL_Rect rect1 = MakeSdlRect(PANEL_LEFT + 180, UI_OFFSET_Y + 168, dialogArt.w(), dialogArt.h()); vecOkDialog.push_back(std::make_unique(&dialogArt, rect1)); SDL_Rect rect2 = MakeSdlRect(PANEL_LEFT + 200, UI_OFFSET_Y + 211, textWidth, 80); - vecOkDialog.push_back(std::make_unique(wrappedText.c_str(), rect2, UiFlags::AlignCenter | UiFlags::ColorDialogWhite)); + vecOkDialog.push_back(std::make_unique(wrappedText, rect2, UiFlags::AlignCenter | UiFlags::ColorDialogWhite)); SDL_Rect rect3 = MakeSdlRect(PANEL_LEFT + 265, UI_OFFSET_Y + 265, SML_BUTTON_WIDTH, SML_BUTTON_HEIGHT); vecOkDialog.push_back(std::make_unique(&SmlButton, _("OK"), &DialogActionOK, rect3)); @@ -201,7 +202,7 @@ void Init(const char *caption, const char *text, bool error, bool renderBehind) vecOkDialog.push_back(std::make_unique(caption, rect2, UiFlags::AlignCenter | UiFlags::ColorDialogYellow)); SDL_Rect rect3 = MakeSdlRect(PANEL_LEFT + 147, UI_OFFSET_Y + 141, textWidth, 190); - vecOkDialog.push_back(std::make_unique(wrappedText.c_str(), rect3, UiFlags::AlignCenter | UiFlags::ColorDialogWhite)); + vecOkDialog.push_back(std::make_unique(wrappedText, rect3, UiFlags::AlignCenter | UiFlags::ColorDialogWhite)); SDL_Rect rect4 = MakeSdlRect(PANEL_LEFT + 264, UI_OFFSET_Y + 335, SML_BUTTON_WIDTH, SML_BUTTON_HEIGHT); vecOkDialog.push_back(std::make_unique(&SmlButton, _("OK"), &DialogActionOK, rect4)); diff --git a/Source/DiabloUI/mainmenu.cpp b/Source/DiabloUI/mainmenu.cpp index a82d6b4dd..e5fdfe028 100644 --- a/Source/DiabloUI/mainmenu.cpp +++ b/Source/DiabloUI/mainmenu.cpp @@ -57,7 +57,7 @@ void MainmenuLoad(const char *name, void (*fnSound)(const char *file)) if (gbIsSpawn && gbIsHellfire) { SDL_Rect rect1 = { (Sint16)(PANEL_LEFT), (Sint16)(UI_OFFSET_Y + 145), 640, 30 }; - vecMainMenuDialog.push_back(std::make_unique(_("Shareware"), rect1, UiFlags::FontSize30 | UiFlags::ColorUiSilver | UiFlags::AlignCenter, 8)); + vecMainMenuDialog.push_back(std::make_unique(_("Shareware").c_str(), rect1, UiFlags::FontSize30 | UiFlags::ColorUiSilver | UiFlags::AlignCenter, 8)); } vecMainMenuDialog.push_back(std::make_unique(vecMenuItems, vecMenuItems.size(), PANEL_LEFT + 64, (UI_OFFSET_Y + 192), 510, 43, UiFlags::FontSize42 | UiFlags::ColorUiGold | UiFlags::AlignCenter, 5)); diff --git a/Source/DiabloUI/progress.cpp b/Source/DiabloUI/progress.cpp index 58d6a1e03..4630d9c4e 100644 --- a/Source/DiabloUI/progress.cpp +++ b/Source/DiabloUI/progress.cpp @@ -25,7 +25,7 @@ void DialogActionCancel() endMenu = true; } -void ProgressLoad(const char *msg) +void ProgressLoad() { LoadBackgroundArt("ui_art\\black.pcx"); LoadArt("ui_art\\spopup.pcx", &ArtPopupSm); @@ -63,9 +63,9 @@ void ProgressRender(BYTE progress) } // namespace -bool UiProgressDialog(const char *msg, int (*fnfunc)()) +bool UiProgressDialog(int (*fnfunc)()) { - ProgressLoad(msg); + ProgressLoad(); SetFadeLevel(256); endMenu = false; diff --git a/Source/DiabloUI/selconn.cpp b/Source/DiabloUI/selconn.cpp index 4ae7e2e50..f1d315cba 100644 --- a/Source/DiabloUI/selconn.cpp +++ b/Source/DiabloUI/selconn.cpp @@ -4,6 +4,7 @@ #include "stores.h" #include "storm/storm_net.hpp" #include "utils/language.h" +#include "utils/utf8.hpp" namespace devilution { @@ -50,25 +51,25 @@ void SelconnLoad() UiAddLogo(&vecSelConnDlg); SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 24), (Sint16)(Sint16)(UI_OFFSET_Y + 161), 590, 35 }; - vecSelConnDlg.push_back(std::make_unique(_("Multi Player Game"), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); + vecSelConnDlg.push_back(std::make_unique(_("Multi Player Game").c_str(), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 218), DESCRIPTION_WIDTH, 21 }; vecSelConnDlg.push_back(std::make_unique(selconn_MaxPlayers, rect2, UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); SDL_Rect rect3 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 256), DESCRIPTION_WIDTH, 21 }; - vecSelConnDlg.push_back(std::make_unique(_("Requirements:"), rect3, UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); + vecSelConnDlg.push_back(std::make_unique(_("Requirements:").c_str(), rect3, UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); SDL_Rect rect4 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 275), DESCRIPTION_WIDTH, 66 }; vecSelConnDlg.push_back(std::make_unique(selconn_Description, rect4, UiFlags::FontSize12 | UiFlags::ColorUiSilverDark, 1, 16)); SDL_Rect rect5 = { (Sint16)(PANEL_LEFT + 30), (Sint16)(UI_OFFSET_Y + 356), 220, 31 }; - vecSelConnDlg.push_back(std::make_unique(_("no gateway needed"), rect5, UiFlags::AlignCenter | UiFlags::FontSize24 | UiFlags::ColorUiSilver, 0)); + vecSelConnDlg.push_back(std::make_unique(_("no gateway needed").c_str(), rect5, UiFlags::AlignCenter | UiFlags::FontSize24 | UiFlags::ColorUiSilver, 0)); SDL_Rect rect6 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 393), DESCRIPTION_WIDTH, 21 }; vecSelConnDlg.push_back(std::make_unique(selconn_Gateway, rect6, UiFlags::AlignCenter | UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); SDL_Rect rect7 = { (Sint16)(PANEL_LEFT + 300), (Sint16)(UI_OFFSET_Y + 211), 295, 33 }; - vecSelConnDlg.push_back(std::make_unique(_("Select Connection"), rect7, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); + vecSelConnDlg.push_back(std::make_unique(_("Select Connection").c_str(), rect7, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); SDL_Rect rect8 = { (Sint16)(PANEL_LEFT + 16), (Sint16)(UI_OFFSET_Y + 427), 250, 35 }; vecSelConnDlg.push_back(std::make_unique(_("Change Gateway"), nullptr, rect8, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontSize30 | UiFlags::ColorUiGold | UiFlags::ElementHidden)); @@ -104,21 +105,21 @@ void SelconnFocus(int value) int players = MAX_PLRS; switch (vecConnItems[value]->m_value) { case SELCONN_TCP: - strcpy(selconn_Description, _("All computers must be connected to a TCP-compatible network.")); + CopyUtf8(selconn_Description, _("All computers must be connected to a TCP-compatible network."), sizeof(selconn_Description)); players = MAX_PLRS; break; case SELCONN_ZT: - strcpy(selconn_Description, _("All computers must be connected to the internet.")); + CopyUtf8(selconn_Description, _("All computers must be connected to the internet."), sizeof(selconn_Description)); players = MAX_PLRS; break; case SELCONN_LOOPBACK: - strcpy(selconn_Description, _("Play by yourself with no network exposure.")); + CopyUtf8(selconn_Description, _("Play by yourself with no network exposure."), sizeof(selconn_Description)); players = 1; break; } - strcpy(selconn_MaxPlayers, fmt::format(_("Players Supported: {:d}"), players).c_str()); - strcpy(selconn_Description, WordWrapString(selconn_Description, DESCRIPTION_WIDTH).c_str()); + CopyUtf8(selconn_MaxPlayers, fmt::format(_("Players Supported: {:d}"), players), sizeof(selconn_MaxPlayers)); + CopyUtf8(selconn_Description, WordWrapString(selconn_Description, DESCRIPTION_WIDTH), sizeof(selconn_Description)); } void SelconnSelect(int value) diff --git a/Source/DiabloUI/selgame.cpp b/Source/DiabloUI/selgame.cpp index 5a9418159..00b538ee7 100644 --- a/Source/DiabloUI/selgame.cpp +++ b/Source/DiabloUI/selgame.cpp @@ -95,7 +95,7 @@ static std::string GetErrorMessageIncompatibility(const GameData &data) } return fmt::format(_("The host is running a different game mode ({:s}) than you."), gameMode); } else { - return fmt::format(_(/* TRANSLATORS: Error message when somebody tries to join a game running another version. */ "Your version {:s} does not match the host {:d}.{:d}.{:d}."), PROJECT_VERSION, data.versionMajor, data.versionMinor, data.versionPatch).c_str(); + return fmt::format(_(/* TRANSLATORS: Error message when somebody tries to join a game running another version. */ "Your version {:s} does not match the host {:d}.{:d}.{:d}."), PROJECT_VERSION, data.versionMajor, data.versionMinor, data.versionPatch); } } @@ -112,7 +112,7 @@ void selgame_GameSelection_Init() return; } - strcpy(selgame_Ip, sgOptions.Network.szPreviousHost); + CopyUtf8(selgame_Ip, sgOptions.Network.szPreviousHost, sizeof(selgame_Ip)); selgame_FreeVectors(); @@ -123,16 +123,16 @@ void selgame_GameSelection_Init() vecSelGameDialog.push_back(std::make_unique(&ArtScrollBarBackground, &ArtScrollBarThumb, &ArtScrollBarArrow, rectScrollbar)); SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 24), (Sint16)(UI_OFFSET_Y + 161), 590, 35 }; - vecSelGameDialog.push_back(std::make_unique(_(ConnectionNames[provider]), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); + vecSelGameDialog.push_back(std::make_unique(_(ConnectionNames[provider]).c_str(), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 211), 205, 192 }; - vecSelGameDialog.push_back(std::make_unique(_("Description:"), rect2, UiFlags::FontSize24 | UiFlags::ColorUiSilver)); + vecSelGameDialog.push_back(std::make_unique(_("Description:").c_str(), rect2, UiFlags::FontSize24 | UiFlags::ColorUiSilver)); SDL_Rect rect3 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 256), DESCRIPTION_WIDTH, 192 }; vecSelGameDialog.push_back(std::make_unique(selgame_Description, rect3, UiFlags::FontSize12 | UiFlags::ColorUiSilverDark, 1, 16)); SDL_Rect rect4 = { (Sint16)(PANEL_LEFT + 300), (Sint16)(UI_OFFSET_Y + 211), 295, 33 }; - vecSelGameDialog.push_back(std::make_unique(_("Select Action"), rect4, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); + vecSelGameDialog.push_back(std::make_unique(_("Select Action").c_str(), rect4, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); #ifdef PACKET_ENCRYPTION vecSelGameDlgItems.push_back(std::make_unique(_("Create Game"), 0, UiFlags::ColorUiGold)); @@ -152,7 +152,7 @@ void selgame_GameSelection_Init() vecSelGameDlgItems.push_back(std::make_unique(_("None"), -1, UiFlags::ElementDisabled | UiFlags::ColorUiSilver)); } else { for (unsigned i = 0; i < Gamelist.size(); i++) { - vecSelGameDlgItems.push_back(std::make_unique(Gamelist[i].name.c_str(), i + 3, UiFlags::ColorUiGold)); + vecSelGameDlgItems.push_back(std::make_unique(Gamelist[i].name, i + 3, UiFlags::ColorUiGold)); } } } @@ -179,13 +179,13 @@ void selgame_GameSelection_Focus(int value) HighlightedItem = value; switch (vecSelGameDlgItems[value]->m_value) { case 0: - strcpy(selgame_Description, _("Create a new game with a difficulty setting of your choice.")); + CopyUtf8(selgame_Description, _("Create a new game with a difficulty setting of your choice."), sizeof(selgame_Description)); break; case 1: - strcpy(selgame_Description, _("Create a new public game that anyone can join with a difficulty setting of your choice.")); + CopyUtf8(selgame_Description, _("Create a new public game that anyone can join with a difficulty setting of your choice."), sizeof(selgame_Description)); break; case 2: - strcpy(selgame_Description, _("Enter an IP or a hostname and join a game already in progress at that address.")); + CopyUtf8(selgame_Description, _("Enter an IP or a hostname and join a game already in progress at that address."), sizeof(selgame_Description)); break; default: const auto &gameInfo = Gamelist[vecSelGameDlgItems[value]->m_value - 3]; @@ -236,7 +236,7 @@ void selgame_GameSelection_Focus(int value) CopyUtf8(selgame_Description, infoString, sizeof(selgame_Description)); break; } - strcpy(selgame_Description, WordWrapString(selgame_Description, DESCRIPTION_WIDTH).c_str()); + CopyUtf8(selgame_Description, WordWrapString(selgame_Description, DESCRIPTION_WIDTH), sizeof(selgame_Description)); } /** @@ -258,7 +258,7 @@ void selgame_GameSelection_Select(int value) selgame_selectedGame = value; if (value > 2) { - strcpy(selgame_Ip, Gamelist[value - 3].name.c_str()); + CopyUtf8(selgame_Ip, Gamelist[value - 3].name, sizeof(selgame_Ip)); selgame_Password_Select(value); return; } @@ -282,10 +282,10 @@ void selgame_GameSelection_Select(int value) switch (value) { case 0: case 1: { - title = _("Create Game"); + title = _("Create Game").c_str(); SDL_Rect rect4 = { (Sint16)(PANEL_LEFT + 299), (Sint16)(UI_OFFSET_Y + 211), 295, 35 }; - vecSelGameDialog.push_back(std::make_unique(_("Select Difficulty"), rect4, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); + vecSelGameDialog.push_back(std::make_unique(_("Select Difficulty").c_str(), rect4, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); vecSelGameDlgItems.push_back(std::make_unique(_("Normal"), DIFF_NORMAL)); vecSelGameDlgItems.push_back(std::make_unique(_("Nightmare"), DIFF_NIGHTMARE)); @@ -303,13 +303,13 @@ void selgame_GameSelection_Select(int value) break; } case 2: { - title = _("Join TCP Games"); + title = _("Join TCP Games").c_str(); SDL_Rect rect4 = { (Sint16)(PANEL_LEFT + 305), (Sint16)(UI_OFFSET_Y + 211), 285, 33 }; - vecSelGameDialog.push_back(std::make_unique(_("Enter address"), rect4, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); + vecSelGameDialog.push_back(std::make_unique(_("Enter address").c_str(), rect4, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); SDL_Rect rect5 = { (Sint16)(PANEL_LEFT + 305), (Sint16)(UI_OFFSET_Y + 314), 285, 33 }; - vecSelGameDialog.push_back(std::make_unique(_("Enter address"), selgame_Ip, 128, false, rect5, UiFlags::FontSize24 | UiFlags::ColorUiGold)); + vecSelGameDialog.push_back(std::make_unique(_("Enter address").c_str(), selgame_Ip, 128, false, rect5, UiFlags::FontSize24 | UiFlags::ColorUiGold)); SDL_Rect rect6 = { (Sint16)(PANEL_LEFT + 299), (Sint16)(UI_OFFSET_Y + 427), 140, 35 }; vecSelGameDialog.push_back(std::make_unique(_("OK"), &UiFocusNavigationSelect, rect6, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontSize30 | UiFlags::ColorUiGold)); @@ -340,19 +340,19 @@ void selgame_Diff_Focus(int value) { switch (vecSelGameDlgItems[value]->m_value) { case DIFF_NORMAL: - strcpy(selgame_Label, _("Normal")); - strcpy(selgame_Description, _("Normal Difficulty\nThis is where a starting character should begin the quest to defeat Diablo.")); + CopyUtf8(selgame_Label, _("Normal"), sizeof(selgame_Label)); + CopyUtf8(selgame_Description, _("Normal Difficulty\nThis is where a starting character should begin the quest to defeat Diablo."), sizeof(selgame_Description)); break; case DIFF_NIGHTMARE: - strcpy(selgame_Label, _("Nightmare")); - strcpy(selgame_Description, _("Nightmare Difficulty\nThe denizens of the Labyrinth have been bolstered and will prove to be a greater challenge. This is recommended for experienced characters only.")); + CopyUtf8(selgame_Label, _("Nightmare"), sizeof(selgame_Label)); + CopyUtf8(selgame_Description, _("Nightmare Difficulty\nThe denizens of the Labyrinth have been bolstered and will prove to be a greater challenge. This is recommended for experienced characters only."), sizeof(selgame_Description)); break; case DIFF_HELL: - strcpy(selgame_Label, _("Hell")); - strcpy(selgame_Description, _("Hell Difficulty\nThe most powerful of the underworld's creatures lurk at the gateway into Hell. Only the most experienced characters should venture in this realm.")); + CopyUtf8(selgame_Label, _("Hell"), sizeof(selgame_Label)); + CopyUtf8(selgame_Description, _("Hell Difficulty\nThe most powerful of the underworld's creatures lurk at the gateway into Hell. Only the most experienced characters should venture in this realm."), sizeof(selgame_Description)); break; } - strcpy(selgame_Description, WordWrapString(selgame_Description, DESCRIPTION_WIDTH).c_str()); + CopyUtf8(selgame_Description, WordWrapString(selgame_Description, DESCRIPTION_WIDTH), sizeof(selgame_Description)); } bool IsDifficultyAllowed(int value) @@ -364,9 +364,9 @@ bool IsDifficultyAllowed(int value) selgame_Free(); if (value == 1) - UiSelOkDialog(title, _("Your character must reach level 20 before you can enter a multiplayer game of Nightmare difficulty."), false); + UiSelOkDialog(title, _("Your character must reach level 20 before you can enter a multiplayer game of Nightmare difficulty.").c_str(), false); if (value == 2) - UiSelOkDialog(title, _("Your character must reach level 30 before you can enter a multiplayer game of Hell difficulty."), false); + UiSelOkDialog(title, _("Your character must reach level 30 before you can enter a multiplayer game of Hell difficulty.").c_str(), false); selgame_Init(); @@ -433,7 +433,7 @@ void selgame_GameSpeedSelection() UiAddLogo(&vecSelGameDialog); SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 24), (Sint16)(UI_OFFSET_Y + 161), 590, 35 }; - vecSelGameDialog.push_back(std::make_unique(_("Create Game"), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); + vecSelGameDialog.push_back(std::make_unique(_("Create Game").c_str(), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 34), (Sint16)(UI_OFFSET_Y + 211), 205, 33 }; vecSelGameDialog.push_back(std::make_unique(selgame_Label, rect2, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); @@ -442,7 +442,7 @@ void selgame_GameSpeedSelection() vecSelGameDialog.push_back(std::make_unique(selgame_Description, rect3, UiFlags::FontSize12 | UiFlags::ColorUiSilverDark, 1, 16)); SDL_Rect rect4 = { (Sint16)(PANEL_LEFT + 299), (Sint16)(UI_OFFSET_Y + 211), 295, 35 }; - vecSelGameDialog.push_back(std::make_unique(_("Select Game Speed"), rect4, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); + vecSelGameDialog.push_back(std::make_unique(_("Select Game Speed").c_str(), rect4, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); vecSelGameDlgItems.push_back(std::make_unique(_("Normal"), 20)); vecSelGameDlgItems.push_back(std::make_unique(_("Fast"), 30)); @@ -464,23 +464,23 @@ void selgame_Speed_Focus(int value) { switch (vecSelGameDlgItems[value]->m_value) { case 20: - strcpy(selgame_Label, _("Normal")); - strcpy(selgame_Description, _("Normal Speed\nThis is where a starting character should begin the quest to defeat Diablo.")); + CopyUtf8(selgame_Label, _("Normal"), sizeof(selgame_Label)); + CopyUtf8(selgame_Description, _("Normal Speed\nThis is where a starting character should begin the quest to defeat Diablo."), sizeof(selgame_Description)); break; case 30: - strcpy(selgame_Label, _("Fast")); - strcpy(selgame_Description, _("Fast Speed\nThe denizens of the Labyrinth have been hastened and will prove to be a greater challenge. This is recommended for experienced characters only.")); + CopyUtf8(selgame_Label, _("Fast"), sizeof(selgame_Label)); + CopyUtf8(selgame_Description, _("Fast Speed\nThe denizens of the Labyrinth have been hastened and will prove to be a greater challenge. This is recommended for experienced characters only."), sizeof(selgame_Description)); break; case 40: - strcpy(selgame_Label, _("Faster")); - strcpy(selgame_Description, _("Faster Speed\nMost monsters of the dungeon will seek you out quicker than ever before. Only an experienced champion should try their luck at this speed.")); + CopyUtf8(selgame_Label, _("Faster"), sizeof(selgame_Label)); + CopyUtf8(selgame_Description, _("Faster Speed\nMost monsters of the dungeon will seek you out quicker than ever before. Only an experienced champion should try their luck at this speed."), sizeof(selgame_Description)); break; case 50: - strcpy(selgame_Label, _("Fastest")); - strcpy(selgame_Description, _("Fastest Speed\nThe minions of the underworld will rush to attack without hesitation. Only a true speed demon should enter at this pace.")); + CopyUtf8(selgame_Label, _("Fastest"), sizeof(selgame_Label)); + CopyUtf8(selgame_Description, _("Fastest Speed\nThe minions of the underworld will rush to attack without hesitation. Only a true speed demon should enter at this pace."), sizeof(selgame_Description)); break; } - strcpy(selgame_Description, WordWrapString(selgame_Description, DESCRIPTION_WIDTH).c_str()); + CopyUtf8(selgame_Description, WordWrapString(selgame_Description, DESCRIPTION_WIDTH), sizeof(selgame_Description)); } void selgame_Speed_Esc() @@ -510,21 +510,21 @@ void selgame_Password_Init(int /*value*/) UiAddLogo(&vecSelGameDialog); SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 24), (Sint16)(UI_OFFSET_Y + 161), 590, 35 }; - vecSelGameDialog.push_back(std::make_unique(_(ConnectionNames[provider]), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); + vecSelGameDialog.push_back(std::make_unique(_(ConnectionNames[provider]).c_str(), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 211), 205, 192 }; - vecSelGameDialog.push_back(std::make_unique(_("Description:"), rect2, UiFlags::FontSize24 | UiFlags::ColorUiSilver)); + vecSelGameDialog.push_back(std::make_unique(_("Description:").c_str(), rect2, UiFlags::FontSize24 | UiFlags::ColorUiSilver)); SDL_Rect rect3 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 256), DESCRIPTION_WIDTH, 192 }; vecSelGameDialog.push_back(std::make_unique(selgame_Description, rect3, UiFlags::FontSize12 | UiFlags::ColorUiSilverDark, 1, 16)); SDL_Rect rect4 = { (Sint16)(PANEL_LEFT + 305), (Sint16)(UI_OFFSET_Y + 211), 285, 33 }; - vecSelGameDialog.push_back(std::make_unique(_("Enter Password"), rect4, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); + vecSelGameDialog.push_back(std::make_unique(_("Enter Password").c_str(), rect4, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); // Allow password to be empty only when joining games bool allowEmpty = selgame_selectedGame == 2; SDL_Rect rect5 = { (Sint16)(PANEL_LEFT + 305), (Sint16)(UI_OFFSET_Y + 314), 285, 33 }; - vecSelGameDialog.push_back(std::make_unique(_("Enter Password"), selgame_Password, 15, allowEmpty, rect5, UiFlags::FontSize24 | UiFlags::ColorUiGold)); + vecSelGameDialog.push_back(std::make_unique(_("Enter Password").c_str(), selgame_Password, 15, allowEmpty, rect5, UiFlags::FontSize24 | UiFlags::ColorUiGold)); SDL_Rect rect6 = { (Sint16)(PANEL_LEFT + 299), (Sint16)(UI_OFFSET_Y + 427), 140, 35 }; vecSelGameDialog.push_back(std::make_unique(_("OK"), &UiFocusNavigationSelect, rect6, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontSize30 | UiFlags::ColorUiGold)); @@ -580,7 +580,7 @@ void selgame_Password_Select(int /*value*/) std::string error = SDL_GetError(); if (error.empty()) error = "Unknown network error"; - UiSelOkDialog(_("Multi Player Game"), error.c_str(), false); + UiSelOkDialog(_("Multi Player Game").c_str(), error.c_str(), false); selgame_Init(); selgame_Password_Init(selgame_selectedGame); } @@ -601,7 +601,7 @@ void selgame_Password_Select(int /*value*/) std::string error = SDL_GetError(); if (error.empty()) error = "Unknown network error"; - UiSelOkDialog(_("Multi Player Game"), error.c_str(), false); + UiSelOkDialog(_("Multi Player Game").c_str(), error.c_str(), false); selgame_Init(); selgame_Password_Init(0); } diff --git a/Source/DiabloUI/selhero.cpp b/Source/DiabloUI/selhero.cpp index 376249b31..4c4c87d37 100644 --- a/Source/DiabloUI/selhero.cpp +++ b/Source/DiabloUI/selhero.cpp @@ -17,6 +17,7 @@ #include "options.h" #include "pfile.h" #include "utils/language.h" +#include "utils/utf8.hpp" #include namespace devilution { @@ -77,12 +78,12 @@ void SelheroFree() void SelheroSetStats() { SELHERO_DIALOG_HERO_IMG->SetFrame(static_cast(selhero_heroInfo.heroclass)); - snprintf(textStats[0], sizeof(textStats[0]), "%i", selhero_heroInfo.level); - snprintf(textStats[1], sizeof(textStats[1]), "%i", selhero_heroInfo.strength); - snprintf(textStats[2], sizeof(textStats[2]), "%i", selhero_heroInfo.magic); - snprintf(textStats[3], sizeof(textStats[3]), "%i", selhero_heroInfo.dexterity); - snprintf(textStats[4], sizeof(textStats[4]), "%i", selhero_heroInfo.vitality); - snprintf(textStats[5], sizeof(textStats[5]), "%i", selhero_heroInfo.saveNumber); + CopyUtf8(textStats[0], fmt::format("{}", selhero_heroInfo.level), sizeof(textStats[0])); + CopyUtf8(textStats[1], fmt::format("{}", selhero_heroInfo.strength), sizeof(textStats[1])); + CopyUtf8(textStats[2], fmt::format("{}", selhero_heroInfo.magic), sizeof(textStats[2])); + CopyUtf8(textStats[3], fmt::format("{}", selhero_heroInfo.dexterity), sizeof(textStats[3])); + CopyUtf8(textStats[4], fmt::format("{}", selhero_heroInfo.vitality), sizeof(textStats[4])); + CopyUtf8(textStats[5], fmt::format("{}", selhero_heroInfo.saveNumber), sizeof(textStats[5])); } UiArtTextButton *SELLIST_DIALOG_DELETE_BUTTON; @@ -128,7 +129,7 @@ void SelheroListSelect(int value) vecSelDlgItems.clear(); SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 264), (Sint16)(UI_OFFSET_Y + 211), 320, 33 }; - vecSelDlgItems.push_back(std::make_unique(_("Choose Class"), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); + vecSelDlgItems.push_back(std::make_unique(_("Choose Class").c_str(), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); vecSelHeroDlgItems.clear(); int itemH = 33; @@ -159,7 +160,7 @@ void SelheroListSelect(int value) memset(&selhero_heroInfo.name, 0, sizeof(selhero_heroInfo.name)); selhero_heroInfo.saveNumber = pfile_ui_get_first_unused_save_num(); SelheroSetStats(); - title = selhero_isMultiPlayer ? _("New Multi Player Hero") : _("New Single Player Hero"); + title = selhero_isMultiPlayer ? _("New Multi Player Hero").c_str() : _("New Single Player Hero").c_str(); return; } @@ -167,7 +168,7 @@ void SelheroListSelect(int value) vecSelDlgItems.clear(); SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 264), (Sint16)(UI_OFFSET_Y + 211), 320, 33 }; - vecSelDlgItems.push_back(std::make_unique(_("Save File Exists"), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); + vecSelDlgItems.push_back(std::make_unique(_("Save File Exists").c_str(), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); vecSelHeroDlgItems.clear(); vecSelHeroDlgItems.push_back(std::make_unique(_("Load Game"), 0)); @@ -181,7 +182,7 @@ void SelheroListSelect(int value) vecSelDlgItems.push_back(std::make_unique(_("Cancel"), &UiFocusNavigationEsc, rect3, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontSize30 | UiFlags::ColorUiGold)); UiInitList(SelheroLoadFocus, SelheroLoadSelect, selhero_List_Init, vecSelDlgItems, true); - title = _("Single Player Characters"); + title = _("Single Player Characters").c_str(); return; } @@ -227,22 +228,22 @@ void SelheroClassSelectorSelect(int value) auto hClass = static_cast(vecSelHeroDlgItems[value]->m_value); if (gbIsSpawn && (hClass == HeroClass::Rogue || hClass == HeroClass::Sorcerer || (hClass == HeroClass::Bard && !hfbard_mpq))) { ArtBackground.Unload(); - UiSelOkDialog(nullptr, _("The Rogue and Sorcerer are only available in the full retail version of Diablo. Visit https://www.gog.com/game/diablo to purchase."), false); + UiSelOkDialog(nullptr, _("The Rogue and Sorcerer are only available in the full retail version of Diablo. Visit https://www.gog.com/game/diablo to purchase.").c_str(), false); LoadBackgroundArt("ui_art\\selhero.pcx"); SelheroListSelect(selhero_SaveCount); return; } - title = selhero_isMultiPlayer ? _("New Multi Player Hero") : _("New Single Player Hero"); + title = selhero_isMultiPlayer ? _("New Multi Player Hero").c_str() : _("New Single Player Hero").c_str(); memset(selhero_heroInfo.name, '\0', sizeof(selhero_heroInfo.name)); if (ShouldPrefillHeroName()) strcpy(selhero_heroInfo.name, SelheroGenerateName(selhero_heroInfo.heroclass)); vecSelDlgItems.clear(); SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 264), (Sint16)(UI_OFFSET_Y + 211), 320, 33 }; - vecSelDlgItems.push_back(std::make_unique(_("Enter Name"), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); + vecSelDlgItems.push_back(std::make_unique(_("Enter Name").c_str(), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 265), (Sint16)(UI_OFFSET_Y + 317), 320, 33 }; - vecSelDlgItems.push_back(std::make_unique(_("Enter Name"), selhero_heroInfo.name, 15, false, rect2, UiFlags::FontSize24 | UiFlags::ColorUiGold)); + vecSelDlgItems.push_back(std::make_unique(_("Enter Name").c_str(), selhero_heroInfo.name, 15, false, rect2, UiFlags::FontSize24 | UiFlags::ColorUiGold)); SDL_Rect rect3 = { (Sint16)(PANEL_LEFT + 279), (Sint16)(UI_OFFSET_Y + 429), 140, 35 }; vecSelDlgItems.push_back(std::make_unique(_("OK"), &UiFocusNavigationSelect, rect3, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiGold)); @@ -271,14 +272,14 @@ void SelheroNameSelect(int /*value*/) // only check names in multiplayer, we don't care about them in single if (selhero_isMultiPlayer && !UiValidPlayerName(selhero_heroInfo.name)) { ArtBackground.Unload(); - UiSelOkDialog(title, _("Invalid name. A name cannot contain spaces, reserved characters, or reserved words.\n"), false); + UiSelOkDialog(title, _("Invalid name. A name cannot contain spaces, reserved characters, or reserved words.\n").c_str(), false); LoadBackgroundArt("ui_art\\selhero.pcx"); } else { if (gfnHeroCreate(&selhero_heroInfo)) { SelheroLoadSelect(1); return; } - UiErrorOkDialog(_(/* TRANSLATORS: Error Message */ "Unable to create character."), vecSelDlgItems); + UiErrorOkDialog(_(/* TRANSLATORS: Error Message */ "Unable to create character.").c_str(), vecSelDlgItems); } memset(selhero_heroInfo.name, '\0', sizeof(selhero_heroInfo.name)); @@ -432,36 +433,36 @@ void selhero_Init() vecSelHeroDialog.push_back(std::move(heroImg)); SDL_Rect rect3 = { (Sint16)(PANEL_LEFT + 39), (Sint16)(UI_OFFSET_Y + 323), 110, 21 }; - vecSelHeroDialog.push_back(std::make_unique(_("Level:"), rect3, UiFlags::AlignRight | UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); + vecSelHeroDialog.push_back(std::make_unique(_("Level:").c_str(), rect3, UiFlags::AlignRight | UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); SDL_Rect rect4 = { (Sint16)(PANEL_LEFT + 39), (Sint16)(UI_OFFSET_Y + 323), 110, 21 }; - vecSelHeroDialog.push_back(std::make_unique(_("Level:"), rect4, UiFlags::AlignRight | UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); + vecSelHeroDialog.push_back(std::make_unique(_("Level:").c_str(), rect4, UiFlags::AlignRight | UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); SDL_Rect rect5 = { (Sint16)(PANEL_LEFT + 159), (Sint16)(UI_OFFSET_Y + 323), 40, 21 }; vecSelHeroDialog.push_back(std::make_unique(textStats[0], rect5, UiFlags::AlignCenter | UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); SDL_Rect rect6 = { (Sint16)(PANEL_LEFT + 39), (Sint16)(UI_OFFSET_Y + 358), 110, 21 }; - vecSelHeroDialog.push_back(std::make_unique(_("Strength:"), rect6, UiFlags::AlignRight | UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); + vecSelHeroDialog.push_back(std::make_unique(_("Strength:").c_str(), rect6, UiFlags::AlignRight | UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); SDL_Rect rect7 = { (Sint16)(PANEL_LEFT + 159), (Sint16)(UI_OFFSET_Y + 358), 40, 21 }; vecSelHeroDialog.push_back(std::make_unique(textStats[1], rect7, UiFlags::AlignCenter | UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); SDL_Rect rect8 = { (Sint16)(PANEL_LEFT + 39), (Sint16)(UI_OFFSET_Y + 380), 110, 21 }; - vecSelHeroDialog.push_back(std::make_unique(_("Magic:"), rect8, UiFlags::AlignRight | UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); + vecSelHeroDialog.push_back(std::make_unique(_("Magic:").c_str(), rect8, UiFlags::AlignRight | UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); SDL_Rect rect9 = { (Sint16)(PANEL_LEFT + 159), (Sint16)(UI_OFFSET_Y + 380), 40, 21 }; vecSelHeroDialog.push_back(std::make_unique(textStats[2], rect9, UiFlags::AlignCenter | UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); SDL_Rect rect10 = { (Sint16)(PANEL_LEFT + 39), (Sint16)(UI_OFFSET_Y + 401), 110, 21 }; - vecSelHeroDialog.push_back(std::make_unique(_("Dexterity:"), rect10, UiFlags::AlignRight | UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); + vecSelHeroDialog.push_back(std::make_unique(_("Dexterity:").c_str(), rect10, UiFlags::AlignRight | UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); SDL_Rect rect11 = { (Sint16)(PANEL_LEFT + 159), (Sint16)(UI_OFFSET_Y + 401), 40, 21 }; vecSelHeroDialog.push_back(std::make_unique(textStats[3], rect11, UiFlags::AlignCenter | UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); SDL_Rect rect12 = { (Sint16)(PANEL_LEFT + 39), (Sint16)(UI_OFFSET_Y + 422), 110, 21 }; - vecSelHeroDialog.push_back(std::make_unique(_("Vitality:"), rect12, UiFlags::AlignRight | UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); + vecSelHeroDialog.push_back(std::make_unique(_("Vitality:").c_str(), rect12, UiFlags::AlignRight | UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); SDL_Rect rect13 = { (Sint16)(PANEL_LEFT + 159), (Sint16)(UI_OFFSET_Y + 422), 40, 21 }; vecSelHeroDialog.push_back(std::make_unique(textStats[4], rect13, UiFlags::AlignCenter | UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); #if _DEBUG SDL_Rect rect14 = { (Sint16)(PANEL_LEFT + 39), (Sint16)(UI_OFFSET_Y + 443), 110, 21 }; - vecSelHeroDialog.push_back(std::make_unique(_("Savegame:"), rect14, UiFlags::AlignRight | UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); + vecSelHeroDialog.push_back(std::make_unique(_("Savegame:").c_str(), rect14, UiFlags::AlignRight | UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); SDL_Rect rect15 = { (Sint16)(PANEL_LEFT + 159), (Sint16)(UI_OFFSET_Y + 443), 40, 21 }; vecSelHeroDialog.push_back(std::make_unique(textStats[5], rect15, UiFlags::AlignCenter | UiFlags::FontSize12 | UiFlags::ColorUiSilverDark)); #endif @@ -473,7 +474,7 @@ void selhero_List_Init() vecSelDlgItems.clear(); SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 264), (Sint16)(UI_OFFSET_Y + 211), 320, 33 }; - vecSelDlgItems.push_back(std::make_unique(_("Select Hero"), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); + vecSelDlgItems.push_back(std::make_unique(_("Select Hero").c_str(), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); vecSelHeroDlgItems.clear(); for (std::size_t i = 0; i < selhero_SaveCount; i++) { @@ -481,7 +482,7 @@ void selhero_List_Init() if (selhero_heros[i].saveNumber == selhero_heroInfo.saveNumber) selectedItem = i; } - vecSelHeroDlgItems.push_back(std::make_unique(_("New Hero"), static_cast(selhero_SaveCount))); + vecSelHeroDlgItems.push_back(std::make_unique(_("New Hero").c_str(), static_cast(selhero_SaveCount))); vecSelDlgItems.push_back(std::make_unique(vecSelHeroDlgItems, 6, PANEL_LEFT + 265, (UI_OFFSET_Y + 256), 320, 26, UiFlags::AlignCenter | UiFlags::FontSize24 | UiFlags::ColorUiGold)); @@ -501,9 +502,9 @@ void selhero_List_Init() UiInitList(SelheroListFocus, SelheroListSelect, SelheroListEsc, vecSelDlgItems, false, nullptr, SelheroListDeleteYesNo, selectedItem); if (selhero_isMultiPlayer) { - title = _("Multi Player Characters"); + title = _("Multi Player Characters").c_str(); } else { - title = _("Single Player Characters"); + title = _("Single Player Characters").c_str(); } } @@ -551,9 +552,9 @@ static void UiSelHeroDialog( char dialogTitle[128]; char dialogText[256]; if (selhero_isMultiPlayer) { - strcpy(dialogTitle, _("Delete Multi Player Hero")); + CopyUtf8(dialogTitle, _("Delete Multi Player Hero"), sizeof(dialogTitle)); } else { - strcpy(dialogTitle, _("Delete Single Player Hero")); + CopyUtf8(dialogTitle, _("Delete Single Player Hero"), sizeof(dialogTitle)); } strcpy(dialogText, fmt::format(_("Are you sure you want to delete the character \"{:s}\"?"), selhero_heroInfo.name).c_str()); diff --git a/Source/DiabloUI/selok.cpp b/Source/DiabloUI/selok.cpp index 63a37e4b6..44c5733e7 100644 --- a/Source/DiabloUI/selok.cpp +++ b/Source/DiabloUI/selok.cpp @@ -4,6 +4,7 @@ #include "control.h" #include "engine/render/text_render.hpp" #include "utils/language.h" +#include "utils/utf8.hpp" namespace devilution { @@ -68,7 +69,7 @@ void UiSelOkDialog(const char *title, const char *body, bool background) vecSelOkDialogItems.push_back(std::make_unique(_("OK"), 0)); vecSelOkDialog.push_back(std::make_unique(vecSelOkDialogItems, 1, PANEL_LEFT + 230, (UI_OFFSET_Y + 390), 180, 35, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiGold)); - strcpy(dialogText, WordWrapString(body, MESSAGE_WIDTH, GameFont24).c_str()); + CopyUtf8(dialogText, WordWrapString(body, MESSAGE_WIDTH, GameFont24), sizeof(dialogText)); UiInitList(nullptr, selok_Select, selok_Esc, vecSelOkDialog, false); diff --git a/Source/DiabloUI/selyesno.cpp b/Source/DiabloUI/selyesno.cpp index b126de724..091d817e2 100644 --- a/Source/DiabloUI/selyesno.cpp +++ b/Source/DiabloUI/selyesno.cpp @@ -3,6 +3,7 @@ #include "DiabloUI/diabloui.h" #include "control.h" #include "utils/language.h" +#include "utils/utf8.hpp" namespace devilution { namespace { @@ -55,7 +56,7 @@ bool UiSelHeroYesNoDialog(const char *title, const char *body) vecSelYesNoDialogItems.push_back(std::make_unique(_("No"), 1)); vecSelYesNoDialog.push_back(std::make_unique(vecSelYesNoDialogItems, vecSelYesNoDialogItems.size(), PANEL_LEFT + 230, (UI_OFFSET_Y + 390), 180, 35, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiGold)); - strcpy(selyesno_confirmationMessage, WordWrapString(body, MESSAGE_WIDTH, GameFont24).c_str()); + CopyUtf8(selyesno_confirmationMessage, WordWrapString(body, MESSAGE_WIDTH, GameFont24), sizeof(selyesno_confirmationMessage)); UiInitList(nullptr, SelyesnoSelect, SelyesnoEsc, vecSelYesNoDialog, true); diff --git a/Source/DiabloUI/settingsmenu.cpp b/Source/DiabloUI/settingsmenu.cpp index 00405b1a3..27ff88408 100644 --- a/Source/DiabloUI/settingsmenu.cpp +++ b/Source/DiabloUI/settingsmenu.cpp @@ -256,8 +256,8 @@ void UiSettingsMenu() optionDescription[0] = '\0'; - const char *titleText = shownMenu == ShownMenuType::Settings ? _("Settings") : selectedOption->GetName().data(); - vecDialog.push_back(std::make_unique(titleText, MakeSdlRect(PANEL_LEFT, UI_OFFSET_Y + 161, PANEL_WIDTH, 35), UiFlags::FontSize30 | UiFlags::ColorUiSilver | UiFlags::AlignCenter, 8)); + string_view titleText = shownMenu == ShownMenuType::Settings ? _("Settings") : selectedOption->GetName(); + vecDialog.push_back(std::make_unique(titleText.data(), MakeSdlRect(PANEL_LEFT, UI_OFFSET_Y + 161, PANEL_WIDTH, 35), UiFlags::FontSize30 | UiFlags::ColorUiSilver | UiFlags::AlignCenter, 8)); vecDialog.push_back(std::make_unique(&ArtScrollBarBackground, &ArtScrollBarThumb, &ArtScrollBarArrow, MakeSdlRect(rectList.position.x + rectList.size.width + 5, rectList.position.y, 25, rectList.size.height))); vecDialog.push_back(std::make_unique(optionDescription, MakeSdlRect(rectDescription), UiFlags::FontSize12 | UiFlags::ColorUiSilverDark | UiFlags::AlignCenter, 1, IsSmallFontTall() ? 22 : 18)); @@ -276,7 +276,7 @@ void UiSettingsMenu() if (catCount > 0) vecDialogItems.push_back(std::make_unique("", static_cast(SpecialMenuEntry::None), UiFlags::ElementDisabled)); catCount += 1; - vecDialogItems.push_back(std::make_unique(pCategory->GetName().data(), static_cast(SpecialMenuEntry::None), UiFlags::ColorWhitegold | UiFlags::ElementDisabled)); + vecDialogItems.push_back(std::make_unique(pCategory->GetName(), static_cast(SpecialMenuEntry::None), UiFlags::ColorWhitegold | UiFlags::ElementDisabled)); categoryCreated = true; } if (selectedOption == pEntry) @@ -284,7 +284,7 @@ void UiSettingsMenu() auto formatArgs = CreateDrawStringFormatArgForEntry(pEntry); if (NeedsTwoLinesToDisplayOption(formatArgs)) { vecDialogItems.push_back(std::make_unique("{}:", formatArgs, vecOptions.size(), UiFlags::ColorUiGold | UiFlags::NeedsNextElement)); - vecDialogItems.push_back(std::make_unique(pEntry->GetValueDescription().data(), vecOptions.size(), UiFlags::ColorUiSilver | UiFlags::ElementDisabled)); + vecDialogItems.push_back(std::make_unique(pEntry->GetValueDescription(), vecOptions.size(), UiFlags::ColorUiSilver | UiFlags::ElementDisabled)); } else { vecDialogItems.push_back(std::make_unique("{}: {}", formatArgs, vecOptions.size(), UiFlags::ColorUiGold)); } @@ -295,14 +295,14 @@ void UiSettingsMenu() case ShownMenuType::ListOption: { auto *pOptionList = static_cast(selectedOption); for (size_t i = 0; i < pOptionList->GetListSize(); i++) { - vecDialogItems.push_back(std::make_unique(pOptionList->GetListDescription(i).data(), i, UiFlags::ColorUiGold)); + vecDialogItems.push_back(std::make_unique(pOptionList->GetListDescription(i), i, UiFlags::ColorUiGold)); } itemToSelect = pOptionList->GetActiveListIndex(); UpdateDescription(*pOptionList); } break; case ShownMenuType::KeyInput: { vecDialogItems.push_back(std::make_unique(_("Bound key:"), static_cast(SpecialMenuEntry::None), UiFlags::ColorWhitegold | UiFlags::ElementDisabled)); - vecDialogItems.push_back(std::make_unique(selectedOption->GetValueDescription().data(), static_cast(SpecialMenuEntry::None), UiFlags::ColorUiGold)); + vecDialogItems.push_back(std::make_unique(selectedOption->GetValueDescription(), static_cast(SpecialMenuEntry::None), UiFlags::ColorUiGold)); assert(IndexKeyInput == vecDialogItems.size() - 1); itemToSelect = IndexKeyInput; eventHandler = [](SDL_Event &event) { diff --git a/Source/DiabloUI/title.cpp b/Source/DiabloUI/title.cpp index 312b1ca23..4ca3c22b5 100644 --- a/Source/DiabloUI/title.cpp +++ b/Source/DiabloUI/title.cpp @@ -43,7 +43,7 @@ void UiTitleDialog() UiAddLogo(&vecTitleScreen, LOGO_BIG, 182); SDL_Rect rect = { (Sint16)(PANEL_LEFT), (Sint16)(UI_OFFSET_Y + 410), 640, 26 }; - vecTitleScreen.push_back(std::make_unique(_("Copyright © 1996-2001 Blizzard Entertainment"), rect, UiFlags::AlignCenter | UiFlags::FontSize24 | UiFlags::ColorUiSilver)); + vecTitleScreen.push_back(std::make_unique(_("Copyright © 1996-2001 Blizzard Entertainment").c_str(), rect, UiFlags::AlignCenter | UiFlags::FontSize24 | UiFlags::ColorUiSilver)); } TitleLoad(); diff --git a/Source/DiabloUI/ui_item.h b/Source/DiabloUI/ui_item.h index 7d794b77f..88ffdf182 100644 --- a/Source/DiabloUI/ui_item.h +++ b/Source/DiabloUI/ui_item.h @@ -262,7 +262,7 @@ public: class UiText : public UiItemBase { public: - UiText(const char *text, SDL_Rect rect, UiFlags flags = UiFlags::ColorDialogWhite) + UiText(string_view text, SDL_Rect rect, UiFlags flags = UiFlags::ColorDialogWhite) : UiItemBase(UiType::Text, rect, flags) , text_(text) { @@ -274,7 +274,7 @@ public: } private: - const char *text_; + string_view text_; }; //============================================================================= @@ -344,14 +344,14 @@ private: class UiListItem { public: - UiListItem(const char *text = "", int value = 0, UiFlags uiFlags = UiFlags::None) + UiListItem(string_view text = "", int value = 0, UiFlags uiFlags = UiFlags::None) : m_text(text) , m_value(value) , uiFlags(uiFlags) { } - UiListItem(const char *text, std::vector &args, int value = 0, UiFlags uiFlags = UiFlags::None) + UiListItem(string_view text, std::vector &args, int value = 0, UiFlags uiFlags = UiFlags::None) : m_text(text) , args(args) , m_value(value) @@ -360,7 +360,7 @@ public: } // private: - const char *m_text; + string_view m_text; std::vector args; int m_value; UiFlags uiFlags; diff --git a/Source/appfat.cpp b/Source/appfat.cpp index 27e1db007..b2c608199 100644 --- a/Source/appfat.cpp +++ b/Source/appfat.cpp @@ -35,7 +35,7 @@ void MsgBox(const char *pszFmt, va_list va) vsnprintf(text, sizeof(text), pszFmt, va); - UiErrorOkDialog(_("Error"), text); + UiErrorOkDialog(_("Error").c_str(), text); } /** @@ -93,44 +93,33 @@ void assert_fail(int nLineNo, const char *pszFile, const char *pszFail) } #endif -void ErrDlg(const char *title, const char *error, const char *logFilePath, int logLineNr) +void ErrDlg(const char *title, string_view error, string_view logFilePath, int logLineNr) { - char text[1024]; - FreeDlg(); - strcpy(text, fmt::format(_(/* TRANSLATORS: Error message that displays relevant information for bug report */ "{:s}\n\nThe error occurred at: {:s} line {:d}"), error, logFilePath, logLineNr).c_str()); + std::string text = fmt::format(_(/* TRANSLATORS: Error message that displays relevant information for bug report */ "{:s}\n\nThe error occurred at: {:s} line {:d}"), error, logFilePath, logLineNr); - UiErrorOkDialog(title, text); + UiErrorOkDialog(title, text.c_str()); app_fatal(nullptr); } -void InsertCDDlg(const char *archiveName) +void InsertCDDlg(string_view archiveName) { - char text[1024]; - - snprintf( - text, - sizeof(text), - "%s", - fmt::format( - _("Unable to open main data archive ({:s}).\n" - "\n" - "Make sure that it is in the game folder."), - archiveName) - .c_str()); - - UiErrorOkDialog(_("Data File Error"), text); + std::string text = fmt::format( + _("Unable to open main data archive ({:s}).\n" + "\n" + "Make sure that it is in the game folder."), + archiveName); + + UiErrorOkDialog(_("Data File Error").c_str(), text.c_str()); app_fatal(nullptr); } -void DirErrorDlg(const char *error) +void DirErrorDlg(string_view error) { - char text[1024]; - - strcpy(text, fmt::format(_(/* TRANSLATORS: Error when Program is not allowed to write data */ "Unable to write to location:\n{:s}"), error).c_str()); + std::string text = fmt::format(_(/* TRANSLATORS: Error when Program is not allowed to write data */ "Unable to write to location:\n{:s}"), error); - UiErrorOkDialog(_("Read-Only Directory Error"), text); + UiErrorOkDialog(_("Read-Only Directory Error").c_str(), text.c_str()); app_fatal(nullptr); } diff --git a/Source/appfat.h b/Source/appfat.h index 8ad743eb3..dda125ea2 100644 --- a/Source/appfat.h +++ b/Source/appfat.h @@ -8,6 +8,7 @@ #include #include "utils/attributes.h" +#include "utils/stdcompat/string_view.hpp" namespace devilution { @@ -49,16 +50,16 @@ void DrawDlg(const char *pszFmt, ...) DVL_PRINTF_ATTRIBUTE(1, 2); /** * @brief Terminates the game and displays an error dialog box based on the given dialog_id. */ -[[noreturn]] void ErrDlg(const char *title, const char *error, const char *logFilePath, int logLineNr); +[[noreturn]] void ErrDlg(const char *title, string_view error, string_view logFilePath, int logLineNr); /** * @brief Terminates the game with an insert CD error dialog. */ -[[noreturn]] void InsertCDDlg(const char *archiveName); +[[noreturn]] void InsertCDDlg(string_view archiveName); /** * @brief Terminates the game with a read-only directory error dialog. */ -[[noreturn]] void DirErrorDlg(const char *error); +[[noreturn]] void DirErrorDlg(string_view error); } // namespace devilution diff --git a/Source/automap.cpp b/Source/automap.cpp index 238e57a08..d0a1afa51 100644 --- a/Source/automap.cpp +++ b/Source/automap.cpp @@ -477,21 +477,24 @@ void DrawAutomapPlr(const Surface &out, const Displacement &myPlayerOffset, int */ void DrawAutomapText(const Surface &out) { - char desc[256]; Point linePosition { 8, 8 }; if (gbIsMultiplayer) { if (strcasecmp("0.0.0.0", szPlayerName) != 0) { - strcat(strcpy(desc, _("Game: ")), szPlayerName); - DrawString(out, desc, linePosition); + std::string description = _("Game: "); + description.append(szPlayerName); + DrawString(out, description, linePosition); linePosition.y += 15; } - if (!PublicGame) - strcat(strcpy(desc, _("Password: ")), szPlayerDescript); - else - strcpy(desc, _("Public Game")); - DrawString(out, desc, linePosition); + std::string description; + if (!PublicGame) { + description = _("Password: "); + description.append(szPlayerDescript); + } else { + description = _("Public Game"); + } + DrawString(out, description, linePosition); linePosition.y += 15; } @@ -501,15 +504,16 @@ void DrawAutomapText(const Surface &out) } if (currlevel != 0) { + std::string description; if (currlevel >= 17 && currlevel <= 20) { - strcpy(desc, fmt::format(_("Level: Nest {:d}"), currlevel - 16).c_str()); + description = fmt::format(_("Level: Nest {:d}"), currlevel - 16); } else if (currlevel >= 21 && currlevel <= 24) { - strcpy(desc, fmt::format(_("Level: Crypt {:d}"), currlevel - 20).c_str()); + description = fmt::format(_("Level: Crypt {:d}"), currlevel - 20); } else { - strcpy(desc, fmt::format(_("Level: {:d}"), currlevel).c_str()); + description = fmt::format(_("Level: {:d}"), currlevel); } - DrawString(out, desc, linePosition); + DrawString(out, description, linePosition); linePosition.y += 15; } string_view difficulty; @@ -524,8 +528,9 @@ void DrawAutomapText(const Surface &out) difficulty = _("Hell"); break; } - CopyUtf8(desc, fmt::format(_(/* TRANSLATORS: {:s} means: Game Difficulty. */ "Difficulty: {:s}"), difficulty), sizeof(desc)); - DrawString(out, desc, linePosition); + + std::string description = fmt::format(_(/* TRANSLATORS: {:s} means: Game Difficulty. */ "Difficulty: {:s}"), difficulty); + DrawString(out, description, linePosition); } std::unique_ptr LoadAutomapData(size_t &tileCount) diff --git a/Source/capture.cpp b/Source/capture.cpp index 522454631..60bef06cc 100644 --- a/Source/capture.cpp +++ b/Source/capture.cpp @@ -183,7 +183,7 @@ void CaptureScreen() if (!success) { Log("Failed to save screenshot at {}", fileName); - RemoveFile(fileName.c_str()); + RemoveFile(fileName); } else { Log("Screenshot saved at {}", fileName); } diff --git a/Source/control.cpp b/Source/control.cpp index 917befd96..f802aae78 100644 --- a/Source/control.cpp +++ b/Source/control.cpp @@ -130,7 +130,7 @@ std::optional pPanelButtons; bool PanelButtons[8]; int PanelButtonIndex; -char TalkSave[8][80]; +char TalkSave[8][MAX_SEND_STR_LEN]; uint8_t TalkSaveIndex; uint8_t NextTalkSave; char TalkMessage[MAX_SEND_STR_LEN]; @@ -694,12 +694,12 @@ void CheckPanelInfo() int yend = PanBtnPos[i].y + mainPanelPosition.y + PanBtnPos[i].h; if (MousePosition.x >= PanBtnPos[i].x + mainPanelPosition.x && MousePosition.x <= xend && MousePosition.y >= PanBtnPos[i].y + mainPanelPosition.y && MousePosition.y <= yend) { if (i != 7) { - strcpy(infostr, _(PanBtnStr[i])); + CopyUtf8(infostr, _(PanBtnStr[i]), sizeof(infostr)); } else { if (gbFriendlyMode) - strcpy(infostr, _("Player friendly")); + CopyUtf8(infostr, _("Player friendly"), sizeof(infostr)); else - strcpy(infostr, _("Player attack")); + CopyUtf8(infostr, _("Player attack"), sizeof(infostr)); } if (PanBtnHotKey[i] != nullptr) { AddPanelString(fmt::format(_("Hotkey: {:s}"), _(PanBtnHotKey[i]))); @@ -709,7 +709,7 @@ void CheckPanelInfo() } } if (!spselflag && MousePosition.x >= 565 + mainPanelPosition.x && MousePosition.x < 621 + mainPanelPosition.x && MousePosition.y >= 64 + mainPanelPosition.y && MousePosition.y < 120 + mainPanelPosition.y) { - strcpy(infostr, _("Select current spell button")); + CopyUtf8(infostr, _("Select current spell button"), sizeof(infostr)); InfoColor = UiFlags::ColorWhite; panelflag = true; AddPanelString(_("Hotkey: 's'")); @@ -880,7 +880,7 @@ void DrawInfoBox(const Surface &out) if (leveltype != DTYPE_TOWN) { const auto &monster = Monsters[pcursmonst]; InfoColor = UiFlags::ColorWhite; - strcpy(infostr, monster.mName); + CopyUtf8(infostr, monster.mName, sizeof(infostr)); ClearPanel(); if (monster._uniqtype != 0) { InfoColor = UiFlags::ColorWhitegold; diff --git a/Source/controls/modifier_hints.cpp b/Source/controls/modifier_hints.cpp index ee0d1a43e..5e54f075d 100644 --- a/Source/controls/modifier_hints.cpp +++ b/Source/controls/modifier_hints.cpp @@ -175,7 +175,8 @@ void InitModifierHints() if (hintBox.surface == nullptr || hintBoxBackground.surface == nullptr) { app_fatal("%s", _("Failed to load UI resources.\n" "\n" - "Make sure devilutionx.mpq is in the game folder and that it is up to date.")); + "Make sure devilutionx.mpq is in the game folder and that it is up to date.") + .c_str()); } } diff --git a/Source/cursor.cpp b/Source/cursor.cpp index acac8b92d..6b27aeb90 100644 --- a/Source/cursor.cpp +++ b/Source/cursor.cpp @@ -24,6 +24,7 @@ #include "trigs.h" #include "utils/attributes.h" #include "utils/language.h" +#include "utils/utf8.hpp" namespace devilution { namespace { @@ -216,7 +217,7 @@ void CheckTown() if (EntranceBoundaryContains(missile.position.tile, cursPosition)) { trigflag = true; ClearPanel(); - strcpy(infostr, _("Town Portal")); + CopyUtf8(infostr, _("Town Portal"), sizeof(infostr)); AddPanelString(fmt::format(_("from {:s}"), Players[missile._misource]._pName)); cursPosition = missile.position.tile; } @@ -231,7 +232,7 @@ void CheckRportal() if (EntranceBoundaryContains(missile.position.tile, cursPosition)) { trigflag = true; ClearPanel(); - strcpy(infostr, _("Portal to")); + CopyUtf8(infostr, _("Portal to"), sizeof(infostr)); AddPanelString(!setlevel ? _("The Unholy Altar") : _("level 15")); cursPosition = missile.position.tile; } diff --git a/Source/diablo.cpp b/Source/diablo.cpp index 727889a72..b490d57b4 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -818,30 +818,30 @@ void RunGameLoop(interface_mode uMsg) [[noreturn]] void PrintHelpAndExit() { - printInConsole("%s", _(/* TRANSLATORS: Commandline Option */ "Options:\n")); - printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "-h, --help", _("Print this message and exit")); - printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--version", _("Print the version and exit")); - printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--data-dir", _("Specify the folder of diabdat.mpq")); - printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--save-dir", _("Specify the folder of save files")); - printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--config-dir", _("Specify the location of diablo.ini")); - printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "-n", _("Skip startup videos")); - printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "-f", _("Display frames per second")); - printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--verbose", _("Enable verbose logging")); - printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--record <#>", _("Record a demo file")); - printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--demo <#>", _("Play a demo file")); - printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--timedemo", _("Disable all frame limiting during demo playback")); - printInConsole("%s", _(/* TRANSLATORS: Commandline Option */ "\nGame selection:\n")); - printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--spawn", _("Force Shareware mode")); - printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--diablo", _("Force Diablo mode")); - printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--hellfire", _("Force Hellfire mode")); - printInConsole("%s", _(/* TRANSLATORS: Commandline Option */ "\nHellfire options:\n")); - printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--nestart", _("Use alternate nest palette")); + printInConsole("%s", _(/* TRANSLATORS: Commandline Option */ "Options:\n").c_str()); + printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "-h, --help", _("Print this message and exit").c_str()); + printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--version", _("Print the version and exit").c_str()); + printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--data-dir", _("Specify the folder of diabdat.mpq").c_str()); + printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--save-dir", _("Specify the folder of save files").c_str()); + printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--config-dir", _("Specify the location of diablo.ini").c_str()); + printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "-n", _("Skip startup videos").c_str()); + printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "-f", _("Display frames per second").c_str()); + printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--verbose", _("Enable verbose logging").c_str()); + printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--record <#>", _("Record a demo file").c_str()); + printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--demo <#>", _("Play a demo file").c_str()); + printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--timedemo", _("Disable all frame limiting during demo playback").c_str()); + printInConsole("%s", _(/* TRANSLATORS: Commandline Option */ "\nGame selection:\n").c_str()); + printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--spawn", _("Force Shareware mode").c_str()); + printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--diablo", _("Force Diablo mode").c_str()); + printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--hellfire", _("Force Hellfire mode").c_str()); + printInConsole("%s", _(/* TRANSLATORS: Commandline Option */ "\nHellfire options:\n").c_str()); + printInConsole(" %-20s %-30s\n", /* TRANSLATORS: Commandline Option */ "--nestart", _("Use alternate nest palette").c_str()); #ifdef _DEBUG printInConsole("\nDebug options:\n"); printInConsole(" %-20s %-30s\n", "-i", "Ignore network timeout"); printInConsole(" %-20s %-30s\n", "+", "Pass commands to the engine"); #endif - printInConsole("%s", _("\nReport bugs at https://github.com/diasurgical/devilutionX/\n")); + printInConsole("%s", _("\nReport bugs at https://github.com/diasurgical/devilutionX/\n").c_str()); diablo_quit(0); } diff --git a/Source/discord/discord.cpp b/Source/discord/discord.cpp index 9a1fc90e2..d7efc1703 100644 --- a/Source/discord/discord.cpp +++ b/Source/discord/discord.cpp @@ -64,9 +64,11 @@ std::string GetLocationString() // Dungeon Name constexpr std::array DungeonStrs = { N_("Town"), N_("Cathedral"), N_("Catacombs"), N_("Caves"), N_("Hell"), N_("Nest"), N_("Crypt") }; - const char *dungeonStr = _(/* TRANSLATORS: type of dungeon (i.e. Cathedral, Caves)*/ "None"); + std::string dungeonStr; if (tracked_data.dungeonArea != DTYPE_NONE) { dungeonStr = _(DungeonStrs[tracked_data.dungeonArea]); + } else { + dungeonStr = _(/* TRANSLATORS: type of dungeon (i.e. Cathedral, Caves)*/ "None"); } // Dungeon Level @@ -96,7 +98,7 @@ std::string GetDetailString() std::string GetStateString() { constexpr std::array DifficultyStrs = { N_("Normal"), N_("Nightmare"), N_("Hell") }; - const char *difficultyStr = _(DifficultyStrs[sgGameInitInfo.nDifficulty]); + std::string difficultyStr = _(DifficultyStrs[sgGameInitInfo.nDifficulty]); return fmt::format(_(/* TRANSLATORS: Discord state i.e. "Nightmare difficulty" */ "{} difficulty"), difficultyStr); } @@ -177,7 +179,7 @@ void UpdateMenu(bool forced) discord::Activity activity = {}; activity.SetName(PROJECT_NAME); - activity.SetState(_(/* TRANSLATORS: Discord activity, not in game */ "In Menu")); + activity.SetState(_(/* TRANSLATORS: Discord activity, not in game */ "In Menu").c_str()); activity.GetTimestamps().SetStart(start_time); diff --git a/Source/dvlnet/tcp_client.cpp b/Source/dvlnet/tcp_client.cpp index b6b5ec593..6675cef58 100644 --- a/Source/dvlnet/tcp_client.cpp +++ b/Source/dvlnet/tcp_client.cpp @@ -62,7 +62,7 @@ int tcp_client::join(std::string addrstr) } } if (plr_self == PLR_BROADCAST) { - SDL_SetError("%s", _("Unable to connect")); + SDL_SetError("%s", _("Unable to connect").c_str()); return -1; } diff --git a/Source/error.cpp b/Source/error.cpp index e4b1e1ed0..c7f61348b 100644 --- a/Source/error.cpp +++ b/Source/error.cpp @@ -168,7 +168,7 @@ void DrawDiabloMsg(const Surface &out) auto message = DiabloMessages.front(); int lineNumber = 0; for (auto &line : TextLines) { - DrawString(out, line.c_str(), { { PANEL_X + 109, dialogStartY + 12 + lineNumber * LineHeight }, { LineWidth, LineHeight } }, UiFlags::AlignCenter, 1, LineHeight); + DrawString(out, line, { { PANEL_X + 109, dialogStartY + 12 + lineNumber * LineHeight }, { LineWidth, LineHeight } }, UiFlags::AlignCenter, 1, LineHeight); lineNumber += 1; } diff --git a/Source/gamemenu.cpp b/Source/gamemenu.cpp index c48ea94d1..8aff3aebb 100644 --- a/Source/gamemenu.cpp +++ b/Source/gamemenu.cpp @@ -156,19 +156,19 @@ void GamemenuGetSpeed() if (gbIsMultiplayer) { sgOptionsMenu[3].dwFlags &= ~(GMENU_ENABLED | GMENU_SLIDER); if (sgGameInitInfo.nTickRate >= 50) - sgOptionsMenu[3].pszStr = _("Speed: Fastest"); + sgOptionsMenu[3].pszStr = _("Speed: Fastest").c_str(); else if (sgGameInitInfo.nTickRate >= 40) - sgOptionsMenu[3].pszStr = _("Speed: Faster"); + sgOptionsMenu[3].pszStr = _("Speed: Faster").c_str(); else if (sgGameInitInfo.nTickRate >= 30) - sgOptionsMenu[3].pszStr = _("Speed: Fast"); + sgOptionsMenu[3].pszStr = _("Speed: Fast").c_str(); else if (sgGameInitInfo.nTickRate == 20) - sgOptionsMenu[3].pszStr = _("Speed: Normal"); + sgOptionsMenu[3].pszStr = _("Speed: Normal").c_str(); return; } sgOptionsMenu[3].dwFlags |= GMENU_ENABLED | GMENU_SLIDER; - sgOptionsMenu[3].pszStr = _("Speed"); + sgOptionsMenu[3].pszStr = _("Speed").c_str(); gmenu_slider_steps(&sgOptionsMenu[3], 46); gmenu_slider_set(&sgOptionsMenu[3], 20, 50, sgGameInitInfo.nTickRate); } diff --git a/Source/help.cpp b/Source/help.cpp index e468f6e95..11e4dbff8 100644 --- a/Source/help.cpp +++ b/Source/help.cpp @@ -172,7 +172,7 @@ void DrawHelp(const Surface &out) const int lineHeight = LineHeight(); const int blankLineHeight = BlankLineHeight(); - const char *title; + string_view title; if (gbIsHellfire) title = gbIsSpawn ? _("Shareware Hellfire Help") : _("Hellfire Help"); else diff --git a/Source/init.cpp b/Source/init.cpp index b7f955248..afff38a93 100644 --- a/Source/init.cpp +++ b/Source/init.cpp @@ -213,7 +213,7 @@ void LoadGameArchives() hfvoice_mpq = LoadMPQ(paths, "hfvoice.mpq"); if (gbIsHellfire && (!hfmonk_mpq || !hfmusic_mpq || !hfvoice_mpq)) { - UiErrorOkDialog(_("Some Hellfire MPQs are missing"), _("Not all Hellfire MPQs were found.\nPlease copy all the hf*.mpq files.")); + UiErrorOkDialog(_("Some Hellfire MPQs are missing").c_str(), _("Not all Hellfire MPQs were found.\nPlease copy all the hf*.mpq files.").c_str()); app_fatal(nullptr); } } @@ -221,7 +221,7 @@ void LoadGameArchives() void init_create_window() { if (!SpawnWindow(PROJECT_NAME)) - app_fatal("%s", _("Unable to create main window")); + app_fatal("%s", _("Unable to create main window").c_str()); dx_init(); gbActive = true; #ifndef USE_SDL1 diff --git a/Source/items.cpp b/Source/items.cpp index 8810635c5..bb2046369 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -657,8 +657,9 @@ void GetBookSpell(Item &item, int lvl) if (s == maxSpells) s = 1; } - strcat(item._iName, pgettext("spell", spelldata[bs].sNameText)); - strcat(item._iIName, pgettext("spell", spelldata[bs].sNameText)); + std::string spellName = pgettext("spell", spelldata[bs].sNameText); + CopyUtf8(item._iName, std::string(item._iName + spellName), sizeof(item._iIName)); + CopyUtf8(item._iIName, std::string(item._iIName + spellName), sizeof(item._iIName)); item._iSpell = bs; item._iMinMag = spelldata[bs].sMinInt; item._ivalue += spelldata[bs].sBookCost; @@ -1126,10 +1127,10 @@ void GetStaffPower(Item &item, int lvl, int bs, bool onlygood) } } - const char *baseName = _(AllItemsList[item.IDidx].iName); - const char *shortName = _(AllItemsList[item.IDidx].iSName); - const char *spellName = pgettext("spell", spelldata[bs].sNameText); - const char *normalFmt = pgettext("spell", /* TRANSLATORS: Constructs item names. Format: {Item} of {Spell}. Example: War Staff of Firewall */ "{0} of {1}"); + string_view baseName = _(AllItemsList[item.IDidx].iName); + string_view shortName = _(AllItemsList[item.IDidx].iSName); + string_view spellName = pgettext("spell", spelldata[bs].sNameText); + string_view normalFmt = pgettext("spell", /* TRANSLATORS: Constructs item names. Format: {Item} of {Spell}. Example: War Staff of Firewall */ "{0} of {1}"); CopyUtf8(item._iName, fmt::format(normalFmt, baseName, spellName), sizeof(item._iName)); if (!StringInPanel(item._iName)) { @@ -1137,8 +1138,8 @@ void GetStaffPower(Item &item, int lvl, int bs, bool onlygood) } if (preidx != -1) { - const char *magicFmt = pgettext("spell", /* TRANSLATORS: Constructs item names. Format: {Prefix} {Item} of {Spell}. Example: King's War Staff of Firewall */ "{0} {1} of {2}"); - const char *prefixName = _(ItemPrefixes[preidx].PLName); + string_view magicFmt = pgettext("spell", /* TRANSLATORS: Constructs item names. Format: {Prefix} {Item} of {Spell}. Example: King's War Staff of Firewall */ "{0} {1} of {2}"); + string_view prefixName = _(ItemPrefixes[preidx].PLName); CopyUtf8(item._iIName, fmt::format(magicFmt, prefixName, baseName, spellName), sizeof(item._iIName)); if (!StringInPanel(item._iIName)) { CopyUtf8(item._iIName, fmt::format(magicFmt, prefixName, shortName, spellName), sizeof(item._iIName)); @@ -1155,13 +1156,13 @@ namespace { std::string GenerateMagicItemName(const string_view &baseNamel, int preidx, int sufidx) { if (preidx != -1 && sufidx != -1) { - const char *fmt = _(/* TRANSLATORS: Constructs item names. Format: {Prefix} {Item} of {Suffix}. Example: King's Long Sword of the Whale */ "{0} {1} of {2}"); + string_view fmt = _(/* TRANSLATORS: Constructs item names. Format: {Prefix} {Item} of {Suffix}. Example: King's Long Sword of the Whale */ "{0} {1} of {2}"); return fmt::format(fmt, _(ItemPrefixes[preidx].PLName), baseNamel, _(ItemSuffixes[sufidx].PLName)); } else if (preidx != -1) { - const char *fmt = _(/* TRANSLATORS: Constructs item names. Format: {Prefix} {Item}. Example: King's Long Sword */ "{0} {1}"); + string_view fmt = _(/* TRANSLATORS: Constructs item names. Format: {Prefix} {Item}. Example: King's Long Sword */ "{0} {1}"); return fmt::format(fmt, _(ItemPrefixes[preidx].PLName), baseNamel); } else if (sufidx != -1) { - const char *fmt = _(/* TRANSLATORS: Constructs item names. Format: {Item} of {Suffix}. Example: Long Sword of the Whale */ "{0} of {1}"); + string_view fmt = _(/* TRANSLATORS: Constructs item names. Format: {Item} of {Suffix}. Example: Long Sword of the Whale */ "{0} of {1}"); return fmt::format(fmt, baseNamel, _(ItemSuffixes[sufidx].PLName)); } @@ -1307,8 +1308,8 @@ void GetOilType(Item &item, int maxLvl) int8_t t = rnd[GenerateRnd(cnt)]; - strcpy(item._iName, _(OilNames[t])); - strcpy(item._iIName, _(OilNames[t])); + CopyUtf8(item._iName, _(OilNames[t]), sizeof(item._iName)); + CopyUtf8(item._iIName, _(OilNames[t]), sizeof(item._iIName)); item._iMiscId = OilMagic[t]; item._ivalue = OilValues[t]; item._iIvalue = OilValues[t]; @@ -1493,7 +1494,7 @@ void GetUniqueItem(Item &item, _unique_items uid) SaveItemPower(item, power); } - strcpy(item._iIName, _(UniqueItems[uid].UIName)); + CopyUtf8(item._iIName, _(UniqueItems[uid].UIName), sizeof(item._iIName)); item._iIvalue = UniqueItems[uid].UIValue; if (item._iMiscId == IMISC_UNIQUE) @@ -2724,8 +2725,8 @@ void InitializeItem(Item &item, int itemData) item._itype = pAllItem.itype; item._iCurs = pAllItem.iCurs; - strcpy(item._iName, _(pAllItem.iName)); - strcpy(item._iIName, _(pAllItem.iName)); + CopyUtf8(item._iName, _(pAllItem.iName), sizeof(item._iName)); + CopyUtf8(item._iIName, _(pAllItem.iName), sizeof(item._iIName)); item._iLoc = pAllItem.iLoc; item._iClass = pAllItem.iClass; item._iMinDam = pAllItem.iMinDam; @@ -2961,8 +2962,8 @@ void GetItemAttrs(Item &item, int itemData, int lvl) { item._itype = AllItemsList[itemData].itype; item._iCurs = AllItemsList[itemData].iCurs; - strcpy(item._iName, _(AllItemsList[itemData].iName)); - strcpy(item._iIName, _(AllItemsList[itemData].iName)); + CopyUtf8(item._iName, _(AllItemsList[itemData].iName), sizeof(item._iName)); + CopyUtf8(item._iIName, _(AllItemsList[itemData].iName), sizeof(item._iIName)); item._iLoc = AllItemsList[itemData].iLoc; item._iClass = AllItemsList[itemData].iClass; item._iMinDam = AllItemsList[itemData].iMinDam; diff --git a/Source/loadsave.cpp b/Source/loadsave.cpp index c36169b4c..020fb6f8a 100644 --- a/Source/loadsave.cpp +++ b/Source/loadsave.cpp @@ -1827,10 +1827,10 @@ void LoadGame(bool firstflag) LoadHelper file(OpenSaveArchive(gSaveNumber), "game"); if (!file.IsValid()) - app_fatal("%s", _("Unable to open save file archive")); + app_fatal("%s", _("Unable to open save file archive").c_str()); if (!IsHeaderValid(file.NextLE())) - app_fatal("%s", _("Invalid save file")); + app_fatal("%s", _("Invalid save file").c_str()); if (gbIsHellfireSaveGame) { giNumberOfLevels = 25; @@ -1861,7 +1861,7 @@ void LoadGame(bool firstflag) int tmpNobjects = file.NextBE(); if (!gbIsHellfire && currlevel > 17) - app_fatal("%s", _("Player is on a Hellfire only level")); + app_fatal("%s", _("Player is on a Hellfire only level").c_str()); for (uint8_t i = 0; i < giNumberOfLevels; i++) { glSeedTbl[i] = file.NextBE(); @@ -2090,7 +2090,7 @@ void SaveGameData() else if (!gbIsSpawn && !gbIsHellfire) file.WriteLE(LoadLE32("RETL")); else - app_fatal("%s", _("Invalid game state")); + app_fatal("%s", _("Invalid game state").c_str()); if (gbIsHellfire) { giNumberOfLevels = 25; @@ -2328,7 +2328,7 @@ void LoadLevel() GetPermLevelNames(szName); LoadHelper file(OpenSaveArchive(gSaveNumber), szName); if (!file.IsValid()) - app_fatal("%s", _("Unable to open save file archive")); + app_fatal("%s", _("Unable to open save file archive").c_str()); if (leveltype != DTYPE_TOWN) { for (int j = 0; j < MAXDUNY; j++) { diff --git a/Source/menu.cpp b/Source/menu.cpp index f9950c8bb..0226e413b 100644 --- a/Source/menu.cpp +++ b/Source/menu.cpp @@ -146,7 +146,7 @@ void mainmenu_loop() if (demo::IsRunning()) menu = MAINMENU_SINGLE_PLAYER; else if (!UiMainMenuDialog(gszProductName, &menu, effects_play_sound, 30)) - app_fatal("%s", _("Unable to display mainmenu")); + app_fatal("%s", _("Unable to display mainmenu").c_str()); switch (menu) { case MAINMENU_NONE: diff --git a/Source/minitext.cpp b/Source/minitext.cpp index 5a3abd306..ae89a1045 100644 --- a/Source/minitext.cpp +++ b/Source/minitext.cpp @@ -38,7 +38,7 @@ const int LineHeight = 38; std::vector TextLines; -void LoadText(const char *text) +void LoadText(string_view text) { TextLines.clear(); diff --git a/Source/monster.cpp b/Source/monster.cpp index 4c9313b1a..d72e3e549 100644 --- a/Source/monster.cpp +++ b/Source/monster.cpp @@ -33,6 +33,7 @@ #include "trigs.h" #include "utils/file_name_generator.hpp" #include "utils/language.h" +#include "utils/stdcompat/string_view.hpp" #include "utils/utf8.hpp" #ifdef _DEBUG @@ -177,7 +178,7 @@ void InitMonster(Monster &monster, Direction rd, int mtype, Point position) monster._mmode = MonsterMode::Stand; monster.MType = &LevelMonsterTypes[mtype]; monster.MData = monster.MType->MData; - monster.mName = pgettext("monster", monster.MData->mName); + monster.mName = pgettext("monster", monster.MData->mName).c_str(); monster.AnimInfo = {}; monster.ChangeAnimationData(MonsterGraphic::Stand); monster.AnimInfo.TickCounterOfCurrentFrame = GenerateRnd(monster.AnimInfo.TicksPerFrame - 1); @@ -3374,7 +3375,7 @@ void BoneDemonAi(int i) AiRangedAvoidance(i, MIS_BONEDEMON, true, 4, 0); } -const char *GetMonsterTypeText(const MonsterData &monsterData) +string_view GetMonsterTypeText(const MonsterData &monsterData) { switch (monsterData.mMonstClass) { case MonsterClass::Animal: @@ -3482,7 +3483,7 @@ void PrepareUniqueMonst(Monster &monster, int uniqindex, int miniontype, int bos } monster.mExp *= 2; - monster.mName = pgettext("monster", uniqueMonsterData.mName); + monster.mName = pgettext("monster", uniqueMonsterData.mName).c_str(); monster._mmaxhp = uniqueMonsterData.mmaxhp << 6; if (!gbIsMultiplayer) @@ -4552,9 +4553,9 @@ void SyncMonsterAnim(Monster &monster) #endif monster.MData = LevelMonsterTypes[monster._mMTidx].MData; if (monster._uniqtype != 0) - monster.mName = pgettext("monster", UniqueMonstersData[monster._uniqtype - 1].mName); + monster.mName = pgettext("monster", UniqueMonstersData[monster._uniqtype - 1].mName).c_str(); else - monster.mName = pgettext("monster", monster.MData->mName); + monster.mName = pgettext("monster", monster.MData->mName).c_str(); if (monster._uniqtype != 0) InitTRNForUniqueMonster(monster); diff --git a/Source/msg.cpp b/Source/msg.cpp index 4322dae90..c41887b37 100644 --- a/Source/msg.cpp +++ b/Source/msg.cpp @@ -33,6 +33,7 @@ #include "towners.h" #include "trigs.h" #include "utils/language.h" +#include "utils/utf8.hpp" namespace devilution { @@ -481,7 +482,7 @@ void DeltaPutItem(const TCmdPItem &message, Point position, BYTE bLevel) && item.dwSeed == message.dwSeed) { if (item.bCmd == TCmdPItem::DroppedItem) return; - app_fatal("%s", _("Trying to drop a floor item?")); + app_fatal("%s", _("Trying to drop a floor item?").c_str()); } } @@ -984,7 +985,7 @@ DWORD OnSpellWall(const TCmd *pCmd, Player &player) auto spell = static_cast(message.wParam1); if (currlevel == 0 && !spelldata[spell].sTownSpell) { - LogError(_("{:s} has cast an illegal spell."), player._pName); + LogError(_("{:s} has cast an illegal spell.").c_str(), player._pName); return sizeof(message); } @@ -1019,7 +1020,7 @@ DWORD OnSpellTile(const TCmd *pCmd, Player &player) auto spell = static_cast(message.wParam1); if (currlevel == 0 && !spelldata[spell].sTownSpell) { - LogError(_("{:s} has cast an illegal spell."), player._pName); + LogError(_("{:s} has cast an illegal spell.").c_str(), player._pName); return sizeof(message); } @@ -1050,7 +1051,7 @@ DWORD OnTargetSpellTile(const TCmd *pCmd, Player &player) auto spell = static_cast(message.wParam1); if (currlevel == 0 && !spelldata[spell].sTownSpell) { - LogError(_("{:s} has cast an illegal spell."), player._pName); + LogError(_("{:s} has cast an illegal spell.").c_str(), player._pName); return sizeof(message); } @@ -1177,7 +1178,7 @@ DWORD OnSpellMonster(const TCmd *pCmd, Player &player) auto spell = static_cast(message.wParam2); if (currlevel == 0 && !spelldata[spell].sTownSpell) { - LogError(_("{:s} has cast an illegal spell."), player._pName); + LogError(_("{:s} has cast an illegal spell.").c_str(), player._pName); return sizeof(message); } @@ -1209,7 +1210,7 @@ DWORD OnSpellPlayer(const TCmd *pCmd, Player &player) auto spell = static_cast(message.wParam2); if (currlevel == 0 && !spelldata[spell].sTownSpell) { - LogError(_("{:s} has cast an illegal spell."), player._pName); + LogError(_("{:s} has cast an illegal spell.").c_str(), player._pName); return sizeof(message); } @@ -1241,7 +1242,7 @@ DWORD OnTargetSpellMonster(const TCmd *pCmd, Player &player) auto spell = static_cast(message.wParam2); if (currlevel == 0 && !spelldata[spell].sTownSpell) { - LogError(_("{:s} has cast an illegal spell."), player._pName); + LogError(_("{:s} has cast an illegal spell.").c_str(), player._pName); return sizeof(message); } @@ -1271,7 +1272,7 @@ DWORD OnTargetSpellPlayer(const TCmd *pCmd, Player &player) auto spell = static_cast(message.wParam2); if (currlevel == 0 && !spelldata[spell].sTownSpell) { - LogError(_("{:s} has cast an illegal spell."), player._pName); + LogError(_("{:s} has cast an illegal spell.").c_str(), player._pName); return sizeof(message); } @@ -1965,7 +1966,7 @@ bool msg_wait_resync() sgbRecvCmd = CMD_DLEVEL_END; gbBufferMsgs = 1; sgdwOwnerWait = SDL_GetTicks(); - success = UiProgressDialog(_("Waiting for game data..."), WaitForTurns); + success = UiProgressDialog(WaitForTurns); gbBufferMsgs = 0; if (!success) { FreePackets(); @@ -1973,13 +1974,13 @@ bool msg_wait_resync() } if (gbGameDestroyed) { - DrawDlg("%s", _("The game ended")); + DrawDlg("%s", _("The game ended").c_str()); FreePackets(); return false; } if (sgbDeltaChunks != MAX_CHUNKS) { - DrawDlg("%s", _("Unable to get level data")); + DrawDlg("%s", _("Unable to get level data").c_str()); FreePackets(); return false; } @@ -2660,8 +2661,8 @@ void NetSendCmdString(uint32_t pmask, const char *pszStr) TCmdString cmd; cmd.bCmd = CMD_STRING; - strcpy(cmd.str, pszStr); - multi_send_msg_packet(pmask, (byte *)&cmd, strlen(pszStr) + 2); + CopyUtf8(cmd.str, pszStr, sizeof(cmd.str)); + multi_send_msg_packet(pmask, (byte *)&cmd, strlen(cmd.str) + 2); } void delta_close_portal(int pnum) diff --git a/Source/multi.cpp b/Source/multi.cpp index 9260ee497..4b7d89b32 100644 --- a/Source/multi.cpp +++ b/Source/multi.cpp @@ -193,7 +193,7 @@ void PlayerLeftMsg(int pnum, bool left) delta_close_portal(pnum); RemovePlrMissiles(pnum); if (left) { - const char *pszFmt = _("Player '{:s}' just left the game"); + string_view pszFmt = _("Player '{:s}' just left the game"); switch (sgdwPlayerLeftReasonTbl[pnum]) { case LEAVE_ENDING: pszFmt = _("Player '{:s}' killed Diablo and left the game!"); @@ -813,7 +813,7 @@ void recv_plrinfo(int pnum, const TCmdPlrInfoHdr &header, bool recv) player.plractive = true; gbActivePlayers++; - const char *szEvent; + string_view szEvent; if (sgbPlayerTurnBitTbl[pnum]) { szEvent = _("Player '{:s}' (level {:d}) just joined the game"); } else { diff --git a/Source/objects.cpp b/Source/objects.cpp index c3636a9c2..41791484c 100644 --- a/Source/objects.cpp +++ b/Source/objects.cpp @@ -5389,11 +5389,11 @@ void GetObjectStr(const Object &object) case OBJ_CRUX1: case OBJ_CRUX2: case OBJ_CRUX3: - strcpy(infostr, _("Crucified Skeleton")); + CopyUtf8(infostr, _("Crucified Skeleton"), sizeof(infostr)); break; case OBJ_LEVER: case OBJ_FLAMELVR: - strcpy(infostr, _("Lever")); + CopyUtf8(infostr, _("Lever"), sizeof(infostr)); break; case OBJ_L1LDOOR: case OBJ_L1RDOOR: @@ -5402,123 +5402,123 @@ void GetObjectStr(const Object &object) case OBJ_L3LDOOR: case OBJ_L3RDOOR: if (object._oVar4 == 1) - strcpy(infostr, _("Open Door")); + CopyUtf8(infostr, _("Open Door"), sizeof(infostr)); if (object._oVar4 == 0) - strcpy(infostr, _("Closed Door")); + CopyUtf8(infostr, _("Closed Door"), sizeof(infostr)); if (object._oVar4 == 2) - strcpy(infostr, _("Blocked Door")); + CopyUtf8(infostr, _("Blocked Door"), sizeof(infostr)); break; case OBJ_BOOK2L: if (setlevel) { if (setlvlnum == SL_BONECHAMB) { - strcpy(infostr, _("Ancient Tome")); + CopyUtf8(infostr, _("Ancient Tome"), sizeof(infostr)); } else if (setlvlnum == SL_VILEBETRAYER) { - strcpy(infostr, _("Book of Vileness")); + CopyUtf8(infostr, _("Book of Vileness"), sizeof(infostr)); } } break; case OBJ_SWITCHSKL: - strcpy(infostr, _("Skull Lever")); + CopyUtf8(infostr, _("Skull Lever"), sizeof(infostr)); break; case OBJ_BOOK2R: - strcpy(infostr, _("Mythical Book")); + CopyUtf8(infostr, _("Mythical Book"), sizeof(infostr)); break; case OBJ_CHEST1: case OBJ_TCHEST1: - strcpy(infostr, _("Small Chest")); + CopyUtf8(infostr, _("Small Chest"), sizeof(infostr)); break; case OBJ_CHEST2: case OBJ_TCHEST2: - strcpy(infostr, _("Chest")); + CopyUtf8(infostr, _("Chest"), sizeof(infostr)); break; case OBJ_CHEST3: case OBJ_TCHEST3: case OBJ_SIGNCHEST: - strcpy(infostr, _("Large Chest")); + CopyUtf8(infostr, _("Large Chest"), sizeof(infostr)); break; case OBJ_SARC: - strcpy(infostr, _("Sarcophagus")); + CopyUtf8(infostr, _("Sarcophagus"), sizeof(infostr)); break; case OBJ_BOOKSHELF: - strcpy(infostr, _("Bookshelf")); + CopyUtf8(infostr, _("Bookshelf"), sizeof(infostr)); break; case OBJ_BOOKCASEL: case OBJ_BOOKCASER: - strcpy(infostr, _("Bookcase")); + CopyUtf8(infostr, _("Bookcase"), sizeof(infostr)); break; case OBJ_BARREL: case OBJ_BARRELEX: - if (currlevel >= 17 && currlevel <= 20) // for hive levels - strcpy(infostr, _("Pod")); // Then a barrel is called a pod - else if (currlevel >= 21 && currlevel <= 24) // for crypt levels - strcpy(infostr, _("Urn")); // Then a barrel is called an urn + if (currlevel >= 17 && currlevel <= 20) // for hive levels + CopyUtf8(infostr, _("Pod"), sizeof(infostr)); // Then a barrel is called a pod + else if (currlevel >= 21 && currlevel <= 24) // for crypt levels + CopyUtf8(infostr, _("Urn"), sizeof(infostr)); // Then a barrel is called an urn else - strcpy(infostr, _("Barrel")); + CopyUtf8(infostr, _("Barrel"), sizeof(infostr)); break; case OBJ_SHRINEL: case OBJ_SHRINER: CopyUtf8(infostr, fmt::format(_(/* TRANSLATORS: {:s} will be a name from the Shrine block above */ "{:s} Shrine"), _(ShrineNames[object._oVar1])), sizeof(infostr)); break; case OBJ_SKELBOOK: - strcpy(infostr, _("Skeleton Tome")); + CopyUtf8(infostr, _("Skeleton Tome"), sizeof(infostr)); break; case OBJ_BOOKSTAND: - strcpy(infostr, _("Library Book")); + CopyUtf8(infostr, _("Library Book"), sizeof(infostr)); break; case OBJ_BLOODFTN: - strcpy(infostr, _("Blood Fountain")); + CopyUtf8(infostr, _("Blood Fountain"), sizeof(infostr)); break; case OBJ_DECAP: - strcpy(infostr, _("Decapitated Body")); + CopyUtf8(infostr, _("Decapitated Body"), sizeof(infostr)); break; case OBJ_BLINDBOOK: - strcpy(infostr, _("Book of the Blind")); + CopyUtf8(infostr, _("Book of the Blind"), sizeof(infostr)); break; case OBJ_BLOODBOOK: - strcpy(infostr, _("Book of Blood")); + CopyUtf8(infostr, _("Book of Blood"), sizeof(infostr)); break; case OBJ_PURIFYINGFTN: - strcpy(infostr, _("Purifying Spring")); + CopyUtf8(infostr, _("Purifying Spring"), sizeof(infostr)); break; case OBJ_ARMORSTAND: case OBJ_WARARMOR: - strcpy(infostr, _("Armor")); + CopyUtf8(infostr, _("Armor"), sizeof(infostr)); break; case OBJ_WARWEAP: - strcpy(infostr, _("Weapon Rack")); + CopyUtf8(infostr, _("Weapon Rack"), sizeof(infostr)); break; case OBJ_GOATSHRINE: - strcpy(infostr, _("Goat Shrine")); + CopyUtf8(infostr, _("Goat Shrine"), sizeof(infostr)); break; case OBJ_CAULDRON: - strcpy(infostr, _("Cauldron")); + CopyUtf8(infostr, _("Cauldron"), sizeof(infostr)); break; case OBJ_MURKYFTN: - strcpy(infostr, _("Murky Pool")); + CopyUtf8(infostr, _("Murky Pool"), sizeof(infostr)); break; case OBJ_TEARFTN: - strcpy(infostr, _("Fountain of Tears")); + CopyUtf8(infostr, _("Fountain of Tears"), sizeof(infostr)); break; case OBJ_STEELTOME: - strcpy(infostr, _("Steel Tome")); + CopyUtf8(infostr, _("Steel Tome"), sizeof(infostr)); break; case OBJ_PEDISTAL: - strcpy(infostr, _("Pedestal of Blood")); + CopyUtf8(infostr, _("Pedestal of Blood"), sizeof(infostr)); break; case OBJ_STORYBOOK: - strcpy(infostr, _(StoryBookName[object._oVar3])); + CopyUtf8(infostr, _(StoryBookName[object._oVar3]), sizeof(infostr)); break; case OBJ_WEAPONRACK: - strcpy(infostr, _("Weapon Rack")); + CopyUtf8(infostr, _("Weapon Rack"), sizeof(infostr)); break; case OBJ_MUSHPATCH: - strcpy(infostr, _("Mushroom Patch")); + CopyUtf8(infostr, _("Mushroom Patch"), sizeof(infostr)); break; case OBJ_LAZSTAND: - strcpy(infostr, _("Vile Stand")); + CopyUtf8(infostr, _("Vile Stand"), sizeof(infostr)); break; case OBJ_SLAINHERO: - strcpy(infostr, _("Slain Hero")); + CopyUtf8(infostr, _("Slain Hero"), sizeof(infostr)); break; default: break; diff --git a/Source/options.cpp b/Source/options.cpp index b6cac668f..72f6fdc0e 100644 --- a/Source/options.cpp +++ b/Source/options.cpp @@ -1020,7 +1020,7 @@ size_t OptionEntryLanguageCode::GetActiveListIndex() const } void OptionEntryLanguageCode::SetActiveListIndex(size_t index) { - strcpy(szCode, languages[index].first.c_str()); + CopyUtf8(szCode, languages[index].first, sizeof(szCode)); NotifyValueChanged(); } @@ -1148,7 +1148,7 @@ string_view KeymapperOptions::Action::GetValueDescription() const if (keyNameIt == sgOptions.Keymapper.keyIDToKeyName.end()) { return ""; } - return keyNameIt->second.c_str(); + return keyNameIt->second; } bool KeymapperOptions::Action::SetValue(int value) diff --git a/Source/panels/mainpanel.cpp b/Source/panels/mainpanel.cpp index caa5bf9a7..b90af5acb 100644 --- a/Source/panels/mainpanel.cpp +++ b/Source/panels/mainpanel.cpp @@ -19,13 +19,13 @@ Art PanelButton; Art PanelButtonGrime; Art PanelButtonDownGrime; -void DrawButtonText(const Surface &out, const char *text, Rectangle placement, UiFlags style, int spacing = 1) +void DrawButtonText(const Surface &out, string_view text, Rectangle placement, UiFlags style, int spacing = 1) { DrawString(out, text, { placement.position + Displacement { 0, 1 }, placement.size }, UiFlags::AlignCenter | UiFlags::KerningFitSpacing | UiFlags::ColorBlack, spacing); DrawString(out, text, placement, UiFlags::AlignCenter | UiFlags::KerningFitSpacing | style, spacing); } -void DrawButtonOnPanel(Point position, const char *text, int frame) +void DrawButtonOnPanel(Point position, string_view text, int frame) { DrawArt(*pBtmBuff, position, &PanelButton, frame); int spacing = 2; @@ -38,7 +38,7 @@ void DrawButtonOnPanel(Point position, const char *text, int frame) DrawButtonText(*pBtmBuff, text, { position, { PanelButton.w(), 0 } }, UiFlags::ColorButtonface, spacing); } -void RenderMainButton(int buttonId, const char *text, int frame) +void RenderMainButton(int buttonId, string_view text, int frame) { Point panelPosition { PanBtnPos[buttonId].x + 4, PanBtnPos[buttonId].y + 17 }; DrawButtonOnPanel(panelPosition, text, frame); @@ -59,7 +59,7 @@ void RenderMainButton(int buttonId, const char *text, int frame) void DrawTalkButton(int buttonId) { - const char *text = _("voice"); + string_view text = _("voice"); Point position { 176, PANEL_HEIGHT + 101 + 18 * buttonId }; DrawArt(*pBtmBuff, position, &TalkButton); int width = std::min(GetLineWidth(text, GameFont12, 1), PanelButton.w()); diff --git a/Source/panels/spell_list.cpp b/Source/panels/spell_list.cpp index 5980f9764..6b1ba31df 100644 --- a/Source/panels/spell_list.cpp +++ b/Source/panels/spell_list.cpp @@ -42,7 +42,7 @@ void PrintSBookSpellType(const Surface &out, Point position, const std::string & DrawVerticalLine(out, rect + Displacement { SPLICONLENGTH - 1, 0 }, SPLICONLENGTH, rectColorIndex); // Align the spell type text with bottom of spell icon - position += Displacement { SPLICONLENGTH / 2 - GetLineWidth(text.c_str()) / 2, (IsSmallFontTall() ? -19 : -15) }; + position += Displacement { SPLICONLENGTH / 2 - GetLineWidth(text) / 2, (IsSmallFontTall() ? -19 : -15) }; // Draw a drop shadow below and to the left of the text DrawString(out, text, position + Displacement { -1, 1 }, UiFlags::ColorBlack); diff --git a/Source/pfile.cpp b/Source/pfile.cpp index 45b08cdde..b5d516dc0 100644 --- a/Source/pfile.cpp +++ b/Source/pfile.cpp @@ -263,7 +263,7 @@ PFileScopedArchiveWriter::PFileScopedArchiveWriter(bool clearTables) , clear_tables_(clearTables) { if (!OpenArchive(save_num_)) - app_fatal("%s", _("Failed to open player archive for writing.")); + app_fatal("%s", _("Failed to open player archive for writing.").c_str()); } PFileScopedArchiveWriter::~PFileScopedArchiveWriter() @@ -305,7 +305,7 @@ void sfile_write_stash() return; if (!StashWriter.Open(GetStashSavePath().c_str())) - app_fatal("%s", _("Failed to open stash archive for writing.")); + app_fatal("%s", _("Failed to open stash archive for writing.").c_str()); SaveStash(); @@ -403,7 +403,7 @@ bool pfile_delete_save(_uiheroinfo *heroInfo) uint32_t saveNum = heroInfo->saveNumber; if (saveNum < MAX_CHARACTERS) { hero_names[saveNum][0] = '\0'; - RemoveFile(GetSavePath(saveNum).c_str()); + RemoveFile(GetSavePath(saveNum)); } return true; } @@ -416,9 +416,9 @@ void pfile_read_player_from_save(uint32_t saveNum, Player &player) { std::optional archive = OpenSaveArchive(saveNum); if (!archive) - app_fatal("%s", _("Unable to open archive")); + app_fatal("%s", _("Unable to open archive").c_str()); if (!ReadHero(*archive, &pkplr)) - app_fatal("%s", _("Unable to load character")); + app_fatal("%s", _("Unable to load character").c_str()); gbValidSaveFile = ArchiveContainsGame(*archive); if (gbValidSaveFile) @@ -442,7 +442,7 @@ bool LevelFileExists() uint32_t saveNum = gSaveNumber; if (!OpenArchive(saveNum)) - app_fatal("%s", _("Unable to read to save file archive")); + app_fatal("%s", _("Unable to read to save file archive").c_str()); bool hasFile = SaveWriter.HasFile(szName); SaveWriter.Close(); @@ -462,7 +462,7 @@ void GetPermLevelNames(char *szPerm) uint32_t saveNum = gSaveNumber; GetTempLevelNames(szPerm); if (!OpenArchive(saveNum)) - app_fatal("%s", _("Unable to read to save file archive")); + app_fatal("%s", _("Unable to read to save file archive").c_str()); bool hasFile = SaveWriter.HasFile(szPerm); SaveWriter.Close(); @@ -481,7 +481,7 @@ void pfile_remove_temp_files() uint32_t saveNum = gSaveNumber; if (!OpenArchive(saveNum)) - app_fatal("%s", _("Unable to write to save file archive")); + app_fatal("%s", _("Unable to write to save file archive").c_str()); SaveWriter.RemoveHashEntries(GetTempSaveNames); SaveWriter.Close(); } diff --git a/Source/player.cpp b/Source/player.cpp index 47c0243a4..ca0d90acf 100644 --- a/Source/player.cpp +++ b/Source/player.cpp @@ -33,6 +33,7 @@ #include "towners.h" #include "utils/language.h" #include "utils/log.hpp" +#include "utils/utf8.hpp" namespace devilution { @@ -3154,7 +3155,7 @@ StartPlayerKill(int pnum, int earflag) if (earflag != 0) { Item ear; InitializeItem(ear, IDI_EAR); - strcpy(ear._iName, fmt::format(_("Ear of {:s}"), player._pName).c_str()); + CopyUtf8(ear._iName, fmt::format(_("Ear of {:s}"), player._pName), sizeof(ear._iName)); switch (player._pClass) { case HeroClass::Sorcerer: ear._iCurs = ICURS_EAR_SORCERER; diff --git a/Source/qol/monhealthbar.cpp b/Source/qol/monhealthbar.cpp index fbe3b3920..e5331d377 100644 --- a/Source/qol/monhealthbar.cpp +++ b/Source/qol/monhealthbar.cpp @@ -35,7 +35,8 @@ void InitMonsterHealthBar() || (resistance.surface == nullptr)) { app_fatal("%s", _("Failed to load UI resources.\n" "\n" - "Make sure devilutionx.mpq is in the game folder and that it is up to date.")); + "Make sure devilutionx.mpq is in the game folder and that it is up to date.") + .c_str()); } } diff --git a/Source/qol/xpbar.cpp b/Source/qol/xpbar.cpp index 4cc718104..26a528bbd 100644 --- a/Source/qol/xpbar.cpp +++ b/Source/qol/xpbar.cpp @@ -75,7 +75,8 @@ void InitXPBar() if (xpbarArt.surface == nullptr) { app_fatal("%s", _("Failed to load UI resources.\n" "\n" - "Make sure devilutionx.mpq is in the game folder and that it is up to date.")); + "Make sure devilutionx.mpq is in the game folder and that it is up to date.") + .c_str()); } } } diff --git a/Source/quests.cpp b/Source/quests.cpp index ae5d2dc9c..21718beb8 100644 --- a/Source/quests.cpp +++ b/Source/quests.cpp @@ -267,7 +267,7 @@ int QuestLogMouseToEntry() return -1; } -void PrintQLString(const Surface &out, int x, int y, const char *str, bool marked, bool disabled = false) +void PrintQLString(const Surface &out, int x, int y, string_view str, bool marked, bool disabled = false) { int width = GetLineWidth(str); x += std::max((257 - width) / 2, 0); diff --git a/Source/restrict.cpp b/Source/restrict.cpp index 7958678c8..d0ccf8d01 100644 --- a/Source/restrict.cpp +++ b/Source/restrict.cpp @@ -15,11 +15,11 @@ void ReadOnlyTest() const std::string path = paths::PrefPath() + "Diablo1ReadOnlyTest.foo"; FILE *f = FOpen(path.c_str(), "wt"); if (f == nullptr) { - DirErrorDlg(paths::PrefPath().c_str()); + DirErrorDlg(paths::PrefPath()); } fclose(f); - RemoveFile(path.c_str()); + RemoveFile(path); } } // namespace devilution diff --git a/Source/sound.cpp b/Source/sound.cpp index 714a729ef..2467aa86d 100644 --- a/Source/sound.cpp +++ b/Source/sound.cpp @@ -170,7 +170,7 @@ std::unique_ptr sound_file_load(const char *path, bool stream) size_t dwBytes = SDL_RWsize(file); auto waveFile = MakeArraySharedPtr(dwBytes); if (SDL_RWread(file, waveFile.get(), dwBytes, 1) == 0) { - ErrDlg("Failed to read file", fmt::format("{}: {}", path, SDL_GetError()).c_str(), __FILE__, __LINE__); + ErrDlg("Failed to read file", fmt::format("{}: {}", path, SDL_GetError()), __FILE__, __LINE__); } int error = snd->DSB.SetChunk(waveFile, dwBytes); SDL_RWclose(file); diff --git a/Source/stores.cpp b/Source/stores.cpp index f8385f730..3d7f4f31c 100644 --- a/Source/stores.cpp +++ b/Source/stores.cpp @@ -223,7 +223,7 @@ void AddOptionsBackButton() void AddItemListBackButton(bool selectable = false) { const int line = BackButtonLine(); - const char *text = _("Back"); + string_view text = _("Back"); if (!selectable && IsSmallFontTall()) { AddSText(0, line, text, UiFlags::ColorWhite | UiFlags::AlignRight, selectable); } else { @@ -354,7 +354,7 @@ void StartSmithBuy() stextsval = 0; /* TRANSLATORS: This text is white space sensitive. Check for correct alignment! */ - AddSText(0, 1, fmt::format(_("I have these items for sale: Your gold: {:d}"), Players[MyPlayerId]._pGold).c_str(), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false); + AddSText(0, 1, fmt::format(_("I have these items for sale: Your gold: {:d}"), Players[MyPlayerId]._pGold), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false); AddSLine(3); ScrollSmithBuy(stextsval); AddItemListBackButton(); @@ -419,7 +419,7 @@ bool StartSmithPremiumBuy() stextsval = 0; /* TRANSLATORS: This text is white space sensitive. Check for correct alignment! */ - AddSText(0, 1, fmt::format(_("I have these premium items for sale: Your gold: {:d}"), Players[MyPlayerId]._pGold).c_str(), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false); + AddSText(0, 1, fmt::format(_("I have these premium items for sale: Your gold: {:d}"), Players[MyPlayerId]._pGold), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false); AddSLine(3); AddItemListBackButton(); @@ -538,7 +538,7 @@ void StartSmithSell() stextscrl = false; /* TRANSLATORS: This text is white space sensitive. Check for correct alignment! */ - AddSText(0, 1, fmt::format(_("You have nothing I want. Your gold: {:d}"), myPlayer._pGold).c_str(), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false); + AddSText(0, 1, fmt::format(_("You have nothing I want. Your gold: {:d}"), myPlayer._pGold), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false); AddSLine(3); AddItemListBackButton(/*selectable=*/true); return; @@ -549,7 +549,7 @@ void StartSmithSell() stextsmax = myPlayer._pNumInv; /* TRANSLATORS: This text is white space sensitive. Check for correct alignment! */ - AddSText(0, 1, fmt::format(_("Which item is for sale? Your gold: {:d}"), myPlayer._pGold).c_str(), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false); + AddSText(0, 1, fmt::format(_("Which item is for sale? Your gold: {:d}"), myPlayer._pGold), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false); AddSLine(3); ScrollSmithSell(stextsval); AddItemListBackButton(); @@ -620,7 +620,7 @@ void StartSmithRepair() stextscrl = false; /* TRANSLATORS: This text is white space sensitive. Check for correct alignment! */ - AddSText(0, 1, fmt::format(_("You have nothing to repair. Your gold: {:d}"), myPlayer._pGold).c_str(), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false); + AddSText(0, 1, fmt::format(_("You have nothing to repair. Your gold: {:d}"), myPlayer._pGold), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false); AddSLine(3); AddItemListBackButton(/*selectable=*/true); return; @@ -631,7 +631,7 @@ void StartSmithRepair() stextsmax = myPlayer._pNumInv; /* TRANSLATORS: This text is white space sensitive. Check for correct alignment! */ - AddSText(0, 1, fmt::format(_("Repair which item? Your gold: {:d}"), myPlayer._pGold).c_str(), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false); + AddSText(0, 1, fmt::format(_("Repair which item? Your gold: {:d}"), myPlayer._pGold), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false); AddSLine(3); ScrollSmithSell(stextsval); @@ -719,7 +719,7 @@ void StartWitchBuy() stextsmax = 20; /* TRANSLATORS: This text is white space sensitive. Check for correct alignment! */ - AddSText(0, 1, fmt::format(_("I have these items for sale: Your gold: {:d}"), Players[MyPlayerId]._pGold).c_str(), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false); + AddSText(0, 1, fmt::format(_("I have these items for sale: Your gold: {:d}"), Players[MyPlayerId]._pGold), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false); AddSLine(3); ScrollWitchBuy(stextsval); AddItemListBackButton(); @@ -812,7 +812,7 @@ void StartWitchSell() stextscrl = false; /* TRANSLATORS: This text is white space sensitive. Check for correct alignment! */ - AddSText(0, 1, fmt::format(_("You have nothing I want. Your gold: {:d}"), myPlayer._pGold).c_str(), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false); + AddSText(0, 1, fmt::format(_("You have nothing I want. Your gold: {:d}"), myPlayer._pGold), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false); AddSLine(3); AddItemListBackButton(/*selectable=*/true); return; @@ -823,7 +823,7 @@ void StartWitchSell() stextsmax = myPlayer._pNumInv; /* TRANSLATORS: This text is white space sensitive. Check for correct alignment! */ - AddSText(0, 1, fmt::format(_("Which item is for sale? Your gold: {:d}"), myPlayer._pGold).c_str(), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false); + AddSText(0, 1, fmt::format(_("Which item is for sale? Your gold: {:d}"), myPlayer._pGold), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false); AddSLine(3); ScrollSmithSell(stextsval); AddItemListBackButton(); @@ -885,7 +885,7 @@ void StartWitchRecharge() stextscrl = false; /* TRANSLATORS: This text is white space sensitive. Check for correct alignment! */ - AddSText(0, 1, fmt::format(_("You have nothing to recharge. Your gold: {:d}"), myPlayer._pGold).c_str(), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false); + AddSText(0, 1, fmt::format(_("You have nothing to recharge. Your gold: {:d}"), myPlayer._pGold), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false); AddSLine(3); AddItemListBackButton(/*selectable=*/true); return; @@ -896,7 +896,7 @@ void StartWitchRecharge() stextsmax = myPlayer._pNumInv; /* TRANSLATORS: This text is white space sensitive. Check for correct alignment! */ - AddSText(0, 1, fmt::format(_("Recharge which item? Your gold: {:d}"), myPlayer._pGold).c_str(), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false); + AddSText(0, 1, fmt::format(_("Recharge which item? Your gold: {:d}"), myPlayer._pGold), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false); AddSLine(3); ScrollSmithSell(stextsval); AddItemListBackButton(); diff --git a/Source/trigs.cpp b/Source/trigs.cpp index a840a6768..d00a972c2 100644 --- a/Source/trigs.cpp +++ b/Source/trigs.cpp @@ -340,7 +340,7 @@ bool ForceTownTrig() if (tileId == -1) break; if (dPiece[cursPosition.x][cursPosition.y] == tileId) { - strcpy(infostr, _("Down to dungeon")); + CopyUtf8(infostr, _("Down to dungeon"), sizeof(infostr)); cursPosition = { 25, 29 }; return true; } @@ -351,7 +351,7 @@ bool ForceTownTrig() if (tileId == -1) break; if (dPiece[cursPosition.x][cursPosition.y] == tileId) { - strcpy(infostr, _("Down to catacombs")); + CopyUtf8(infostr, _("Down to catacombs"), sizeof(infostr)); cursPosition = { 49, 21 }; return true; } @@ -361,7 +361,7 @@ bool ForceTownTrig() if (IsWarpOpen(DTYPE_CAVES)) { for (int i = 1199; i <= 1220; i++) { if (dPiece[cursPosition.x][cursPosition.y] == i) { - strcpy(infostr, _("Down to caves")); + CopyUtf8(infostr, _("Down to caves"), sizeof(infostr)); cursPosition = { 17, 69 }; return true; } @@ -371,7 +371,7 @@ bool ForceTownTrig() if (IsWarpOpen(DTYPE_HELL)) { for (int i = 1240; i <= 1255; i++) { if (dPiece[cursPosition.x][cursPosition.y] == i) { - strcpy(infostr, _("Down to hell")); + CopyUtf8(infostr, _("Down to hell"), sizeof(infostr)); cursPosition = { 41, 80 }; return true; } @@ -383,7 +383,7 @@ bool ForceTownTrig() if (tileId == -1) break; if (dPiece[cursPosition.x][cursPosition.y] == tileId) { - strcpy(infostr, _("Down to Hive")); + CopyUtf8(infostr, _("Down to Hive"), sizeof(infostr)); cursPosition = { 80, 62 }; return true; } @@ -395,7 +395,7 @@ bool ForceTownTrig() if (tileId == -1) break; if (dPiece[cursPosition.x][cursPosition.y] == tileId) { - strcpy(infostr, _("Down to Crypt")); + CopyUtf8(infostr, _("Down to Crypt"), sizeof(infostr)); cursPosition = { 36, 24 }; return true; } @@ -413,7 +413,7 @@ bool ForceL1Trig() if (currlevel > 1) CopyUtf8(infostr, fmt::format(_("Up to level {:d}"), currlevel - 1), sizeof(infostr)); else - strcpy(infostr, _("Up to town")); + CopyUtf8(infostr, _("Up to town"), sizeof(infostr)); for (int j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABPREVLVL) { cursPosition = trigs[j].position; @@ -446,7 +446,7 @@ bool ForceL1Trig() } } if (dPiece[cursPosition.x][cursPosition.y] == 317) { - strcpy(infostr, _("Cornerstone of the World")); + CopyUtf8(infostr, _("Cornerstone of the World"), sizeof(infostr)); return true; } for (int i = 0; L5DownList[i] != -1; i++) { @@ -468,7 +468,7 @@ bool ForceL1Trig() int dx = abs(trigs[j].position.x - cursPosition.x); int dy = abs(trigs[j].position.y - cursPosition.y); if (dx < 4 && dy < 4) { - strcpy(infostr, _("Up to town")); + CopyUtf8(infostr, _("Up to town"), sizeof(infostr)); cursPosition = trigs[j].position; return true; } @@ -520,7 +520,7 @@ bool ForceL2Trig() int dx = abs(trigs[j].position.x - cursPosition.x); int dy = abs(trigs[j].position.y - cursPosition.y); if (dx < 4 && dy < 4) { - strcpy(infostr, _("Up to town")); + CopyUtf8(infostr, _("Up to town"), sizeof(infostr)); cursPosition = trigs[j].position; return true; } @@ -599,7 +599,7 @@ bool ForceL3Trig() int dx = abs(trigs[j].position.x - cursPosition.x); int dy = abs(trigs[j].position.y - cursPosition.y); if (dx < 4 && dy < 4) { - strcpy(infostr, _("Up to town")); + CopyUtf8(infostr, _("Up to town"), sizeof(infostr)); cursPosition = trigs[j].position; return true; } @@ -616,7 +616,7 @@ bool ForceL3Trig() int dx = abs(trigs[j].position.x - cursPosition.x); int dy = abs(trigs[j].position.y - cursPosition.y); if (dx < 4 && dy < 4) { - strcpy(infostr, _("Up to town")); + CopyUtf8(infostr, _("Up to town"), sizeof(infostr)); cursPosition = trigs[j].position; return true; } @@ -663,7 +663,7 @@ bool ForceL4Trig() int dx = abs(trigs[j].position.x - cursPosition.x); int dy = abs(trigs[j].position.y - cursPosition.y); if (dx < 4 && dy < 4) { - strcpy(infostr, _("Up to town")); + CopyUtf8(infostr, _("Up to town"), sizeof(infostr)); cursPosition = trigs[j].position; return true; } @@ -676,7 +676,7 @@ bool ForceL4Trig() if (currlevel == 15) { for (int i = 0; L4PentaList[i] != -1; i++) { if (dPiece[cursPosition.x][cursPosition.y] == L4PentaList[i]) { - strcpy(infostr, _("Down to Diablo")); + CopyUtf8(infostr, _("Down to Diablo"), sizeof(infostr)); for (int j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABNEXTLVL) { cursPosition = trigs[j].position; diff --git a/Source/utils/file_util.cpp b/Source/utils/file_util.cpp index 218022397..0a8ec3b4d 100644 --- a/Source/utils/file_util.cpp +++ b/Source/utils/file_util.cpp @@ -140,7 +140,7 @@ bool ResizeFile(const char *path, std::uintmax_t size) #endif } -void RemoveFile(const char *lpFileName) +void RemoveFile(string_view lpFileName) { #if defined(_WIN64) || defined(_WIN32) const auto pathUtf16 = ToWideChar(lpFileName); @@ -150,7 +150,7 @@ void RemoveFile(const char *lpFileName) } ::DeleteFileW(&pathUtf16[0]); #else - std::string name = lpFileName; + std::string name { lpFileName }; std::replace(name.begin(), name.end(), '\\', '/'); FILE *f = fopen(name.c_str(), "r+"); if (f != nullptr) { diff --git a/Source/utils/file_util.h b/Source/utils/file_util.h index 303ff4d1a..4ead6d72b 100644 --- a/Source/utils/file_util.h +++ b/Source/utils/file_util.h @@ -14,7 +14,7 @@ bool FileExists(const char *path); bool FileExistsAndIsWriteable(const char *path); bool GetFileSize(const char *path, std::uintmax_t *size); bool ResizeFile(const char *path, std::uintmax_t size); -void RemoveFile(const char *lpFileName); +void RemoveFile(string_view lpFileName); std::optional CreateFileStream(const char *path, std::ios::openmode mode); FILE *FOpen(const char *path, const char *mode); diff --git a/Source/utils/language.h b/Source/utils/language.h index f3866380f..676fc323d 100644 --- a/Source/utils/language.h +++ b/Source/utils/language.h @@ -2,9 +2,9 @@ #include -#define _(x) LanguageTranslate(x).c_str() -#define ngettext(x, y, z) LanguagePluralTranslate(x, y, z).c_str() -#define pgettext(context, x) LanguageParticularTranslate(context, x).c_str() +#define _(x) LanguageTranslate(x) +#define ngettext(x, y, z) LanguagePluralTranslate(x, y, z) +#define pgettext(context, x) LanguageParticularTranslate(context, x) #define N_(x) (x) #define P_(context, x) (x) @@ -13,7 +13,6 @@ void LanguageInitialize(); const std::string &LanguageParticularTranslate(const char *context, const char *message); const std::string &LanguagePluralTranslate(const char *singular, const char *plural, int count); const std::string &LanguageTranslate(const char *key); -const char *LanguageMetadata(const char *key); // Chinese and Japanese, and Korean small font is 16px instead of a 12px one for readability. bool IsSmallFontTall();