diff --git a/CMakeLists.txt b/CMakeLists.txt index 19fd5d673f..b326931e79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -280,22 +280,16 @@ set(DUSK_COMPANY_NAME "Twilit Realm") set(DUSK_FILE_DESCRIPTION "Dusk") set(DUSK_PRODUCT_NAME "Dusk") set(DUSK_COPYRIGHT "Copyright (C) Twilit Realm contributors") -set(DUSK_GAME_NAME "GZ2E") -set(DUSK_GAME_VERSION "01") -set(DUSK_TP_VERSION ${DUSK_GAME_NAME}${DUSK_GAME_VERSION}) - -message(STATUS "dusk: Game Version: ${DUSK_TP_VERSION}") source_group("dolzel" FILES ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${REL_FILES}) source_group("dusk" FILES ${DUSK_FILES}) -set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0 - DUSK_TP_VERSION="${DUSK_TP_VERSION}" DUSK_GAME_NAME="${DUSK_GAME_NAME}" DUSK_GAME_VERSION="${DUSK_GAME_VERSION}") +set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0) set(GAME_INCLUDE_DIRS include src - assets/${DUSK_TP_VERSION} + assets/GZ2E01 # TODO: make this dynamic if needed? libs/JSystem/include libs extern/aurora/include/dolphin diff --git a/cmake-variants.yaml b/cmake-variants.yaml index 62d2642311..37edcede95 100644 --- a/cmake-variants.yaml +++ b/cmake-variants.yaml @@ -13,13 +13,3 @@ buildType: short: RelWithDebInfo long: Optimized, with debug symbols buildType: RelWithDebInfo - -tp_version: - default: GZ2E01 - description: TP Version - choices: - GZ2E01: - short: GZ2E01 - long: GZ2E01 - settings: - DUSK_TP_VERSION: GZ2E01 diff --git a/files.cmake b/files.cmake index af101b6c47..d45dd7dc7c 100644 --- a/files.cmake +++ b/files.cmake @@ -1466,4 +1466,5 @@ set(DUSK_FILES src/dusk/OSThread.cpp src/dusk/OSMutex.cpp src/dusk/discord_presence.cpp + src/dusk/version.cpp ) diff --git a/include/d/d_name.h b/include/d/d_name.h index e685871738..3ac6592457 100644 --- a/include/d/d_name.h +++ b/include/d/d_name.h @@ -89,7 +89,7 @@ public: void MojiSelectAnm3(); int mojiChange(u8); void selectMojiSet(); - #if REGION_JPN + #if TARGET_PC || REGION_JPN int checkDakuon(int, u8); int setDakuon(int, u8); #endif diff --git a/include/d/d_s_logo.h b/include/d/d_s_logo.h index 56d10eef82..ab714a17ae 100644 --- a/include/d/d_s_logo.h +++ b/include/d/d_s_logo.h @@ -79,7 +79,7 @@ public: bool isProgressiveMode(); void setRenderMode(); - #if VERSION == VERSION_GCN_PAL || PLATFORM_WII || PLATFORM_SHIELD + #if TARGET_PC || VERSION == VERSION_GCN_PAL || PLATFORM_WII || PLATFORM_SHIELD u8 getPalLanguage(); #endif @@ -149,7 +149,7 @@ public: /* 0x200 */ dDlst_2D_c* mNvLogo; /* 0x204 */ dDlst_2D_c* mMocImg; #endif -#if VERSION == VERSION_GCN_PAL +#if TARGET_PC || VERSION == VERSION_GCN_PAL /* 0x1FC */ mDoDvdThd_mountArchive_c* mpPalLogoResCommand; #endif /* 0x1FC */ request_of_phase_process_class* m_preLoad_dylPhase; diff --git a/include/dusk/dvd_asset.hpp b/include/dusk/dvd_asset.hpp index 014c683d44..8594d4631c 100644 --- a/include/dusk/dvd_asset.hpp +++ b/include/dusk/dvd_asset.hpp @@ -1,22 +1,31 @@ #pragma once #include "dolphin/types.h" +#include "version.hpp" namespace dusk { +struct OffsetVersion { + version::GameVersion mGameVersion; + u32 mOffset; + + constexpr OffsetVersion(const version::GameVersion gameVersion, const u32 offset) + : mGameVersion(gameVersion), mOffset(offset) {} +}; + /** * Load bytes from the main DOL by GameCube virtual address */ -bool LoadDolAsset(void* dst, u32 virtualAddress, s32 size); +bool LoadDolAsset(void* dst, std::initializer_list virtualAddress, s32 size); /** * Load bytes from a REL file in the ISO filesystem, dst must be 32-byte aligned */ -bool LoadRelAsset(void* dst, const char* dvdPath, s32 offset, s32 size); +bool LoadRelAsset(void* dst, const char* dvdPath, std::initializer_list offset, s32 size); /** * Load bytes from a REL inside RELS.arc */ -bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, s32 offset, s32 size); +bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, std::initializer_list offset, s32 size); } // namespace dusk diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 039e51af7d..9721b93614 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -13,12 +13,26 @@ enum class BloomMode : int { Dusk = 2, }; +enum class GameLanguage : u8 { + English = OS_LANGUAGE_ENGLISH, + German = OS_LANGUAGE_GERMAN, + French = OS_LANGUAGE_FRENCH, + Spanish = OS_LANGUAGE_SPANISH, + Italian = OS_LANGUAGE_ITALIAN, +}; + namespace config { template <> struct ConfigEnumRange { static constexpr auto min = BloomMode::Off; static constexpr auto max = BloomMode::Dusk; }; + +template <> +struct ConfigEnumRange { + static constexpr auto min = GameLanguage::English; + static constexpr auto max = GameLanguage::Italian; +}; } // Persistent user settings @@ -46,6 +60,8 @@ struct UserSettings { // Game settings struct { + ConfigVar language; + // QoL ConfigVar enableQuickTransform; ConfigVar hideTvSettingsScreen; diff --git a/include/dusk/version.hpp b/include/dusk/version.hpp new file mode 100644 index 0000000000..fe393b049b --- /dev/null +++ b/include/dusk/version.hpp @@ -0,0 +1,67 @@ +#ifndef DUSK_VERSION_HPP +#define DUSK_VERSION_HPP + +/** + * Functionality for switching game behavior based on the loaded game version (e.g. PAL/JPN, GC/Wii) + */ +namespace dusk::version { + enum class GameVersion : u8 { + GcnUsa = VERSION_GCN_USA, + GcnPal = VERSION_GCN_PAL, + GcnJpn = VERSION_GCN_JPN, + WiiUsaRev0 = VERSION_WII_USA_R0, + WiiUsa = VERSION_WII_USA_R2, + WiiPal = VERSION_WII_PAL, + WiiJpn = VERSION_WII_JPN, + WiiKor = VERSION_WII_KOR, + }; + + bool isGcn(); + bool isWii(); + bool isPalOrAtLeastWiiR2(); + + bool isRegionPal(); + bool isRegionJpn(); + bool isRegionUsa(); + + GameVersion getGameVersion(); + + const DVDDiskID& getDiskID(); + + void init(); + + template + struct VersionOption { + GameVersion mVersion; + T mValue; + + constexpr VersionOption(GameVersion version, T value) : mVersion(version), mValue(value) {} + }; + + template + const T& versionSelect(const std::initializer_list> options) { + const auto version = getGameVersion(); + for (const auto& opt : options) { + if (opt.mVersion == version) { + return opt.mValue; + } + } + + // Unable to find value. + abort(); + } + + template + const T& versionSelect(const std::initializer_list> options, const T& defaultValue) { + const auto version = getGameVersion(); + for (const auto& opt : options) { + if (opt.mVersion == version) { + return opt.mValue; + } + } + + return defaultValue; + } +} // namespace dusk::version + +#endif // DUSK_VERSION_HPP diff --git a/include/global.h b/include/global.h index 9301d12e11..556c5f6207 100644 --- a/include/global.h +++ b/include/global.h @@ -230,12 +230,16 @@ using std::isnan; // Some basic macros that are more convenient than putting down #if blocks for one-line changes. #if TARGET_PC #define IF_DUSK(statement) statement +#define IF_DUSK_BLOCK(cond) if (cond) { +#define IF_DUSK_BLOCK_END } #define IF_DUSK_ARG(expr) , expr #define IF_NOT_DUSK(statement) #define DUSK_IF_ELSE(dusk, orig) dusk #else #define IF_DUSK(statement) #define IF_DUSK_ARG(expr) +#define IF_DUSK_BLOCK(cond) +#define IF_DUSK_BLOCK_END #define IF_NOT_DUSK(statement) statement #define DUSK_IF_ELSE(dusk, orig) orig #endif diff --git a/src/d/actor/d_a_mant.cpp b/src/d/actor/d_a_mant.cpp index 282502419f..6a559c0e1c 100644 --- a/src/d/actor/d_a_mant.cpp +++ b/src/d/actor/d_a_mant.cpp @@ -13,9 +13,12 @@ #if TARGET_PC #include "dusk/dvd_asset.hpp" #include "dusk/frame_interpolation.h" -static u8* l_Egnd_mantTEX_get() { alignas(32) static u8 buf[0x4000]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0x1C00, 0x4000), true); return buf; } -static u8* l_Egnd_mantTEX_U_get() { alignas(32) static u8 buf[0x4000]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0x5C00, 0x4000), true); return buf; } -static u8* l_Egnd_mantPAL_get() { alignas(32) static u8 buf[0x60]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0x9C00, 0x60), true); return buf; } + +using GameVersion = dusk::version::GameVersion; + +static u8* l_Egnd_mantTEX_get() { alignas(32) static u8 buf[0x4000]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", {{GameVersion::GcnUsa, 0x1C00}, {GameVersion::GcnPal, 0x1C00}}, 0x4000), true); return buf; } +static u8* l_Egnd_mantTEX_U_get() { alignas(32) static u8 buf[0x4000]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", {{GameVersion::GcnUsa, 0x5C00}, {GameVersion::GcnPal, 0x5C00}}, 0x4000), true); return buf; } +static u8* l_Egnd_mantPAL_get() { alignas(32) static u8 buf[0x60]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", {{GameVersion::GcnUsa, 0x9C00}, {GameVersion::GcnPal, 0x9C00}}, 0x60), true); return buf; } #define l_Egnd_mantTEX (l_Egnd_mantTEX_get()) #define l_Egnd_mantTEX_U (l_Egnd_mantTEX_U_get()) #define l_Egnd_mantPAL (l_Egnd_mantPAL_get()) @@ -251,7 +254,9 @@ static u32 l_texCoord[338] = { }; #if TARGET_PC -static u8* l_Egnd_mantDL_get() { alignas(32) static u8 buf[0x3EC]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0xA9A0, 0x3EC), true); return buf; } +using GameVersion = dusk::version::GameVersion; + +static u8* l_Egnd_mantDL_get() { alignas(32) static u8 buf[0x3EC]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", {{GameVersion::GcnUsa, 0xA9A0}, {GameVersion::GcnPal, 0xA9A0}}, 0x3EC), true); return buf; } #define l_Egnd_mantDL (l_Egnd_mantDL_get()) #else #include "assets/l_Egnd_mantDL.h" diff --git a/src/d/actor/d_a_mg_fish.cpp b/src/d/actor/d_a_mg_fish.cpp index 90781345ad..6791bcb61c 100644 --- a/src/d/actor/d_a_mg_fish.cpp +++ b/src/d/actor/d_a_mg_fish.cpp @@ -22,6 +22,7 @@ #include "d/d_s_play.h" #include "d/d_vibration.h" #include "f_op/f_op_kankyo_mng.h" +#include "dusk/version.hpp" #include #define ANM_MG_FISH_MOUTH_CLOSE 4 @@ -3230,7 +3231,17 @@ static int daMg_Fish_Execute(mg_fish_class* i_this) { daPy_py_c* player = daPy_getPlayerActorClass(); -#if VERSION == VERSION_GCN_JPN +#if TARGET_PC + if (dusk::version::isRegionJpn()) { + lit_1008 = 0; + } else if (dusk::version::isRegionPal()) { + if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH) { + lit_1008 = 2; + } else { + lit_1008 = 0; + } + } +#elif VERSION == VERSION_GCN_JPN lit_1008 = 0; #elif VERSION == VERSION_GCN_PAL if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH) { @@ -3843,7 +3854,19 @@ static int daMg_Fish_Create(fopAc_ac_c* i_this) { a_this->mResName = "O_gD_bott"; } -#if VERSION == VERSION_GCN_JPN +#if TARGET_PC + if (dusk::version::isRegionJpn()) { + lit_1008 = 0; + } else if (dusk::version::isRegionPal()) { + if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH) { + lit_1008 = 2; + } else { + lit_1008 = 0; + } + } else { + lit_1008 = 1; + } +#elif VERSION == VERSION_GCN_JPN lit_1008 = 0; #elif VERSION == VERSION_GCN_PAL if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH) { diff --git a/src/d/actor/d_a_mg_fshop.cpp b/src/d/actor/d_a_mg_fshop.cpp index 99f39e410e..f0905efd5d 100644 --- a/src/d/actor/d_a_mg_fshop.cpp +++ b/src/d/actor/d_a_mg_fshop.cpp @@ -5,14 +5,15 @@ #include "d/dolzel_rel.h" // IWYU pragma: keep +#include "Z2AudioLib/Z2Instances.h" +#include "d/actor/d_a_mg_fish.h" #include "d/actor/d_a_mg_fshop.h" #include "d/actor/d_a_npc_henna.h" -#include "d/actor/d_a_mg_fish.h" #include "d/actor/d_a_player.h" -#include "f_op/f_op_camera_mng.h" -#include "d/d_timer.h" #include "d/d_s_play.h" -#include "Z2AudioLib/Z2Instances.h" +#include "d/d_timer.h" +#include "dusk/version.hpp" +#include "f_op/f_op_camera_mng.h" #if TARGET_PC #include "dusk/gyro.h" @@ -1742,7 +1743,18 @@ static int daFshop_Create(fopAc_ac_c* actor) { fopAcM_createChild(fpcNm_FSHOP_e, fopAcM_GetID(actor), 0xFFFFFF23, &actor->current.pos, fopAcM_GetRoomNo(actor), NULL, NULL, -1, NULL); u8 sp10; -#if VERSION == VERSION_GCN_PAL || VERSION == VERSION_WII_PAL +#if TARGET_PC + if (dusk::version::isRegionPal()) { + if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH) { + sp10 = 2; + } else { + sp10 = 0; + } + } else { + sp10 = 1; + } + +#elif VERSION == VERSION_GCN_PAL || VERSION == VERSION_WII_PAL if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH) { sp10 = 2; } else { diff --git a/src/d/actor/d_a_mg_rod.cpp b/src/d/actor/d_a_mg_rod.cpp index 96ad7aa148..956a9e3cff 100644 --- a/src/d/actor/d_a_mg_rod.cpp +++ b/src/d/actor/d_a_mg_rod.cpp @@ -25,6 +25,8 @@ #include #include +#include "dusk/version.hpp" + class dmg_rod_HIO_c : public JORReflexible { public: dmg_rod_HIO_c(); @@ -5734,10 +5736,22 @@ static void play_camera_u(dmg_rod_class* i_this) { static int dmg_rod_Execute(dmg_rod_class* i_this) { fopAc_ac_c* actor = &i_this->actor; + #if TARGET_PC + if (dusk::version::isPalOrAtLeastWiiR2()) { + if (dComIfGs_getPalLanguage() == 0) { + data_804BBBD4 = 2; + } else { + data_804BBBD4 = 0; + } + } else if (dusk::version::isRegionJpn()) { + data_804BBBD4 = 0; + } else { + data_804BBBD4 = 1; + } //TODO: It seems possible that dComIfGs_getPalLanguage returns a constant value for non-PAL // versions (causing the first block to be elided), and it's also possible that the value // being compared against is an enum value with per-version definitions. - #if VERSION == VERSION_SHIELD_DEBUG + #elif VERSION == VERSION_SHIELD_DEBUG if (dComIfGs_getPalLanguage() == 1) { data_804BBBD4 = 2; } else { @@ -6303,7 +6317,19 @@ static int dmg_rod_Create(fopAc_ac_c* i_this) { heap_size = 0xC9A0; } - #if VERSION == VERSION_SHIELD_DEBUG + #if TARGET_PC + if (dusk::version::isPalOrAtLeastWiiR2()) { + if (dComIfGs_getPalLanguage() == 0) { + data_804BBBD4 = 2; + } else { + data_804BBBD4 = 0; + } + } else if (dusk::version::isRegionJpn()) { + data_804BBBD4 = 0; + } else { + data_804BBBD4 = 1; + } + #elif VERSION == VERSION_SHIELD_DEBUG if (dComIfGs_getPalLanguage() == 1) { data_804BBBD4 = 2; } else { diff --git a/src/d/actor/d_a_player.cpp b/src/d/actor/d_a_player.cpp index 8ceb0ef237..6148d23e3a 100644 --- a/src/d/actor/d_a_player.cpp +++ b/src/d/actor/d_a_player.cpp @@ -369,18 +369,17 @@ JKRHeap* daPy_anmHeap_c::setAnimeHeap() { #if !PLATFORM_WII #if TARGET_PC #include "dusk/dvd_asset.hpp" +using GameVersion = dusk::version::GameVersion; static const u8* l_sightDL_get() { static u8 buf[0x89]; static bool _ = ( dusk::LoadDolAsset( buf, - #if VERSION == VERSION_GCN_PAL - 0x803BBDA0, - #elif VERSION == VERSION_GCN_JPN - 0x803B4220, - #elif VERSION == VERSION_GCN_USA - 0x803BA0C0, - #endif +{ + {GameVersion::GcnUsa, 0x803BA0C0}, + {GameVersion::GcnPal, 0x803BBDA0}, + {GameVersion::GcnJpn, 0x803B4220} + }, 0x89 ), true diff --git a/src/d/actor/d_a_title.cpp b/src/d/actor/d_a_title.cpp index 6df52abc5b..a75a96cb2e 100644 --- a/src/d/actor/d_a_title.cpp +++ b/src/d/actor/d_a_title.cpp @@ -1,21 +1,22 @@ #include "d/dolzel_rel.h" // IWYU pragma: keep +#include "JSystem/J2DGraph/J2DScreen.h" +#include "JSystem/J2DGraph/J2DTextBox.h" +#include "JSystem/JKernel/JKRExpHeap.h" +#include "JSystem/JKernel/JKRMemArchive.h" #include "d/actor/d_a_title.h" +#include "d/d_com_inf_game.h" +#include "d/d_demo.h" +#include "d/d_menu_collect.h" +#include "d/d_pane_class_alpha.h" #include "d/d_s_logo.h" #include "d/d_s_play.h" -#include "d/d_demo.h" -#include "d/d_pane_class_alpha.h" -#include "d/d_menu_collect.h" +#include "dusk/version.hpp" +#include "f_op/f_op_msg_mng.h" +#include "f_op/f_op_overlap_mng.h" +#include "f_op/f_op_scene_mng.h" #include "m_Do/m_Do_Reset.h" #include "m_Do/m_Do_controller_pad.h" -#include "d/d_com_inf_game.h" -#include "JSystem/JKernel/JKRExpHeap.h" -#include "f_op/f_op_overlap_mng.h" -#include "f_op/f_op_msg_mng.h" -#include "f_op/f_op_scene_mng.h" -#include "JSystem/J2DGraph/J2DScreen.h" -#include "JSystem/JKernel/JKRMemArchive.h" -#include "JSystem/J2DGraph/J2DTextBox.h" #include "m_Do/m_Do_graphic.h" #ifdef TARGET_PC @@ -49,7 +50,10 @@ static u8 const lit_3772[12] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -#if VERSION == VERSION_GCN_PAL +#if TARGET_PC +using namespace dusk::version; +#define l_arcName versionSelect({{GameVersion::GcnPal, "TitlePal"}}, "Title") +#elif VERSION == VERSION_GCN_PAL static char const l_arcName[] = "TitlePal"; #else static char const l_arcName[] = "Title"; @@ -59,7 +63,7 @@ daTit_HIO_c::daTit_HIO_c() { mPSScaleX = 1.0f; mPSScaleY = 1.0f; - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC || VERSION == VERSION_GCN_PAL switch (OSGetLanguage()) { case OS_LANGUAGE_ENGLISH: case OS_LANGUAGE_GERMAN: diff --git a/src/d/actor/d_flower.inc b/src/d/actor/d_flower.inc index 1850e1e1ad..5f54ea4bda 100644 --- a/src/d/actor/d_flower.inc +++ b/src/d/actor/d_flower.inc @@ -17,7 +17,8 @@ const u16 l_J_Ohana00_64TEX__height = 63; #if TARGET_PC #include "dusk/dvd_asset.hpp" -static u8* l_J_Ohana00_64TEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x9060, 0x800), true); return buf; } +using GameVersion = dusk::version::GameVersion; +static u8* l_J_Ohana00_64TEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x9060}, {GameVersion::GcnPal, 0x9060}}, 0x800), true); return buf; } #define l_J_Ohana00_64TEX (l_J_Ohana00_64TEX_get()) #else #include "assets/l_J_Ohana00_64TEX.h" @@ -113,10 +114,12 @@ static u8 l_flowerTexCoord[] = { 0x3E, 0xA7, 0x72, 0xD6, 0xBD, 0x2F, 0x46, 0xAA}; #if TARGET_PC -static u8* l_J_hana00DL_get() { static u8 buf[0x150]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x9D20, 0x150), true); return buf; } -static u8* l_J_hana00_cDL_get() { static u8 buf[0xDE]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x9E80, 0xDE), true); return buf; } -static u8* l_matDL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x9F60, 0x99), true); return buf; } -static u8* l_matLight4DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xA000, 0x99), true); return buf; } +using GameVersion = dusk::version::GameVersion; + +static u8* l_J_hana00DL_get() { static u8 buf[0x150]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x9D20}, {GameVersion::GcnPal, 0x9D20}}, 0x150), true); return buf; } +static u8* l_J_hana00_cDL_get() { static u8 buf[0xDE]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x9E80}, {GameVersion::GcnPal, 0x9E80}}, 0xDE), true); return buf; } +static u8* l_matDL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x9F60}, {GameVersion::GcnPal, 0x9F60}}, 0x99), true); return buf; } +static u8* l_matLight4DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0xA000}, {GameVersion::GcnPal, 0xA000}}, 0x99), true); return buf; } #define l_J_hana00DL (l_J_hana00DL_get()) #define l_J_hana00_cDL (l_J_hana00_cDL_get()) #define l_matDL (l_matDL_get()) @@ -142,7 +145,8 @@ const u16 l_J_Ohana01_64128_0419TEX__height = 127; #endif #if TARGET_PC -static u8* l_J_Ohana01_64128_0419TEX_get() { static u8 buf[0x1000]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xA0A0, 0x1000), true); return buf; } +using GameVersion = dusk::version::GameVersion; +static u8* l_J_Ohana01_64128_0419TEX_get() { static u8 buf[0x1000]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0xA0A0}, {GameVersion::GcnPal, 0xA0A0}}, 0x1000), true); return buf; } #define l_J_Ohana01_64128_0419TEX (l_J_Ohana01_64128_0419TEX_get()) #else #include "assets/l_J_Ohana01_64128_0419TEX.h" @@ -274,11 +278,13 @@ static u8 l_flowerTexCoord2[] = { 0x40, 0x1B, 0x7D, 0x52, 0x3F, 0x80, 0x3F, 0x79, 0x40, 0x1B, 0x7D, 0x52, 0x3F, 0x51, 0x10, 0x6F}; #if TARGET_PC -static u8* l_J_hana01DL_get() { static u8 buf[0x138]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xB7C0, 0x138), true); return buf; } -static u8* l_J_hana01_c_00DL_get() { static u8 buf[0xDE]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xB900, 0xDE), true); return buf; } -static u8* l_J_hana01_c_01DL_get() { static u8 buf[0x128]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xB9E0, 0x128), true); return buf; } -static u8* l_mat2DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xBB20, 0x99), true); return buf; } -static u8* l_mat2Light4DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xBBC0, 0x99), true); return buf; } +using GameVersion = dusk::version::GameVersion; + +static u8* l_J_hana01DL_get() { static u8 buf[0x138]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0xB7C0}, {GameVersion::GcnPal, 0xB7C0}}, 0x138), true); return buf; } +static u8* l_J_hana01_c_00DL_get() { static u8 buf[0xDE]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0xB900}, {GameVersion::GcnPal, 0xB900}}, 0xDE), true); return buf; } +static u8* l_J_hana01_c_01DL_get() { static u8 buf[0x128]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0xB9E0}, {GameVersion::GcnPal, 0xB9E0}}, 0x128), true); return buf; } +static u8* l_mat2DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0xBB20}, {GameVersion::GcnPal, 0xBB20}}, 0x99), true); return buf; } +static u8* l_mat2Light4DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0xBBC0}, {GameVersion::GcnPal, 0xBBC0}}, 0x99), true); return buf; } #define l_J_hana01DL (l_J_hana01DL_get()) #define l_J_hana01_c_00DL (l_J_hana01_c_00DL_get()) #define l_J_hana01_c_01DL (l_J_hana01_c_01DL_get()) diff --git a/src/d/actor/d_grass.inc b/src/d/actor/d_grass.inc index ab2724060f..9bc8815753 100644 --- a/src/d/actor/d_grass.inc +++ b/src/d/actor/d_grass.inc @@ -20,8 +20,9 @@ const u16 l_M_kusa05_RGBATEX__height = 31; #if TARGET_PC #include "dusk/dvd_asset.hpp" -static u8* l_M_kusa05_RGBATEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x7680, 0x800), true); return buf; } -static u8* l_M_Hijiki00TEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x7E80, 0x800), true); return buf; } +using GameVersion = dusk::version::GameVersion; +static u8* l_M_kusa05_RGBATEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x7680}, {GameVersion::GcnPal, 0x7680}}, 0x800), true); return buf; } +static u8* l_M_Hijiki00TEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x7E80}, {GameVersion::GcnPal, 0x7E80}}, 0x800), true); return buf; } #define l_M_kusa05_RGBATEX (l_M_kusa05_RGBATEX_get()) #define l_M_Hijiki00TEX (l_M_Hijiki00TEX_get()) #else @@ -113,12 +114,14 @@ static u8 l_texCoord[160] = { }; #if TARGET_PC -static u8* l_M_Kusa_9qDL_get() { static u8 buf[0xCB]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8B00, 0xCB), true); return buf; } -static u8* l_M_Kusa_9q_cDL_get() { static u8 buf[0xCB]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8BE0, 0xCB), true); return buf; } -static u8* l_M_TenGusaDL_get() { static u8 buf[0xD4]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8CC0, 0xD4), true); return buf; } -static u8* l_Tengusa_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8DA0, 0xA8), true); return buf; } -static u8* l_kusa9q_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8E60, 0xA8), true); return buf; } -static u8* l_kusa9q_l4_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8F20, 0xA8), true); return buf; } +using GameVersion = dusk::version::GameVersion; + +static u8* l_M_Kusa_9qDL_get() { static u8 buf[0xCB]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x8B00}, {GameVersion::GcnPal, 0x8B00}}, 0xCB), true); return buf; } +static u8* l_M_Kusa_9q_cDL_get() { static u8 buf[0xCB]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x8BE0}, {GameVersion::GcnPal, 0x8BE0}}, 0xCB), true); return buf; } +static u8* l_M_TenGusaDL_get() { static u8 buf[0xD4]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x8CC0}, {GameVersion::GcnPal, 0x8CC0}}, 0xD4), true); return buf; } +static u8* l_Tengusa_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x8DA0}, {GameVersion::GcnPal, 0x8DA0}}, 0xA8), true); return buf; } +static u8* l_kusa9q_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x8E60}, {GameVersion::GcnPal, 0x8E60}}, 0xA8), true); return buf; } +static u8* l_kusa9q_l4_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x8F20}, {GameVersion::GcnPal, 0x8F20}}, 0xA8), true); return buf; } #define l_M_Kusa_9qDL (l_M_Kusa_9qDL_get()) #define l_M_Kusa_9q_cDL (l_M_Kusa_9q_cDL_get()) #define l_M_TenGusaDL (l_M_TenGusaDL_get()) diff --git a/src/d/d_file_sel_info.cpp b/src/d/d_file_sel_info.cpp index f305f59a9e..0c987e6d63 100644 --- a/src/d/d_file_sel_info.cpp +++ b/src/d/d_file_sel_info.cpp @@ -14,6 +14,8 @@ #include #include +#include "dusk/version.hpp" + dFile_info_c::dFile_info_c(JKRArchive* i_archive, u8 param_1) { mArchive = i_archive; field_0x22 = param_1; @@ -169,7 +171,18 @@ void dFile_info_c::setSaveDate(dSv_save_c* i_savedata) { OSCalendarTime time; OSTicksToCalendarTime(i_savedata->getPlayer().getPlayerStatusB().getDateIpl(), &time); - #if (VERSION == VERSION_GCN_JPN) || (VERSION == VERSION_WII_JPN) + #if TARGET_PC + if (dusk::version::isRegionJpn()) { + sprintf(mSaveDate, "%d.%02d.%02d %02d:%02d", time.year, time.mon + 1, time.mday, + time.hour, time.min); + } else if (dusk::version::isRegionPal() && dComIfGs_getPalLanguage() != dSv_player_config_c::LANGUAGE_ENGLISH) { + sprintf(mSaveDate, "%02d/%02d/%d %02d:%02d", time.mday, time.mon + 1, time.year, time.hour, + time.min); + } else { + sprintf(mSaveDate, "%02d/%02d/%d %02d:%02d", time.mon + 1, time.mday, time.year, time.hour, + time.min); + } + #elif (VERSION == VERSION_GCN_JPN) || (VERSION == VERSION_WII_JPN) sprintf(mSaveDate, "%d.%02d.%02d %02d:%02d", time.year, time.mon + 1, time.mday, time.hour, time.min); #elif VERSION == VERSION_GCN_PAL diff --git a/src/d/d_menu_fishing.cpp b/src/d/d_menu_fishing.cpp index 615323767b..b76002d540 100644 --- a/src/d/d_menu_fishing.cpp +++ b/src/d/d_menu_fishing.cpp @@ -16,6 +16,8 @@ #include "m_Do/m_Do_graphic.h" #include +#include "dusk/version.hpp" + typedef void (dMenu_Fishing_c::*initFunc)(); initFunc map_init_process[] = { &dMenu_Fishing_c::wait_init, @@ -135,9 +137,9 @@ bool dMenu_Fishing_c::isSync() { } void dMenu_Fishing_c::init() { - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC || VERSION == VERSION_GCN_PAL BOOL isEnglish = FALSE; - if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH) { + if (dusk::version::isRegionUsa() || (dusk::version::isRegionPal() && dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH)) { isEnglish = TRUE; } #endif @@ -145,7 +147,7 @@ void dMenu_Fishing_c::init() { for (int i = 0; i < MAX_FINDABLE_FISHES; i++) { if (dComIfGs_getFishNum(i) != 0) { // Fish has been caught once, display it along with it's params - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC || VERSION == VERSION_GCN_PAL if (isEnglish) { setFishParam(i, dComIfGs_getFishNum(i), dComIfGs_getFishSize(i) / 2.54f); } else { diff --git a/src/d/d_msg_class.cpp b/src/d/d_msg_class.cpp index 7af18f0732..4040eb0d7f 100644 --- a/src/d/d_msg_class.cpp +++ b/src/d/d_msg_class.cpp @@ -307,7 +307,7 @@ static u8 getOutFontNumberType(int param_0) { } } -#if VERSION == VERSION_GCN_PAL +#if TARGET_PC || VERSION == VERSION_GCN_PAL static void setPlayerName(char* i_player_name, u8 param_2) { if (param_2 != 0) { strcpy(i_player_name, dComIfGs_getPlayerName()); @@ -1485,7 +1485,7 @@ bool jmessage_tMeasureProcessor::do_tag(u32 i_tag, void const* i_data, u32 i_siz char buffer[40]; switch (i_tag & 0xFF00FFFF) { case MSGTAG_PLAYER_GENITIV: - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC || VERSION == VERSION_GCN_PAL if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_GERMAN) { setPlayerName(buffer, 1); } else { @@ -1495,7 +1495,7 @@ bool jmessage_tMeasureProcessor::do_tag(u32 i_tag, void const* i_data, u32 i_siz push_word(buffer); return true; case MSGTAG_HORSE_GENITIV: - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC || VERSION == VERSION_GCN_PAL if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_GERMAN) { setHorseName(buffer, 1); } else { @@ -4270,7 +4270,7 @@ bool jmessage_string_tMeasureProcessor::do_tag(u32 i_tag, void const* i_data, u3 char buffer[40]; switch (i_tag & 0xFF00FFFF) { case MSGTAG_PLAYER_GENITIV: - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC || VERSION == VERSION_GCN_PAL if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_GERMAN) { setPlayerName(buffer, 1); } else { @@ -4281,7 +4281,7 @@ bool jmessage_string_tMeasureProcessor::do_tag(u32 i_tag, void const* i_data, u3 stack_pushCurrent(buffer); break; case MSGTAG_HORSE_GENITIV: - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC || VERSION == VERSION_GCN_PAL if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_GERMAN) { setHorseName(buffer, 1); } else { @@ -4878,7 +4878,7 @@ bool jmessage_string_tRenderingProcessor::do_tag(u32 i_tag, void const* i_data, char buffer[40]; switch (i_tag & 0xFF00FFFF) { case MSGTAG_PLAYER_GENITIV: - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC || VERSION == VERSION_GCN_PAL if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_GERMAN) { setPlayerName(buffer, 1); } else { @@ -4889,7 +4889,7 @@ bool jmessage_string_tRenderingProcessor::do_tag(u32 i_tag, void const* i_data, push_word(buffer); break; case MSGTAG_HORSE_GENITIV: - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC || VERSION == VERSION_GCN_PAL if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_GERMAN) { setHorseName(buffer, 1); } else { diff --git a/src/d/d_msg_object.cpp b/src/d/d_msg_object.cpp index 9b7b64ebda..ae0e3d8427 100644 --- a/src/d/d_msg_object.cpp +++ b/src/d/d_msg_object.cpp @@ -24,9 +24,11 @@ #include "f_op/f_op_msg_mng.h" #include #include + +#include "JSystem/JKernel/JKRExpHeap.h" +#include "dusk/version.hpp" #include "m_Do/m_Do_controller_pad.h" #include "m_Do/m_Do_lib.h" -#include "JSystem/JKernel/JKRExpHeap.h" #if TARGET_PC #include "dusk/settings.h" @@ -1643,7 +1645,30 @@ void dMsgObject_c::readMessageGroupLocal(mDoDvdThd_mountXArchive_c** p_arcMount) #else #if TARGET_PC // Original game UB - snprintf(arcName, sizeof(arcName), "/res/Msgus/bmgres%d.arc", msgGroup); + + if (dusk::version::isRegionPal()) { + switch (dComIfGs_getPalLanguage()) { + case dSv_player_config_c::LANGUAGE_GERMAN: + snprintf(arcName, sizeof(arcName), "/res/Msgde/bmgres%d.arc", msgGroup); + break; + case dSv_player_config_c::LANGUAGE_FRENCH: + snprintf(arcName, sizeof(arcName), "/res/Msgfr/bmgres%d.arc", msgGroup); + break; + case dSv_player_config_c::LANGUAGE_SPANISH: + snprintf(arcName, sizeof(arcName), "/res/Msgsp/bmgres%d.arc", msgGroup); + break; + case dSv_player_config_c::LANGUAGE_ITALIAN: + snprintf(arcName, sizeof(arcName), "/res/Msgit/bmgres%d.arc", msgGroup); + break; + default: + snprintf(arcName, sizeof(arcName), "/res/Msguk/bmgres%d.arc", msgGroup); + } + } else if (dusk::version::isRegionJpn()) { + snprintf(arcName, sizeof(arcName), "/res/Msgjp/bmgres%d.arc", msgGroup); + } else { + snprintf(arcName, sizeof(arcName), "/res/Msgus/bmgres%d.arc", msgGroup); + } + #else sprintf(arcName, "/res/Msgus/bmgres%d.arc", msgGroup); #endif diff --git a/src/d/d_msg_unit.cpp b/src/d/d_msg_unit.cpp index f773abd373..7bbe8b3d70 100644 --- a/src/d/d_msg_unit.cpp +++ b/src/d/d_msg_unit.cpp @@ -334,11 +334,11 @@ void dMsgUnit_c::setTag(int i_type, int i_value, char* o_buffer, bool param_4) { vals[1] = ((dMsgUnit_inf1_section_t*)pInfoBlock)->entries[i_type].endFrame; #endif -#if REGION_PAL +#if TARGET_PC || REGION_PAL if (i_value == 1 || (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_FRENCH && i_value == 0)) { -#elif !REGION_USA +#elif !REGION_USA // Dusk TODO: What? This checks for Spanish when *not* PAL or USA? if (i_value == 1 || (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_SPANISH && i_value == 0)) { diff --git a/src/d/d_name.cpp b/src/d/d_name.cpp index e4232eff34..1f3ccbb1d7 100644 --- a/src/d/d_name.cpp +++ b/src/d/d_name.cpp @@ -8,9 +8,15 @@ #include "m_Do/m_Do_controller_pad.h" #include #include + #include "JSystem/J2DGraph/J2DAnmLoader.h" +#include "dusk/version.hpp" #include "f_op/f_op_msg_mng.h" +static bool isPalOrJpn() { + return dusk::version::isRegionPal() || dusk::version::isRegionJpn(); +} + static const char* l_mojiHira[65] = { "あ", "い", "う", "え", "お", "か", "き", "く", "け", "こ", "さ", "し", "す", "せ", "そ", "た", "ち", "つ", "て", "と", "な", "に", "ぬ", "ね", "の", "は", @@ -66,15 +72,31 @@ static const char* l_mojiEisu[65] = { "X", "k", "x", ",", "L", "Y", "l", "y", ".", "M", "Z", "m", "z", " ", }; -#if REGION_PAL -static char* l_mojiEisuPal_1[65] = { +#if TARGET_PC +// The game normally mutates this string list to fill in the real character codes. +// That can't work on a modern platform, so instead I've filled them out ahead of time. +static const char* l_mojiEisuPal_1[65] = { + "A", "N", "\xC0", "\xCF", "1", "B", "O", "\xC1", "\xD0", "2", "C", "P", "\xC2", "\xD1", "3", "D", "Q", + "\xC3", "\xD2", "4", "E", "R", "\xC4", "\xD3", "5", "F", "S", "\xC5", "\xD4", "6", "G", "T", "\xC6", "\xD5", + "7", "H", "U", "\xC7", "\xD6", "8", "I", "V", "\xC8", "\xD7", "9", "J", "W", "\xC9", "\xD8", "0", "K", + "X", "\xCA", "\xD9", ",", "L", "Y", "\xCB", "\xDA", ".", "M", "Z", "\xCC", "\xDB", " ", +}; + +static const char* l_mojiEisuPal_2[65] = { + "a", "n", "\xE0", "\xEF", "1", "b", "o", "\xE1", "\xF0", "2", "c", "p", "\xE2", "\xF1", "3", "d", "q", + "\xE3", "\xF2", "4", "e", "r", "\xE4", "\xF3", "5", "f", "s", "\xE5", "\xF4", "6", "g", "t", "\xE6", + "\xF5", "7", "h", "u", "\xE7", "\xF6", "8", "i", "v", "\xE8", "\xF7", "9", "j", "w", "\xE9", "\xF8", "0", + "k", "x", "\xEA", "\xF9", ",", "l", "y", "\xEB", "\xFA", ".", "m", "z", "\xEC", "\xFB", " ", +}; +#elif REGION_PAL +static const char* l_mojiEisuPal_1[65] = { "A", "N", "AA", "BB", "1", "B", "O", "CC", "DD", "2", "C", "P", "EE", "FF", "3", "D", "Q", "GG", "HH", "4", "E", "R", "II", "JJ", "5", "F", "S", "KK", "LL", "6", "G", "T", "MM", "NN", "7", "H", "U", "OO", "PP", "8", "I", "V", "QQ", "RR", "9", "J", "W", "SS", "TT", "0", "K", "X", "UU", "VV", ",", "L", "Y", "WW", "XX", ".", "M", "Z", "YY", "ZZ", " ", }; -static char* l_mojiEisuPal_2[65] = { +static const char* l_mojiEisuPal_2[65] = { "a", "n", "aa", "bb", "1", "b", "o", "cc", "dd", "2", "c", "p", "ee", "ff", "3", "d", "q", "gg", "hh", "4", "e", "r", "ii", "jj", "5", "f", "s", "kk", "ll", "6", "g", "t", "mm", "nn", "7", "h", "u", "oo", "pp", "8", "i", "v", "qq", "rr", "9", "j", "w", "ss", "tt", "0", @@ -82,6 +104,16 @@ static char* l_mojiEisuPal_2[65] = { }; #endif +#if TARGET_PC +// ' ' (full-width space) +#define SPACE_MAYBE_FULL (dusk::version::isRegionJpn() ? '\x81\x40' : ' ') +#elif REGION_JPN +// ' ' (full-width space) +#define SPACE_MAYBE_FULL '\x81\x40' +#else +#define SPACE_MAYBE_FULL ' ' +#endif + static dNm_HIO_c g_nmHIO; typedef void (dName_c::*selProcFunc)(void); @@ -163,13 +195,18 @@ void dName_c::init() { field_0x2ac = mSelProc; field_0x2ad = mSelProc; field_0x2ae = field_0x2ac; - #if REGION_PAL || REGION_JPN + #if TARGET_PC + mMojiSet = isPalOrJpn() ? MOJI_HIRA : MOJI_EIGO; + #elif REGION_PAL || REGION_JPN mMojiSet = MOJI_HIRA; #else mMojiSet = MOJI_EIGO; #endif mPrevMojiSet = 255; - #if REGION_PAL || REGION_JPN + #if TARGET_PC + mSelMenu = isPalOrJpn() ? MENU_HIRA : MENU_END; + mPrevSelMenu = isPalOrJpn() ? MENU_HIRA : MENU_END; + #elif REGION_PAL || REGION_JPN mSelMenu = MENU_HIRA; mPrevSelMenu = MENU_HIRA; #else @@ -187,7 +224,8 @@ void dName_c::initial() { mNextNameStr[0] = 0; } - #if REGION_PAL || REGION_JPN + #if TARGET_PC || REGION_PAL || REGION_JPN + IF_DUSK_BLOCK(isPalOrJpn()) if (mSelProc == PROC_MOJI_SELECT) { mMenuIcon[mMojiSet]->scale(g_nmHIO.mMenuScale, g_nmHIO.mMenuScale); mMenuText[mMojiSet]->setWhite(JUtility::TColor(0xC8, 0xC8, 0xC8, 0xFF)); @@ -196,6 +234,7 @@ void dName_c::initial() { mMenuText[mPrevMojiSet]->setWhite(JUtility::TColor(0x96, 0x96, 0x96, 0xFF)); } } + IF_DUSK_BLOCK_END #endif } @@ -230,8 +269,8 @@ void dName_c::_move() { stick->checkTrigger(); (this->*SelProc[mSelProc])(); - #if REGION_PAL || REGION_JPN - if (mDoCPd_c::getTrigY(PAD_1)) { + #if TARGET_PC || REGION_PAL || REGION_JPN + if (IF_DUSK(isPalOrJpn() &&) mDoCPd_c::getTrigY(PAD_1)) { mDoAud_seStart(Z2SE_SY_DUMMY, 0, 0, 0); mPrevMojiSet = mMojiSet; mMojiSet++; @@ -245,8 +284,8 @@ void dName_c::_move() { mojiListChange(); } else { #endif - #if REGION_JPN - if (mDoCPd_c::getTrigX(PAD_1)) { + #if TARGET_PC || REGION_JPN + if (IF_DUSK(dusk::version::isRegionJpn() &&) mDoCPd_c::getTrigX(PAD_1)) { if (mCurPos != 0) { if (mojiChange(mCurPos - 1) == 1) { mDoAud_seStart(Z2SE_SY_DUMMY, 0, 0, 0); @@ -283,12 +322,14 @@ void dName_c::_move() { backSpace(); } } else if (mDoCPd_c::getTrigStart(PAD_1)) { +#define EIGO_OR_END DUSK_IF_ELSE((dusk::version::isRegionPal() ? MENU_EIGO : MENU_END), MENU_END) + #if REGION_PAL if ((mSelProc != PROC_MENU_SELECT || mSelMenu != MENU_EIGO) && (mSelProc == PROC_MENU_SELECT || mSelProc == PROC_MOJI_SELECT)) { #else - if ((mSelProc != PROC_MENU_SELECT || mSelMenu != MENU_END) && + if ((mSelProc != PROC_MENU_SELECT || mSelMenu != EIGO_OR_END) && (mSelProc == PROC_MENU_SELECT || mSelProc == PROC_MOJI_SELECT)) { #endif @@ -297,7 +338,7 @@ void dName_c::_move() { #if REGION_PAL mSelMenu = MENU_EIGO; #else - mSelMenu = MENU_END; + mSelMenu = EIGO_OR_END; #endif switch (mSelProc) { @@ -314,10 +355,10 @@ void dName_c::_move() { } } } - #if REGION_JPN + #if TARGET_PC || REGION_JPN } #endif - #if REGION_PAL || REGION_JPN + #if TARGET_PC || REGION_PAL || REGION_JPN } #endif @@ -327,10 +368,9 @@ void dName_c::_move() { int dName_c::nameCheck() { for (int i = 8, len = 7; i > 0; i--) { #if REGION_JPN - // ' ' (full-width space) if (mChrInfo[len].mCharacter != ' ' && mChrInfo[len].mCharacter != '\x81\x40') { #else - if (mChrInfo[len].mCharacter != ' ') { + if (mChrInfo[len].mCharacter != ' ' IF_DUSK(&& (!dusk::version::isRegionJpn() || mChrInfo[len].mCharacter != '\x81\x40'))) { #endif return len + 1; } @@ -344,8 +384,8 @@ void dName_c::playNameSet(int nameLength) { char* str = mInputStr; for (int i = 0; i < nameLength; i++) { - #if REGION_JPN - if (mChrInfo[i].mMojiSet == 2) { + #if TARGET_PC || REGION_JPN + if (!dusk::version::isRegionJpn() || mChrInfo[i].mMojiSet == 2) { *str = mChrInfo[i].mCharacter; str += 1; } else { @@ -727,7 +767,34 @@ int dName_c::getMoji() { int result = -1; const char* moji; - #if REGION_PAL + #if TARGET_PC + if (dusk::version::isRegionPal()) { + switch (mMojiSet) { + case MOJI_HIRA: + moji = l_mojiEisuPal_1[mCharRow + mCharColumn * 5]; + break; + case MOJI_KATA: + moji = l_mojiEisuPal_2[mCharRow + mCharColumn * 5]; + break; + default: + abort(); + } + } else { + switch (mMojiSet) { + case MOJI_HIRA: + moji = l_mojiHira[mCharRow + mCharColumn * 5]; + break; + case MOJI_KATA: + moji = l_mojikata[mCharRow + mCharColumn * 5]; + break; + case MOJI_EIGO: + moji = l_mojiEisu[mCharRow + mCharColumn * 5]; + break; + default: + abort(); + } + } + #elif REGION_PAL switch (mMojiSet) { case MOJI_HIRA: moji = l_mojiEisuPal_1[mCharRow + mCharColumn * 5]; @@ -750,7 +817,17 @@ int dName_c::getMoji() { } #endif - #if REGION_JPN + #if TARGET_PC + if (dusk::version::isRegionJpn()) { + if (*(u8*)moji >> 4 == 0x8 || *(u8*)moji >> 4 == 0x9) { + result = *(u16*)moji; + } else { + result = *moji; + } + } else { + result = *moji; + } + #elif REGION_JPN if (*(u8*)moji >> 4 == 0x8 || *(u8*)moji >> 4 == 0x9) { result = *(u16*)moji; } else { @@ -763,6 +840,14 @@ int dName_c::getMoji() { return result; } +#if TARGET_PC +#define CHAR_TRUNC(val) (dusk::version::isRegionPal() ? val & 0xFF : val) +#elif REGION_PAL +#define CHAR_TRUNC(val) (val & 0xFF) +#else +#define CHAR_TRUNC(val) val +#endif + void dName_c::setMoji(int moji) { if (mCurPos == 8 || nameCheck() == 8) { mDoAud_seStart(Z2SE_SYS_ERROR, NULL, 0, 0); @@ -771,24 +856,14 @@ void dName_c::setMoji(int moji) { s32 notEmpty = false; for (int i = mCurPos; i < 8; i++) { - #if REGION_JPN - // ' ' (full-width space) - if (mChrInfo[i].mCharacter != '\x81\x40') { - #else - if (mChrInfo[i].mCharacter != ' ') { - #endif + if (mChrInfo[i].mCharacter != SPACE_MAYBE_FULL) { notEmpty = true; break; } } if (notEmpty) { - #if REGION_JPN - // ' ' (full-width space) - if (mChrInfo[7].mCharacter == '\x81\x40') { - #else - if (mChrInfo[7].mCharacter == ' ') { - #endif + if (mChrInfo[7].mCharacter == SPACE_MAYBE_FULL) { for (int i = 6; i >= mCurPos; i--) { mChrInfo[i + 1] = mChrInfo[i]; } @@ -797,11 +872,7 @@ void dName_c::setMoji(int moji) { mChrInfo[mCurPos].mRow = mCharRow; mChrInfo[mCurPos].mMojiSet = mMojiSet; mChrInfo[mCurPos].field_0x3 = 1; - #if REGION_PAL - mChrInfo[mCurPos].mCharacter = moji & 0xFF; - #else - mChrInfo[mCurPos].mCharacter = moji; - #endif + mChrInfo[mCurPos].mCharacter = CHAR_TRUNC(moji); if (mCurPos != 8) { mLastCurPos = mCurPos; @@ -814,11 +885,7 @@ void dName_c::setMoji(int moji) { mChrInfo[mCurPos].mRow = mCharRow; mChrInfo[mCurPos].mMojiSet = mMojiSet; mChrInfo[mCurPos].field_0x3 = 1; - #if REGION_PAL - mChrInfo[mCurPos].mCharacter = moji & 0xFF; - #else - mChrInfo[mCurPos].mCharacter = moji; - #endif + mChrInfo[mCurPos].mCharacter = CHAR_TRUNC(moji); if (mCurPos != 8) { mLastCurPos = mCurPos; @@ -844,13 +911,8 @@ void dName_c::setNameText() { "CR\x1b" "CC[000000]\x1bGM[0]%c\x1bHM\x1b" "CC[ffffff]\x1bGM[0]%c", - #if REGION_PAL - (u8)mChrInfo[i].mCharacter & 0xFF, - (u8)mChrInfo[i].mCharacter & 0xFF - #else - (u8)mChrInfo[i].mCharacter, - (u8)mChrInfo[i].mCharacter - #endif + CHAR_TRUNC((u8)mChrInfo[i].mCharacter), + CHAR_TRUNC((u8)mChrInfo[i].mCharacter) ); #if REGION_JPN } else { @@ -889,7 +951,29 @@ void dName_c::nameCursorMove() { void dName_c::selectCursorMove() { int idx; - #if REGION_PAL + #if TARGET_PC + if (dusk::version::isRegionPal()) { + if (mCharColumn < 3) { + idx = 0; + } else if (mCharColumn < 6) { + idx = 1; + } else if (mCharColumn >= 6) { + idx = 2; + } + } else if (dusk::version::isRegionJpn()) { + if (mCharColumn < 3) { + idx = 0; + } else if (mCharColumn < 6) { + idx = 1; + } else if (mCharColumn < 8) { + idx = 2; + } else if (mCharColumn >= 8) { + idx = 3; + } + } else { + idx = 3; + } + #elif REGION_PAL if (mCharColumn < 3) { idx = 0; } else if (mCharColumn < 6) { @@ -930,7 +1014,36 @@ void dName_c::selectCursorMove() { void dName_c::menuCursorPosSet() { mPrevSelMenu = mSelMenu; - #if REGION_PAL + #if TARGET_PC + if (dusk::version::isRegionPal()) { + if (mCharColumn < 3) { + mSelMenu = MENU_HIRA; + } else if (mCharColumn < 6) { + mSelMenu = MENU_KATA; + } else if (mCharColumn >= 6) { + mSelMenu = MENU_EIGO; + } + } else if (dusk::version::isRegionJpn()) { + if (mCharColumn < 3) { + mSelMenu = MENU_HIRA; + return; + } + if (mCharColumn < 6) { + mSelMenu = MENU_KATA; + return; + } + if (mCharColumn < 8) { + mSelMenu = MENU_EIGO; + return; + } + if (mCharColumn >= 8) { + mSelMenu = MENU_END; + return; + } + } else { + mSelMenu = MENU_END; + } + #elif REGION_PAL if (mCharColumn < 3) { mSelMenu = MENU_HIRA; } else if (mCharColumn < 6) { @@ -961,28 +1074,28 @@ void dName_c::menuCursorPosSet() { } void dName_c::MenuSelect() { - #if REGION_PAL || REGION_JPN - if (stick->checkRightTrigger()) { + #if TARGET_PC || REGION_PAL || REGION_JPN + if (isPalOrJpn() && stick->checkRightTrigger()) { mDoAud_seStart(Z2SE_SY_CURSOR_OPTION, NULL, 0, 0); mPrevSelMenu = mSelMenu; mSelMenu++; #if REGION_PAL if (mSelMenu > MENU_EIGO) { #else - if (mSelMenu > MENU_END) { + if (mSelMenu > EIGO_OR_END) { #endif mSelMenu = MENU_HIRA; } MenuSelectAnmInit(); mSelProc = PROC_MENU_SEL_ANM; - } else if (stick->checkLeftTrigger()) { + } else if (isPalOrJpn() && stick->checkLeftTrigger()) { mDoAud_seStart(Z2SE_SY_CURSOR_OPTION, NULL, 0, 0); mPrevSelMenu = mSelMenu; if (mSelMenu == MENU_HIRA) { #if REGION_JPN mSelMenu = MENU_END; #else - mSelMenu = MENU_EIGO; + mSelMenu = dusk::version::isRegionJpn() ? MENU_END : MENU_EIGO; #endif } else { mSelMenu--; @@ -1009,7 +1122,7 @@ void dName_c::MenuSelect() { #if REGION_PAL if (mSelMenu == MENU_EIGO) { #else - if (mSelMenu == MENU_END) { + if (mSelMenu == EIGO_OR_END) { #endif if (nameCheck() != 0) { mDoAud_seStart(Z2SE_SY_NAME_OK, NULL, 0, 0); @@ -1024,7 +1137,7 @@ void dName_c::MenuSelect() { #if REGION_PAL if (mSelMenu == MENU_EIGO) { #else - if (mSelMenu == MENU_END) { + if (mSelMenu == EIGO_OR_END) { #endif if (nameCheck() != 0) { mDoAud_seStart(Z2SE_SY_NAME_OK, NULL, 0, 0); @@ -1067,9 +1180,11 @@ void dName_c::MenuSelectAnm2() { if (canMove == true) { if (prevMenu_i != mojiSet_i) { mMenuText[prevMenu_i]->setWhite(JUtility::TColor(0x96, 0x96, 0x96, 0xFF)); - #if REGION_PAL || REGION_JPN + #if TARGET_PC || REGION_PAL || REGION_JPN + IF_DUSK_BLOCK(isPalOrJpn()) mMenuIcon[mojiSet_i]->scale(g_nmHIO.mMenuScale, g_nmHIO.mMenuScale); mMenuText[mojiSet_i]->setWhite(JUtility::TColor(0xC8, 0xC8, 0xC8, 0xFF)); + IF_DUSK_BLOCK_END #endif } selectCursorMove(); @@ -1081,6 +1196,11 @@ void dName_c::MenuSelectAnm2() { void dName_c::MenuSelectAnm3() {} void dName_c::menuAbtnSelect() { +#if TARGET_PC + if (dusk::version::isRegionPal() && mSelMenu == MENU_EIGO) { + goto pal_eigo; + } +#endif switch (mSelMenu) { case MENU_HIRA: case MENU_KATA: @@ -1098,6 +1218,7 @@ void dName_c::menuAbtnSelect() { #else case MENU_END: #endif + IF_DUSK(pal_eigo:) int nameNum = nameCheck(); if (nameNum != 0) { playNameSet(nameNum); @@ -1116,44 +1237,33 @@ void dName_c::backSpace() { if (mCurPos != 0) { mDoAud_seStart(Z2SE_SY_NAME_DELETE, NULL, 0, 0); - #if REGION_JPN - // ' ' (full-width space) - if (mCurPos == 8 && mChrInfo[7].mCharacter != '\x81\x40') { - #else - if (mCurPos == 8 && mChrInfo[7].mCharacter != ' ') { - #endif + if (mCurPos == 8 && mChrInfo[7].mCharacter != SPACE_MAYBE_FULL) { mChrInfo[7].mColumn = 7; mChrInfo[7].mRow = 1; - #if REGION_PAL || REGION_JPN + #if TARGET_PC + mChrInfo[7].mMojiSet = isPalOrJpn() ? MOJI_HIRA : MOJI_EIGO; + #elif REGION_PAL || REGION_JPN mChrInfo[7].mMojiSet = MOJI_HIRA; #else mChrInfo[7].mMojiSet = MOJI_EIGO; #endif mChrInfo[7].field_0x3 = 1; - #if REGION_JPN - // ' ' (full-width space) - mChrInfo[7].mCharacter = '\x81\x40'; - #else - mChrInfo[7].mCharacter = ' '; - #endif + mChrInfo[7].mCharacter = SPACE_MAYBE_FULL; } else { for (int i = mCurPos - 1; i < 7; i++) { mChrInfo[i] = mChrInfo[i + 1]; } mChrInfo[7].mColumn = 7; mChrInfo[7].mRow = 1; - #if REGION_PAL || REGION_JPN +#if TARGET_PC + mChrInfo[7].mMojiSet = isPalOrJpn() ? MOJI_HIRA : MOJI_EIGO; +#elif REGION_PAL || REGION_JPN mChrInfo[7].mMojiSet = MOJI_HIRA; #else mChrInfo[7].mMojiSet = MOJI_EIGO; #endif mChrInfo[7].field_0x3 = 1; - #if REGION_JPN - // ' ' (full-width space) - mChrInfo[7].mCharacter = '\x81\x40'; - #else - mChrInfo[7].mCharacter = ' '; - #endif + mChrInfo[7].mCharacter = SPACE_MAYBE_FULL; } setNameText(); @@ -1164,7 +1274,31 @@ void dName_c::backSpace() { } void dName_c::mojiListChange() { - #if REGION_PAL + #if TARGET_PC + const char** mojiSet; + if (dusk::version::isRegionPal()) { + switch (mMojiSet) { + case MOJI_HIRA: + mojiSet = l_mojiEisuPal_1; + break; + case MOJI_KATA: + mojiSet = l_mojiEisuPal_2; + break; + } + } else { + switch (mMojiSet) { + case MOJI_HIRA: + mojiSet = l_mojiHira; + break; + case MOJI_KATA: + mojiSet = l_mojikata; + break; + case MOJI_EIGO: + mojiSet = l_mojiEisu; + break; + } + } + #elif REGION_PAL char** mojiSet; switch (mMojiSet) { @@ -1212,7 +1346,8 @@ void dName_c::mojiListChange() { strcpy(mMojiText[i], buf); } - #if REGION_PAL || REGION_JPN + #if TARGET_PC || REGION_PAL || REGION_JPN + IF_DUSK_BLOCK(isPalOrJpn()) if (mSelProc == PROC_MOJI_SELECT) { mMenuIcon[mMojiSet]->scale(g_nmHIO.mMenuScale, g_nmHIO.mMenuScale); mMenuText[mMojiSet]->setWhite(JUtility::TColor(0xC8, 0xC8, 0xC8, 0xFF)); @@ -1221,6 +1356,7 @@ void dName_c::mojiListChange() { mMenuText[mPrevMojiSet]->setWhite(JUtility::TColor(0x96, 0x96, 0x96, 0xFF)); } } + IF_DUSK_BLOCK_END #endif } @@ -1241,9 +1377,11 @@ void dName_c::menuCursorMove2() { if (menu_i != mojiSet_i) { mMenuIcon[menu_i]->scale(g_nmHIO.mMenuScale, g_nmHIO.mMenuScale); mMenuText[menu_i]->setWhite(JUtility::TColor(0xC8, 0xC8, 0xC8, 0xFF)); - #if REGION_PAL || REGION_JPN + #if TARGET_PC || REGION_PAL || REGION_JPN + IF_DUSK_BLOCK(isPalOrJpn()) mMenuIcon[mojiSet_i]->scale(1.0f, 1.0f); mMenuText[mojiSet_i]->setWhite(JUtility::TColor(0x96, 0x96, 0x96, 0xFF)); + IF_DUSK_BLOCK_END #endif } @@ -1265,7 +1403,9 @@ void dName_c::selectCursorPosSet(int row) { mCharColumn = 3; break; case MENU_EIGO: - #if REGION_PAL + #if TARGET_PC + mCharColumn = dusk::version::isRegionPal() ? 8 : 6; + #elif REGION_PAL mCharColumn = 8; #else mCharColumn = 6; @@ -1481,9 +1621,11 @@ void dName_c::screenSet() { #endif } - #if !(REGION_PAL || REGION_JPN) + #if TARGET_PC || !(REGION_PAL || REGION_JPN) + IF_DUSK_BLOCK(!isPalOrJpn()) mMenuIcon[0]->hide(); mMenuIcon[1]->hide(); + IF_DUSK_BLOCK_END #endif mMojiPane = nameIn.NameInScr->search(MULTI_CHAR('moji_n')); @@ -1501,25 +1643,28 @@ void dName_c::screenSet() { ((J2DTextBox*)nameTagPane[i])->setFont(nameIn.font); ((J2DTextBox*)nameTagPane[i])->setString(72, ""); ((J2DTextBox*)nameTagPane[i])->setWhite(JUtility::TColor(0xC8, 0xC8, 0xC8, 0xFF)); - #if REGION_PAL + #if TARGET_PC || REGION_PAL + IF_DUSK_BLOCK(dusk::version::isRegionPal()) ((J2DTextBox*)nameTagPane[i])->resize(24.0f, 23.0f); + IF_DUSK_BLOCK_END #endif mNameText[i] = ((J2DTextBox*)nameTagPane[i])->getStringPtr(); } - #if REGION_PAL + #if REGION_PAL // DUSK version note: this code mutates strings. We just edit the table. + IF_DUSK_BLOCK(dusk::version::isRegionPal()) int idx = 2; - static u8 palMoji00[13] = { + static const u8 palMoji00[13] = { 0xC0, 0xC1, 0xC2, 0xC4, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, }; - static u8 palMoji01[13] = { + static const u8 palMoji01[13] = { 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD6, 0x8C, 0xD9, 0xDA, 0xDB, 0xDC, 0x2D, }; - static u8 palMoji10[13] = { + static const u8 palMoji10[13] = { 0xE0, 0xE1, 0xE2, 0xE4, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, }; - static u8 palMoji11[13] = { + static const u8 palMoji11[13] = { 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF6, 0x9C, 0xF9, 0xFA, 0xFB, 0xFC, 0xDF, }; @@ -1536,6 +1681,7 @@ void dName_c::screenSet() { l_mojiEisuPal_2[idx + 1][0] = palMoji11[i]; l_mojiEisuPal_2[idx + 1][1] = 0; } + IF_DUSK_BLOCK_END #endif mCharColumn = 0; @@ -1574,18 +1720,15 @@ void dName_c::displayInit() { mNameCursor[i]->hide(); mChrInfo[i].mColumn = 7; mChrInfo[i].mRow = 1; - #if REGION_PAL || REGION_JPN + #if TARGET_PC + mChrInfo[i].mMojiSet = isPalOrJpn() ? MOJI_HIRA : MOJI_EIGO; + #elif REGION_PAL || REGION_JPN mChrInfo[i].mMojiSet = MOJI_HIRA; #else mChrInfo[i].mMojiSet = MOJI_EIGO; #endif mChrInfo[i].field_0x3 = 1; - #if REGION_JPN - // ' ' (full-width space) - mChrInfo[i].mCharacter = '\x81\x40'; - #else - mChrInfo[i].mCharacter = ' '; - #endif + mChrInfo[i].mCharacter = SPACE_MAYBE_FULL; } mIsInputEnd = false; @@ -1596,7 +1739,63 @@ void dName_c::NameStrSet() { int i = 0; while (*moji != 0) { - #if REGION_PAL + #if TARGET_PC + if (dusk::version::isRegionPal()) { + mChrInfo[i].mCharacter = static_cast(*moji); + + for (int j = 0; j < 65; j++) { + if (mChrInfo[i].mCharacter == *(u8*)l_mojiEisuPal_1[j] || + mChrInfo[i].mCharacter == *(u16*)l_mojiEisuPal_2[j]) + { + mChrInfo[i].mColumn = j / 5; + mChrInfo[i].mRow = j % 5; + mChrInfo[i].mMojiSet = MOJI_HIRA; + break; + } + } + moji++; + i++; + } else { + if (*(u8*)moji >> 4 == 8 || *(u8*)moji >> 4 == 9) { + mChrInfo[i].mCharacter = *(u16*)moji; + + for (int j = 0; j < 65; j++) { + if (mChrInfo[i].mCharacter == *(u16*)l_mojiHira[j] || + mChrInfo[i].mCharacter == *(u16*)l_mojiHira2[j] || + mChrInfo[i].mCharacter == *(u16*)l_mojiHira3[j]) + { + mChrInfo[i].mColumn = j / 5; + mChrInfo[i].mRow = j % 5; + mChrInfo[i].mMojiSet = MOJI_HIRA; + break; + } else if (mChrInfo[i].mCharacter == *(u16*)l_mojikata[j] || + mChrInfo[i].mCharacter == *(u16*)l_mojikata2[j] || + mChrInfo[i].mCharacter == *(u16*)l_mojikata3[j]) + { + mChrInfo[i].mColumn = j / 5; + mChrInfo[i].mRow = j % 5; + mChrInfo[i].mMojiSet = MOJI_KATA; + break; + } + } + moji += 2; + i++; + } else { + mChrInfo[i].mCharacter = *moji; + + for (int j = 0; j < 65; j++) { + if (mChrInfo[i].mCharacter == *(u8*)l_mojiEisu[j]) { + mChrInfo[i].mColumn = j / 5; + mChrInfo[i].mRow = j % 5; + mChrInfo[i].mMojiSet = MOJI_EIGO; + break; + } + } + moji++; + i++; + } + } + #elif REGION_PAL mChrInfo[i].mCharacter = static_cast(*moji); for (int j = 0; j < 65; j++) { @@ -1669,7 +1868,9 @@ s32 dName_c::getMenuPosIdx(u8 selPos) { result = 1; break; case 2: - #if REGION_PAL + #if TARGET_PC + result = dusk::version::isRegionPal() ? 3 : 2; + #elif REGION_PAL result = 3; #else result = 2; diff --git a/src/d/d_s_logo.cpp b/src/d/d_s_logo.cpp index f04df0fa39..cc5d0114a4 100644 --- a/src/d/d_s_logo.cpp +++ b/src/d/d_s_logo.cpp @@ -24,6 +24,7 @@ #include "JSystem/JUtility/JUTConsole.h" #include "dusk/logging.h" +#include "dusk/version.hpp" #if !PLATFORM_GCN #include @@ -44,7 +45,12 @@ struct homeBtnData { }; #endif -#if VERSION == VERSION_SHIELD +#if TARGET_PC +using namespace dusk::version; + +#define LOGO_ARC versionSelect({{GameVersion::GcnJpn, "Logo"}, {GameVersion::GcnPal, "LogoPal"}}, "LogoUs") +#define MSG_PATH versionSelect({{GameVersion::GcnJpn, "/res/Msgjp/bmgres.arc"}}, "/res/Msgus/bmgres.arc") +#elif VERSION == VERSION_SHIELD #define LOGO_ARC "LogoUs" #define MSG_PATH "/res/Msgcn/bmgres.arc" #elif VERSION == VERSION_GCN_JPN @@ -789,7 +795,13 @@ dScnLogo_c::~dScnLogo_c() { JKR_DELETE(mProgressiveNo); JKR_DELETE(mProgressiveSel); - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC + if (getGameVersion() == GameVersion::GcnPal) { + mpPalLogoResCommand->getArchive()->removeResourceAll(); + mpPalLogoResCommand->getArchive()->unmount(); + mpPalLogoResCommand->destroy(); + } + #elif VERSION == VERSION_GCN_PAL mpPalLogoResCommand->getArchive()->removeResourceAll(); mpPalLogoResCommand->getArchive()->unmount(); mpPalLogoResCommand->destroy(); @@ -951,7 +963,8 @@ static int phase_0(dScnLogo_c* i_this) { JUT_ASSERT(1528, i_this->mLogo01Heap != NULL); JKRHEAP_NAME(i_this->mLogo01Heap, "Logo01"); - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC || VERSION == VERSION_GCN_PAL + IF_DUSK_BLOCK(getGameVersion() == GameVersion::GcnPal) switch (i_this->getPalLanguage()) { case 1: i_this->mpPalLogoResCommand = mDoDvdThd_mountArchive_c::create("/res/Layout/LogoPalGm.arc", 0, NULL); @@ -970,6 +983,7 @@ static int phase_0(dScnLogo_c* i_this) { i_this->mpPalLogoResCommand = mDoDvdThd_mountArchive_c::create("/res/Layout/LogoPalUk.arc", 0, NULL); break; } + IF_DUSK_BLOCK_END #endif #if PLATFORM_WII || PLATFORM_SHIELD @@ -990,7 +1004,8 @@ static int phase_1(dScnLogo_c* i_this) { } #endif - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC || VERSION == VERSION_GCN_PAL + IF_DUSK_BLOCK(getGameVersion() == GameVersion::GcnPal) if (!mDoDvdThd::SyncWidthSound) { return cPhs_INIT_e; } @@ -998,6 +1013,7 @@ static int phase_1(dScnLogo_c* i_this) { if (!i_this->mpPalLogoResCommand->sync()) { return cPhs_INIT_e; } + IF_DUSK_BLOCK_END #endif int rt; @@ -1237,7 +1253,113 @@ void dScnLogo_c::logoInitGC() { ResTIMG* dolbyImg = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 3); mDolbyLogo = JKR_NEW dDlst_2D_c(dolbyImg, 189, 150, 232, 112, 255); -#if VERSION == VERSION_GCN_PAL +#if TARGET_PC + if (getGameVersion() == GameVersion::GcnPal) { + u8 language = getPalLanguage(); + if (language >= 5) { + language = 0; + } + + static const char* choice[] = { + "50_60_choice_eng.bti", + "50_60_choice_ger.bti", + "50_60_choice_fra.bti", + "50_60_choice_spa.bti", + "50_60_choice_ita.bti", + }; + + static const char* yes[] = { + "60_set_eng.bti", + "60_set_ger.bti", + "60_set_fra.bti", + "60_set_spa.bti", + "60_set_ita.bti", + }; + + static const char* no[] = { + "50_set_eng.bti", + "50_set_ger.bti", + "50_set_fra.bti", + "50_set_spa.bti", + "50_set_ita.bti", + }; + + static const char* prog[] = { + "progressive_pro.bti", + "progressive_pro_gm.bti", + "progressive_pro_fr.bti", + "progressive_pro_sp.bti", + "progressive_pro_it.bti", + }; + + static const char* intr[] = { + "progressive_inter.bti", + "progressive_inter_gm.bti", + "progressive_inter_fr.bti", + "progressive_inter_sp.bti", + "progressive_inter_it.bti", + }; + + static const char* warning[] = { + "warning.bti", + "warning_gm.bti", + "warning_fr.bti", + "warning_sp.bti", + "warning_it.bti", + }; + + static const char* warningPs[] = { + "warning_pstart.bti", + "warning_pstart_gm.bti", + "warning_pstart_fr.bti", + "warning_pstart_sp.bti", + "warning_pstart_it.bti", + }; + + ResTIMG* warningImg = (ResTIMG*)mpPalLogoResCommand->getArchive()->getResource('DAT ', warning[language]); + mWarning = JKR_NEW dDlst_2D_c(warningImg, 0, 0, FB_WIDTH, FB_HEIGHT, 255); + + ResTIMG* warnStartImg = (ResTIMG*)mpPalLogoResCommand->getArchive()->getResource('DAT ', warningPs[language]); + mWarningStart = JKR_NEW dDlst_2D_c(warnStartImg, 0, 359, FB_WIDTH, 48, 255); + + ResTIMG* progChoiceImg = (ResTIMG*)mpPalLogoResCommand->getArchive()->getResource('DAT ', choice[language]); + mProgressiveChoice = JKR_NEW dDlst_2D_c(progChoiceImg, 113, 143, 416, 210, 255); + + ResTIMG* progYesImg = (ResTIMG*)mpPalLogoResCommand->getArchive()->getResource('DAT ', yes[language]); + mProgressiveYes = JKR_NEW dDlst_2D_c(progYesImg, 121, 352, 200, 72, 255); + mProgressiveYes->getPicture()->setWhite(JUtility::TColor(160, 160, 160, 255)); + + ResTIMG* progNoImg = (ResTIMG*)mpPalLogoResCommand->getArchive()->getResource('DAT ', no[language]); + mProgressiveNo = JKR_NEW dDlst_2D_c(progNoImg, 320, 352, 200, 72, 255); + mProgressiveNo->getPicture()->setWhite(JUtility::TColor(160, 160, 160, 255)); + + mProgressivePro = (ResTIMG*)mpPalLogoResCommand->getArchive()->getResource('DAT ', prog[language]); + mProgressiveInter = (ResTIMG*)mpPalLogoResCommand->getArchive()->getResource('DAT ', intr[language]); + mProgressiveSel = JKR_NEW dDlst_2D_c(mProgressivePro, 153, 309, 336, 88, 255); + } else { + ResTIMG* warningImg = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 10); + mWarning = JKR_NEW dDlst_2D_c(warningImg, 0, 0, FB_WIDTH, FB_HEIGHT, 255); + + ResTIMG* warnStartImg = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 11); + mWarningStart = JKR_NEW dDlst_2D_c(warnStartImg, 0, 359, FB_WIDTH, 48, 255); + + ResTIMG* progChoiceImg = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 5); + mProgressiveChoice = JKR_NEW dDlst_2D_c(progChoiceImg, 113, 281, 416, 72, 255); + + ResTIMG* progYesImg = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 9); + mProgressiveYes = JKR_NEW dDlst_2D_c(progYesImg, 211, 372, 80, 32, 255); + mProgressiveYes->getPicture()->setWhite(JUtility::TColor(160, 160, 160, 255)); + + ResTIMG* progNoImg = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 7); + mProgressiveNo = JKR_NEW dDlst_2D_c(progNoImg, 350, 372, 80, 32, 255); + mProgressiveNo->getPicture()->setWhite(JUtility::TColor(160, 160, 160, 255)); + + mProgressivePro = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 8); + mProgressiveInter = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 6); + mProgressiveSel = JKR_NEW dDlst_2D_c(mProgressivePro, 153, 309, 336, 88, 255); + } + +#elif VERSION == VERSION_GCN_PAL u8 language = getPalLanguage(); if (language >= 5) { language = 0; @@ -1395,7 +1517,30 @@ void dScnLogo_c::dvdDataLoad() { mpButtonCommand = aramMount(BUTTON_RES_PATH, mDoExt_getJ2dHeap()); mpCardIconCommand = aramMount(ICON_RES_PATH, mDoExt_getJ2dHeap()); - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC + if (getGameVersion() == GameVersion::GcnPal) { + switch (getPalLanguage()) { + case 1: + mpBmgResCommand = onMemMount("/res/Msgde/bmgres.arc"); + break; + case 2: + mpBmgResCommand = onMemMount("/res/Msgfr/bmgres.arc"); + break; + case 3: + mpBmgResCommand = onMemMount("/res/Msgsp/bmgres.arc"); + break; + case 4: + mpBmgResCommand = onMemMount("/res/Msgit/bmgres.arc"); + break; + case 0: + default: + mpBmgResCommand = onMemMount("/res/Msguk/bmgres.arc"); + break; + } + } else { + mpBmgResCommand = onMemMount(MSG_PATH); + } + #elif VERSION == VERSION_GCN_PAL switch (getPalLanguage()) { case 1: mpBmgResCommand = onMemMount("/res/Msgde/bmgres.arc"); @@ -1435,7 +1580,10 @@ void dScnLogo_c::dvdDataLoad() { mpMsgResCommand[1] = aramMount(MSG_RES1_PATH, mDoExt_getJ2dHeap()); mpMsgResCommand[2] = aramMount(MSG_RES2_PATH, mDoExt_getJ2dHeap()); mpMsgResCommand[3] = aramMount(MSG_RES3_PATH, mDoExt_getJ2dHeap()); -#if VERSION == VERSION_GCN_JPN +#if TARGET_PC + const auto res4Path = versionSelect({{GameVersion::GcnJpn, "/res/Layout/msgres04.arc"}}, "/res/Layout/msgres04F.arc"); + mpMsgResCommand[4] = aramMount( res4Path, mDoExt_getJ2dHeap()); +#elif VERSION == VERSION_GCN_JPN mpMsgResCommand[4] = aramMount("/res/Layout/msgres04.arc", mDoExt_getJ2dHeap()); #else mpMsgResCommand[4] = aramMount("/res/Layout/msgres04F.arc", mDoExt_getJ2dHeap()); @@ -1445,7 +1593,23 @@ void dScnLogo_c::dvdDataLoad() { mpMain2DCommand = onMemMount(MAIN2D_PATH); -#if VERSION == VERSION_GCN_JPN +#if TARGET_PC + const auto fontResPath = versionSelect( + { + {GameVersion::GcnJpn, "/res/Fontjp/fontres.arc"}, + {GameVersion::GcnPal, "/res/Fonteu/fontres.arc"}, + }, "/res/Fontus/fontres.arc"); + const auto fontRubyPath = versionSelect( + { + {GameVersion::GcnJpn, "/res/Fontjp/rubyres.arc"}, + {GameVersion::GcnPal, "/res/Fonteu/rubyres.arc"}, + }, "/res/Fontus/rubyres.arc"); + + // Note: GCN_JPN mounts this archive as tail instead of head. + // I'm guessing this is fine since we have more RAM. + mpFontResCommand = onMemMount(fontResPath); + mpRubyResCommand = onMemMount(fontRubyPath); +#elif VERSION == VERSION_GCN_JPN mpFontResCommand = mDoDvdThd_mountXArchive_c::create("/res/Fontjp/fontres.arc", 1, JKRArchive::MOUNT_MEM, NULL); mpRubyResCommand = onMemMount("/res/Fontjp/rubyres.arc"); #elif VERSION == VERSION_GCN_PAL @@ -1545,7 +1709,7 @@ static int dScnLogo_IsDelete(dScnLogo_c* i_this) { return 1; } -#if VERSION == VERSION_GCN_PAL || PLATFORM_WII || PLATFORM_SHIELD +#if TARGET_PC || VERSION == VERSION_GCN_PAL || PLATFORM_WII || PLATFORM_SHIELD u8 dScnLogo_c::getPalLanguage() { u8 language; diff --git a/src/d/d_save.cpp b/src/d/d_save.cpp index 3289a49c64..be95d1f190 100644 --- a/src/d/d_save.cpp +++ b/src/d/d_save.cpp @@ -16,6 +16,8 @@ #include #include +#include "dusk/version.hpp" + #if PLATFORM_WII || PLATFORM_SHIELD #include #include @@ -1027,7 +1029,7 @@ void dSv_player_config_c::init() { mAttentionType = 0; mVibration = 1; -#if DEBUG +#if DEBUG // DUSK VERSION SUPPORT: This field isn't used, so we can ignore it. mLanguage = SCGetLanguage(); #elif REGION_PAL || VERSION >= VERSION_WII_USA_R2 mLanguage = OSGetLanguage(); @@ -1072,7 +1074,8 @@ void dSv_player_config_c::setVibration(u8 i_status) { } u8 dSv_player_config_c::getPalLanguage() const { -#if VERSION == VERSION_GCN_PAL +#if TARGET_PC || VERSION == VERSION_GCN_PAL + IF_DUSK_BLOCK(dusk::version::getGameVersion() == dusk::version::GameVersion::GcnPal) switch (OSGetLanguage()) { case 0: return LANGUAGE_ENGLISH; @@ -1085,6 +1088,7 @@ u8 dSv_player_config_c::getPalLanguage() const { case 4: return LANGUAGE_ITALIAN; } + IF_DUSK_BLOCK_END #elif VERSION >= VERSION_WII_USA_R0 switch (SCGetLanguage()) { case 1: diff --git a/src/dusk/config.cpp b/src/dusk/config.cpp index 176967359d..856cdce4a3 100644 --- a/src/dusk/config.cpp +++ b/src/dusk/config.cpp @@ -154,6 +154,7 @@ namespace dusk::config { template class ConfigImpl; template class ConfigImpl; template class ConfigImpl; + template class ConfigImpl; } void dusk::config::Register(ConfigVarBase& configVar) { diff --git a/src/dusk/crash_reporting.cpp b/src/dusk/crash_reporting.cpp index 0499f0d6a1..657e5ef5d2 100644 --- a/src/dusk/crash_reporting.cpp +++ b/src/dusk/crash_reporting.cpp @@ -167,7 +167,6 @@ void InitializeCrashReporting() { sentry_set_tag("git_branch", DUSK_WC_BRANCH); sentry_set_tag("build_type", DUSK_BUILD_TYPE); - sentry_set_tag("tp_version", DUSK_TP_VERSION); g_sentryInitialized = true; DuskLog.info("Initialized Sentry crash reporting"); diff --git a/src/dusk/dvd_asset.cpp b/src/dusk/dvd_asset.cpp index b9e0729be9..75c82107cc 100644 --- a/src/dusk/dvd_asset.cpp +++ b/src/dusk/dvd_asset.cpp @@ -80,8 +80,19 @@ static s32 DolVaToFileOffset(u32 va) { return -1; } -bool LoadDolAsset(void* dst, u32 virtualAddress, s32 size) { - s32 fileOffset = DolVaToFileOffset(virtualAddress); +static u32 GetOffsetForVersion(std::initializer_list version) { + const auto gameVersion = dusk::version::getGameVersion(); + for (auto elem : version) { + if (elem.mGameVersion == gameVersion) { + return elem.mOffset; + } + } + + DuskLog.fatal("Unable to find offset for this game version!"); +} + +bool LoadDolAsset(void* dst, std::initializer_list virtualAddress, s32 size) { + s32 fileOffset = DolVaToFileOffset(GetOffsetForVersion(virtualAddress)); if (fileOffset < 0) { return false; } @@ -95,13 +106,16 @@ bool LoadDolAsset(void* dst, u32 virtualAddress, s32 size) { return true; } -bool LoadRelAsset(void* dst, const char* dvdPath, s32 offset, s32 size) { - void* p = JKRDvdRipper::loadToMainRAM(dvdPath, (u8*)dst, EXPAND_SWITCH_UNKNOWN1, (u32)size, nullptr, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, (u32)offset, nullptr, nullptr); - if (!p) DuskLog.fatal("dvd_asset: failed to load {} (offset={:#x} size={:#x})", dvdPath, offset, size); +bool LoadRelAsset(void* dst, const char* dvdPath, std::initializer_list offset, s32 size) { + auto resOffset = GetOffsetForVersion(offset); + void* p = JKRDvdRipper::loadToMainRAM(dvdPath, (u8*)dst, EXPAND_SWITCH_UNKNOWN1, (u32)size, nullptr, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, resOffset, nullptr, nullptr); + if (!p) DuskLog.fatal("dvd_asset: failed to load {} (offset={:#x} size={:#x})", dvdPath, resOffset, size); return p != nullptr; } -bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, s32 offset, s32 size) { +bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, std::initializer_list offset, s32 size) { + auto resOffset = GetOffsetForVersion(offset); + // On TARGET_PC, cDyl_InitCallback skips DynamicModuleControl::initialize() due to static linking // Mount RELS.arc on first use so sArchive is available static bool s_mountAttempted = false; @@ -118,7 +132,7 @@ bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, s32 o DuskLog.fatal("dvd_asset: {} not found in RELS archive", relFileName); return false; } - std::memcpy(dst, rel + offset, size); + std::memcpy(dst, rel + resOffset, size); return true; } diff --git a/src/dusk/imgui/ImGuiPreLaunchWindow.cpp b/src/dusk/imgui/ImGuiPreLaunchWindow.cpp index 2727e78718..6347e9bc01 100644 --- a/src/dusk/imgui/ImGuiPreLaunchWindow.cpp +++ b/src/dusk/imgui/ImGuiPreLaunchWindow.cpp @@ -22,6 +22,10 @@ typedef void (ImGuiPreLaunchWindow::*drawFunc)(); drawFunc drawTable[2] = {&ImGuiPreLaunchWindow::drawMainMenu, &ImGuiPreLaunchWindow::drawOptions}; +static constexpr std::array skLanguageNames = { + "English", "German", "French", "Spanish", "Italian" +}; + static constexpr std::array skGameDiscFileFilters{{ {"Game Disc Images", "iso;gcm;ciso;gcz;nfs;rvz;wbfs;wia;tgc"}, {"All Files", "*"}, @@ -195,6 +199,20 @@ void ImGuiPreLaunchWindow::drawOptions() { false); } + // TODO: Only show if PAL disc selected? + // Language selection + auto selectedLanguage = getSettings().game.language.getValue(); + if (ImGui::BeginCombo("Language", skLanguageNames[static_cast(selectedLanguage)])) { + for (u8 i = 0; i < skLanguageNames.size(); ++i) { + if (ImGui::Selectable(skLanguageNames[i])) { + getSettings().game.language.setValue(static_cast(i)); + config::Save(); + } + } + + ImGui::EndCombo(); + } + AuroraBackend configuredBackend = BACKEND_AUTO; const std::string& configuredBackendId = getSettings().backend.graphicsBackend; if (!try_parse_backend(configuredBackendId, configuredBackend)) { diff --git a/src/dusk/iso_validate.cpp b/src/dusk/iso_validate.cpp index 755b4eede0..0b4a19ae9c 100644 --- a/src/dusk/iso_validate.cpp +++ b/src/dusk/iso_validate.cpp @@ -19,6 +19,7 @@ constexpr const char* TP_GAME_IDS[] = { constexpr const char* SUPPORTED_TP_GAME_IDS[] = { "GZ2E01", // GCN USA + "GZ2P01", // GCN PAL }; template diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 3e6ee733fe..c7d19beb31 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -20,6 +20,8 @@ UserSettings g_userSettings = { }, .game = { + .language { "game.language", GameLanguage::English }, + // Quality of Life .enableQuickTransform {"game.enableQuickTransform", false}, .hideTvSettingsScreen {"game.hideTvSettingsScreen", false}, @@ -123,6 +125,7 @@ void registerSettings() { Register(g_userSettings.audio.enableReverb); // Game + Register(g_userSettings.game.language); Register(g_userSettings.game.enableQuickTransform); Register(g_userSettings.game.hideTvSettingsScreen); Register(g_userSettings.game.skipWarningScreen); diff --git a/src/dusk/version.cpp b/src/dusk/version.cpp new file mode 100644 index 0000000000..e925dabaf8 --- /dev/null +++ b/src/dusk/version.cpp @@ -0,0 +1,82 @@ +#include "dusk/version.hpp" + +#include "dusk/logging.h" + +namespace dusk::version { + +using namespace std::string_view_literals; + +static bool versionInitialized; +static GameVersion gameVersion; +static DVDDiskID diskId; + +void init() { + versionInitialized = true; + + if (!DVDLowReadDiskID(&diskId, nullptr)) { + DuskLog.fatal("DVDLowReadDiskID failed to return instantly."); + } + + std::string_view company(diskId.company, sizeof(diskId.company)); + std::string_view game(diskId.gameName, sizeof(diskId.gameName)); + + if (company != "01"sv) { + DuskLog.fatal("Wrong company ID in disc: {}", company); + } + + if (game == "GZ2E"sv) { + gameVersion = GameVersion::GcnUsa; + } else if (game == "GZ2P") { + gameVersion = GameVersion::GcnPal; + } else { + // TODO: Handle remaining valid versions. + DuskLog.fatal("Unknown/unsupported game version in disc: {}", game); + } + + DuskLog.info("Loaded game disc is {}{}", game, company); +} + +bool isGcn() { + return getGameVersion() == GameVersion::GcnUsa + || getGameVersion() == GameVersion::GcnPal + || getGameVersion() == GameVersion::GcnJpn; +} + +bool isWii() { + return getGameVersion() == GameVersion::WiiUsaRev0 + || getGameVersion() == GameVersion::WiiUsa + || getGameVersion() == GameVersion::WiiPal + || getGameVersion() == GameVersion::WiiJpn + || getGameVersion() == GameVersion::WiiKor; +} + +bool isPalOrAtLeastWiiR2() { + return getGameVersion() == GameVersion::GcnPal || getGameVersion() >= GameVersion::WiiUsa; +} + +bool isRegionJpn() { + return getGameVersion() == GameVersion::WiiJpn || getGameVersion() == GameVersion::GcnJpn; +} + +bool isRegionPal() { + return getGameVersion() == GameVersion::WiiPal || getGameVersion() == GameVersion::GcnPal; +} + +bool isRegionUsa() { + return getGameVersion() == GameVersion::WiiUsa || getGameVersion() == GameVersion::WiiUsaRev0 + || getGameVersion() == GameVersion::GcnUsa; +} + +GameVersion getGameVersion() { + if (!versionInitialized) { + abort(); + } + + return gameVersion; +} + +const DVDDiskID& getDiskID() { + return diskId; +} + +} // namespace dusk::version \ No newline at end of file diff --git a/src/m_Do/m_Do_MemCard.cpp b/src/m_Do/m_Do_MemCard.cpp index 5cb612f128..dbf962b173 100644 --- a/src/m_Do/m_Do_MemCard.cpp +++ b/src/m_Do/m_Do_MemCard.cpp @@ -12,6 +12,7 @@ #include "os_report.h" #include "dusk/os.h" #include "dusk/main.h" +#include "dusk/version.hpp" #if PLATFORM_WII || PLATFORM_SHIELD #include @@ -79,7 +80,11 @@ void mDoMemCd_Ctrl_c::ThdInit() { #if !PLATFORM_SHIELD CARDSetLoadType((CARDFileType)dusk::getSettings().backend.cardFileType.getValue()); - CARDInit(DUSK_GAME_NAME, DUSK_GAME_VERSION); + char version[5] = {}; + char maker[3] = {}; + std::memcpy(version, dusk::version::getDiskID().gameName, 4); + std::memcpy(maker, dusk::version::getDiskID().company, 2); + CARDInit(version, maker); #endif mCopyToPos = 0; diff --git a/src/m_Do/m_Do_MemCardRWmng.cpp b/src/m_Do/m_Do_MemCardRWmng.cpp index 518bdd27e9..d7739d6158 100644 --- a/src/m_Do/m_Do_MemCardRWmng.cpp +++ b/src/m_Do/m_Do_MemCardRWmng.cpp @@ -11,6 +11,8 @@ #include #include +#include "dusk/version.hpp" + #if VERSION == VERSION_GCN_JPN #define HEADER_TITLE "ゼルダの伝説 トワイライトプリンセス" #define HEADER_COMMENT "%d月%d日のセーブデータです" @@ -313,12 +315,44 @@ s32 mDoMemCdRWm_StoreBannerNAND(NANDFileInfo* file) { #endif static void mDoMemCdRWm_BuildHeader(mDoMemCdRWm_HeaderData* header) { +#if !TARGET_PC snprintf(header->mTitle, sizeof(header->mTitle), HEADER_TITLE); +#endif OSCalendarTime time; OSTicksToCalendarTime(OSGetTime(), &time); -#if VERSION == VERSION_GCN_PAL +#if TARGET_PC + if (dusk::version::isRegionPal()) { + snprintf(header->mTitle, sizeof(header->mTitle), HEADER_TITLE); + + switch (dComIfGs_getPalLanguage()) { + case dSv_player_config_c::LANGUAGE_ENGLISH: + snprintf(header->mComment, sizeof(header->mComment), "%d/%d Save Data", time.mon + 1, time.mday); + break; + case dSv_player_config_c::LANGUAGE_GERMAN: + snprintf(header->mComment, sizeof(header->mComment), "%d/%d Spielstand", time.mday, time.mon + 1); + break; + case dSv_player_config_c::LANGUAGE_FRENCH: + snprintf(header->mComment, sizeof(header->mComment), "Donn%ces de jeu %d/%d", 0xE9, time.mday, time.mon + 1); + break; + case dSv_player_config_c::LANGUAGE_SPANISH: + snprintf(header->mComment, sizeof(header->mComment), "Datos guardados el %d/%d", time.mday, time.mon + 1); + break; + case dSv_player_config_c::LANGUAGE_ITALIAN: + snprintf(header->mComment, sizeof(header->mComment), "Dati salvati: %d/%d", time.mday, time.mon + 1); + break; + } + } else if (dusk::version::isRegionUsa()) { + snprintf(header->mTitle, sizeof(header->mTitle), HEADER_TITLE); + + snprintf(header->mComment, sizeof(header->mComment), HEADER_COMMENT, time.mon + 1, time.mday); + } else { + // TODO JPN SHIFT-JIS + // snprintf(header->mTitle, sizeof(header->mTitle), "ゼルダの伝説 トワイライトプリンセス"); + // snprintf(header->mComment, sizeof(header->mComment), "%d月%d日のセーブデータです", time.mon + 1, time.mday); + } +#elif VERSION == VERSION_GCN_PAL switch (dComIfGs_getPalLanguage()) { case dSv_player_config_c::LANGUAGE_ENGLISH: snprintf(header->mComment, sizeof(header->mComment), "%d/%d Save Data", time.mon + 1, time.mday); diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 579cbd8c8b..d25debb38e 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -71,6 +71,7 @@ #include "dusk/config.hpp" #include "dusk/imgui/ImGuiConsole.hpp" #include "dusk/settings.h" +#include "dusk/version.hpp" #include "dusk/discord_presence.hpp" #include "tracy/Tracy.hpp" #include "f_pc/f_pc_draw.h" @@ -465,6 +466,23 @@ static constexpr PADDefaultMapping defaultPadMapping = { static bool mainCalled = false; +static u8 selectedLanguage; + +u8 OSGetLanguage() { + return selectedLanguage; +} + +static void LanguageInit() { + // Keep language at 0 (English) if not on a PAL disk. + // Doubt this matters, but avoid funky shit. + if (!dusk::version::isRegionPal()) { + return; + } + + // Cache this to avoid funky shenanigans. + selectedLanguage = static_cast(dusk::getSettings().game.language.getValue()); +} + // ========================================================================= // PC ENTRY POINT // ========================================================================= @@ -597,6 +615,9 @@ int game_main(int argc, char* argv[]) { } } + dusk::version::init(); + LanguageInit(); + OSInit(); mDoMain::sPowerOnTime = OSGetTime();