diff --git a/docs/architecture/gameplay/patch-system.md b/docs/architecture/gameplay/patch-system.md index 500a458103..12566eb5ed 100644 --- a/docs/architecture/gameplay/patch-system.md +++ b/docs/architecture/gameplay/patch-system.md @@ -599,15 +599,28 @@ Three rules apply to every module that writes into it: Every registered hook is match-scoped. A new one must follow all of it, not just the parts the dispatcher enforces: -- Install/clear happens through `ARM9Hook_SetMatchHooksActive`, driven by the battle-runtime latch - (`mode == MODE_BATTLE_RUNTIME && flow == FLOW_ACTIVE_MATCH`). +- Install/clear happens through `ARM9Hook_SetMatchHooksActive`, driven by the battle-runtime latch. + That latch is two-stage and the stages need not fall on the same frame: `BIT_BATTLE_RUNTIME_SEEN` + sticks once `mode == MODE_BATTLE_RUNTIME && flow == FLOW_ACTIVE_MATCH` has been observed, and + `BIT_BATTLE_RUNTIME_MODE` completes on the first frame after that where the local player's HP is + not 0. Everything hung off the latch therefore lands on a spawned player rather than during the + spawn window. An unresolved HP pointer counts as in play, so the latch cannot stall. - **Gate the request-producing side on `BIT_BATTLE_RUNTIME_MODE` too**, not just `BIT_IN_GAME_INIT`. A request queued during the join/countdown otherwise survives on its TTL and fires on the first battle-runtime frame, before the player state it acts on is settled. - Clear pending host-side requests on the battle-runtime edge and in the lifecycle resets (`ResetTransientInputState`, emu start/stop/boot, savestate reconcile). -- Weapon-equipping paths keep the spawn-window guard: while `player+0xE1 != 0` (spawn - invincibility) the native equip is unsafe, and Method 1 hands that request to the legacy route. +- **Every native dispatcher has to clear the spawn barrier**, because the match latch is a + match boundary and respawn is a player boundary. Spawn restores HP early and the same player + runtime update falls through to the input hooks, so a native call can land inside the update that + spawned the player. `MelonPrimeCore::IsFirstPostSpawnInput()` (defined in + `MelonPrimeGameInput.cpp`) identifies that one hook via `player+0xE1 == configured - 1`; each + dispatcher drops its pending request and returns false there, letting the site's original + instruction run. Drop, never defer — replaying a pressed edge from before the respawn is the + behaviour being prevented. +- **And the request-producing side hands the whole `player+0xE1 != 0` window to the non-native + path.** The dispatcher barrier only sees requests that actually reach a hook; this covers the + rest of the invulnerability countdown. The two are complementary, not alternatives. --- diff --git a/docs/features/melonprime-settings/input-methods.md b/docs/features/melonprime-settings/input-methods.md index 3796f34b74..7ac9f27a51 100644 --- a/docs/features/melonprime-settings/input-methods.md +++ b/docs/features/melonprime-settings/input-methods.md @@ -14,9 +14,23 @@ and zoom requests are generated: | Zoom method | Metroid.Input.ZoomMethod | 0 | 0 legacy, 1 retired alias, 2 native, 3 native 3 | Each domain stores one integer, so its methods are mutually exclusive by -construction. The dialog enforces the same thing directly: ticking Method 2 -clears Method 1 for weapon and transform, and ticking Method 3 clears Method 2 -for zoom (and the reverse in each case). +construction, and value 0 -- the behaviour you get when no new method is +selected -- is the **Standard Method**. It has its own checkbox rather than +being "nothing ticked", so the selector reads as exactly-one-of-N: + +| Domain | Standard | New | New 2 | New 3 | +| --- | --- | --- | --- | --- | +| Weapon change | value 0 | value 1 | value 2 | — | +| Alt-Form transform | value 0 | value 1 | value 2 | — | +| Zoom | value 0 | — | value 2 | value 3 | + +The dialog enforces the grouping directly: ticking one box clears the others in +its domain, and clearing the last ticked box puts it back rather than leaving +the group empty. The boxes stay checkboxes to match the rest of the dialog, but +they behave as a radio group. The Standard zoom box is available in every +build; only the experimental New Method 2 and New Method 3 boxes are +developer-build only. A release build therefore always runs the Standard zoom +path. `Metroid.Input.AltFormTransformMethod` is authoritative. When it is absent, the value is migrated once from the older boolean key: true becomes 1, false becomes @@ -135,7 +149,8 @@ Like every other native path, this one is match-scoped and follows the same three conventions: - **The battle-runtime latch gates it end to end.** Hooks are installed on the - first `mode == MODE_BATTLE_RUNTIME && flow == FLOW_ACTIVE_MATCH` frame, so + first frame where the local player is in play (HP != 0) after + `mode == MODE_BATTLE_RUNTIME && flow == FLOW_ACTIVE_MATCH` has been seen, so requests are neither queued nor serviced outside it. Without that gate a press during the join/countdown could be held by its TTL and then fire on the very first battle-runtime frame. `HandleBattleRuntimeEnter` also drops any @@ -196,6 +211,106 @@ PC-relative request loads, and the battle-runtime authoring rule are canonical i shared ROM code cave" — read that before adding or moving one. DirectInvocation owns 0x02003F50..0x02003FBB and no data block: its dispatcher hands the request over in r0-r2. +## Zoom + +Value 0 is the Standard zoom path. Value 1 is a retired configuration value that +behaves as value 0. Value 2 uses the native SetPlayerScopeZoom path from the +weapon action update. Value 3 is New Method 3: the same setter called from the +player input update, described under DirectInvocation above. + +| ROM | SetPlayerScopeZoom site | +| --- | ---: | +| JP1.0 / JP1.1 | 0x02015C98 | +| US1.0 | 0x02015CB8 | +| US1.1 | 0x02015CBC | +| EU1.0 | 0x02015CB0 | +| EU1.1 | 0x02015CBC | +| KR1.0 | 0x0201CEBC | + +The native weapon-action path uses the shared action consumer for JP/US/EU +and 0x0200D07C for KR, with a trampoline at 0x02003F00 and scratch area at +0x02003F40. The activation edge, guest scope call, and release behavior must +be tested independently from zoom sensitivity scaling. + +## Native methods are gated on the local player being in play + +Every native method -- weapon New / New 2, transform New / New 2, zoom New 2 / +New 3 -- refuses to fire while the local player's HP is 0. That covers two +states, not just one: killed and waiting to respawn, and not yet spawned after +the match starts. A native call reaches past whatever the game does with a +player who is not in play, so the request is dropped rather than deferred: it is +not queued, and a request already queued when the player goes down is cleared +instead of firing on respawn. + +The gate is applied twice on purpose, at the host queue site and again in the +ARM9 dispatch, because the queue-to-dispatch window is several frames wide and +the player can leave play inside it. + +Standard Method is unaffected. It is the game reacting to the emulator's own +simulated touch/menu input, so the game's own handling of a dead player already +applies. + +HP is read through the local player's cached pointer; an unresolved pointer +counts as alive, so a native path is never disabled just because the pointer +cache has not been rebuilt yet. + +## Spawn barrier + +The battle-runtime latch is a *match* boundary; respawn is a *player* boundary, +and the two are not the same. Spawn restores HP early but keeps initialising +camera, model, animation, gun and HUD state well past that point, and the same +player runtime update then falls through to the player input update and its +hook sites. So "HP is not 0 and the hook was reached" is satisfied inside the +very update that spawned the player, and a native call made there lands on +half-initialised state. + +There are two layers, because they cover different cases. + +**Whole window, producer side.** While the local player is inside the spawn +invulnerability countdown (`player+0xE1 != 0`), every native method hands the +request to the Standard path instead of making a native call: weapon goes +through the legacy touch route, and transform and zoom fall through to their +Standard branches. The native request is cleared rather than left pending, and +zoom keeps its shared pressed-edge latch in sync so leaving the window mid-hold +cannot fire a stale toggle. + +**First post-spawn hook, dispatcher side.** The producer check cannot see a +request that was queued *before* the boundary and only reaches the hook after +it, so every native dispatcher additionally drops whatever lands on the one +input hook inside the update that spawned the player. That hook needs no host +latch to identify: Spawn stores the hunter's configured invulnerability into +`player+0xE1`, and the same update decrements it exactly once before reaching +the input code, so there and only there + +```text +player+0xE1 == (uint8_t)([player+0x404] + 0xE2) - 1 +``` + +The next update reads `configured - 2`, so this second layer only ever costs one +input frame. The request is dropped rather than deferred, because replaying a +pressed edge from before the respawn is the behaviour to avoid. + +Structure offsets are identical on all seven ROMs, so neither layer needs a +per-version address table. + +During the spawn window the input still does something -- it runs the Standard +method -- rather than being swallowed. The trade is that the selected method is +briefly not the one in use. + +Evidence: mphCodex `Direct-Invocation-Spawn-Freeze-Investigation-JP1_0.md`. + +## Lifecycle and interactions + +Native hooks are match-scoped. Configuration changes are consumed by +NotifyConfigChanged and reconciled by the ARM9 hook installer. A hook being +installed is not proof that the input edge reached the guest; inspect the +behavioral path as well. + +Stylus mode can intentionally bypass native aim-related controls. Joy2Key and +SnapTap can change the host edge sequence before the native hook sees it. +Immediate Input Edge Overlay is a developer diagnostic that shares a post-poll +boundary and must not create duplicate fire/zoom/transform actions. + ## Verification checklist - Test each selector with the other selectors at their defaults. @@ -203,6 +318,11 @@ shared ROM code cave" — read that before adding or moving one. DirectInvocatio - Test Method 2 for weapon and transform separately, then together, then combined with Method 1 on the other selector (shared hook PC). - Verify each pair is exclusive in the dialog and after a save/reload cycle. +- Die, then press each bound action while down: no weapon change, transform or + zoom may occur, and none may fire late on respawn. +- Press each bound action on the exact spawn/respawn frame: dropped, no freeze. +- Press each bound action on the frame after: the native path runs normally. +- Hold an action across match start and across a respawn: no late replay. - For zoom Method 3, test Alt-Form, mid-transform, and a non-zoom weapon; each must refuse the toggle rather than zoom. - Verify one action per physical edge, not one action per frame. diff --git a/src/GPU3D_Compute.cpp b/src/GPU3D_Compute.cpp index 5b754fcf64..3ddc78ffd1 100644 --- a/src/GPU3D_Compute.cpp +++ b/src/GPU3D_Compute.cpp @@ -960,7 +960,7 @@ void ComputeRenderer3D::RenderFrame() s32 ytop = ScreenHeight, ybot = 0; for (int i = 0; i < polygon->NumVertices; i++) { - if (HiresCoordinates) + if (HiresCoordinates && ScaleFactor > 1) { scaledPositions[i][0] = (polygon->Vertices[i]->HiresPosition[0] * ScaleFactor) >> 4; scaledPositions[i][1] = (polygon->Vertices[i]->HiresPosition[1] * ScaleFactor) >> 4; diff --git a/src/GPU_DX12.cpp b/src/GPU_DX12.cpp index da78542b03..7928ff2a1b 100644 --- a/src/GPU_DX12.cpp +++ b/src/GPU_DX12.cpp @@ -221,8 +221,10 @@ void DX12Renderer::SetRenderSettings(RendererSettings& settings) { // DX12 rasterizes the original DS polygons as scanline spans. Better // Polygons is a triangle-splitting workaround for raster backends and - // is intentionally not part of the DX12 renderer contract. - dx12->SetRenderSettings(settings.ScaleFactor, settings.HiresCoordinates); + // is intentionally not part of the DX12 renderer contract. High- + // resolution coordinates are mandatory for DX12 above native 1x; its + // 3D renderer still selects FinalPosition at 1x. + dx12->SetRenderSettings(settings.ScaleFactor, true); } // Configuration acquisition only: the values are forwarded to the // low-latency controller, which decides what the hardware can honour. diff --git a/src/GPU_OpenGL.cpp b/src/GPU_OpenGL.cpp index 37069f4820..dfbb025760 100644 --- a/src/GPU_OpenGL.cpp +++ b/src/GPU_OpenGL.cpp @@ -336,7 +336,9 @@ void GLRenderer::SetRenderSettings(RendererSettings& settings) if (IsCompute) { auto rend3d = dynamic_cast(Rend3D.get()); - rend3d->SetRenderSettings(settings.ScaleFactor, settings.HiresCoordinates); + // OpenGL Compute always uses high-resolution coordinates above native + // 1x. ComputeRenderer3D keeps the 1x FinalPosition bypass internally. + rend3d->SetRenderSettings(settings.ScaleFactor, true); } else { diff --git a/src/GPU_Vulkan.cpp b/src/GPU_Vulkan.cpp index d2b81f3ad9..982231f99b 100644 --- a/src/GPU_Vulkan.cpp +++ b/src/GPU_Vulkan.cpp @@ -237,8 +237,10 @@ void VulkanRenderer::SetRenderSettings(RendererSettings& settings) // BetterPolygons is a triangle-splitting workaround for the classic // OpenGL/native Metal raster paths. Vulkan follows GPU3D_Compute and // rasterizes each DS polygon directly as scanline spans, so only the - // scale and coordinate-mode settings apply. - vulkan->SetRenderSettings(settings.ScaleFactor, settings.HiresCoordinates); + // scale and coordinate-mode settings apply. High-resolution + // coordinates are a mandatory Vulkan renderer contract; the 3D + // renderer still selects FinalPosition at native 1x. + vulkan->SetRenderSettings(settings.ScaleFactor, true); } } diff --git a/src/frontend/qt_sdl/Config.cpp b/src/frontend/qt_sdl/Config.cpp index 97e8700ddb..affa8e57d3 100644 --- a/src/frontend/qt_sdl/Config.cpp +++ b/src/frontend/qt_sdl/Config.cpp @@ -265,6 +265,7 @@ namespace Config {"Instance*.Metroid.Enable.stylusMode", false}, {"Instance*.Metroid.Enable.topScreenTouch", false}, {"Instance*.Metroid.Enable.touchScreenAimOnly", false}, + {"Instance*.Metroid.Enable.touchScreenAimOnlySuspendForTransform", false}, {"Instance*.Metroid.Enable.stylusHideCursorInGame", false}, {"Instance*.Metroid.Enable.stylusConfineCursorToTopScreen", false}, {"Instance*.Metroid.Enable.stylusHoldCursorAtCenterWhenNotClicking", false}, diff --git a/src/frontend/qt_sdl/InputConfig/MelonPrimeInputConfig.cpp b/src/frontend/qt_sdl/InputConfig/MelonPrimeInputConfig.cpp index aa8eaa68b1..82ac31a026 100644 --- a/src/frontend/qt_sdl/InputConfig/MelonPrimeInputConfig.cpp +++ b/src/frontend/qt_sdl/InputConfig/MelonPrimeInputConfig.cpp @@ -20,6 +20,11 @@ #include #include #include +#include +#include +#include +#include +#include #include "../MelonPrimeColorDialogPrefs.h" #include "../MelonPrime.h" #include "../EmuThread.h" @@ -37,6 +42,10 @@ #include #include // MELONPRIME_RESET_SENSITIVITY_SECTION_FROM_CONFIG_V17 #include +#include +#include + +#include #include #include @@ -190,11 +199,13 @@ MelonPrimeInputConfig::MelonPrimeInputConfig(EmuInstance* emu, QWidget* parent) setupKeyBindings(instcfg, keycfg, joycfg); setupSensitivityAndToggles(instcfg); setupInputMethodSection(instcfg); + setupSettingsOrganization(); setupCollapsibleSections(instcfg); setupCustomHudWidgets(instcfg); setupPreviewConnections(); setupCustomHudCode(); MelonPrime::UiText::LocalizeWidgetTree(this); + refreshSettingsPresentation(); #if defined(__APPLE__) && defined(MELONPRIME_ENABLE_METAL) // scatter-budget-exempt: native Metal preset UI, not input dispatch refreshMacMetalPresetText(); #endif @@ -210,6 +221,7 @@ MelonPrimeInputConfig::MelonPrimeInputConfig(EmuInstance* emu, QWidget* parent) // Must run after every widget (UI-defined and programmatic) exists so the // guard reaches all of them. installWheelScrollGuards(); + ui->scrollSettings->viewport()->installEventFilter(this); m_applyPreviewEnabled = true; } @@ -288,19 +300,32 @@ void MelonPrimeInputConfig::installWheelScrollGuards() bool MelonPrimeInputConfig::eventFilter(QObject* obj, QEvent* event) { + if (obj == ui->scrollSettings->viewport() && event->type() == QEvent::Resize) + { + refreshSettingsPresentation(); + } + if (event->type() == QEvent::Wheel) { QWidget* w = qobject_cast(obj); if (w && !w->hasFocus()) { // The user is scrolling the page, not adjusting this control. - // Forward the wheel to the enclosing scroll area's viewport so the - // page scrolls, and swallow it here so the value never changes. + // Update the enclosing area's scrollbar directly. Re-dispatching + // the same QWheelEvent synchronously can re-enter Qt's event path + // while the original control is still handling it. for (QWidget* p = w->parentWidget(); p; p = p->parentWidget()) { if (auto* area = qobject_cast(p)) { - QApplication::sendEvent(area->viewport(), event); + auto* wheel = static_cast(event); + QScrollBar* const bar = area->verticalScrollBar(); + int distance = wheel->pixelDelta().y(); + if (distance == 0) { + const int steps = wheel->angleDelta().y() / 120; + distance = steps * bar->singleStep() * 3; + } + bar->setValue(bar->value() - distance); break; } } @@ -339,13 +364,21 @@ void MelonPrimeInputConfig::setupMenuLanguageControl(Config::Table& instcfg) m_menuLanguageGroup = new QGroupBox(QStringLiteral("Language"), ui->scrollSettingsContents); m_menuLanguageGroup->setObjectName(QStringLiteral("groupMetroidMenuLanguage")); - auto* layout = new QVBoxLayout(m_menuLanguageGroup); + auto* layout = new QHBoxLayout(m_menuLanguageGroup); layout->setContentsMargins(8, 8, 8, 8); layout->setSpacing(6); m_lblMenuLanguage = new QLabel(QStringLiteral("Menu Language"), m_menuLanguageGroup); m_comboMenuLanguage = new QComboBox(m_menuLanguageGroup); m_comboMenuLanguage->setObjectName(QStringLiteral("comboMetroidMenuLanguage")); + m_comboMenuLanguage->setSizeAdjustPolicy( + QComboBox::AdjustToMinimumContentsLengthWithIcon); + m_comboMenuLanguage->setMinimumContentsLength(22); + m_comboMenuLanguage->setMinimumWidth(260); + m_comboMenuLanguage->setMaximumWidth(420); + m_comboMenuLanguage->view()->setMinimumWidth(260); + m_comboMenuLanguage->view()->setMaximumWidth(420); + m_comboMenuLanguage->view()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); const MelonPrime::UiText::MenuLangId systemLang = MelonPrime::UiText::DetectSystemMenuLanguage(); const QString systemLabel = MelonPrime::UiText::MenuLanguageDisplayName(systemLang); @@ -368,6 +401,7 @@ void MelonPrimeInputConfig::setupMenuLanguageControl(Config::Table& instcfg) layout->addWidget(m_lblMenuLanguage); layout->addWidget(m_comboMenuLanguage); + layout->addStretch(1); ui->metroidVLayout->insertWidget(0, m_menuLanguageGroup); @@ -379,6 +413,7 @@ void MelonPrimeInputConfig::setupMenuLanguageControl(Config::Table& instcfg) MelonPrime::UiText::SetMenuLanguageSelection( m_comboMenuLanguage->currentData().toInt()); MelonPrime::UiText::LocalizeWidgetTree(this); + refreshSettingsPresentation(); #if defined(__APPLE__) && defined(MELONPRIME_ENABLE_METAL) // scatter-budget-exempt: native Metal preset UI, not input dispatch refreshMacMetalPresetText(); #endif @@ -480,6 +515,10 @@ void MelonPrimeInputConfig::buildSettingBindings() { C::StylusHideCursorInGame, K::CheckBool, ui->cbMetroidEnableStylusHideCursorInGame }, // 51 { C::StylusConfineCursorToTopScreen, K::CheckBool, ui->cbMetroidEnableStylusConfineCursorToTopScreen }, // 52 { C::StylusHoldCursorAtCenterWhenNotClicking, K::CheckBool, ui->cbMetroidEnableStylusHoldCursorAtCenterWhenNotClicking }, // 53 + // Sub-option of TouchScreenAimOnly. Appended so every historical binding + // index stays stable; only the tail load range grows. + { C::TouchScreenAimOnlySuspendForTransform, K::CheckBool, + ui->cbMetroidEnableTouchScreenAimOnlySuspendForTransform }, // 54 }; } @@ -697,7 +736,7 @@ void MelonPrimeInputConfig::setupSensitivityAndToggles(Config::Table& instcfg) // V15 appended bindings 45..47: distance, inverted disable parent, custom mode. // Mouse-wheel weapon cycling is now Next/Previous Weapon (Secondary) bindings. loadBindingsRange(instcfg, 45, 48); // MELONPRIME_DISABLE_CHECKBOX_SEMANTICS_V15 - loadBindingsRange(instcfg, 49, 54); // top-screen touch, touch-screen aim-only, stylus cursor options + loadBindingsRange(instcfg, 49, 55); // top-screen touch, touch-screen aim-only (+ its sub-option), stylus cursor options if (!instcfg.HasKey(MelonPrime::CfgKey::MorphBoostSwipeEnabled) && instcfg.GetInt(MelonPrime::CfgKey::MorphBoostSwipeDistance) <= 0) { m_cbMetroidDisableMorphBoostSwipe->setChecked(true); @@ -916,7 +955,10 @@ void MelonPrimeInputConfig::setupInputMethodSection(Config::Table& instcfg) || m_cbMetroidUseNewTransformMethod || m_cbMetroidUseNewTransformMethod2 || m_cbMetroidUseNewZoomMethod2 - || m_cbMetroidUseNewZoomMethod3) + || m_cbMetroidUseNewZoomMethod3 + || m_cbMetroidUseStandardWeaponSwitchMethod + || m_cbMetroidUseStandardTransformMethod + || m_cbMetroidUseStandardZoomMethod) { return; } @@ -968,6 +1010,28 @@ void MelonPrimeInputConfig::setupInputMethodSection(Config::Table& instcfg) addDeveloperWidget(ui->cbMetroidEnableNativeAimPostFoldWrite); addDeveloperWidget(ui->lblMetroidNativeAimHookModeDesc); + const int weaponSwitchMethod = + std::clamp(instcfg.GetInt(MelonPrime::CfgKey::WeaponSwitchMethod), 0, 2); + + m_cbMetroidUseStandardWeaponSwitchMethod = new QCheckBox( + "Use Standard Method for Weapon Change", + m_sectionInputMethod); + m_cbMetroidUseStandardWeaponSwitchMethod->setToolTip( + "Checked: use the built-in weapon switching the emulator has always used."); + m_cbMetroidUseStandardWeaponSwitchMethod->setChecked( + weaponSwitchMethod == MelonPrime::WeaponSwitchMethod::LegacyTouch); + sectionLayout->addWidget(m_cbMetroidUseStandardWeaponSwitchMethod); + + auto* weaponStdDesc = new QLabel( + "Standard Method simulates the touch/menu weapon switching the emulator has always used. " + "Pick this to rule the native paths out of a problem.", + m_sectionInputMethod); + weaponStdDesc->setObjectName(QStringLiteral("lblMetroidWeaponSwitchStandardDesc")); + weaponStdDesc->setWordWrap(true); + weaponStdDesc->setStyleSheet("QLabel { margin-left: 20px; }"); + sectionLayout->addWidget(weaponStdDesc); + sectionLayout->addSpacing(6); + m_cbMetroidUseNewWeaponSwitchMethod = new QCheckBox( "Use New Method for Weapon Change", m_sectionInputMethod); @@ -985,8 +1049,6 @@ void MelonPrimeInputConfig::setupInputMethodSection(Config::Table& instcfg) desc->setStyleSheet("QLabel { margin-left: 20px; }"); sectionLayout->addWidget(desc); - const int weaponSwitchMethod = - std::clamp(instcfg.GetInt(MelonPrime::CfgKey::WeaponSwitchMethod), 0, 2); m_cbMetroidUseNewWeaponSwitchMethod->setChecked( weaponSwitchMethod == MelonPrime::WeaponSwitchMethod::NewNative); @@ -1037,12 +1099,6 @@ void MelonPrimeInputConfig::setupInputMethodSection(Config::Table& instcfg) fireDesc->setStyleSheet("QLabel { margin-left: 20px; }"); addDeveloperWidget(fireDesc); - m_cbMetroidUseNewTransformMethod = new QCheckBox( - "Use New Method for Alt-Form Transform", - m_sectionInputMethod); - m_cbMetroidUseNewTransformMethod->setToolTip( - "Checked: use the native ARM9 TransformRequest hook. " - "Unchecked: use the older touch/menu simulation path."); // The int key is authoritative; the legacy bool only seeds it for configs // written before New Method 2 existed. const int altFormTransformMethod = @@ -1051,6 +1107,32 @@ void MelonPrimeInputConfig::setupInputMethodSection(Config::Table& instcfg) : (instcfg.GetBool(MelonPrime::CfgKey::DirectAltFormTransform) ? MelonPrime::AltFormTransformMethod::NewNativeGate : MelonPrime::AltFormTransformMethod::LegacyTouch); + + m_cbMetroidUseStandardTransformMethod = new QCheckBox( + "Use Standard Method for Alt-Form Transform", + m_sectionInputMethod); + m_cbMetroidUseStandardTransformMethod->setToolTip( + "Checked: use the built-in transform the emulator has always used."); + m_cbMetroidUseStandardTransformMethod->setChecked( + altFormTransformMethod == MelonPrime::AltFormTransformMethod::LegacyTouch); + sectionLayout->addSpacing(6); + sectionLayout->addWidget(m_cbMetroidUseStandardTransformMethod); + + auto* transformStdDesc = new QLabel( + "Standard Method simulates the touch/menu transform the emulator has always used. " + "Pick this to rule the native paths out of a problem.", + m_sectionInputMethod); + transformStdDesc->setObjectName(QStringLiteral("lblMetroidTransformStandardDesc")); + transformStdDesc->setWordWrap(true); + transformStdDesc->setStyleSheet("QLabel { margin-left: 20px; }"); + sectionLayout->addWidget(transformStdDesc); + + m_cbMetroidUseNewTransformMethod = new QCheckBox( + "Use New Method for Alt-Form Transform", + m_sectionInputMethod); + m_cbMetroidUseNewTransformMethod->setToolTip( + "Checked: use the native ARM9 TransformRequest hook. " + "Unchecked: use the older touch/menu simulation path."); m_cbMetroidUseNewTransformMethod->setChecked( altFormTransformMethod == MelonPrime::AltFormTransformMethod::NewNativeGate); sectionLayout->addSpacing(6); @@ -1087,7 +1169,34 @@ void MelonPrimeInputConfig::setupInputMethodSection(Config::Table& instcfg) transform2Desc->setStyleSheet("QLabel { margin-left: 20px; }"); sectionLayout->addWidget(transform2Desc); - const int zoomMethod = std::clamp(instcfg.GetInt(MelonPrime::CfgKey::ZoomInputMethod), 0, 3); + const int configuredZoomMethod = + std::clamp(instcfg.GetInt(MelonPrime::CfgKey::ZoomInputMethod), 0, 3); + // Public builds expose only the Standard path. Normalize any stale native + // value before initializing the always-available Standard checkbox. + const int zoomMethod = kDeveloperOnlyFeaturesEnabled + ? configuredZoomMethod + : MelonPrime::ZoomInputMethod::LegacyFixedR; + + m_cbMetroidUseStandardZoomMethod = new QCheckBox( + "Use Standard Method for Zoom", + m_sectionInputMethod); + m_cbMetroidUseStandardZoomMethod->setToolTip( + "Checked: use the built-in zoom the emulator has always used."); + m_cbMetroidUseStandardZoomMethod->setChecked( + zoomMethod != MelonPrime::ZoomInputMethod::NewNativeToggle + && zoomMethod != MelonPrime::ZoomInputMethod::NewDirectInvocation); + m_cbMetroidUseStandardZoomMethod->setEnabled(true); + sectionLayout->addSpacing(6); + sectionLayout->addWidget(m_cbMetroidUseStandardZoomMethod); + + auto* zoomStdDesc = new QLabel( + "Standard Method presses the zoom button the player's control preset binds. " + "Pick this to rule the native paths out of a problem.", + m_sectionInputMethod); + zoomStdDesc->setObjectName(QStringLiteral("lblMetroidZoomStandardDesc")); + zoomStdDesc->setWordWrap(true); + zoomStdDesc->setStyleSheet("QLabel { margin-left: 20px; }"); + sectionLayout->addWidget(zoomStdDesc); m_cbMetroidUseNewZoomMethod2 = new QCheckBox( "Use New Method 2 for Zoom", @@ -1143,27 +1252,57 @@ void MelonPrimeInputConfig::setupInputMethodSection(Config::Table& instcfg) addDeveloperWidget(zoom3Desc); - // Method selectors are stored as one integer per domain, so the boxes in a - // pair are mutually exclusive: ticking one clears the other instead of - // letting the save silently pick a winner. - auto makeExclusive = [](QCheckBox* a, QCheckBox* b) { - if (!a || !b) + // Each domain stores one integer, so its selector is exactly-one-of-N: + // Standard is a real choice rather than "nothing ticked". Checkboxes keep + // the look of the rest of the dialog while behaving like a radio group -- + // ticking one clears the rest, and clearing the last one puts it back + // instead of leaving the group empty. + auto makeExclusiveGroup = [](std::initializer_list members) { + QVector group; + for (QCheckBox* const box : members) { + if (box) + group.append(box); + } + if (group.size() < 2) return; - QObject::connect(a, &QCheckBox::toggled, b, [b](bool on) { - if (on && b->isChecked()) - b->setChecked(false); - }); - QObject::connect(b, &QCheckBox::toggled, a, [a](bool on) { - if (on && a->isChecked()) - a->setChecked(false); - }); + // Shared re-entrancy guard: setChecked() below re-enters these slots. + const auto busy = std::make_shared(false); + for (QCheckBox* const box : group) { + QObject::connect(box, &QCheckBox::toggled, box, + [group, box, busy](bool on) { + if (*busy) + return; + *busy = true; + if (on) { + for (QCheckBox* const other : group) { + if (other != box) + other->setChecked(false); + } + } + else { + bool anyChecked = false; + for (QCheckBox* const other : group) { + if (other->isChecked()) { + anyChecked = true; + break; + } + } + if (!anyChecked) + box->setChecked(true); + } + *busy = false; + }); + } }; - makeExclusive(m_cbMetroidUseNewWeaponSwitchMethod, - m_cbMetroidUseNewWeaponSwitchMethod2); - makeExclusive(m_cbMetroidUseNewTransformMethod, - m_cbMetroidUseNewTransformMethod2); - makeExclusive(m_cbMetroidUseNewZoomMethod2, - m_cbMetroidUseNewZoomMethod3); + makeExclusiveGroup({ m_cbMetroidUseStandardWeaponSwitchMethod, + m_cbMetroidUseNewWeaponSwitchMethod, + m_cbMetroidUseNewWeaponSwitchMethod2 }); + makeExclusiveGroup({ m_cbMetroidUseStandardTransformMethod, + m_cbMetroidUseNewTransformMethod, + m_cbMetroidUseNewTransformMethod2 }); + makeExclusiveGroup({ m_cbMetroidUseStandardZoomMethod, + m_cbMetroidUseNewZoomMethod2, + m_cbMetroidUseNewZoomMethod3 }); int insertIndex = parentLayout->indexOf(ui->sectionInputSettings); if (insertIndex < 0) @@ -1176,10 +1315,194 @@ void MelonPrimeInputConfig::setupInputMethodSection(Config::Table& instcfg) updateAimControlsForStylusMode(ui->cbMetroidEnableStylusMode->isChecked()); } +void MelonPrimeInputConfig::setupSettingsOrganization() +{ + auto* inputLayout = qobject_cast(ui->sectionInputSettings->layout()); + if (!inputLayout) + return; + + // Keep the Sensitivity section limited to actual aim tuning. Touch/stylus, + // Morph Ball gesture and remapper compatibility controls all describe how + // input is produced, so they belong together under Input Settings. + auto detachWidget = [](QWidget* widget) { + if (!widget) + return; + if (QWidget* parent = widget->parentWidget()) { + if (QLayout* layout = parent->layout()) + layout->removeWidget(widget); + } + }; + auto appendInputWidget = [&](QWidget* widget) { + if (!widget) + return; + detachWidget(widget); + widget->setParent(ui->sectionInputSettings); + inputLayout->addWidget(widget); + }; + auto appendSeparator = [&]() { + auto* separator = new QFrame(ui->sectionInputSettings); + separator->setFrameShape(QFrame::HLine); + separator->setFrameShadow(QFrame::Sunken); + inputLayout->addWidget(separator); + }; + + // Re-add the pre-existing compatibility controls last, after the primary + // touch/stylus and gesture settings. + detachWidget(ui->cbMetroidApplyJoy2KeySupport); + detachWidget(ui->lblMetroidJoy2KeySupportDesc); + + appendInputWidget(ui->cbMetroidEnableStylusMode); + appendInputWidget(ui->cbMetroidEnableTouchScreenAimOnly); + appendInputWidget(ui->cbMetroidEnableTouchScreenAimOnlySuspendForTransform); + appendInputWidget(ui->cbMetroidEnableTopScreenTouch); + appendInputWidget(ui->cbMetroidEnableStylusHideCursorInGame); + appendInputWidget(ui->cbMetroidEnableStylusConfineCursorToTopScreen); + appendInputWidget(ui->cbMetroidEnableStylusHoldCursorAtCenterWhenNotClicking); + + appendSeparator(); + appendInputWidget(m_cbMetroidDisableMorphBoostSwipe); + appendInputWidget(m_lblMetroidDisableMorphBoostSwipeDesc); + appendInputWidget(m_cbMetroidMorphBoostCustomRawThreshold); + appendInputWidget(m_lblMetroidMorphBoostCustomRawThresholdDesc); + + detachWidget(m_lblMetroidMorphBoostMouseSensitivity); + detachWidget(m_spinMetroidMorphBoostMouseSensitivity); + auto* morphThresholdRow = new QWidget(ui->sectionInputSettings); + morphThresholdRow->setObjectName(QStringLiteral("rowMetroidMorphBoostMouseSensitivity")); + auto* morphThresholdLayout = new QHBoxLayout(morphThresholdRow); + morphThresholdLayout->setContentsMargins(0, 0, 0, 0); + morphThresholdLayout->addWidget(m_lblMetroidMorphBoostMouseSensitivity, 1); + morphThresholdLayout->addWidget(m_spinMetroidMorphBoostMouseSensitivity); + inputLayout->addWidget(morphThresholdRow); + appendInputWidget(m_lblMetroidMorphBoostMouseSensitivityDesc); + + appendSeparator(); + appendInputWidget(ui->cbMetroidApplyJoy2KeySupport); + appendInputWidget(ui->lblMetroidJoy2KeySupportDesc); + + // The .ui file accumulated sections in feature-arrival order. Present the + // same widgets in task order: common input first, gameplay next, display + // and presentation after that, and maintenance/developer controls last. + const QList orderedSections = { + m_menuLanguageGroup, + ui->btnToggleSensitivity, + ui->sectionSensitivity, + ui->btnToggleInputSettings, + ui->sectionInputSettings, + m_btnToggleInputMethod, + m_sectionInputMethod, + ui->btnToggleGameplay, + ui->sectionGameplay, + ui->btnToggleGameFeature, + ui->sectionGameFeature, + ui->btnToggleDisableFeatures, + ui->sectionDisableFeatures, + ui->btnToggleLowHpWarning, + ui->sectionLowHpWarning, + ui->btnToggleInGameApply, + ui->sectionInGameApply, + ui->btnToggleInGameAspectRatio, + ui->sectionInGameAspectRatio, + ui->btnToggleScreenSync, + ui->sectionScreenSync, + ui->btnToggleCursorClipSettings, + ui->sectionCursorClipSettings, + ui->btnToggleVideo, + ui->sectionVideo, + ui->btnToggleVolume, + ui->sectionVolume, + ui->btnToggleLicense, + ui->sectionLicense, + ui->btnToggleBugFix, + ui->sectionBugFix, + ui->btnToggleDeveloperOnly, + ui->sectionDeveloperOnly, + }; + + for (QWidget* widget : orderedSections) { + if (widget) + ui->metroidVLayout->removeWidget(widget); + } + int insertionIndex = 0; + for (QWidget* widget : orderedSections) { + if (widget) + ui->metroidVLayout->insertWidget(insertionIndex++, widget); + } +} + +void MelonPrimeInputConfig::refreshSettingsPresentation() +{ + // Long translated help text should wrap vertically instead of expanding + // the settings page and forcing the horizontal scrollbar seen in the old + // single-column layout. + ui->scrollSettings->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + ui->scrollSettingsContents->setMinimumWidth(0); + const int viewportWidth = ui->scrollSettings->viewport()->width(); + if (viewportWidth > 0) + ui->scrollSettingsContents->setMaximumWidth(viewportWidth); + + // QCheckBox has no word-wrap property. Keep every original checkbox intact + // and insert visual line breaks into its complete translated caption. This + // preserves its normal click target, enabled state, signals and bindings. + const int captionWidth = qMax(160, viewportWidth - 96); + for (QCheckBox* checkBox : ui->tabMetroid->findChildren()) { + const QString currentText = checkBox->text(); + const QString previousRendered = + checkBox->property("_melonprime_wrapped_rendered_text").toString(); + QString fullText = + checkBox->property("_melonprime_wrapped_full_text").toString(); + + // Localization restores a fresh, unwrapped caption. Treat any text + // other than our last rendered value as the new full translation. + if (previousRendered.isEmpty() || currentText != previousRendered) { + fullText = currentText; + checkBox->setProperty("_melonprime_wrapped_full_text", fullText); + } + if (fullText.isEmpty()) + continue; + + QTextLayout textLayout(fullText, checkBox->font()); + QTextOption textOption; + textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); + textLayout.setTextOption(textOption); + textLayout.beginLayout(); + QString wrappedText; + while (true) { + QTextLine line = textLayout.createLine(); + if (!line.isValid()) + break; + line.setLineWidth(captionWidth); + if (!wrappedText.isEmpty()) + wrappedText += QLatin1Char('\n'); + wrappedText += fullText.mid(line.textStart(), line.textLength()); + } + textLayout.endLayout(); + + checkBox->setText(wrappedText); + checkBox->setAccessibleName(fullText); + checkBox->setProperty("_melonprime_wrapped_rendered_text", wrappedText); + checkBox->setMinimumWidth(0); + QSizePolicy policy = checkBox->sizePolicy(); + policy.setHorizontalPolicy(QSizePolicy::Expanding); + checkBox->setSizePolicy(policy); + } +} + void MelonPrimeInputConfig::updateAimControlsForStylusMode(bool stylusEnabled) { + // Stylus-specific options retain their saved check state, but cannot be + // edited until Stylus Mode itself is enabled. + ui->cbMetroidEnableTouchScreenAimOnly->setEnabled(stylusEnabled); + // Sub-option: only meaningful while the parent patch is actually on. + ui->cbMetroidEnableTouchScreenAimOnlySuspendForTransform->setEnabled( + stylusEnabled && ui->cbMetroidEnableTouchScreenAimOnly->isChecked()); + ui->cbMetroidEnableStylusHideCursorInGame->setEnabled(stylusEnabled); + ui->cbMetroidEnableTopScreenTouch->setEnabled(stylusEnabled); + ui->cbMetroidEnableStylusConfineCursorToTopScreen->setEnabled(stylusEnabled); + ui->cbMetroidEnableStylusHoldCursorAtCenterWhenNotClicking->setEnabled(stylusEnabled); + const bool enableAimControls = !stylusEnabled; ui->metroidAimSensitvitySpinBox->setEnabled(enableAimControls); ui->metroidAimSensitvityLabel->setEnabled(enableAimControls); @@ -1238,6 +1561,12 @@ void MelonPrimeInputConfig::updateAimControlsForStylusMode(bool stylusEnabled) m_cbMetroidUseNewZoomMethod2->setEnabled(kDeveloperOnlyFeaturesEnabled); if (m_cbMetroidUseNewZoomMethod3) m_cbMetroidUseNewZoomMethod3->setEnabled(kDeveloperOnlyFeaturesEnabled); + if (m_cbMetroidUseStandardZoomMethod) + m_cbMetroidUseStandardZoomMethod->setEnabled(true); + if (m_cbMetroidUseStandardWeaponSwitchMethod) + m_cbMetroidUseStandardWeaponSwitchMethod->setEnabled(true); + if (m_cbMetroidUseStandardTransformMethod) + m_cbMetroidUseStandardTransformMethod->setEnabled(true); ui->lblMetroidDirectAltFormTransformDesc->setEnabled(true); } @@ -1565,6 +1894,12 @@ void MelonPrimeInputConfig::on_cbMetroidEnableStylusMode_stateChanged(int state) updateAimControlsForStylusMode(state != 0); } +void MelonPrimeInputConfig::on_cbMetroidEnableTouchScreenAimOnly_stateChanged(int) +{ + // Refresh the sub-option, which is only meaningful while this one is on. + updateAimControlsForStylusMode(ui->cbMetroidEnableStylusMode->isChecked()); +} + void MelonPrimeInputConfig::on_cbMetroidDisableMphAimSmoothing_stateChanged(int) { updateAimControlsForStylusMode(ui->cbMetroidEnableStylusMode->isChecked()); diff --git a/src/frontend/qt_sdl/InputConfig/MelonPrimeInputConfig.h b/src/frontend/qt_sdl/InputConfig/MelonPrimeInputConfig.h index 951ecd8ee1..99acc2b74b 100644 --- a/src/frontend/qt_sdl/InputConfig/MelonPrimeInputConfig.h +++ b/src/frontend/qt_sdl/InputConfig/MelonPrimeInputConfig.h @@ -122,6 +122,7 @@ private slots: void on_cbMetroidHudCrosshairDeadbandEnable_stateChanged(int state); void on_dsbMetroidHudCrosshairDeadband_valueChanged(double value); void on_cbMetroidEnableStylusMode_stateChanged(int state); + void on_cbMetroidEnableTouchScreenAimOnly_stateChanged(int state); void on_cbMetroidDisableMphAimSmoothing_stateChanged(int state); void on_cbMetroidExpandStageMatrix_stateChanged(int state); void on_comboMetroidLowHpWarningMode_currentIndexChanged(int index); @@ -152,6 +153,8 @@ private slots: void setupMenuLanguageControl(Config::Table& instcfg); void setupSensitivityAndToggles(Config::Table& instcfg); void setupInputMethodSection(Config::Table& instcfg); + void setupSettingsOrganization(); + void refreshSettingsPresentation(); void setupCollapsibleSections(Config::Table& instcfg); void setupPreviewConnections(); void setupCustomHudCode(); @@ -192,6 +195,9 @@ private slots: bool m_applyPreviewActive = false; QPushButton* m_btnToggleInputMethod = nullptr; QWidget* m_sectionInputMethod = nullptr; + QCheckBox* m_cbMetroidUseStandardWeaponSwitchMethod = nullptr; + QCheckBox* m_cbMetroidUseStandardTransformMethod = nullptr; + QCheckBox* m_cbMetroidUseStandardZoomMethod = nullptr; QCheckBox* m_cbMetroidUseNewWeaponSwitchMethod = nullptr; QCheckBox* m_cbMetroidUseNewWeaponSwitchMethod2 = nullptr; QCheckBox* m_cbMetroidUseNewBipedFireMethod = nullptr; diff --git a/src/frontend/qt_sdl/InputConfig/MelonPrimeInputConfig.ui b/src/frontend/qt_sdl/InputConfig/MelonPrimeInputConfig.ui index 22531aafbf..b9a0aedf1f 100644 --- a/src/frontend/qt_sdl/InputConfig/MelonPrimeInputConfig.ui +++ b/src/frontend/qt_sdl/InputConfig/MelonPrimeInputConfig.ui @@ -146,30 +146,41 @@ - Use the Whole Touch Screen for Aiming (Disables the touch-screen HUD buttons: Morph Ball, weapon quick slots and the weapon menu. Double-tap jump and the touch boost gesture still work) + Use the Whole Touch Screen for Aiming (Disables the touch-screen HUD buttons: Transform, weapon quick slots and the weapon menu. Double-tap jump and the touch boost gesture still work) + QCheckBox { margin-left: 24px; } + + Turn It Off Briefly While a Standard-Method Transform Fires (The Standard transform taps the touch-screen Transform button, which the option above disables. This re-enables the HUD hit-test for those few frames only) + QCheckBox { margin-left: 44px; } + + + Hide the Cursor During Gameplay Even in Stylus Mode (Presentation only: the pointer stays free, so stylus aiming and touch input are unaffected) + QCheckBox { margin-left: 24px; } - + Enable Touch Input on the Top Screen + QCheckBox { margin-left: 24px; } - + Confine the Cursor to the Top Screen During a Match in Stylus Mode (Windows only) + QCheckBox { margin-left: 24px; } - + Hold the Cursor at the Center While No Click Is Held During a Match in Stylus Mode (every drag then starts from the center with its full range) + QCheckBox { margin-left: 24px; } - + 0 @@ -182,14 +193,14 @@ - + Aim sensitivity (default: 63) - + 0.000001 @@ -208,14 +219,14 @@ - + Aim Y-Axis Scale (default: 1.5147) - + (1.5147 = MPH native; option: 1.9429 = perfectly matches X/Y angular velocity) @@ -228,7 +239,7 @@ - + 0.000000 @@ -247,19 +258,19 @@ - + <html><head/><body><p><b>Input threshold (deadzone + snap)</b> (recommended: 0.01 [default] or 0.5): |x|&lt;a → 0, a ≤ |x|&lt;1 → ±1, |x|≥1 → as is (a=0: off = all values under 1 ignored, no snap)<br/>When your aim isn't going the way you want, try lowering this value.</p></body></html> - + Enable Aim Sub-pixel Accumulator (Carry fractional mouse movement across frames. Enable for smoother low-sensitivity aiming) - + Reset sensitivity values @@ -434,7 +445,7 @@ The EU ROM has a hidden Japanese option — setting your DS firmware to Japanese - Show Enemy HP Meter Online + Show Enemy Target Information Online diff --git a/src/frontend/qt_sdl/InputConfig/MelonPrimeInputConfigConfig.cpp b/src/frontend/qt_sdl/InputConfig/MelonPrimeInputConfigConfig.cpp index 92cfe61e6b..3832d19b79 100644 --- a/src/frontend/qt_sdl/InputConfig/MelonPrimeInputConfigConfig.cpp +++ b/src/frontend/qt_sdl/InputConfig/MelonPrimeInputConfigConfig.cpp @@ -150,21 +150,26 @@ void MelonPrimeInputConfig::saveConfig() MelonPrime::CfgKey::FpsCameraLock, m_cbMetroidFpsCameraLock->isChecked()); } - if (m_cbMetroidUseNewZoomMethod2) { + if (m_cbMetroidUseStandardZoomMethod || m_cbMetroidUseNewZoomMethod2) { // Writing this back also normalizes the retired NewPresetBinding value // out of older configs: it now behaves exactly like LegacyFixedR. - // The two boxes are kept mutually exclusive in the dialog; Method 3 - // still wins here so a stale pair can never store an ambiguous state. + // Standard is the public/default path and is the fallback whenever the + // developer-only native boxes are unavailable or unchecked. The three + // boxes are kept mutually exclusive in the dialog; Method 3 still wins + // here so a stale pair can never store an ambiguous state. const bool zoomMethod3 = kDeveloperOnlyFeaturesEnabled && m_cbMetroidUseNewZoomMethod3 && m_cbMetroidUseNewZoomMethod3->isChecked(); + const bool zoomMethod2 = + kDeveloperOnlyFeaturesEnabled + && m_cbMetroidUseNewZoomMethod2 + && m_cbMetroidUseNewZoomMethod2->isChecked(); instcfg.SetInt( MelonPrime::CfgKey::ZoomInputMethod, zoomMethod3 ? MelonPrime::ZoomInputMethod::NewDirectInvocation - : (kDeveloperOnlyFeaturesEnabled - && m_cbMetroidUseNewZoomMethod2->isChecked() + : (zoomMethod2 ? MelonPrime::ZoomInputMethod::NewNativeToggle : MelonPrime::ZoomInputMethod::LegacyFixedR)); } diff --git a/src/frontend/qt_sdl/MelonPrime.cpp b/src/frontend/qt_sdl/MelonPrime.cpp index bd52bb3c2e..25eb97c842 100644 --- a/src/frontend/qt_sdl/MelonPrime.cpp +++ b/src/frontend/qt_sdl/MelonPrime.cpp @@ -359,16 +359,35 @@ namespace MelonPrime { #ifdef MELONPRIME_DS // Cold: battle-runtime latch + match-end poll. One flags load; RAM reads: // pre-latch lobby: currentMode only (skip flow until mode==0x0E) + // pre-latch, stage 1 already seen: local HP only // post-latch live match: battleFlowState only const uint32_t matchLifecycleFlags = m_flags.packed; if (UNLIKELY((matchLifecycleFlags & StateFlags::BIT_IN_GAME_INIT) && !(matchLifecycleFlags & StateFlags::BIT_END_OF_GAME_PATCH_RESTORED))) { if (!(matchLifecycleFlags & StateFlags::BIT_BATTLE_RUNTIME_MODE)) { - const uint8_t mode = *m_ptrs.currentMode; - if (mode == BattleFlow::MODE_BATTLE_RUNTIME) { - const uint8_t flowState = *m_ptrs.battleFlowState; - if (flowState == BattleFlow::FLOW_ACTIVE_MATCH) - HandleBattleRuntimeEnter(); + // Two stages, and they need not complete on the same frame. + // + // Stage 1 is sticky: the mode/flow pair only says the match + // is live, not that the local player exists in it yet, and + // it can stop reporting one again while the player is still + // waiting to spawn. Once seen, it stays seen. + if (!(matchLifecycleFlags & StateFlags::BIT_BATTLE_RUNTIME_SEEN)) { + const uint8_t mode = *m_ptrs.currentMode; + if (mode == BattleFlow::MODE_BATTLE_RUNTIME + && *m_ptrs.battleFlowState == BattleFlow::FLOW_ACTIVE_MATCH) + { + m_flags.set(StateFlags::BIT_BATTLE_RUNTIME_SEEN); + } + } + // Stage 2 completes the latch on the first frame the local + // player is in play, so the battle-runtime registry patches, + // the match ARM9 hooks and the guest trampolines they author + // all land on a spawned player. An unresolved HP pointer + // reads as in play, so this can never stall on a cold cache. + if (m_flags.test(StateFlags::BIT_BATTLE_RUNTIME_SEEN) + && IsLocalPlayerAlive()) + { + HandleBattleRuntimeEnter(); } } else { const uint8_t flowState = *m_ptrs.battleFlowState; @@ -416,6 +435,7 @@ namespace MelonPrime { m_flags.clear(StateFlags::BIT_IN_GAME_INIT); m_flags.clear(StateFlags::BIT_END_OF_GAME_PATCH_RESTORED); m_flags.clear(StateFlags::BIT_BATTLE_RUNTIME_MODE); + m_flags.clear(StateFlags::BIT_BATTLE_RUNTIME_SEEN); #ifdef MELONPRIME_DS // PatchLifecycle Step 3 / Site D — hook deactivation only. // Flag clears and the transient-input / HUD / weapon-switch @@ -587,6 +607,7 @@ namespace MelonPrime { melonDS::u8* const mainRAM = nds->MainRAM; m_flags.clear(StateFlags::BIT_END_OF_GAME_PATCH_RESTORED); m_flags.clear(StateFlags::BIT_BATTLE_RUNTIME_MODE); + m_flags.clear(StateFlags::BIT_BATTLE_RUNTIME_SEEN); m_flags.set(StateFlags::BIT_IN_GAME_INIT); ResetTransientInputState( TR_OverlayHeld | TR_DirectTransform | TR_BipedFire | TR_WeaponSwitchPending diff --git a/src/frontend/qt_sdl/MelonPrime.h b/src/frontend/qt_sdl/MelonPrime.h index b42ffa3aa0..5a88778442 100644 --- a/src/frontend/qt_sdl/MelonPrime.h +++ b/src/frontend/qt_sdl/MelonPrime.h @@ -402,6 +402,20 @@ namespace MelonPrime { melonDS::NDS* nds, uint8_t romGroupIndex); + // Shared spawn barrier for every native input method. True on the + // first player-input hook of the same runtime update that just + // respawned this player -- see + // Direct-Invocation-Spawn-Freeze-Investigation-JP1_0.md. Defined in + // MelonPrimeGameInput.cpp so all four hook fragments can call it. + [[nodiscard]] bool IsFirstPostSpawnInput( + melonDS::NDS* nds, uint32_t player) const noexcept; + + // Local player is still inside the spawn invulnerability countdown + // (player+0xE1 != 0). Every native input method hands its request to + // the Standard path for the whole of that window; the barrier above + // only covers a request that crosses the boundary from outside it. + [[nodiscard]] bool IsLocalPlayerInSpawnInvulnerability() const noexcept; + // --- "New Method 2": mphCodex DirectInvocation (transform + weapon) --- // One hook site, one guest mailbox; see // MelonPrimePatchDirectInvocationHook.inc. @@ -558,6 +572,9 @@ namespace MelonPrime { // "New Method 3" for zoom. Mutually exclusive with the native toggle // above; both are resolved from Metroid.Input.ZoomMethod. bool m_enableDirectInvocationZoom = false; + // Lift the TouchScreenAimOnly patch for the duration of a Standard + // transform, which taps a touch-screen HUD button that patch disables. + bool m_suspendTouchAimOnlyForTransform = false; #ifdef MELONPRIME_DS bool m_enableNativeWeaponSwitch = false; // "New Method 2" (mphCodex DirectInvocation). Independent of the @@ -929,7 +946,13 @@ namespace MelonPrime { static constexpr uint32_t BIT_IN_GAME = 1u << 1; static constexpr uint32_t BIT_IN_GAME_INIT = 1u << 2; static constexpr uint32_t BIT_END_OF_GAME_PATCH_RESTORED = 1u << 12; - // Latched on first mode==0x0E && flow==0 after join; battle patches/hooks apply here. + // Stage 1 of the battle-runtime latch, sticky: the game has reported + // a live match (mode==0x0E && flow==0) at least once since join. It + // does not have to still be reporting one when stage 2 completes. + static constexpr uint32_t BIT_BATTLE_RUNTIME_SEEN = 1u << 17; + // Stage 2, the latch itself: stage 1 has happened AND the local + // player is in play (HP != 0). Battle patches/hooks apply here, so + // they land on a spawned player rather than during the spawn window. static constexpr uint32_t BIT_BATTLE_RUNTIME_MODE = 1u << 15; static constexpr uint32_t BIT_PAUSED = 1u << 3; static constexpr uint32_t BIT_IN_ADVENTURE = 1u << 4; @@ -1184,6 +1207,20 @@ namespace MelonPrime { && ((*m_ptrs.jumpFlag & 0x10) != 0); } + // Local player is in play: spawned and not down. HP 0 covers both + // states -- killed and waiting to respawn, and not yet spawned after + // the match starts -- which is why this is phrased as "alive" rather + // than "dead". Every native input method is gated on it: the legacy + // touch/menu paths are the game reacting to its own simulated input, + // but a native call reaches past whatever the game does with a player + // that is not in play. + // + // An unresolved HP pointer reads as alive, so a native path is never + // disabled just because the pointer cache has not been rebuilt yet. + [[nodiscard]] FORCE_INLINE bool IsLocalPlayerAlive() const noexcept { + return !m_ptrs.health || *m_ptrs.health != 0; + } + template [[nodiscard]] FORCE_INLINE T* GetRamPointer(melonDS::u8* ram, melonDS::u32 addr) { return reinterpret_cast(&ram[addr & 0x3FFFFF]); diff --git a/src/frontend/qt_sdl/MelonPrimeDef.h b/src/frontend/qt_sdl/MelonPrimeDef.h index 3046805892..e00ee4431b 100644 --- a/src/frontend/qt_sdl/MelonPrimeDef.h +++ b/src/frontend/qt_sdl/MelonPrimeDef.h @@ -39,6 +39,7 @@ namespace MelonPrime { inline constexpr const char* StylusMode = "Metroid.Enable.stylusMode"; inline constexpr const char* TopScreenTouch = "Metroid.Enable.topScreenTouch"; inline constexpr const char* TouchScreenAimOnly = "Metroid.Enable.touchScreenAimOnly"; + inline constexpr const char* TouchScreenAimOnlySuspendForTransform = "Metroid.Enable.touchScreenAimOnlySuspendForTransform"; inline constexpr const char* StylusHideCursorInGame = "Metroid.Enable.stylusHideCursorInGame"; inline constexpr const char* StylusConfineCursorToTopScreen = "Metroid.Enable.stylusConfineCursorToTopScreen"; inline constexpr const char* StylusHoldCursorAtCenterWhenNotClicking = "Metroid.Enable.stylusHoldCursorAtCenterWhenNotClicking"; diff --git a/src/frontend/qt_sdl/MelonPrimeGameInput.cpp b/src/frontend/qt_sdl/MelonPrimeGameInput.cpp index 6edf519b59..276cacdb10 100644 --- a/src/frontend/qt_sdl/MelonPrimeGameInput.cpp +++ b/src/frontend/qt_sdl/MelonPrimeGameInput.cpp @@ -498,12 +498,24 @@ namespace MelonPrime { return; } - if (m_enableNativeZoomToggle) { + // Spawn invulnerability window: every native method defers to the + // Standard path for its whole duration. Keep the shared pressed-edge + // latch in sync so leaving the window mid-hold does not fire a stale + // toggle, exactly as the alt-form branch above does. + if (UNLIKELY(nativeZoom && IsLocalPlayerInSpawnInvulnerability())) { + m_nativeZoomTogglePrevDown = zoomDown; +#ifdef MELONPRIME_DS + m_nativeZoomPending.Clear(); + m_directInvocationPending.ClearZoom(); +#endif + if (!zoomDown) + return; + } + else if (m_enableNativeZoomToggle) { UpdateNativeZoomToggleInput(); return; } - - if (m_enableDirectInvocationZoom) { + else if (m_enableDirectInvocationZoom) { UpdateDirectInvocationZoomInput(); return; } @@ -651,6 +663,83 @@ namespace MelonPrime { m_aimResidualY = 0; } + // ========================================================================= + // Shared spawn barrier for the native input methods. + // + // Spawn (JP1_0 0201212C) restores HP early but keeps initialising camera, + // model, animation, gun and HUD state well past that point, and the same + // player runtime update (0200EEAC) then falls through to the player input + // update (02026374) and its ProcessTouchInput call site. So "HP > 0 and we + // reached the hook" is satisfied inside the very update that spawned the + // player, and a native call made there lands on half-initialised state. + // + // The boundary is identifiable without any host latch. Spawn stores the + // hunter's configured invulnerability into player+0xE1, and the same update + // decrements it exactly once before reaching the input code, so on that + // first input hook, and only there: + // + // player+0xE1 == (uint8_t)([player+0x404] + 0xE2) - 1 + // + // The next update reads configured-2, so this costs one input frame rather + // than the whole invulnerability window. Structure offsets are the same on + // all seven ROMs, so this needs no per-version address table. + // + // See docs: mphCodex Direct-Invocation-Spawn-Freeze-Investigation-JP1_0.md. + // ========================================================================= + namespace { + constexpr uint32_t kPlayerSpawnInvulnOffset = 0xE1u; + constexpr uint32_t kPlayerValuesPtrOffset = 0x404u; + constexpr uint32_t kPlayerValuesSpawnInvulnOffset = 0xE2u; + + [[nodiscard]] FORCE_INLINE bool SpawnBarrier_IsMainRamRange( + uint32_t address, uint32_t size) noexcept + { + return size != 0 + && address >= 0x02000000u + && size - 1u <= 0x023FFFFFu - address; + } + } // anonymous namespace + + bool MelonPrimeCore::IsFirstPostSpawnInput( + melonDS::NDS* nds, uint32_t player) const noexcept + { + if (!nds || !SpawnBarrier_IsMainRamRange(player + kPlayerValuesPtrOffset, 4u)) + return false; + + const uint32_t values = Read32(nds->MainRAM, player + kPlayerValuesPtrOffset); + if (!SpawnBarrier_IsMainRamRange(values, kPlayerValuesSpawnInvulnOffset + 2u)) + return false; + + // player+0xE1 is a byte, so the configured value is compared truncated + // the same way Spawn stores it. + const uint8_t configured = static_cast( + Read16(nds->MainRAM, values + kPlayerValuesSpawnInvulnOffset)); + if (configured == 0) + return false; + + const uint8_t current = Read8(nds->MainRAM, player + kPlayerSpawnInvulnOffset); + return current == static_cast(configured - 1u); + } + + bool MelonPrimeCore::IsLocalPlayerInSpawnInvulnerability() const noexcept + { + if (!m_flags.test(StateFlags::BIT_IN_GAME_INIT)) + return false; + + melonDS::NDS* const nds = emuInstance ? emuInstance->getNDS() : nullptr; + if (!nds) + return false; + + const uint32_t addr = + m_currentRom.playerStructStart + + static_cast(m_playerPosition) * Consts::PLAYER_ADDR_INC + + kPlayerSpawnInvulnOffset; + if (!SpawnBarrier_IsMainRamRange(addr, 1u)) + return false; + + return Read8(nds->MainRAM, addr) != 0; + } + // ========================================================================= // Hook implementation unity fragments. // diff --git a/src/frontend/qt_sdl/MelonPrimeGameWeapon.cpp b/src/frontend/qt_sdl/MelonPrimeGameWeapon.cpp index 8f491de6e5..4d253a4360 100644 --- a/src/frontend/qt_sdl/MelonPrimeGameWeapon.cpp +++ b/src/frontend/qt_sdl/MelonPrimeGameWeapon.cpp @@ -87,7 +87,6 @@ namespace MelonPrime { return weaponId == PowerBeam || weaponId == Missile || weaponId == OmegaCannon; } - constexpr uint32_t kPlayerSpawnInvincibilityOffset = 0xE1u; COLD_FUNCTION void ShowOmegaWeaponSwitchBlockedMessage(EmuInstance* emuInstance) { @@ -384,6 +383,31 @@ namespace MelonPrime { } #ifdef MELONPRIME_DS + // Spawn invulnerability window: hand the request to the Standard path + // for its whole duration rather than making a native call. The + // dispatcher's first-post-spawn barrier stays as well -- it covers a + // request that crosses the boundary from outside this window, which + // this producer-side check cannot see. + if ((m_enableDirectInvocationWeapon || m_enableNativeWeaponSwitch) + && UNLIKELY(IsLocalPlayerInSpawnInvulnerability())) + { + m_weaponSwitchPending.Clear(); + m_directInvocationPending.ClearWeapon(); + return SwitchWeaponLegacyTouchFallback(weaponId); + } + + // A native method must not fire while the local player is not in play. + // Refuse the request outright rather than rerouting it to the legacy + // path: "the selected method does nothing until you are in play" is + // easier to reason about than a silent method swap for one window. + if ((m_enableDirectInvocationWeapon || m_enableNativeWeaponSwitch) + && !IsLocalPlayerAlive()) + { + m_weaponSwitchPending.Clear(); + m_directInvocationPending.ClearWeapon(); + return false; + } + if (m_enableDirectInvocationWeapon) { // "New Method 2": mphCodex DirectInvocation. The hook calls the // game's own TryEquipWeapon(player, id, 0) from the @@ -392,19 +416,6 @@ namespace MelonPrime { // native-only path: an unserviceable site is reported instead of // being hidden behind the legacy touch route. melonDS::NDS* const nds = emuInstance->getNDS(); - const uint32_t playerBase = - m_currentRom.playerStructStart - + static_cast(m_playerPosition) * Consts::PLAYER_ADDR_INC; - // Same spawn-window guard as Method 1: the native equip is not safe - // while spawn invincibility is still counting down, so hand this one - // request to the legacy route rather than dropping or forcing it. - if (UNLIKELY(m_flags.test(StateFlags::BIT_IN_GAME_INIT) - && Read8(nds->MainRAM, playerBase + kPlayerSpawnInvincibilityOffset) != 0)) - { - m_directInvocationPending.ClearWeapon(); - return SwitchWeaponLegacyTouchFallback(weaponId); - } - const uint8_t romIdx = m_currentRom.romGroupIndex; if (m_flags.test(StateFlags::BIT_BATTLE_RUNTIME_MODE) && DirectInvocationHook_IsRomSupported(romIdx) @@ -418,16 +429,6 @@ namespace MelonPrime { if (m_enableNativeWeaponSwitch) { melonDS::NDS* const nds = emuInstance->getNDS(); - const uint32_t playerBase = - m_currentRom.playerStructStart - + static_cast(m_playerPosition) * Consts::PLAYER_ADDR_INC; - if (UNLIKELY(m_flags.test(StateFlags::BIT_IN_GAME_INIT) - && Read8(nds->MainRAM, playerBase + kPlayerSpawnInvincibilityOffset) != 0)) - { - m_weaponSwitchPending.Clear(); - return SwitchWeaponLegacyTouchFallback(weaponId); - } - const uint8_t romIdx = m_currentRom.romGroupIndex; if (WeaponSwitchHook_IsRomSupported(romIdx) && WeaponSwitchHook_IsSiteValid(nds, romIdx)) diff --git a/src/frontend/qt_sdl/MelonPrimeInGame.cpp b/src/frontend/qt_sdl/MelonPrimeInGame.cpp index 2e19c78e9d..6bcd512df3 100644 --- a/src/frontend/qt_sdl/MelonPrimeInGame.cpp +++ b/src/frontend/qt_sdl/MelonPrimeInGame.cpp @@ -6,6 +6,9 @@ #include "Screen.h" #include "MelonPrimeDef.h" #include "MelonPrimeGameRomAddrTable.h" +#ifdef MELONPRIME_DS +#include "MelonPrimePatchTouchScreenAimOnly.h" +#endif #include #include @@ -142,8 +145,20 @@ namespace MelonPrime { if (isStylusMode) m_flags.set(StateFlags::BIT_BLOCK_STYLUS); auto* nds = emuInstance->getNDS(); + // A native method must not fire while the local player is not in play + // (killed, or not yet spawned), and it does nothing at all rather than + // quietly falling through to the legacy simulation below. Only the + // legacy path itself still runs then -- that is the game reacting to + // its own simulated input. + const bool localPlayerNotInPlay = !IsLocalPlayerAlive(); + // Spawn invulnerability window: every native method defers to the + // Standard path below for its whole duration. + const bool spawnWindow = IsLocalPlayerInSpawnInvulnerability(); + #ifdef MELONPRIME_DS - if (m_enableDirectInvocationTransform) { + if (m_enableDirectInvocationTransform && !spawnWindow) { + if (localPlayerNotInPlay) + return; // "New Method 2": queue one mailbox request for the ARM9 // DirectInvocation hook. It calls the game's own transform request // from the ProcessTouchInput call site -- no synthetic touch and no @@ -158,7 +173,9 @@ namespace MelonPrime { } #endif - if (m_enableDirectAltFormTransform) { + if (m_enableDirectAltFormTransform && !spawnWindow) { + if (localPlayerNotInPlay) + return; // TransformGateHook redirects Gate A/B into the game's native // TransformRequest path. Keep a short pending window so a press is // not lost if the game reaches the transform gate a few frames late. @@ -171,6 +188,17 @@ namespace MelonPrime { // layout -- the left-handed presets put it at X 0..47 instead of // 208..255 -- so the tap has to be mapped through the preset or it only // ever lands on Touch R and Dual R. +#ifdef MELONPRIME_DS + // "Use the Whole Touch Screen for Aiming" neutralises exactly the + // hit-test this tap depends on, so with that patch active the Standard + // transform silently stops working. Opt-in: lift the patch for the tap + // and put it straight back. Same shape as the NoDoubleTapJump patch the + // legacy weapon path brackets its own touch sequence with. + const bool liftTouchAimOnly = m_suspendTouchAimOnlyForTransform; + if (UNLIKELY(liftTouchAimOnly)) + TouchScreenAimOnly_RestoreOnce(m_patchState, nds, m_currentRom.romGroupIndex); +#endif + nds->ReleaseScreen(); FrameAdvanceTwice(); using namespace Consts::UI; @@ -178,6 +206,15 @@ namespace MelonPrime { FrameAdvanceTwice(); nds->ReleaseScreen(); FrameAdvanceTwice(); + +#ifdef MELONPRIME_DS + // Re-apply through the owning module so it re-reads config and stays + // the single writer of that patch state. + if (UNLIKELY(liftTouchAimOnly)) { + TouchScreenAimOnly_ApplyOnce( + m_patchState, nds, localCfg, m_currentRom.romGroupIndex); + } +#endif } COLD_FUNCTION void MelonPrimeCore::HandleRareWeaponSwitch() diff --git a/src/frontend/qt_sdl/MelonPrimeLifecycle.cpp b/src/frontend/qt_sdl/MelonPrimeLifecycle.cpp index c53e5378ee..d128a055e8 100644 --- a/src/frontend/qt_sdl/MelonPrimeLifecycle.cpp +++ b/src/frontend/qt_sdl/MelonPrimeLifecycle.cpp @@ -69,6 +69,7 @@ namespace MelonPrime { m_moonLikeAimFastThresholdQ12 = s.moonLikeAimFastThresholdQ12; m_enableImmediateInputEdgeOverlay = s.immediateInputEdgeOverlay; m_enableDirectAltFormTransform = s.directAltFormTransform; + m_suspendTouchAimOnlyForTransform = s.touchScreenAimOnlySuspendForTransform; m_enableMorphBoostSwipe = s.morphBoostSwipeEnabled; // MELONPRIME_MORPH_BOOST_MODE_CONTROLS_V14 m_enableMorphBoostCustomRawThreshold = s.morphBoostCustomRawThreshold; if (!m_enableDirectAltFormTransform) @@ -342,6 +343,7 @@ namespace MelonPrime { m_postSavestateReconcilePending = true; m_flags.clear(StateFlags::BIT_IN_GAME_INIT); m_flags.clear(StateFlags::BIT_BATTLE_RUNTIME_MODE); + m_flags.clear(StateFlags::BIT_BATTLE_RUNTIME_SEEN); m_flags.clear(StateFlags::BIT_END_OF_GAME_PATCH_RESTORED); ResetTransientInputState( TR_AimResiduals | TR_OverlayHeld | TR_DirectTransform @@ -474,6 +476,7 @@ namespace MelonPrime { m_flags.clear(StateFlags::BIT_IN_GAME_INIT); m_flags.clear(StateFlags::BIT_END_OF_GAME_PATCH_RESTORED); m_flags.clear(StateFlags::BIT_BATTLE_RUNTIME_MODE); + m_flags.clear(StateFlags::BIT_BATTLE_RUNTIME_SEEN); } } diff --git a/src/frontend/qt_sdl/MelonPrimeLocalization/inc/MelonPrimeObjectTranslationsMethods.inc b/src/frontend/qt_sdl/MelonPrimeLocalization/inc/MelonPrimeObjectTranslationsMethods.inc index daa88924a6..665c2dd17a 100644 --- a/src/frontend/qt_sdl/MelonPrimeLocalization/inc/MelonPrimeObjectTranslationsMethods.inc +++ b/src/frontend/qt_sdl/MelonPrimeLocalization/inc/MelonPrimeObjectTranslationsMethods.inc @@ -373,4 +373,55 @@ {MenuLangId::ChineseHongKong, "新方式 3 從遊戲原本的玩家輸入處理(而非武器動作處理)呼叫同一個原生縮放設定函式,並先檢查與觸控路徑相同的條件:處於或正在變為另一形態時不縮放,且僅在裝備可縮放武器時生效。縮放音效與準星仍由遊戲處理。不能與新方式 2 同時使用。"}, {MenuLangId::Korean, "새 방식 3은 무기 액션 처리가 아니라 게임 본래의 플레이어 입력 처리에서 동일한 네이티브 줌 설정 함수를 호출하며, 터치 경로와 같은 조건을 먼저 확인합니다. 다른 형태이거나 변형 중일 때는 줌하지 않고, 줌이 가능한 무기를 장착했을 때만 동작합니다. 줌 사운드와 조준선은 게임이 처리합니다. 새 방식 2와 함께 사용할 수 없습니다."}, } + }, + { + "lblMetroidWeaponSwitchStandardDesc", + { + {MenuLangId::Japanese, "通常方式は、これまでエミュレーター側で使ってきたタッチ/メニュー模擬による武器切替です。問題が新方式によるものかどうかを切り分けたいときに選んでください。"}, + {MenuLangId::German, "Die Standardmethode ist der bisher verwendete Waffenwechsel über simulierte Touch-/Menüeingaben. Wähle sie, um die nativen Pfade als Fehlerursache auszuschließen."}, + {MenuLangId::Spanish, "El método estándar es el cambio de arma mediante la simulación de toque/menú que se ha usado siempre. Elígelo para descartar las rutas nativas como causa de un problema."}, + {MenuLangId::French, "La méthode standard est le changement d’arme par simulation tactile/menu utilisé jusqu’ici. Choisissez-la pour écarter les voies natives comme cause d’un problème."}, + {MenuLangId::Italian, "Il metodo standard è il cambio arma tramite simulazione touch/menu usato finora. Scegli questo per escludere i percorsi nativi come causa di un problema."}, + {MenuLangId::Dutch, "De standaardmethode is de wapenwissel via gesimuleerde touch-/menu-invoer die altijd is gebruikt. Kies deze om de native paden als oorzaak van een probleem uit te sluiten."}, + {MenuLangId::Portuguese, "O método padrão é a troca de arma por simulação de toque/menu que sempre foi usada. Escolha-o para descartar os caminhos nativos como causa de um problema."}, + {MenuLangId::Russian, "Стандартный метод — это смена оружия через имитацию касания/меню, которая использовалась всегда. Выберите его, чтобы исключить нативные пути как причину проблемы."}, + {MenuLangId::ChineseSimplified, "标准方式是模拟器一直使用的触控/菜单模拟武器切换。想排除新方式是否为问题原因时请选择此项。"}, + {MenuLangId::ChineseTraditional, "標準方式是模擬器一直使用的觸控/選單模擬武器切換。想排除新方式是否為問題原因時請選擇此項。"}, + {MenuLangId::ChineseHongKong, "標準方式是模擬器一直使用的觸控/選單模擬武器切換。想排除新方式是否為問題原因時請選擇此項。"}, + {MenuLangId::Korean, "기본 방식은 지금까지 사용해 온 터치/메뉴 모방 무기 변경입니다. 문제의 원인이 새 방식인지 가려내고 싶을 때 선택하세요."}, + } + }, + { + "lblMetroidTransformStandardDesc", + { + {MenuLangId::Japanese, "通常方式は、これまでエミュレーター側で使ってきたタッチ/メニュー模擬による変形です。問題が新方式によるものかどうかを切り分けたいときに選んでください。"}, + {MenuLangId::German, "Die Standardmethode ist die bisher verwendete Verwandlung über simulierte Touch-/Menüeingaben. Wähle sie, um die nativen Pfade als Fehlerursache auszuschließen."}, + {MenuLangId::Spanish, "El método estándar es la transformación mediante la simulación de toque/menú que se ha usado siempre. Elígelo para descartar las rutas nativas como causa de un problema."}, + {MenuLangId::French, "La méthode standard est la transformation par simulation tactile/menu utilisée jusqu’ici. Choisissez-la pour écarter les voies natives comme cause d’un problème."}, + {MenuLangId::Italian, "Il metodo standard è la trasformazione tramite simulazione touch/menu usata finora. Scegli questo per escludere i percorsi nativi come causa di un problema."}, + {MenuLangId::Dutch, "De standaardmethode is de transformatie via gesimuleerde touch-/menu-invoer die altijd is gebruikt. Kies deze om de native paden als oorzaak van een probleem uit te sluiten."}, + {MenuLangId::Portuguese, "O método padrão é a transformação por simulação de toque/menu que sempre foi usada. Escolha-o para descartar os caminhos nativos como causa de um problema."}, + {MenuLangId::Russian, "Стандартный метод — это превращение через имитацию касания/меню, которое использовалось всегда. Выберите его, чтобы исключить нативные пути как причину проблемы."}, + {MenuLangId::ChineseSimplified, "标准方式是模拟器一直使用的触控/菜单模拟变形。想排除新方式是否为问题原因时请选择此项。"}, + {MenuLangId::ChineseTraditional, "標準方式是模擬器一直使用的觸控/選單模擬變形。想排除新方式是否為問題原因時請選擇此項。"}, + {MenuLangId::ChineseHongKong, "標準方式是模擬器一直使用的觸控/選單模擬變形。想排除新方式是否為問題原因時請選擇此項。"}, + {MenuLangId::Korean, "기본 방식은 지금까지 사용해 온 터치/메뉴 모방 변형입니다. 문제의 원인이 새 방식인지 가려내고 싶을 때 선택하세요."}, + } + }, + { + "lblMetroidZoomStandardDesc", + { + {MenuLangId::Japanese, "通常方式は、プレイヤーの操作プリセットが割り当てているズームボタンを押します。問題が新方式によるものかどうかを切り分けたいときに選んでください。"}, + {MenuLangId::German, "Die Standardmethode drückt die Zoom-Taste, die das Steuerungs-Preset des Spielers belegt. Wähle sie, um die nativen Pfade als Fehlerursache auszuschließen."}, + {MenuLangId::Spanish, "El método estándar pulsa el botón de zoom que asigna el ajuste de control del jugador. Elígelo para descartar las rutas nativas como causa de un problema."}, + {MenuLangId::French, "La méthode standard appuie sur la touche de zoom attribuée par le préréglage de commandes du joueur. Choisissez-la pour écarter les voies natives comme cause d’un problème."}, + {MenuLangId::Italian, "Il metodo standard preme il pulsante di zoom assegnato dal preset dei comandi del giocatore. Scegli questo per escludere i percorsi nativi come causa di un problema."}, + {MenuLangId::Dutch, "De standaardmethode drukt op de zoomknop die de besturingsinstelling van de speler toewijst. Kies deze om de native paden als oorzaak van een probleem uit te sluiten."}, + {MenuLangId::Portuguese, "O método padrão pressiona o botão de zoom atribuído pela predefinição de controlos do jogador. Escolha-o para descartar os caminhos nativos como causa de um problema."}, + {MenuLangId::Russian, "Стандартный метод нажимает кнопку зума, назначенную схемой управления игрока. Выберите его, чтобы исключить нативные пути как причину проблемы."}, + {MenuLangId::ChineseSimplified, "标准方式会按下玩家操作预设所分配的缩放按键。想排除新方式是否为问题原因时请选择此项。"}, + {MenuLangId::ChineseTraditional, "標準方式會按下玩家操作預設所分配的縮放按鍵。想排除新方式是否為問題原因時請選擇此項。"}, + {MenuLangId::ChineseHongKong, "標準方式會按下玩家操作預設所分配的縮放按鍵。想排除新方式是否為問題原因時請選擇此項。"}, + {MenuLangId::Korean, "기본 방식은 플레이어의 조작 프리셋이 할당한 확대 버튼을 누릅니다. 문제의 원인이 새 방식인지 가려내고 싶을 때 선택하세요."}, + } } diff --git a/src/frontend/qt_sdl/MelonPrimeLocalization/inc/MelonPrimeTranslationsDeveloper.inc b/src/frontend/qt_sdl/MelonPrimeLocalization/inc/MelonPrimeTranslationsDeveloper.inc index 2570555160..c2d0435a9b 100644 --- a/src/frontend/qt_sdl/MelonPrimeLocalization/inc/MelonPrimeTranslationsDeveloper.inc +++ b/src/frontend/qt_sdl/MelonPrimeLocalization/inc/MelonPrimeTranslationsDeveloper.inc @@ -80,6 +80,87 @@ {MenuLangId::Hebrew, "השתמש בשיטה החדשה להחלפת נשק"}, } }, + { + "Use Standard Method for Weapon Change", + { + {MenuLangId::Japanese, "武器変更に通常方式を使う"}, + {MenuLangId::German, "Standardmethode für Waffenwechsel verwenden"}, + {MenuLangId::Spanish, "Usar método estándar para cambio de arma"}, + {MenuLangId::French, "Utiliser la méthode standard pour le changement d'arme"}, + {MenuLangId::Italian, "Usa il metodo standard per cambiare arma"}, + {MenuLangId::Dutch, "Standaardmethode voor wapenwissel gebruiken"}, + {MenuLangId::Portuguese, "Usar método padrão para troca de arma"}, + {MenuLangId::Russian, "Использовать стандартный метод смены оружия"}, + {MenuLangId::ChineseSimplified, "使用标准方式切换武器"}, + {MenuLangId::ChineseTraditional, "使用標準方式切換武器"}, + {MenuLangId::ChineseHongKong, "使用標準方式切換武器"}, + {MenuLangId::Korean, "무기 변경에 기본 방식 사용"}, + {MenuLangId::Arabic, "استخدام الطريقة القياسية لتغيير السلاح"}, + {MenuLangId::Indonesian, "Gunakan metode standar untuk ganti senjata"}, + {MenuLangId::Ukrainian, "Використовувати стандартний метод зміни зброї"}, + {MenuLangId::Greek, "Χρήση τυπικής μεθόδου αλλαγής όπλου"}, + {MenuLangId::Swedish, "Använd standardmetod för vapenbyte"}, + {MenuLangId::Thai, "ใช้วิธีมาตรฐานสำหรับเปลี่ยนอาวุธ"}, + {MenuLangId::Czech, "Použít standardní metodu změny zbraně"}, + {MenuLangId::Danish, "Brug standardmetode til våbenskift"}, + {MenuLangId::Turkish, "Silah değişimi için standart yöntemi kullan"}, + {MenuLangId::Norwegian, "Bruk standardmetode for våpenbytte"}, + {MenuLangId::Hungarian, "Szabványos módszer használata fegyverváltáshoz"}, + {MenuLangId::Finnish, "Käytä vakiomenetelmää aseenvaihtoon"}, + {MenuLangId::Vietnamese, "Dùng phương pháp tiêu chuẩn để đổi vũ khí"}, + {MenuLangId::Polish, "Użyj standardowej metody zmiany broni"}, + {MenuLangId::Romanian, "Folosește metoda standard pentru schimbarea armei"}, + {MenuLangId::Filipino, "Gamitin ang karaniwang paraan sa pagpapalit ng sandata"}, + {MenuLangId::Swahili, "Tumia mbinu ya kawaida ya kubadilisha silaha"}, + {MenuLangId::Croatian, "Koristi standardnu metodu za promjenu oružja"}, + {MenuLangId::Icelandic, "Nota staðlaða aðferð fyrir vopnaskipti"}, + {MenuLangId::Hindi, "हथियार बदलने के लिए मानक विधि का उपयोग करें"}, + {MenuLangId::Bengali, "অস্ত্র পরিবর্তনের জন্য আদর্শ পদ্ধতি ব্যবহার করুন"}, + {MenuLangId::Urdu, "ہتھیار بدلنے کے لیے معیاری طریقہ استعمال کریں"}, + {MenuLangId::Punjabi, "ਹਥਿਆਰ ਬਦਲਣ ਲਈ ਮਿਆਰੀ ਤਰੀਕਾ ਵਰਤੋ"}, + {MenuLangId::Telugu, "ఆయుధం మార్చడానికి ప్రామాణిక విధానాన్ని వాడు"}, + {MenuLangId::Persian, "برای تغییر سلاح از روش استاندارد استفاده کن"}, + {MenuLangId::Malay, "Gunakan kaedah standard untuk tukar senjata"}, + {MenuLangId::Marathi, "शस्त्र बदलण्यासाठी मानक पद्धत वापरा"}, + {MenuLangId::Tamil, "ஆயுதம் மாற்ற நிலையான முறையைப் பயன்படுத்து"}, + {MenuLangId::Gujarati, "હથિયાર બદલવા માટે પ્રમાણભૂત પદ્ધતિ વાપરો"}, + {MenuLangId::Kannada, "ಆಯುಧ ಬದಲಿಸಲು ಪ್ರಮಾಣಿತ ವಿಧಾನ ಬಳಸಿ"}, + {MenuLangId::Odia, "ଅସ୍ତ୍ର ପରିବର୍ତ୍ତନ ପାଇଁ ମାନକ ପଦ୍ଧତି ବ୍ୟବହାର କରନ୍ତୁ"}, + {MenuLangId::Malayalam, "ആയുധം മാറ്റാൻ സ്റ്റാൻഡേർഡ് രീതി ഉപയോഗിക്കുക"}, + {MenuLangId::Burmese, "လက်နက်ပြောင်းရန် စံနည်းလမ်းကို သုံးပါ"}, + {MenuLangId::Uzbek, "Qurol almashtirish uchun standart usuldan foydalanish"}, + {MenuLangId::Azerbaijani, "Silah dəyişmək üçün standart üsuldan istifadə et"}, + {MenuLangId::Nepali, "हतियार परिवर्तनका लागि मानक विधि प्रयोग गर्नुहोस्"}, + {MenuLangId::Sinhala, "අවි මාරු කිරීමට සම්මත ක්‍රමය භාවිතා කරන්න"}, + {MenuLangId::Khmer, "ប្រើវិធីស្តង់ដារសម្រាប់ប្តូរអាវុធ"}, + {MenuLangId::Lao, "ໃຊ້ວິທີມາດຕະຖານສຳລັບປ່ຽນອາວຸດ"}, + {MenuLangId::Armenian, "Օգտագործել ստանդարտ մեթոդ զենքը փոխելու համար"}, + {MenuLangId::Albanian, "Përdor metodën standarde për ndërrimin e armës"}, + {MenuLangId::Georgian, "იარაღის შეცვლისთვის გამოიყენე სტანდარტული მეთოდი"}, + {MenuLangId::Bosnian, "Koristi standardnu metodu za promjenu oružja"}, + {MenuLangId::Serbian, "Користи стандардни метод за промену оружја"}, + {MenuLangId::Macedonian, "Користи стандарден метод за промена на оружје"}, + {MenuLangId::Bulgarian, "Използвай стандартен метод за смяна на оръжие"}, + {MenuLangId::Belarusian, "Выкарыстоўваць стандартны метад для змены зброі"}, + {MenuLangId::Maltese, "Uża metodu standard biex tbiddel l-arma"}, + {MenuLangId::Mongolian, "Зэвсэг солиход стандарт аргыг ашиглах"}, + {MenuLangId::Latvian, "Izmantot standarta metodi ieroča maiņai"}, + {MenuLangId::Lithuanian, "Naudoti standartinį būdą ginklui keisti"}, + {MenuLangId::Afrikaans, "Gebruik standaardmetode om wapen te wissel"}, + {MenuLangId::Irish, "Úsáid modh caighdeánach chun arm a athrú"}, + {MenuLangId::Assamese, "অস্ত্ৰ সলনি কৰিবলৈ মানক পদ্ধতি ব্যৱহাৰ কৰক"}, + {MenuLangId::Amharic, "መሣሪያ ለመቀየር መደበኛውን ዘዴ ተጠቀም"}, + {MenuLangId::Estonian, "Kasuta relva vahetamiseks standardmeetodit"}, + {MenuLangId::Kazakh, "Қаруды ауыстыру үшін стандартты әдісті қолдану"}, + {MenuLangId::Catalan, "Utilitza el mètode estàndard per canviar d arma"}, + {MenuLangId::Kyrgyz, "Курал алмаштыруу үчүн стандарттык ыкманы колдонуу"}, + {MenuLangId::Slovak, "Použiť štandardnú metódu na zmenu zbrane"}, + {MenuLangId::Slovenian, "Uporabi standardno metodo za menjavo orožja"}, + {MenuLangId::Zulu, "Sebenzisa indlela evamile yokushintsha isikhali"}, + {MenuLangId::Basque, "Erabili metodo estandarra arma aldatzeko"}, + {MenuLangId::Hebrew, "השתמש בשיטה הרגילה להחלפת נשק"}, + } + }, { "Use New Method 2 for Weapon Change", { @@ -323,6 +404,87 @@ {MenuLangId::Hebrew, "השתמש בשיטה החדשה למעבר לצורה חלופית"}, } }, + { + "Use Standard Method for Alt-Form Transform", + { + {MenuLangId::Japanese, "別形態への変形に通常方式を使う"}, + {MenuLangId::German, "Standardmethode für Alt-Form-Transformation verwenden"}, + {MenuLangId::Spanish, "Usar el método estándar para la forma alternativa"}, + {MenuLangId::French, "Utiliser la méthode standard pour la forme alternative"}, + {MenuLangId::Italian, "Usa il metodo standard per la forma alternativa"}, + {MenuLangId::Dutch, "Standaardmethode voor Alt-Form-transformatie gebruiken"}, + {MenuLangId::Portuguese, "Usar método padrão para transformação Alt-Form"}, + {MenuLangId::Russian, "Использовать стандартный метод преобразования Alt-Form"}, + {MenuLangId::ChineseSimplified, "Alt-Form 变形使用标准方法"}, + {MenuLangId::ChineseTraditional, "Alt-Form 變形使用標準方法"}, + {MenuLangId::ChineseHongKong, "Alt-Form 變形使用標準方法"}, + {MenuLangId::Korean, "Alt-Form 변형에 기본 방식 사용"}, + {MenuLangId::Arabic, "استخدام الطريقة القياسية لتحويل Alt-Form"}, + {MenuLangId::Indonesian, "Gunakan Metode Standar untuk Transformasi Alt-Form"}, + {MenuLangId::Ukrainian, "Використовувати стандартний метод перетворення Alt-Form"}, + {MenuLangId::Greek, "Χρήση τυπικής μεθόδου για Alt-Form Transform"}, + {MenuLangId::Swedish, "Använd standardmetod för Alt-Form-transform"}, + {MenuLangId::Thai, "ใช้วิธีมาตรฐานสำหรับ Alt-Form Transform"}, + {MenuLangId::Czech, "Použít standardní metodu pro Alt-Form transformaci"}, + {MenuLangId::Danish, "Brug standardmetode til Alt-Form-transform"}, + {MenuLangId::Turkish, "Alt-Form Dönüşümü için standart yöntemi kullan"}, + {MenuLangId::Norwegian, "Bruk standardmetode for Alt-Form-transform"}, + {MenuLangId::Hungarian, "Szabványos módszer használata Alt-Form átalakításhoz"}, + {MenuLangId::Finnish, "Käytä vakiomenetelmää Alt-Form-muunnokseen"}, + {MenuLangId::Vietnamese, "Dùng phương pháp tiêu chuẩn cho Biến đổi Alt-Form"}, + {MenuLangId::Polish, "Użyj standardowej metody transformacji Alt-Form"}, + {MenuLangId::Romanian, "Folosește metoda standard pentru transformarea Alt-Form"}, + {MenuLangId::Filipino, "Gamitin ang karaniwang paraan sa pagbabago ng ibang anyo"}, + {MenuLangId::Swahili, "Tumia mbinu ya kawaida ya kubadilisha umbo mbadala"}, + {MenuLangId::Croatian, "Koristi standardnu metodu za pretvorbu u alternativni oblik"}, + {MenuLangId::Icelandic, "Nota staðlaða aðferð fyrir umbreytingu í aðra mynd"}, + {MenuLangId::Hindi, "वैकल्पिक रूप में बदलने के लिए मानक विधि का उपयोग करें"}, + {MenuLangId::Bengali, "বিকল্প রূপে পরিবর্তনের জন্য আদর্শ পদ্ধতি ব্যবহার করুন"}, + {MenuLangId::Urdu, "متبادل شکل میں بدلنے کے لیے معیاری طریقہ استعمال کریں"}, + {MenuLangId::Punjabi, "ਵਿਕਲਪਿਕ ਰੂਪ ਵਿੱਚ ਬਦਲਣ ਲਈ ਮਿਆਰੀ ਤਰੀਕਾ ਵਰਤੋ"}, + {MenuLangId::Telugu, "ప్రత్యామ్నాయ రూపంలోకి మారేందుకు ప్రామాణిక విధానాన్ని వాడు"}, + {MenuLangId::Persian, "برای تبدیل به شکل جایگزین از روش استاندارد استفاده کن"}, + {MenuLangId::Malay, "Gunakan kaedah standard untuk berubah ke bentuk alternatif"}, + {MenuLangId::Marathi, "पर्यायी रूपात बदलण्यासाठी मानक पद्धत वापरा"}, + {MenuLangId::Tamil, "மாற்று வடிவமாக மாற நிலையான முறையைப் பயன்படுத்து"}, + {MenuLangId::Gujarati, "વૈકલ્પિક રૂપમાં બદલવા માટે પ્રમાણભૂત પદ્ધતિ વાપરો"}, + {MenuLangId::Kannada, "ಪರ್ಯಾಯ ರೂಪಕ್ಕೆ ಬದಲಿಸಲು ಪ್ರಮಾಣಿತ ವಿಧಾನ ಬಳಸಿ"}, + {MenuLangId::Odia, "ବିକଳ୍ପ ରୂପକୁ ବଦଳିବା ପାଇଁ ମାନକ ପଦ୍ଧତି ବ୍ୟବହାର କରନ୍ତୁ"}, + {MenuLangId::Malayalam, "മാറ്റു രൂപത്തിലേക്ക് മാറാൻ സ്റ്റാൻഡേർഡ് രീതി ഉപയോഗിക്കുക"}, + {MenuLangId::Burmese, "အခြားပုံစံသို့ ပြောင်းရန် စံနည်းလမ်းကို သုံးပါ"}, + {MenuLangId::Uzbek, "Muqobil shaklga o‘tish uchun standart usuldan foydalanish"}, + {MenuLangId::Azerbaijani, "Alternativ formaya çevrilmək üçün standart üsuldan istifadə et"}, + {MenuLangId::Nepali, "वैकल्पिक रूपमा परिवर्तन गर्न मानक विधि प्रयोग गर्नुहोस्"}, + {MenuLangId::Sinhala, "විකල්ප ස්වරූපයට මාරුවීමට සම්මත ක්‍රමය භාවිතා කරන්න"}, + {MenuLangId::Khmer, "ប្រើវិធីស្តង់ដារសម្រាប់បម្លែងទៅទម្រង់ជំនួស"}, + {MenuLangId::Lao, "ໃຊ້ວິທີມາດຕະຖານສຳລັບປ່ຽນເປັນຮ່າງທາງເລືອກ"}, + {MenuLangId::Armenian, "Օգտագործել ստանդարտ մեթոդ այլընտրանքային ձևի փոխակերպման համար"}, + {MenuLangId::Albanian, "Përdor metodën standarde për kalimin në formën alternative"}, + {MenuLangId::Georgian, "ალტერნატიულ ფორმად გარდაქმნისთვის გამოიყენე სტანდარტული მეთოდი"}, + {MenuLangId::Bosnian, "Koristi standardnu metodu za pretvaranje u alternativni oblik"}, + {MenuLangId::Serbian, "Користи стандардни метод за претварање у алтернативни облик"}, + {MenuLangId::Macedonian, "Користи стандарден метод за претворање во алтернативна форма"}, + {MenuLangId::Bulgarian, "Използвай стандартен метод за преобразуване в алтернативна форма"}, + {MenuLangId::Belarusian, "Выкарыстоўваць стандартны метад для ператварэння ў альтэрнатыўную форму"}, + {MenuLangId::Maltese, "Uża metodu standard biex tinbidel għal forma alternattiva"}, + {MenuLangId::Mongolian, "Өөр хэлбэрт хувирахад стандарт аргыг ашиглах"}, + {MenuLangId::Latvian, "Izmantot standarta metodi pārvēršanai alternatīvajā formā"}, + {MenuLangId::Lithuanian, "Naudoti standartinį būdą virsti alternatyvia forma"}, + {MenuLangId::Afrikaans, "Gebruik standaardmetode om na alternatiewe vorm te verander"}, + {MenuLangId::Irish, "Úsáid modh caighdeánach chun athrú go foirm mhalartach"}, + {MenuLangId::Assamese, "বিকল্প ৰূপলৈ সলনি কৰিবলৈ মানক পদ্ধতি ব্যৱহাৰ কৰক"}, + {MenuLangId::Amharic, "ወደ አማራጭ ቅርጽ ለመቀየር መደበኛውን ዘዴ ተጠቀም"}, + {MenuLangId::Estonian, "Kasuta alternatiivvormiks muutumiseks standardmeetodit"}, + {MenuLangId::Kazakh, "Баламалы түрге ауысу үшін стандартты әдісті қолдану"}, + {MenuLangId::Catalan, "Utilitza el mètode estàndard per transformar-se en forma alternativa"}, + {MenuLangId::Kyrgyz, "Альтернативдүү формага өтүү үчүн стандарттык ыкманы колдонуу"}, + {MenuLangId::Slovak, "Použiť štandardnú metódu na premenu do alternatívnej formy"}, + {MenuLangId::Slovenian, "Uporabi standardno metodo za preobrazbo v alternativno obliko"}, + {MenuLangId::Zulu, "Sebenzisa indlela evamile yokuguquka ube yifomu elihlukile"}, + {MenuLangId::Basque, "Erabili metodo estandarra forma alternatibora bihurtzeko"}, + {MenuLangId::Hebrew, "השתמש בשיטה הרגילה למעבר לצורה חלופית"}, + } + }, { "Use New Method 2 for Alt-Form Transform", { @@ -566,6 +728,87 @@ {MenuLangId::Hebrew, "השתמש בשיטה החדשה 2 לזום"}, } }, + { + "Use Standard Method for Zoom", + { + {MenuLangId::Japanese, "ズームに通常方式を使う"}, + {MenuLangId::German, "Standardmethode für Zoom verwenden"}, + {MenuLangId::Spanish, "Usar método estándar para el zoom"}, + {MenuLangId::French, "Utiliser la méthode standard pour le zoom"}, + {MenuLangId::Italian, "Usa il metodo standard per lo zoom"}, + {MenuLangId::Dutch, "Standaardmethode voor zoom gebruiken"}, + {MenuLangId::Portuguese, "Usar método padrão para zoom"}, + {MenuLangId::Russian, "Использовать стандартный метод для зума"}, + {MenuLangId::ChineseSimplified, "缩放使用标准方法"}, + {MenuLangId::ChineseTraditional, "縮放使用標準方法"}, + {MenuLangId::ChineseHongKong, "縮放使用標準方法"}, + {MenuLangId::Korean, "확대에 기본 방식 사용"}, + {MenuLangId::Arabic, "استخدام الطريقة القياسية للتكبير"}, + {MenuLangId::Indonesian, "Gunakan Metode Standar untuk zoom"}, + {MenuLangId::Ukrainian, "Використовувати стандартний метод для зуму"}, + {MenuLangId::Greek, "Χρήση τυπικής μεθόδου για ζουμ"}, + {MenuLangId::Swedish, "Använd standardmetod för zoom"}, + {MenuLangId::Thai, "ใช้วิธีมาตรฐาน สำหรับซูม"}, + {MenuLangId::Czech, "Použít standardní metodu pro zoom"}, + {MenuLangId::Danish, "Brug standardmetode til zoom"}, + {MenuLangId::Turkish, "Zoom için Standart Yöntemi kullan"}, + {MenuLangId::Norwegian, "Bruk standardmetode for zoom"}, + {MenuLangId::Hungarian, "Szabványos módszer használata zoomhoz"}, + {MenuLangId::Finnish, "Käytä vakiomenetelmää zoomiin"}, + {MenuLangId::Vietnamese, "Dùng Phương pháp tiêu chuẩn cho zoom"}, + {MenuLangId::Polish, "Użyj standardowej metody do zoomu"}, + {MenuLangId::Romanian, "Folosește metoda standard pentru zoom"}, + {MenuLangId::Filipino, "Gamitin ang karaniwang paraan sa pag-zoom"}, + {MenuLangId::Swahili, "Tumia mbinu ya kawaida ya ya kukuza"}, + {MenuLangId::Croatian, "Koristi standardnu metodu za zumiranje"}, + {MenuLangId::Icelandic, "Nota staðlaða aðferð fyrir aðdrátt"}, + {MenuLangId::Hindi, "ज़ूम के लिए मानक विधि का उपयोग करें"}, + {MenuLangId::Bengali, "জুমের জন্য আদর্শ পদ্ধতি ব্যবহার করুন"}, + {MenuLangId::Urdu, "زوم کے لیے معیاری طریقہ استعمال کریں"}, + {MenuLangId::Punjabi, "ਜ਼ੂਮ ਲਈ ਮਿਆਰੀ ਤਰੀਕਾ ਵਰਤੋ"}, + {MenuLangId::Telugu, "జూమ్ కోసం ప్రామాణిక విధానాన్ని వాడు"}, + {MenuLangId::Persian, "برای زوم از روش استاندارد استفاده کن"}, + {MenuLangId::Malay, "Gunakan kaedah standard untuk zum"}, + {MenuLangId::Marathi, "झूमसाठी मानक पद्धत वापरा"}, + {MenuLangId::Tamil, "ஜூமிற்கு நிலையான முறையைப் பயன்படுத்து"}, + {MenuLangId::Gujarati, "ઝૂમ માટે પ્રમાણભૂત પદ્ધતિ વાપરો"}, + {MenuLangId::Kannada, "ಜೂಮ್ ಮಾಡಲು ಪ್ರಮಾಣಿತ ವಿಧಾನ ಬಳಸಿ"}, + {MenuLangId::Odia, "ଜୁମ୍ ପାଇଁ ମାନକ ପଦ୍ଧତି ବ୍ୟବହାର କରନ୍ତୁ"}, + {MenuLangId::Malayalam, "സൂം ചെയ്യാൻ സ്റ്റാൻഡേർഡ് രീതി ഉപയോഗിക്കുക"}, + {MenuLangId::Burmese, "ဇူးမ်အတွက် စံနည်းလမ်းကို သုံးပါ"}, + {MenuLangId::Uzbek, "Masshtablash uchun standart usuldan foydalanish"}, + {MenuLangId::Azerbaijani, "Yaxınlaşdırma üçün standart üsuldan istifadə et"}, + {MenuLangId::Nepali, "जुमका लागि मानक विधि प्रयोग गर्नुहोस्"}, + {MenuLangId::Sinhala, "සූම් සඳහා සම්මත ක්‍රමය භාවිතා කරන්න"}, + {MenuLangId::Khmer, "ប្រើវិធីស្តង់ដារ សម្រាប់ពង្រីក"}, + {MenuLangId::Lao, "ໃຊ້ວິທີມາດຕະຖານ ສຳລັບຊູມ"}, + {MenuLangId::Armenian, "Օգտագործել ստանդարտ մեթոդ մեծացման համար"}, + {MenuLangId::Albanian, "Përdor metodën standarde për zmadhim"}, + {MenuLangId::Georgian, "გადიდებისთვის გამოიყენე სტანდარტული მეთოდი"}, + {MenuLangId::Bosnian, "Koristi standardnu metodu za zumiranje"}, + {MenuLangId::Serbian, "Користи стандардни метод за зумирање"}, + {MenuLangId::Macedonian, "Користи стандарден метод за зумирање"}, + {MenuLangId::Bulgarian, "Използвай стандартен метод за мащабиране"}, + {MenuLangId::Belarusian, "Выкарыстоўваць стандартны метад для маштабавання"}, + {MenuLangId::Maltese, "Uża metodu standard għaż-żum"}, + {MenuLangId::Mongolian, "Томруулахад стандарт аргыг ашиглах"}, + {MenuLangId::Latvian, "Izmantot standarta metodi tālummaiņai"}, + {MenuLangId::Lithuanian, "Naudoti standartinį būdą priartinimui"}, + {MenuLangId::Afrikaans, "Gebruik standaardmetode vir inzoem"}, + {MenuLangId::Irish, "Úsáid modh caighdeánach don zúmáil"}, + {MenuLangId::Assamese, "জুমৰ বাবে মানক পদ্ধতি ব্যৱহাৰ কৰক"}, + {MenuLangId::Amharic, "ለማጉላት መደበኛውን ዘዴ ተጠቀም"}, + {MenuLangId::Estonian, "Kasuta suumimiseks standardmeetodit"}, + {MenuLangId::Kazakh, "Масштабтау үшін стандартты әдісті қолдану"}, + {MenuLangId::Catalan, "Utilitza el mètode estàndard per al zoom"}, + {MenuLangId::Kyrgyz, "Чоңойтуу үчүн стандарттык ыкманы колдонуу"}, + {MenuLangId::Slovak, "Použiť štandardnú metódu na priblíženie"}, + {MenuLangId::Slovenian, "Uporabi standardno metodo za približanje"}, + {MenuLangId::Zulu, "Sebenzisa indlela evamile yokusondeza"}, + {MenuLangId::Basque, "Erabili metodo estandarra zoomerako"}, + {MenuLangId::Hebrew, "השתמש בשיטה הרגילה לזום"}, + } + }, { "Use New Method 3 for Zoom", { diff --git a/src/frontend/qt_sdl/MelonPrimeLocalization/inc/MelonPrimeTranslationsMetroidGameplay.inc b/src/frontend/qt_sdl/MelonPrimeLocalization/inc/MelonPrimeTranslationsMetroidGameplay.inc index 3bee7470ed..191253b81c 100644 --- a/src/frontend/qt_sdl/MelonPrimeLocalization/inc/MelonPrimeTranslationsMetroidGameplay.inc +++ b/src/frontend/qt_sdl/MelonPrimeLocalization/inc/MelonPrimeTranslationsMetroidGameplay.inc @@ -1377,84 +1377,101 @@ } }, { - "Use the Whole Touch Screen for Aiming (Disables the touch-screen HUD buttons: Morph Ball, weapon quick slots and the weapon menu. Double-tap jump and the touch boost gesture still work)", + "Use the Whole Touch Screen for Aiming (Disables the touch-screen HUD buttons: Transform, weapon quick slots and the weapon menu. Double-tap jump and the touch boost gesture still work)", { - {MenuLangId::Japanese, "タッチスクリーン全体をエイムに使う (下画面のHUDボタン (モーフボール、武器クイックスロット、武器メニュー) を無効化します。ダブルタップジャンプとタッチのブーストは引き続き使えます)"}, - {MenuLangId::German, "Gesamten Touchscreen zum Zielen verwenden (Deaktiviert die HUD-Schaltflächen auf dem Touchscreen: Morph-Ball, Waffen-Schnellwahl und Waffenmenü. Doppeltipp-Sprung und die BOOST-Wischgeste funktionieren weiterhin)"}, - {MenuLangId::Spanish, "Usar toda la pantalla táctil para apuntar (Desactiva los botones del HUD de la pantalla táctil: MORFOSFERA, accesos rápidos de armas y menú de armas. El salto con doble toque y el gesto de TURBO táctil siguen funcionando)"}, - {MenuLangId::French, "Utiliser tout l’écran tactile pour viser (Désactive les boutons de l’ATH sur l’écran tactile : BOULE MORPHING, raccourcis d’armes et menu des armes. Le saut par double tape et le geste de BOOST tactile restent disponibles)"}, - {MenuLangId::Italian, "Usa tutto lo schermo tattile per mirare (Disattiva i pulsanti dell’HUD sullo schermo tattile: MORFOSFERA, slot rapidi delle armi e menu delle armi. Il salto con doppio tocco e il gesto di TURBO tattile continuano a funzionare)"}, - {MenuLangId::Dutch, "Het hele aanraakscherm gebruiken om te richten (Schakelt de HUD-knoppen op het aanraakscherm uit: Morph Ball, wapensnelvakken en het wapenmenu. Springen met dubbele tik en het boostgebaar blijven werken)"}, - {MenuLangId::Portuguese, "Usar todo o ecrã tátil para apontar (Desativa os botões do HUD no ecrã tátil: Morph Ball, atalhos de armas e menu de armas. O salto com toque duplo e o gesto de boost tátil continuam a funcionar)"}, - {MenuLangId::Russian, "Использовать весь сенсорный экран для прицеливания (Отключает кнопки HUD на сенсорном экране: Морфошар, быстрые слоты оружия и меню оружия. Прыжок двойным касанием и жест ускорения продолжают работать)"}, - {MenuLangId::ChineseSimplified, "使用整个触摸屏进行瞄准 (禁用触摸屏上的 HUD 按钮:变球、武器快捷槽和武器菜单。双击跳跃和触摸加速手势仍然可用)"}, - {MenuLangId::ChineseTraditional, "使用整個觸控螢幕進行瞄準 (停用觸控螢幕上的 HUD 按鈕:變球、武器快捷槽與武器選單。雙擊跳躍與觸控加速手勢仍可使用)"}, - {MenuLangId::ChineseHongKong, "使用整個觸控螢幕進行瞄準 (停用觸控螢幕上的 HUD 按鈕:變球、武器快捷槽與武器選單。雙擊跳躍與觸控加速手勢仍可使用)"}, - {MenuLangId::Korean, "터치스크린 전체를 조준에 사용 (터치스크린의 HUD 버튼을 비활성화합니다: 모프볼, 무기 퀵 슬롯, 무기 메뉴. 더블 탭 점프와 터치 부스트 제스처는 그대로 작동합니다)"}, - {MenuLangId::Arabic, "استخدام شاشة اللمس بالكامل للتصويب (يعطّل أزرار واجهة العرض على شاشة اللمس: Morph Ball وفتحات الأسلحة السريعة وقائمة الأسلحة. تظل القفزة بنقرتين وإيماءة الاندفاع باللمس تعملان)"}, - {MenuLangId::Indonesian, "Gunakan seluruh layar sentuh untuk membidik (Menonaktifkan tombol HUD di layar sentuh: Morph Ball, slot cepat senjata, dan menu senjata. Lompatan ketuk ganda dan gerakan boost sentuh tetap berfungsi)"}, - {MenuLangId::Ukrainian, "Використовувати весь сенсорний екран для прицілювання (Вимикає кнопки HUD на сенсорному екрані: Морфокуля, швидкі слоти зброї та меню зброї. Стрибок подвійним дотиком і жест прискорення продовжують працювати)"}, - {MenuLangId::Greek, "Χρήση ολόκληρης της οθόνης αφής για σκόπευση (Απενεργοποιεί τα κουμπιά HUD στην οθόνη αφής: Morph Ball, γρήγορες θέσεις όπλων και μενού όπλων. Το άλμα με διπλό χτύπημα και η χειρονομία boost εξακολουθούν να λειτουργούν)"}, - {MenuLangId::Swedish, "Använd hela pekskärmen för att sikta (Inaktiverar HUD-knapparna på pekskärmen: Morph Ball, vapensnabbplatser och vapenmenyn. Hopp med dubbeltryck och boostgesten fungerar fortfarande)"}, - {MenuLangId::Thai, "ใช้หน้าจอสัมผัสทั้งหมดในการเล็ง (ปิดใช้งานปุ่ม HUD บนหน้าจอสัมผัส: Morph Ball ช่องอาวุธด่วน และเมนูอาวุธ การกระโดดด้วยการแตะสองครั้งและท่าทางบูสต์แบบสัมผัสยังใช้งานได้)"}, - {MenuLangId::Czech, "Použít celou dotykovou obrazovku k míření (Vypne tlačítka HUD na dotykové obrazovce: Morph Ball, rychlé sloty zbraní a nabídku zbraní. Skok dvojitým klepnutím a dotykové gesto boostu fungují dál)"}, - {MenuLangId::Danish, "Brug hele berøringsskærmen til at sigte (Deaktiverer HUD-knapperne på berøringsskærmen: Morph Ball, hurtigpladser til våben og våbenmenuen. Hop med dobbelttryk og boost-bevægelsen virker fortsat)"}, - {MenuLangId::Turkish, "Nişan almak için tüm dokunmatik ekranı kullan (Dokunmatik ekrandaki HUD düğmelerini devre dışı bırakır: Morph Ball, silah hızlı yuvaları ve silah menüsü. Çift dokunuşla zıplama ve dokunmatik boost hareketi çalışmaya devam eder)"}, - {MenuLangId::Norwegian, "Bruk hele berøringsskjermen til å sikte (Deaktiverer HUD-knappene på berøringsskjermen: Morph Ball, hurtigplasser for våpen og våpenmenyen. Hopp med dobbelttrykk og boost-bevegelsen fungerer fortsatt)"}, - {MenuLangId::Hungarian, "A teljes érintőképernyő használata célzáshoz (Letiltja az érintőképernyő HUD-gombjait: Morph Ball, fegyver-gyorshelyek és fegyvermenü. A dupla koppintásos ugrás és az érintéses boost mozdulat továbbra is működik)"}, - {MenuLangId::Finnish, "Käytä koko kosketusnäyttöä tähtäämiseen (Poistaa käytöstä kosketusnäytön HUD-painikkeet: Morph Ball, aseiden pikapaikat ja asevalikko. Kaksoisnapautushyppy ja kosketusboost-ele toimivat edelleen)"}, - {MenuLangId::Vietnamese, "Dùng toàn bộ màn hình cảm ứng để ngắm bắn (Tắt các nút HUD trên màn hình cảm ứng: Morph Ball, ô vũ khí nhanh và menu vũ khí. Nhảy bằng chạm hai lần và thao tác tăng tốc bằng cảm ứng vẫn hoạt động)"}, - {MenuLangId::Polish, "Używaj całego ekranu dotykowego do celowania (Wyłącza przyciski HUD na ekranie dotykowym: Morph Ball, szybkie sloty broni i menu broni. Skok podwójnym dotknięciem oraz gest przyspieszenia nadal działają)"}, - {MenuLangId::Romanian, "Folosește tot ecranul tactil pentru ochire (Dezactivează butoanele HUD de pe ecranul tactil: Morph Ball, sloturile rapide de arme și meniul de arme. Saltul prin dublă atingere și gestul de boost tactil funcționează în continuare)"}, - {MenuLangId::Filipino, "Gamitin ang buong touch screen para sa pagpuntirya (Hindi na gagana ang mga HUD button sa touch screen: Morph Ball, mga quick slot ng armas, at menu ng armas. Gumagana pa rin ang double-tap jump at ang touch boost gesture)"}, - {MenuLangId::Swahili, "Tumia skrini nzima ya kugusa kulenga (Huzima vitufe vya HUD kwenye skrini ya kugusa: Morph Ball, nafasi za haraka za silaha na menyu ya silaha. Kuruka kwa kugusa mara mbili na ishara ya boost bado hufanya kazi)"}, - {MenuLangId::Croatian, "Koristi cijeli zaslon osjetljiv na dodir za ciljanje (Onemogućuje HUD gumbe na dodirnom zaslonu: Morph Ball, brze utore za oružje i izbornik oružja. Skok dvostrukim dodirom i gesta ubrzanja i dalje rade)"}, - {MenuLangId::Icelandic, "Nota allan snertiskjáinn til að miða (Slekkur á HUD-hnöppunum á snertiskjánum: Morph Ball, flýtihólf vopna og vopnavalmynd. Stökk með tvísmelli og boost-bendingin virka áfram)"}, - {MenuLangId::Hindi, "निशाना लगाने के लिए पूरी टच स्क्रीन का उपयोग करें (टच स्क्रीन के HUD बटन बंद कर देता है: Morph Ball, हथियार क्विक स्लॉट और हथियार मेन्यू। डबल-टैप जंप और टच बूस्ट जेस्चर काम करते रहेंगे)"}, - {MenuLangId::Bengali, "লক্ষ্য স্থির করতে পুরো টাচ স্ক্রিন ব্যবহার করুন (টাচ স্ক্রিনের HUD বোতামগুলি নিষ্ক্রিয় করে: Morph Ball, অস্ত্রের কুইক স্লট এবং অস্ত্রের মেনু। ডাবল-ট্যাপ জাম্প ও টাচ বুস্ট জেসচার আগের মতোই কাজ করবে)"}, - {MenuLangId::Urdu, "نشانہ لگانے کے لیے پوری ٹچ اسکرین استعمال کریں (ٹچ اسکرین کے HUD بٹن غیر فعال کر دیتا ہے: Morph Ball، ہتھیاروں کے کوئیک سلاٹ اور ہتھیاروں کا مینو۔ ڈبل ٹیپ جمپ اور ٹچ بوسٹ اشارہ بدستور کام کرتے رہیں گے)"}, - {MenuLangId::Punjabi, "ਨਿਸ਼ਾਨਾ ਲਗਾਉਣ ਲਈ ਪੂਰੀ ਟੱਚ ਸਕ੍ਰੀਨ ਵਰਤੋ (ਟੱਚ ਸਕ੍ਰੀਨ ਦੇ HUD ਬਟਨ ਬੰਦ ਕਰ ਦਿੰਦਾ ਹੈ: Morph Ball, ਹਥਿਆਰਾਂ ਦੇ ਤੇਜ਼ ਸਲਾਟ ਅਤੇ ਹਥਿਆਰ ਮੀਨੂ। ਡਬਲ-ਟੈਪ ਜੰਪ ਅਤੇ ਟੱਚ ਬੂਸਟ ਇਸ਼ਾਰਾ ਕੰਮ ਕਰਦੇ ਰਹਿਣਗੇ)"}, - {MenuLangId::Telugu, "గురి పెట్టడానికి మొత్తం టచ్ స్క్రీన్‌ను ఉపయోగించు (టచ్ స్క్రీన్‌లోని HUD బటన్‌లను నిలిపివేస్తుంది: Morph Ball, ఆయుధ క్విక్ స్లాట్‌లు మరియు ఆయుధ మెనూ. డబుల్-ట్యాప్ జంప్ మరియు టచ్ బూస్ట్ సంజ్ఞ యథావిధిగా పనిచేస్తాయి)"}, - {MenuLangId::Persian, "برای نشانه‌گیری از کل صفحه لمسی استفاده کن (دکمه‌های HUD روی صفحه لمسی را غیرفعال می‌کند: Morph Ball، اسلات‌های سریع سلاح و منوی سلاح. پرش با دو ضربه و حرکت شتاب لمسی همچنان کار می‌کنند)"}, - {MenuLangId::Malay, "Gunakan keseluruhan skrin sentuh untuk membidik (Melumpuhkan butang HUD pada skrin sentuh: Morph Ball, slot pantas senjata dan menu senjata. Lompatan ketik dua kali dan gerak isyarat boost sentuh masih berfungsi)"}, - {MenuLangId::Marathi, "नेम धरण्यासाठी संपूर्ण टच स्क्रीन वापरा (टच स्क्रीनवरील HUD बटणे बंद करते: Morph Ball, शस्त्रांचे क्विक स्लॉट आणि शस्त्र मेनू. डबल-टॅप जंप आणि टच बूस्ट हावभाव पूर्वीप्रमाणे चालतील)"}, - {MenuLangId::Tamil, "இலக்கு வைக்க முழு தொடுதிரையையும் பயன்படுத்து (தொடுதிரையில் உள்ள HUD பொத்தான்களை முடக்குகிறது: Morph Ball, ஆயுத விரைவு இடங்கள் மற்றும் ஆயுத மெனு. இரட்டைத் தட்டல் தாவல் மற்றும் தொடு பூஸ்ட் சைகை தொடர்ந்து வேலை செய்யும்)"}, - {MenuLangId::Gujarati, "નિશાન લેવા માટે આખી ટચ સ્ક્રીન વાપરો (ટચ સ્ક્રીન પરના HUD બટન બંધ કરે છે: Morph Ball, હથિયારના ક્વિક સ્લોટ અને હથિયાર મેનૂ. ડબલ-ટૅપ જમ્પ અને ટચ બૂસ્ટ હાવભાવ ચાલુ રહેશે)"}, - {MenuLangId::Kannada, "ಗುರಿಯಿಡಲು ಸಂಪೂರ್ಣ ಸ್ಪರ್ಶ ಪರದೆಯನ್ನು ಬಳಸಿ (ಸ್ಪರ್ಶ ಪರದೆಯ HUD ಬಟನ್‌ಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ: Morph Ball, ಆಯುಧಗಳ ತ್ವರಿತ ಸ್ಲಾಟ್‌ಗಳು ಮತ್ತು ಆಯುಧ ಮೆನು. ಡಬಲ್-ಟ್ಯಾಪ್ ಜಂಪ್ ಮತ್ತು ಸ್ಪರ್ಶ ಬೂಸ್ಟ್ ಸನ್ನೆ ಮೊದಲಿನಂತೆ ಕೆಲಸ ಮಾಡುತ್ತವೆ)"}, - {MenuLangId::Odia, "ଲକ୍ଷ୍ୟ ସ୍ଥିର କରିବା ପାଇଁ ପୁରା ଟଚ୍ ସ୍କ୍ରିନ୍ ବ୍ୟବହାର କରନ୍ତୁ (ଟଚ୍ ସ୍କ୍ରିନ୍‌ର HUD ବଟନ୍‌ଗୁଡ଼ିକୁ ନିଷ୍କ୍ରିୟ କରେ: Morph Ball, ଅସ୍ତ୍ରର କୁଇକ୍ ସ୍ଲଟ୍ ଏବଂ ଅସ୍ତ୍ର ମେନୁ। ଡବଲ୍-ଟ୍ୟାପ୍ ଜମ୍ପ୍ ଏବଂ ଟଚ୍ ବୁଷ୍ଟ୍ ଜେଶ୍ଚର୍ ପୂର୍ବପରି କାମ କରିବ)"}, - {MenuLangId::Malayalam, "ലക്ഷ്യം വയ്ക്കാൻ ടച്ച് സ്ക്രീൻ മുഴുവനും ഉപയോഗിക്കുക (ടച്ച് സ്ക്രീനിലെ HUD ബട്ടണുകൾ പ്രവർത്തനരഹിതമാക്കുന്നു: Morph Ball, ആയുധങ്ങളുടെ ക്വിക്ക് സ്ലോട്ടുകൾ, ആയുധ മെനു. ഡബിൾ-ടാപ്പ് ജംപും ടച്ച് ബൂസ്റ്റ് ജെസ്ചറും പഴയതുപോലെ പ്രവർത്തിക്കും)"}, - {MenuLangId::Burmese, "ချိန်ရွယ်ရန် ထိတွေ့မျက်နှာပြင်တစ်ခုလုံးကို အသုံးပြုပါ (ထိတွေ့မျက်နှာပြင်ရှိ HUD ခလုတ်များကို ပိတ်သည်- Morph Ball၊ လက်နက်အမြန်နေရာများနှင့် လက်နက်မီနူး။ နှစ်ချက်ထိ ခုန်ခြင်းနှင့် ထိတွေ့ဘူးစ့်လက်ဟန်မှာ ဆက်လက်အလုပ်လုပ်နေမည်)"}, - {MenuLangId::Uzbek, "Nishonga olish uchun butun sensorli ekrandan foydalanish (Sensorli ekrandagi HUD tugmalarini o‘chiradi: Morph Ball, qurollarning tezkor uyalari va qurol menyusi. Ikki marta bosib sakrash va sensorli boost ishorasi ishlashda davom etadi)"}, - {MenuLangId::Azerbaijani, "Nişan almaq üçün bütün toxunma ekranından istifadə et (Toxunma ekranındakı HUD düymələrini deaktiv edir: Morph Ball, silahların sürətli yuvaları və silah menyusu. İkiqat toxunuşla tullanma və toxunma ilə sürətlənmə jesti işləməyə davam edir)"}, - {MenuLangId::Nepali, "निशाना लगाउन सम्पूर्ण टच स्क्रिन प्रयोग गर्नुहोस् (टच स्क्रिनका HUD बटनहरू निष्क्रिय पार्छ: Morph Ball, हतियारका क्विक स्लट र हतियार मेनु। डबल-ट्याप जम्प र टच बुस्ट इसारा पहिलेजस्तै काम गर्नेछन्)"}, - {MenuLangId::Sinhala, "ඉලක්ක කිරීමට මුළු ස්පර්ශ තිරයම භාවිත කරන්න (ස්පර්ශ තිරයේ HUD බොත්තම් අක්‍රීය කරයි: මෝර්ෆ් බෝල, අවි ඉක්මන් තැන් සහ අවි මෙනුව. ද්විත්ව තට්ටු පිම්ම සහ ස්පර්ශ බූස්ට් ඉංගිතය තවදුරටත් ක්‍රියා කරයි)"}, - {MenuLangId::Khmer, "ប្រើអេក្រង់ប៉ះទាំងមូលដើម្បីតម្រង់ (បិទប៊ូតុង HUD នៅលើអេក្រង់ប៉ះ៖ Morph Ball រន្ធអាវុធរហ័ស និងម៉ឺនុយអាវុធ។ ការលោតដោយប៉ះពីរដង និងកាយវិការបង្កើនល្បឿនដោយប៉ះនៅតែដំណើរការ)"}, - {MenuLangId::Lao, "ໃຊ້ໜ້າຈໍສຳຜັດທັງໝົດເພື່ອເລັງ (ປິດປຸ່ມ HUD ເທິງໜ້າຈໍສຳຜັດ: Morph Ball, ຊ່ອງອາວຸດດ່ວນ ແລະ ເມນູອາວຸດ. ການກະໂດດດ້ວຍການແຕະສອງເທື່ອ ແລະ ທ່າທາງເລັ່ງດ້ວຍການສຳຜັດຍັງໃຊ້ໄດ້)"}, - {MenuLangId::Armenian, "Օգտագործել ամբողջ հպէկրանը նշանառության համար (Անջատում է հպէկրանի HUD կոճակները՝ Morph Ball, զենքերի արագ բջիջները և զենքերի ընտրացանկը։ Կրկնակի հպումով ցատկը և հպումով արագացման ժեստը շարունակում են աշխատել)"}, - {MenuLangId::Albanian, "Përdor të gjithë ekranin me prekje për të shënjestruar (Çaktivizon butonat e HUD-it në ekranin me prekje: Morph Ball, foletë e shpejta të armëve dhe menynë e armëve. Kërcimi me prekje të dyfishtë dhe gjesti i boost-it me prekje vazhdojnë të funksionojnë)"}, - {MenuLangId::Georgian, "დასამიზნებლად მთელი სენსორული ეკრანის გამოყენება (გამორთავს სენსორულ ეკრანზე HUD-ის ღილაკებს: Morph Ball, იარაღის სწრაფი უჯრები და იარაღის მენიუ. ორმაგი შეხებით ხტომა და შეხებით აჩქარების ჟესტი კვლავ მუშაობს)"}, - {MenuLangId::Bosnian, "Koristi cijeli ekran osjetljiv na dodir za ciljanje (Onemogućava HUD dugmad na ekranu osjetljivom na dodir: Morph Ball, brze slotove oružja i meni oružja. Skok dvostrukim dodirom i gest ubrzanja i dalje rade)"}, - {MenuLangId::Serbian, "Користи цео екран осетљив на додир за циљање (Онемогућава HUD дугмад на екрану осетљивом на додир: Morph Ball, брзе слотове оружја и мени оружја. Скок двоструким додиром и покрет за убрзање и даље раде)"}, - {MenuLangId::Macedonian, "Користи го целиот екран на допир за нишанење (Ги оневозможува HUD копчињата на екранот на допир: Morph Ball, брзите слотови за оружје и менито за оружје. Скокот со двоен допир и гестот за забрзување и понатаму работат)"}, - {MenuLangId::Bulgarian, "Използвай целия сензорен екран за прицелване (Изключва бутоните на HUD на сензорния екран: Morph Ball, бързите слотове за оръжия и менюто за оръжия. Скокът с двойно докосване и жестът за ускорение продължават да работят)"}, - {MenuLangId::Belarusian, "Выкарыстоўваць увесь сэнсарны экран для прыцэльвання (Адключае кнопкі HUD на сэнсарным экране: Morph Ball, хуткія слоты зброі і меню зброі. Скачок падвойным дотыкам і жэст паскарэння працягваюць працаваць)"}, - {MenuLangId::Maltese, "Uża l-iskrin tal-mess kollu biex timmira (Jiddiżattiva l-buttuni tal-HUD fuq l-iskrin tal-mess: Morph Ball, l-islots mgħaġġla tal-armi u l-menu tal-armi. Il-qbiża b’żewġ tektikiet u l-ġest tal-boost bil-mess jibqgħu jaħdmu)"}, - {MenuLangId::Mongolian, "Онилохдоо мэдрэгчтэй дэлгэцийг бүхэлд нь ашиглах (Мэдрэгчтэй дэлгэц дэх HUD товчнуудыг идэвхгүй болгоно: Morph Ball, зэвсгийн хурдан нүд болон зэвсгийн цэс. Хоёр товшилтоор үсрэх ба хүрэлтээр хурдасгах хөдөлгөөн хэвээр ажиллана)"}, - {MenuLangId::Latvian, "Izmantot visu skārienekrānu mērķēšanai (Atspējo HUD pogas uz skārienekrāna: Morph Ball, ieroču ātrās vietas un ieroču izvēlni. Lēciens ar dubultskārienu un paātrinājuma žests joprojām darbojas)"}, - {MenuLangId::Lithuanian, "Taikymui naudoti visą jutiklinį ekraną (Išjungia jutiklinio ekrano HUD mygtukus: Morph Ball, greitąsias ginklų vietas ir ginklų meniu. Šuolis dvigubu bakstelėjimu ir pagreitinimo gestas veikia toliau)"}, - {MenuLangId::Afrikaans, "Gebruik die hele raakskerm om te mik (Skakel die HUD-knoppies op die raakskerm af: Morph Ball, wapensnelgleuwe en die wapenkieslys. Spring met dubbeltik en die boost-gebaar werk steeds)"}, - {MenuLangId::Irish, "Úsáid an scáileán tadhaill ar fad chun aidhmiú (Díchumasaíonn sé cnaipí an HUD ar an scáileán tadhaill: Morph Ball, sliotáin mhearrochtana na n-arm agus roghchlár na n-arm. Oibríonn an léim le tapáil dhúbailte agus gotha an boost i gcónaí)"}, - {MenuLangId::Assamese, "লক্ষ্য স্থিৰ কৰিবলৈ গোটেই টাচ স্ক্ৰীন ব্যৱহাৰ কৰক (টাচ স্ক্ৰীনৰ HUD বুটামসমূহ নিষ্ক্ৰিয় কৰে: Morph Ball, অস্ত্ৰৰ ক্ষিপ্ৰ স্লট আৰু অস্ত্ৰ মেনু। ডাবল-টেপ জাম্প আৰু টাচ বুষ্ট নিৰ্দেশ আগৰ দৰেই কাম কৰিব)"}, - {MenuLangId::Amharic, "ለማነጣጠር መላውን የንክኪ ማያ ገጽ ተጠቀም (በንክኪ ማያ ገጹ ላይ ያሉትን የHUD አዝራሮች ያሰናክላል፦ Morph Ball፣ የመሣሪያ ፈጣን ማስገቢያዎች እና የመሣሪያ ምናሌ። ባለሁለት ንክኪ ዝላይ እና የንክኪ ቡስት እንቅስቃሴ መስራታቸውን ይቀጥላሉ)"}, - {MenuLangId::Estonian, "Kasuta sihtimiseks kogu puuteekraani (Keelab puuteekraani HUD-nupud: Morph Ball, relvade kiirpesad ja relvamenüü. Topeltpuudutusega hüpe ja kiirendusžest töötavad endiselt)"}, - {MenuLangId::Kazakh, "Көздеу үшін бүкіл сенсорлық экранды пайдалану (Сенсорлық экрандағы HUD түймелерін өшіреді: Morph Ball, қарудың жылдам ұяшықтары және қару мәзірі. Қос түртумен секіру және сенсорлық үдеу қимылы жұмысын жалғастырады)"}, - {MenuLangId::Catalan, "Usa tota la pantalla tàctil per apuntar (Desactiva els botons del HUD de la pantalla tàctil: Morph Ball, les ranures ràpides d’armes i el menú d’armes. El salt amb doble toc i el gest d’impuls tàctil continuen funcionant)"}, - {MenuLangId::Kyrgyz, "Мээлөө үчүн бүт сенсордук экранды колдонуу (Сенсордук экрандагы HUD баскычтарын өчүрөт: Morph Ball, куралдын ыкчам уячалары жана курал менюсу. Кош таптап секирүү жана тийүү менен ылдамдатуу жаңсоосу иштей берет)"}, - {MenuLangId::Slovak, "Použiť celú dotykovú obrazovku na mierenie (Vypne tlačidlá HUD na dotykovej obrazovke: Morph Ball, rýchle sloty zbraní a ponuku zbraní. Skok dvojitým ťuknutím a dotykové gesto boostu fungujú naďalej)"}, - {MenuLangId::Slovenian, "Uporabi celoten zaslon na dotik za merjenje (Onemogoči gumbe HUD na zaslonu na dotik: Morph Ball, hitre reže za orožje in meni orožja. Skok z dvojnim dotikom in poteza za pospešek še naprej delujeta)"}, - {MenuLangId::Zulu, "Sebenzisa sonke isikrini sokuthinta ukuze ukhombe (Ikhubaza izinkinobho ze-HUD esikrinini sokuthinta: Morph Ball, izikhala ezisheshayo zezikhali nemenyu yezikhali. Ukugxuma ngokuthinta kabili nokunyakaza kwe-boost kusasebenza)"}, - {MenuLangId::Basque, "Erabili ukipen-pantaila osoa apuntatzeko (Ukipen-pantailako HUD botoiak desgaitzen ditu: Morph Ball, armen zirrikitu azkarrak eta armen menua. Ukitu bikoitzeko jauziak eta ukipen bidezko boost keinuak funtzionatzen jarraitzen dute)"}, - {MenuLangId::Hebrew, "השתמש בכל מסך המגע לכיוון (משבית את לחצני ה-HUD במסך המגע: Morph Ball, משבצות הנשק המהירות ותפריט הנשק. קפיצת הנקישה הכפולה ומחוות הבוסט במגע ממשיכות לפעול)"}, + {MenuLangId::Japanese, "タッチスクリーン全体をエイムに使う (下画面のHUDボタン (トランスフォーム、武器クイックスロット、武器メニュー) を無効化します。ダブルタップジャンプとタッチのブーストは引き続き使えます)"}, + {MenuLangId::German, "Gesamten Touchscreen zum Zielen verwenden (Deaktiviert die HUD-Schaltflächen auf dem Touchscreen: Verwandlung, Waffen-Schnellwahl und Waffenmenü. Doppeltipp-Sprung und die BOOST-Wischgeste funktionieren weiterhin)"}, + {MenuLangId::Spanish, "Usar toda la pantalla táctil para apuntar (Desactiva los botones del HUD de la pantalla táctil: transformación, accesos rápidos de armas y menú de armas. El salto con doble toque y el gesto de TURBO táctil siguen funcionando)"}, + {MenuLangId::French, "Utiliser tout l’écran tactile pour viser (Désactive les boutons de l’ATH sur l’écran tactile : transformation, raccourcis d’armes et menu des armes. Le saut par double tape et le geste de BOOST tactile restent disponibles)"}, + {MenuLangId::Italian, "Usa tutto lo schermo tattile per mirare (Disattiva i pulsanti dell’HUD sullo schermo tattile: trasformazione, slot rapidi delle armi e menu delle armi. Il salto con doppio tocco e il gesto di TURBO tattile continuano a funzionare)"}, + {MenuLangId::Dutch, "Het hele aanraakscherm gebruiken om te richten (Schakelt de HUD-knoppen op het aanraakscherm uit: transformatie, wapensnelvakken en het wapenmenu. Springen met dubbele tik en het boostgebaar blijven werken)"}, + {MenuLangId::Portuguese, "Usar todo o ecrã tátil para apontar (Desativa os botões do HUD no ecrã tátil: transformação, atalhos de armas e menu de armas. O salto com toque duplo e o gesto de boost tátil continuam a funcionar)"}, + {MenuLangId::Russian, "Использовать весь сенсорный экран для прицеливания (Отключает кнопки HUD на сенсорном экране: превращение, быстрые слоты оружия и меню оружия. Прыжок двойным касанием и жест ускорения продолжают работать)"}, + {MenuLangId::ChineseSimplified, "使用整个触摸屏进行瞄准 (禁用触摸屏上的 HUD 按钮:变形、武器快捷槽和武器菜单。双击跳跃和触摸加速手势仍然可用)"}, + {MenuLangId::ChineseTraditional, "使用整個觸控螢幕進行瞄準 (停用觸控螢幕上的 HUD 按鈕:變形、武器快捷槽與武器選單。雙擊跳躍與觸控加速手勢仍可使用)"}, + {MenuLangId::ChineseHongKong, "使用整個觸控螢幕進行瞄準 (停用觸控螢幕上的 HUD 按鈕:變形、武器快捷槽與武器選單。雙擊跳躍與觸控加速手勢仍可使用)"}, + {MenuLangId::Korean, "터치스크린 전체를 조준에 사용 (터치스크린의 HUD 버튼을 비활성화합니다: 변형, 무기 퀵 슬롯, 무기 메뉴. 더블 탭 점프와 터치 부스트 제스처는 그대로 작동합니다)"}, + {MenuLangId::Arabic, "استخدام شاشة اللمس بالكامل للتصويب (يعطّل أزرار واجهة العرض على شاشة اللمس: التحول وفتحات الأسلحة السريعة وقائمة الأسلحة. تظل القفزة بنقرتين وإيماءة الاندفاع باللمس تعملان)"}, + {MenuLangId::Indonesian, "Gunakan seluruh layar sentuh untuk membidik (Menonaktifkan tombol HUD di layar sentuh: transformasi, slot cepat senjata, dan menu senjata. Lompatan ketuk ganda dan gerakan boost sentuh tetap berfungsi)"}, + {MenuLangId::Ukrainian, "Використовувати весь сенсорний екран для прицілювання (Вимикає кнопки HUD на сенсорному екрані: перетворення, швидкі слоти зброї та меню зброї. Стрибок подвійним дотиком і жест прискорення продовжують працювати)"}, + {MenuLangId::Greek, "Χρήση ολόκληρης της οθόνης αφής για σκόπευση (Απενεργοποιεί τα κουμπιά HUD στην οθόνη αφής: μεταμόρφωση, γρήγορες θέσεις όπλων και μενού όπλων. Το άλμα με διπλό χτύπημα και η χειρονομία boost εξακολουθούν να λειτουργούν)"}, + {MenuLangId::Swedish, "Använd hela pekskärmen för att sikta (Inaktiverar HUD-knapparna på pekskärmen: förvandling, vapensnabbplatser och vapenmenyn. Hopp med dubbeltryck och boostgesten fungerar fortfarande)"}, + {MenuLangId::Thai, "ใช้หน้าจอสัมผัสทั้งหมดในการเล็ง (ปิดใช้งานปุ่ม HUD บนหน้าจอสัมผัส: การแปลงร่าง ช่องอาวุธด่วน และเมนูอาวุธ การกระโดดด้วยการแตะสองครั้งและท่าทางบูสต์แบบสัมผัสยังใช้งานได้)"}, + {MenuLangId::Czech, "Použít celou dotykovou obrazovku k míření (Vypne tlačítka HUD na dotykové obrazovce: proměna, rychlé sloty zbraní a nabídku zbraní. Skok dvojitým klepnutím a dotykové gesto boostu fungují dál)"}, + {MenuLangId::Danish, "Brug hele berøringsskærmen til at sigte (Deaktiverer HUD-knapperne på berøringsskærmen: forvandling, hurtigpladser til våben og våbenmenuen. Hop med dobbelttryk og boost-bevægelsen virker fortsat)"}, + {MenuLangId::Turkish, "Nişan almak için tüm dokunmatik ekranı kullan (Dokunmatik ekrandaki HUD düğmelerini devre dışı bırakır: dönüşüm, silah hızlı yuvaları ve silah menüsü. Çift dokunuşla zıplama ve dokunmatik boost hareketi çalışmaya devam eder)"}, + {MenuLangId::Norwegian, "Bruk hele berøringsskjermen til å sikte (Deaktiverer HUD-knappene på berøringsskjermen: forvandling, hurtigplasser for våpen og våpenmenyen. Hopp med dobbelttrykk og boost-bevegelsen fungerer fortsatt)"}, + {MenuLangId::Hungarian, "A teljes érintőképernyő használata célzáshoz (Letiltja az érintőképernyő HUD-gombjait: átváltozás, fegyver-gyorshelyek és fegyvermenü. A dupla koppintásos ugrás és az érintéses boost mozdulat továbbra is működik)"}, + {MenuLangId::Finnish, "Käytä koko kosketusnäyttöä tähtäämiseen (Poistaa käytöstä kosketusnäytön HUD-painikkeet: muuntuminen, aseiden pikapaikat ja asevalikko. Kaksoisnapautushyppy ja kosketusboost-ele toimivat edelleen)"}, + {MenuLangId::Vietnamese, "Dùng toàn bộ màn hình cảm ứng để ngắm bắn (Tắt các nút HUD trên màn hình cảm ứng: biến đổi, ô vũ khí nhanh và menu vũ khí. Nhảy bằng chạm hai lần và thao tác tăng tốc bằng cảm ứng vẫn hoạt động)"}, + {MenuLangId::Polish, "Używaj całego ekranu dotykowego do celowania (Wyłącza przyciski HUD na ekranie dotykowym: przemiana, szybkie sloty broni i menu broni. Skok podwójnym dotknięciem oraz gest przyspieszenia nadal działają)"}, + {MenuLangId::Romanian, "Folosește tot ecranul tactil pentru ochire (Dezactivează butoanele HUD de pe ecranul tactil: transformarea, sloturile rapide de arme și meniul de arme. Saltul prin dublă atingere și gestul de boost tactil funcționează în continuare)"}, + {MenuLangId::Filipino, "Gamitin ang buong touch screen para sa pagpuntirya (Hindi na gagana ang mga HUD button sa touch screen: pagbabago, mga quick slot ng armas, at menu ng armas. Gumagana pa rin ang double-tap jump at ang touch boost gesture)"}, + {MenuLangId::Swahili, "Tumia skrini nzima ya kugusa kulenga (Huzima vitufe vya HUD kwenye skrini ya kugusa: kubadilika, nafasi za haraka za silaha na menyu ya silaha. Kuruka kwa kugusa mara mbili na ishara ya boost bado hufanya kazi)"}, + {MenuLangId::Croatian, "Koristi cijeli zaslon osjetljiv na dodir za ciljanje (Onemogućuje HUD gumbe na dodirnom zaslonu: preobrazba, brze utore za oružje i izbornik oružja. Skok dvostrukim dodirom i gesta ubrzanja i dalje rade)"}, + {MenuLangId::Icelandic, "Nota allan snertiskjáinn til að miða (Slekkur á HUD-hnöppunum á snertiskjánum: umbreyting, flýtihólf vopna og vopnavalmynd. Stökk með tvísmelli og boost-bendingin virka áfram)"}, + {MenuLangId::Hindi, "निशाना लगाने के लिए पूरी टच स्क्रीन का उपयोग करें (टच स्क्रीन के HUD बटन बंद कर देता है: रूपांतरण, हथियार क्विक स्लॉट और हथियार मेन्यू। डबल-टैप जंप और टच बूस्ट जेस्चर काम करते रहेंगे)"}, + {MenuLangId::Bengali, "লক্ষ্য স্থির করতে পুরো টাচ স্ক্রিন ব্যবহার করুন (টাচ স্ক্রিনের HUD বোতামগুলি নিষ্ক্রিয় করে: রূপান্তর, অস্ত্রের কুইক স্লট এবং অস্ত্রের মেনু। ডাবল-ট্যাপ জাম্প ও টাচ বুস্ট জেসচার আগের মতোই কাজ করবে)"}, + {MenuLangId::Urdu, "نشانہ لگانے کے لیے پوری ٹچ اسکرین استعمال کریں (ٹچ اسکرین کے HUD بٹن غیر فعال کر دیتا ہے: تبدیلی، ہتھیاروں کے کوئیک سلاٹ اور ہتھیاروں کا مینو۔ ڈبل ٹیپ جمپ اور ٹچ بوسٹ اشارہ بدستور کام کرتے رہیں گے)"}, + {MenuLangId::Punjabi, "ਨਿਸ਼ਾਨਾ ਲਗਾਉਣ ਲਈ ਪੂਰੀ ਟੱਚ ਸਕ੍ਰੀਨ ਵਰਤੋ (ਟੱਚ ਸਕ੍ਰੀਨ ਦੇ HUD ਬਟਨ ਬੰਦ ਕਰ ਦਿੰਦਾ ਹੈ: ਤਬਦੀਲੀ, ਹਥਿਆਰਾਂ ਦੇ ਤੇਜ਼ ਸਲਾਟ ਅਤੇ ਹਥਿਆਰ ਮੀਨੂ। ਡਬਲ-ਟੈਪ ਜੰਪ ਅਤੇ ਟੱਚ ਬੂਸਟ ਇਸ਼ਾਰਾ ਕੰਮ ਕਰਦੇ ਰਹਿਣਗੇ)"}, + {MenuLangId::Telugu, "గురి పెట్టడానికి మొత్తం టచ్ స్క్రీన్‌ను ఉపయోగించు (టచ్ స్క్రీన్‌లోని HUD బటన్‌లను నిలిపివేస్తుంది: మార్పు, ఆయుధ క్విక్ స్లాట్‌లు మరియు ఆయుధ మెనూ. డబుల్-ట్యాప్ జంప్ మరియు టచ్ బూస్ట్ సంజ్ఞ యథావిధిగా పనిచేస్తాయి)"}, + {MenuLangId::Persian, "برای نشانه‌گیری از کل صفحه لمسی استفاده کن (دکمه‌های HUD روی صفحه لمسی را غیرفعال می‌کند: تغییر شکل، اسلات‌های سریع سلاح و منوی سلاح. پرش با دو ضربه و حرکت شتاب لمسی همچنان کار می‌کنند)"}, + {MenuLangId::Malay, "Gunakan keseluruhan skrin sentuh untuk membidik (Melumpuhkan butang HUD pada skrin sentuh: perubahan, slot pantas senjata dan menu senjata. Lompatan ketik dua kali dan gerak isyarat boost sentuh masih berfungsi)"}, + {MenuLangId::Marathi, "नेम धरण्यासाठी संपूर्ण टच स्क्रीन वापरा (टच स्क्रीनवरील HUD बटणे बंद करते: रूपांतर, शस्त्रांचे क्विक स्लॉट आणि शस्त्र मेनू. डबल-टॅप जंप आणि टच बूस्ट हावभाव पूर्वीप्रमाणे चालतील)"}, + {MenuLangId::Tamil, "இலக்கு வைக்க முழு தொடுதிரையையும் பயன்படுத்து (தொடுதிரையில் உள்ள HUD பொத்தான்களை முடக்குகிறது: மாற்றம், ஆயுத விரைவு இடங்கள் மற்றும் ஆயுத மெனு. இரட்டைத் தட்டல் தாவல் மற்றும் தொடு பூஸ்ட் சைகை தொடர்ந்து வேலை செய்யும்)"}, + {MenuLangId::Gujarati, "નિશાન લેવા માટે આખી ટચ સ્ક્રીન વાપરો (ટચ સ્ક્રીન પરના HUD બટન બંધ કરે છે: રૂપાંતર, હથિયારના ક્વિક સ્લોટ અને હથિયાર મેનૂ. ડબલ-ટૅપ જમ્પ અને ટચ બૂસ્ટ હાવભાવ ચાલુ રહેશે)"}, + {MenuLangId::Kannada, "ಗುರಿಯಿಡಲು ಸಂಪೂರ್ಣ ಸ್ಪರ್ಶ ಪರದೆಯನ್ನು ಬಳಸಿ (ಸ್ಪರ್ಶ ಪರದೆಯ HUD ಬಟನ್‌ಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ: ಪರಿವರ್ತನೆ, ಆಯುಧಗಳ ತ್ವರಿತ ಸ್ಲಾಟ್‌ಗಳು ಮತ್ತು ಆಯುಧ ಮೆನು. ಡಬಲ್-ಟ್ಯಾಪ್ ಜಂಪ್ ಮತ್ತು ಸ್ಪರ್ಶ ಬೂಸ್ಟ್ ಸನ್ನೆ ಮೊದಲಿನಂತೆ ಕೆಲಸ ಮಾಡುತ್ತವೆ)"}, + {MenuLangId::Odia, "ଲକ୍ଷ୍ୟ ସ୍ଥିର କରିବା ପାଇଁ ପୁରା ଟଚ୍ ସ୍କ୍ରିନ୍ ବ୍ୟବହାର କରନ୍ତୁ (ଟଚ୍ ସ୍କ୍ରିନ୍‌ର HUD ବଟନ୍‌ଗୁଡ଼ିକୁ ନିଷ୍କ୍ରିୟ କରେ: ରୂପାନ୍ତର, ଅସ୍ତ୍ରର କୁଇକ୍ ସ୍ଲଟ୍ ଏବଂ ଅସ୍ତ୍ର ମେନୁ। ଡବଲ୍-ଟ୍ୟାପ୍ ଜମ୍ପ୍ ଏବଂ ଟଚ୍ ବୁଷ୍ଟ୍ ଜେଶ୍ଚର୍ ପୂର୍ବପରି କାମ କରିବ)"}, + {MenuLangId::Malayalam, "ലക്ഷ്യം വയ്ക്കാൻ ടച്ച് സ്ക്രീൻ മുഴുവനും ഉപയോഗിക്കുക (ടച്ച് സ്ക്രീനിലെ HUD ബട്ടണുകൾ പ്രവർത്തനരഹിതമാക്കുന്നു: മാറ്റം, ആയുധങ്ങളുടെ ക്വിക്ക് സ്ലോട്ടുകൾ, ആയുധ മെനു. ഡബിൾ-ടാപ്പ് ജംപും ടച്ച് ബൂസ്റ്റ് ജെസ്ചറും പഴയതുപോലെ പ്രവർത്തിക്കും)"}, + {MenuLangId::Burmese, "ချိန်ရွယ်ရန် ထိတွေ့မျက်နှာပြင်တစ်ခုလုံးကို အသုံးပြုပါ (ထိတွေ့မျက်နှာပြင်ရှိ HUD ခလုတ်များကို ပိတ်သည်- ပြောင်းလဲမှု၊ လက်နက်အမြန်နေရာများနှင့် လက်နက်မီနူး။ နှစ်ချက်ထိ ခုန်ခြင်းနှင့် ထိတွေ့ဘူးစ့်လက်ဟန်မှာ ဆက်လက်အလုပ်လုပ်နေမည်)"}, + {MenuLangId::Uzbek, "Nishonga olish uchun butun sensorli ekrandan foydalanish (Sensorli ekrandagi HUD tugmalarini o‘chiradi: o‘zgarish, qurollarning tezkor uyalari va qurol menyusi. Ikki marta bosib sakrash va sensorli boost ishorasi ishlashda davom etadi)"}, + {MenuLangId::Azerbaijani, "Nişan almaq üçün bütün toxunma ekranından istifadə et (Toxunma ekranındakı HUD düymələrini deaktiv edir: çevrilmə, silahların sürətli yuvaları və silah menyusu. İkiqat toxunuşla tullanma və toxunma ilə sürətlənmə jesti işləməyə davam edir)"}, + {MenuLangId::Nepali, "निशाना लगाउन सम्पूर्ण टच स्क्रिन प्रयोग गर्नुहोस् (टच स्क्रिनका HUD बटनहरू निष्क्रिय पार्छ: रूपान्तरण, हतियारका क्विक स्लट र हतियार मेनु। डबल-ट्याप जम्प र टच बुस्ट इसारा पहिलेजस्तै काम गर्नेछन्)"}, + {MenuLangId::Sinhala, "ඉලක්ක කිරීමට මුළු ස්පර්ශ තිරයම භාවිත කරන්න (ස්පර්ශ තිරයේ HUD බොත්තම් අක්‍රීය කරයි: පරිවර්තනය, අවි ඉක්මන් තැන් සහ අවි මෙනුව. ද්විත්ව තට්ටු පිම්ම සහ ස්පර්ශ බූස්ට් ඉංගිතය තවදුරටත් ක්‍රියා කරයි)"}, + {MenuLangId::Khmer, "ប្រើអេក្រង់ប៉ះទាំងមូលដើម្បីតម្រង់ (បិទប៊ូតុង HUD នៅលើអេក្រង់ប៉ះ៖ ការបម្លែង រន្ធអាវុធរហ័ស និងម៉ឺនុយអាវុធ។ ការលោតដោយប៉ះពីរដង និងកាយវិការបង្កើនល្បឿនដោយប៉ះនៅតែដំណើរការ)"}, + {MenuLangId::Lao, "ໃຊ້ໜ້າຈໍສຳຜັດທັງໝົດເພື່ອເລັງ (ປິດປຸ່ມ HUD ເທິງໜ້າຈໍສຳຜັດ: ການແປງ, ຊ່ອງອາວຸດດ່ວນ ແລະ ເມນູອາວຸດ. ການກະໂດດດ້ວຍການແຕະສອງເທື່ອ ແລະ ທ່າທາງເລັ່ງດ້ວຍການສຳຜັດຍັງໃຊ້ໄດ້)"}, + {MenuLangId::Armenian, "Օգտագործել ամբողջ հպէկրանը նշանառության համար (Անջատում է հպէկրանի HUD կոճակները՝ փոխակերպում, զենքերի արագ բջիջները և զենքերի ընտրացանկը։ Կրկնակի հպումով ցատկը և հպումով արագացման ժեստը շարունակում են աշխատել)"}, + {MenuLangId::Albanian, "Përdor të gjithë ekranin me prekje për të shënjestruar (Çaktivizon butonat e HUD-it në ekranin me prekje: shndërrim, foletë e shpejta të armëve dhe menynë e armëve. Kërcimi me prekje të dyfishtë dhe gjesti i boost-it me prekje vazhdojnë të funksionojnë)"}, + {MenuLangId::Georgian, "დასამიზნებლად მთელი სენსორული ეკრანის გამოყენება (გამორთავს სენსორულ ეკრანზე HUD-ის ღილაკებს: გარდაქმნა, იარაღის სწრაფი უჯრები და იარაღის მენიუ. ორმაგი შეხებით ხტომა და შეხებით აჩქარების ჟესტი კვლავ მუშაობს)"}, + {MenuLangId::Bosnian, "Koristi cijeli ekran osjetljiv na dodir za ciljanje (Onemogućava HUD dugmad na ekranu osjetljivom na dodir: preobrazba, brze slotove oružja i meni oružja. Skok dvostrukim dodirom i gest ubrzanja i dalje rade)"}, + {MenuLangId::Serbian, "Користи цео екран осетљив на додир за циљање (Онемогућава HUD дугмад на екрану осетљивом на додир: претварање, брзе слотове оружја и мени оружја. Скок двоструким додиром и покрет за убрзање и даље раде)"}, + {MenuLangId::Macedonian, "Користи го целиот екран на допир за нишанење (Ги оневозможува HUD копчињата на екранот на допир: преобразување, брзите слотови за оружје и менито за оружје. Скокот со двоен допир и гестот за забрзување и понатаму работат)"}, + {MenuLangId::Bulgarian, "Използвай целия сензорен екран за прицелване (Изключва бутоните на HUD на сензорния екран: превръщане, бързите слотове за оръжия и менюто за оръжия. Скокът с двойно докосване и жестът за ускорение продължават да работят)"}, + {MenuLangId::Belarusian, "Выкарыстоўваць увесь сэнсарны экран для прыцэльвання (Адключае кнопкі HUD на сэнсарным экране: пераўтварэнне, хуткія слоты зброі і меню зброі. Скачок падвойным дотыкам і жэст паскарэння працягваюць працаваць)"}, + {MenuLangId::Maltese, "Uża l-iskrin tal-mess kollu biex timmira (Jiddiżattiva l-buttuni tal-HUD fuq l-iskrin tal-mess: bidla, l-islots mgħaġġla tal-armi u l-menu tal-armi. Il-qbiża b’żewġ tektikiet u l-ġest tal-boost bil-mess jibqgħu jaħdmu)"}, + {MenuLangId::Mongolian, "Онилохдоо мэдрэгчтэй дэлгэцийг бүхэлд нь ашиглах (Мэдрэгчтэй дэлгэц дэх HUD товчнуудыг идэвхгүй болгоно: хувиралт, зэвсгийн хурдан нүд болон зэвсгийн цэс. Хоёр товшилтоор үсрэх ба хүрэлтээр хурдасгах хөдөлгөөн хэвээр ажиллана)"}, + {MenuLangId::Latvian, "Izmantot visu skārienekrānu mērķēšanai (Atspējo HUD pogas uz skārienekrāna: pārvēršanās, ieroču ātrās vietas un ieroču izvēlni. Lēciens ar dubultskārienu un paātrinājuma žests joprojām darbojas)"}, + {MenuLangId::Lithuanian, "Taikymui naudoti visą jutiklinį ekraną (Išjungia jutiklinio ekrano HUD mygtukus: virtimas, greitąsias ginklų vietas ir ginklų meniu. Šuolis dvigubu bakstelėjimu ir pagreitinimo gestas veikia toliau)"}, + {MenuLangId::Afrikaans, "Gebruik die hele raakskerm om te mik (Skakel die HUD-knoppies op die raakskerm af: verandering, wapensnelgleuwe en die wapenkieslys. Spring met dubbeltik en die boost-gebaar werk steeds)"}, + {MenuLangId::Irish, "Úsáid an scáileán tadhaill ar fad chun aidhmiú (Díchumasaíonn sé cnaipí an HUD ar an scáileán tadhaill: claochlú, sliotáin mhearrochtana na n-arm agus roghchlár na n-arm. Oibríonn an léim le tapáil dhúbailte agus gotha an boost i gcónaí)"}, + {MenuLangId::Assamese, "লক্ষ্য স্থিৰ কৰিবলৈ গোটেই টাচ স্ক্ৰীন ব্যৱহাৰ কৰক (টাচ স্ক্ৰীনৰ HUD বুটামসমূহ নিষ্ক্ৰিয় কৰে: ৰূপান্তৰ, অস্ত্ৰৰ ক্ষিপ্ৰ স্লট আৰু অস্ত্ৰ মেনু। ডাবল-টেপ জাম্প আৰু টাচ বুষ্ট নিৰ্দেশ আগৰ দৰেই কাম কৰিব)"}, + {MenuLangId::Amharic, "ለማነጣጠር መላውን የንክኪ ማያ ገጽ ተጠቀም (በንክኪ ማያ ገጹ ላይ ያሉትን የHUD አዝራሮች ያሰናክላል፦ መቀየር፣ የመሣሪያ ፈጣን ማስገቢያዎች እና የመሣሪያ ምናሌ። ባለሁለት ንክኪ ዝላይ እና የንክኪ ቡስት እንቅስቃሴ መስራታቸውን ይቀጥላሉ)"}, + {MenuLangId::Estonian, "Kasuta sihtimiseks kogu puuteekraani (Keelab puuteekraani HUD-nupud: muundumine, relvade kiirpesad ja relvamenüü. Topeltpuudutusega hüpe ja kiirendusžest töötavad endiselt)"}, + {MenuLangId::Kazakh, "Көздеу үшін бүкіл сенсорлық экранды пайдалану (Сенсорлық экрандағы HUD түймелерін өшіреді: айналу, қарудың жылдам ұяшықтары және қару мәзірі. Қос түртумен секіру және сенсорлық үдеу қимылы жұмысын жалғастырады)"}, + {MenuLangId::Catalan, "Usa tota la pantalla tàctil per apuntar (Desactiva els botons del HUD de la pantalla tàctil: transformació, les ranures ràpides d’armes i el menú d’armes. El salt amb doble toc i el gest d’impuls tàctil continuen funcionant)"}, + {MenuLangId::Kyrgyz, "Мээлөө үчүн бүт сенсордук экранды колдонуу (Сенсордук экрандагы HUD баскычтарын өчүрөт: өзгөрүү, куралдын ыкчам уячалары жана курал менюсу. Кош таптап секирүү жана тийүү менен ылдамдатуу жаңсоосу иштей берет)"}, + {MenuLangId::Slovak, "Použiť celú dotykovú obrazovku na mierenie (Vypne tlačidlá HUD na dotykovej obrazovke: premena, rýchle sloty zbraní a ponuku zbraní. Skok dvojitým ťuknutím a dotykové gesto boostu fungujú naďalej)"}, + {MenuLangId::Slovenian, "Uporabi celoten zaslon na dotik za merjenje (Onemogoči gumbe HUD na zaslonu na dotik: preobrazba, hitre reže za orožje in meni orožja. Skok z dvojnim dotikom in poteza za pospešek še naprej delujeta)"}, + {MenuLangId::Zulu, "Sebenzisa sonke isikrini sokuthinta ukuze ukhombe (Ikhubaza izinkinobho ze-HUD esikrinini sokuthinta: ukuguquka, izikhala ezisheshayo zezikhali nemenyu yezikhali. Ukugxuma ngokuthinta kabili nokunyakaza kwe-boost kusasebenza)"}, + {MenuLangId::Basque, "Erabili ukipen-pantaila osoa apuntatzeko (Ukipen-pantailako HUD botoiak desgaitzen ditu: eraldaketa, armen zirrikitu azkarrak eta armen menua. Ukitu bikoitzeko jauziak eta ukipen bidezko boost keinuak funtzionatzen jarraitzen dute)"}, + {MenuLangId::Hebrew, "השתמש בכל מסך המגע לכיוון (משבית את לחצני ה-HUD במסך המגע: שינוי צורה, משבצות הנשק המהירות ותפריט הנשק. קפיצת הנקישה הכפולה ומחוות הבוסט במגע ממשיכות לפעול)"}, + } + }, + { + "Turn It Off Briefly While a Standard-Method Transform Fires (The Standard transform taps the touch-screen Transform button, which the option above disables. This re-enables the HUD hit-test for those few frames only)", + { + {MenuLangId::Japanese, "通常方式のトランスフォーム発火中だけ一時的にオフにする (通常方式の変形は下画面のトランスフォームボタンをタップしますが、上の設定はそれを無効化します。この設定はその数フレームの間だけHUDの判定を戻します)"}, + {MenuLangId::German, "Kurz deaktivieren, während eine Verwandlung per Standardmethode ausgelöst wird (Die Standardmethode tippt auf die Verwandlungs-Schaltfläche des Touchscreens, die die Option darüber deaktiviert. Dies stellt die HUD-Trefferprüfung nur für diese wenigen Frames wieder her)"}, + {MenuLangId::Spanish, "Desactivarlo brevemente mientras se activa una transformación con el método estándar (El método estándar toca el botón de transformación de la pantalla táctil, que la opción anterior desactiva. Esto reactiva la detección del HUD solo durante esos pocos fotogramas)"}, + {MenuLangId::French, "Le désactiver brièvement pendant une transformation par la méthode standard (La méthode standard appuie sur le bouton de transformation de l’écran tactile, que l’option ci-dessus désactive. Cela réactive la détection de l’ATH pendant ces quelques images seulement)"}, + {MenuLangId::Italian, "Disattivarlo brevemente durante una trasformazione con il metodo standard (Il metodo standard tocca il pulsante di trasformazione sullo schermo tattile, che l’opzione sopra disattiva. Questo riabilita il rilevamento dell’HUD solo per quei pochi fotogrammi)"}, + {MenuLangId::Dutch, "Even uitschakelen terwijl een transformatie via de standaardmethode wordt uitgevoerd (De standaardmethode tikt op de transformatieknop van het aanraakscherm, die de optie hierboven uitschakelt. Dit herstelt de HUD-detectie alleen voor die paar frames)"}, + {MenuLangId::Portuguese, "Desativar por breves instantes enquanto uma transformação pelo método padrão é acionada (O método padrão toca no botão de transformação do ecrã tátil, que a opção acima desativa. Isto reativa a deteção do HUD apenas durante esses poucos fotogramas)"}, + {MenuLangId::Russian, "Кратковременно отключать во время превращения стандартным методом (Стандартный метод нажимает кнопку превращения на сенсорном экране, которую отключает параметр выше. Это возвращает проверку попадания по HUD только на эти несколько кадров)"}, + {MenuLangId::ChineseSimplified, "标准方式变形发动期间临时关闭 (标准方式的变形会点击触摸屏上的变形按钮,而上面的设置会禁用它。本设置仅在那几帧内恢复 HUD 判定)"}, + {MenuLangId::ChineseTraditional, "標準方式變形發動期間暫時關閉 (標準方式的變形會點擊觸控螢幕上的變形按鈕,而上面的設定會停用它。本設定僅在那幾影格內恢復 HUD 判定)"}, + {MenuLangId::ChineseHongKong, "標準方式變形發動期間暫時關閉 (標準方式的變形會點擊觸控螢幕上的變形按鈕,而上面的設定會停用它。本設定僅在那幾影格內恢復 HUD 判定)"}, + {MenuLangId::Korean, "기본 방식 변형이 발동하는 동안만 일시적으로 끄기 (기본 방식의 변형은 터치스크린의 변형 버튼을 탭하지만, 위 설정이 이를 비활성화합니다. 이 설정은 그 몇 프레임 동안만 HUD 판정을 되돌립니다)"}, } }, { diff --git a/src/frontend/qt_sdl/MelonPrimeLocalization/inc/MelonPrimeTranslationsMetroidOptions.inc b/src/frontend/qt_sdl/MelonPrimeLocalization/inc/MelonPrimeTranslationsMetroidOptions.inc index 3d5e2d195a..49a7680cb4 100644 --- a/src/frontend/qt_sdl/MelonPrimeLocalization/inc/MelonPrimeTranslationsMetroidOptions.inc +++ b/src/frontend/qt_sdl/MelonPrimeLocalization/inc/MelonPrimeTranslationsMetroidOptions.inc @@ -162,84 +162,90 @@ } }, { - "Show Enemy HP Meter Online", + "Show Enemy Target Information Online", { - {MenuLangId::Japanese, "オンライン対戦で敵HPゲージを表示"}, - {MenuLangId::German, "Feindliche HP-Anzeige im Netzspiel anzeigen"}, - {MenuLangId::Spanish, "Mostrar indicador de HP del enemigo en red"}, - {MenuLangId::French, "Afficher la jauge HP ennemie en réseau"}, - {MenuLangId::Italian, "Mostra indicatore HP del nemico in rete"}, - {MenuLangId::Dutch, "Vijandelijke HP-balk in netwerkspel tonen"}, - {MenuLangId::Portuguese, "Mostrar medidor de HP do inimigo em rede"}, - {MenuLangId::Russian, "Показывать шкалу HP врага в сетевой игре"}, - {MenuLangId::ChineseSimplified, "联机时显示敌人 HP 条"}, - {MenuLangId::ChineseTraditional, "連線時顯示敵人 HP 條"}, - {MenuLangId::ChineseHongKong, "連線時顯示敵人 HP 條"}, - {MenuLangId::Korean, "온라인 대전에서 적 HP 게이지 표시"}, - {MenuLangId::Arabic, "إظهار مقياس HP للعدو في اللعب الشبكي"}, - {MenuLangId::Indonesian, "Tampilkan pengukur HP musuh saat bermain jaringan"}, - {MenuLangId::Ukrainian, "Показувати шкалу HP ворога в мережевій грі"}, - {MenuLangId::Greek, "Εμφάνιση μετρητή HP εχθρού σε δικτυακό παιχνίδι"}, - {MenuLangId::Swedish, "Visa fiendens HP-mätare vid nätspel"}, - {MenuLangId::Thai, "แสดงเกจ HP ศัตรูในการเล่นผ่านเครือข่าย"}, - {MenuLangId::Czech, "Zobrazit ukazatel HP nepřítele při síťové hře"}, - {MenuLangId::Danish, "Vis fjendens HP-måler ved netspil"}, - {MenuLangId::Turkish, "Ağ oyununda düşman HP göstergesini göster"}, - {MenuLangId::Norwegian, "Vis fiendens HP-måler i nettverksspill"}, - {MenuLangId::Hungarian, "Ellenség HP-mérőjének megjelenítése hálózati játékban"}, - {MenuLangId::Finnish, "Näytä vihollisen HP-mittari verkkopelissä"}, - {MenuLangId::Vietnamese, "Hiển thị thanh HP của địch khi chơi qua mạng"}, - {MenuLangId::Polish, "Pokaż wskaźnik HP wroga w grze sieciowej"}, - {MenuLangId::Romanian, "Afișează indicatorul HP al inamicului în jocul prin rețea"}, - {MenuLangId::Filipino, "Ipakita ang panukat ng HP ng kalaban sa larong pang-network"}, - {MenuLangId::Swahili, "Onyesha kipimo cha HP cha adui katika mchezo wa mtandao"}, - {MenuLangId::Croatian, "Prikaži mjerač HP-a neprijatelja u mrežnoj igri"}, - {MenuLangId::Icelandic, "Sýna HP-mæli óvinar í netspili"}, - {MenuLangId::Hindi, "नेटवर्क खेल में दुश्मन का HP मापक दिखाएँ"}, - {MenuLangId::Bengali, "নেটওয়ার্ক খেলায় শত্রুর HP মাপক দেখান"}, - {MenuLangId::Urdu, "نیٹ ورک کھیل میں دشمن کا HP پیمانہ دکھائیں"}, - {MenuLangId::Punjabi, "ਨੈੱਟਵਰਕ ਖੇਡ ਵਿੱਚ ਦੁਸ਼ਮਣ ਦਾ HP ਮਾਪਕ ਵੇਖਾਓ"}, - {MenuLangId::Telugu, "నెట్‌వర్క్ ఆటలో శత్రువు HP కొలమానాన్ని చూపించు"}, - {MenuLangId::Persian, "نمایش نوار HP دشمن در بازی شبکه‌ای"}, - {MenuLangId::Malay, "Papar tolok HP musuh dalam permainan rangkaian"}, - {MenuLangId::Marathi, "नेटवर्क खेळात शत्रूचा HP मापक दाखवा"}, - {MenuLangId::Tamil, "வலைப்பிணைப்பு விளையாட்டில் எதிரியின் HP அளவுகோலைக் காட்டு"}, - {MenuLangId::Gujarati, "નેટવર્ક રમતમાં શત્રુનો HP માપક બતાવો"}, - {MenuLangId::Kannada, "ಜಾಲಾಟದಲ್ಲಿ ಶತ್ರುವಿನ HP ಮಾಪಕವನ್ನು ತೋರಿಸಿ"}, - {MenuLangId::Odia, "ନେଟୱାର୍କ ଖେଳରେ ଶତ୍ରୁର HP ମାପକ ଦେଖାନ୍ତୁ"}, - {MenuLangId::Malayalam, "നെറ്റ്‌വർക്ക് കളിയിൽ ശത്രുവിന്റെ HP അളവുകോൽ കാണിക്കുക"}, - {MenuLangId::Burmese, "ကွန်ရက်ကစားမှုတွင် ရန်သူ HP တိုင်းကိရိယာကို ပြပါ"}, - {MenuLangId::Uzbek, "Tarmoq o‘yinida dushmanning HP o‘lchagichini ko‘rsatish"}, - {MenuLangId::Azerbaijani, "Şəbəkə oyununda düşmənin HP göstəricisini göstər"}, - {MenuLangId::Nepali, "नेटवर्क खेलमा शत्रुको HP मापक देखाउनुहोस्"}, - {MenuLangId::Sinhala, "මාර්ගගත ක්‍රීඩාවේ සතුරාගේ HP මීටරය පෙන්වන්න"}, - {MenuLangId::Khmer, "បង្ហាញរង្វាស់ HP របស់សត្រូវក្នុងការលេងបណ្តាញ"}, - {MenuLangId::Lao, "ສະແດງມາດວັດ HP ຂອງສັດຕູໃນການຫຼິ້ນຜ່ານເຄືອຂ່າຍ"}, - {MenuLangId::Armenian, "Ցույց տալ հակառակորդի HP ցուցիչը ցանցային խաղում"}, - {MenuLangId::Albanian, "Shfaq treguesin HP të armikut në lojën në rrjet"}, - {MenuLangId::Georgian, "ქსელურ თამაშში მტრის HP მაჩვენებლის ჩვენება"}, - {MenuLangId::Bosnian, "Prikaži mjerač HP-a neprijatelja u mrežnoj igri"}, - {MenuLangId::Serbian, "Прикажи мерач HP-а непријатеља у мрежној игри"}, - {MenuLangId::Macedonian, "Прикажи мерач на HP на непријателот во мрежна игра"}, - {MenuLangId::Bulgarian, "Показвай измерителя на HP на врага в мрежова игра"}, - {MenuLangId::Belarusian, "Паказваць шкалу HP ворага ў сеткавай гульні"}, - {MenuLangId::Maltese, "Uri l-kejl tal-HP tal-għadu fil-logħba tan-netwerk"}, - {MenuLangId::Mongolian, "Сүлжээний тоглолтод дайсны HP хэмжигчийг харуулах"}, - {MenuLangId::Latvian, "Rādīt ienaidnieka HP mērītāju tīkla spēlē"}, - {MenuLangId::Lithuanian, "Rodyti priešo HP matuoklį tinklo žaidime"}, - {MenuLangId::Afrikaans, "Wys vyand se HP-aanwyser in netwerkspel"}, - {MenuLangId::Irish, "Taispeáin tomhas HP an namhad i gcluiche líonra"}, - {MenuLangId::Assamese, "নেটৱৰ্ক খেলত শত্ৰুৰ HP মাপক দেখুৱাওক"}, - {MenuLangId::Amharic, "በአውታረመረብ ጨዋታ ውስጥ የጠላት HP መለኪያ አሳይ"}, - {MenuLangId::Estonian, "Kuva vaenlase HP-mõõdik võrgumängus"}, - {MenuLangId::Kazakh, "Желілік ойында қарсыластың HP көрсеткішін көрсету"}, - {MenuLangId::Catalan, "Mostra el mesurador d’HP de l’enemic en joc de xarxa"}, - {MenuLangId::Kyrgyz, "Тармак оюнунда душмандын HP көрсөткүчүн көрсөтүү"}, - {MenuLangId::Slovak, "Zobraziť ukazovateľ HP nepriateľa v sieťovej hre"}, - {MenuLangId::Slovenian, "Prikaži merilnik HP sovražnika v omrežni igri"}, - {MenuLangId::Zulu, "Bonisa isilinganiso se-HP sesitha emdlalweni wenethiwekhi"}, - {MenuLangId::Basque, "Erakutsi etsaiaren HP neurgailua sareko jokoan"}, - {MenuLangId::Hebrew, "הצג מד HP של אויב במשחק רשת"}, + {MenuLangId::English, "Show Enemy Target Information Online"}, + {MenuLangId::EnglishGB, "Show Enemy Target Information Online"}, + {MenuLangId::EnglishUS, "Show Enemy Target Information Online"}, + {MenuLangId::Japanese, "オンライン対戦で敵ターゲット情報を表示"}, + {MenuLangId::German, "Informationen zu feindlichen Zielen im Netzspiel anzeigen"}, + {MenuLangId::Spanish, "Mostrar información del objetivo enemigo en línea"}, + {MenuLangId::SpanishLatAm, "Mostrar información del objetivo enemigo en línea"}, + {MenuLangId::French, "Afficher les informations sur la cible ennemie en ligne"}, + {MenuLangId::FrenchCanada, "Afficher les informations sur la cible ennemie en ligne"}, + {MenuLangId::Italian, "Mostra informazioni sul bersaglio nemico online"}, + {MenuLangId::Dutch, "Informatie over vijandelijke doelen in netwerkspel tonen"}, + {MenuLangId::Portuguese, "Mostrar informações do alvo inimigo online"}, + {MenuLangId::PortugueseBrazil, "Mostrar informações do alvo inimigo online"}, + {MenuLangId::Russian, "Показывать информацию о цели врага в сетевой игре"}, + {MenuLangId::ChineseSimplified, "联机时显示敌方目标信息"}, + {MenuLangId::ChineseTraditional, "連線時顯示敵方目標資訊"}, + {MenuLangId::ChineseHongKong, "連線時顯示敵方目標資訊"}, + {MenuLangId::Korean, "온라인 대전에서 적 대상 정보 표시"}, + {MenuLangId::Arabic, "إظهار معلومات هدف العدو في اللعب الشبكي"}, + {MenuLangId::Indonesian, "Tampilkan informasi target musuh saat bermain jaringan"}, + {MenuLangId::Ukrainian, "Показувати інформацію про ціль ворога в мережевій грі"}, + {MenuLangId::Greek, "Εμφάνιση πληροφοριών στόχου εχθρού σε δικτυακό παιχνίδι"}, + {MenuLangId::Swedish, "Visa information om fiendens mål vid nätspel"}, + {MenuLangId::Thai, "แสดงข้อมูลเป้าหมายของศัตรูในการเล่นผ่านเครือข่าย"}, + {MenuLangId::Czech, "Zobrazit informace o cíli nepřítele při síťové hře"}, + {MenuLangId::Danish, "Vis oplysninger om fjendens mål ved netspil"}, + {MenuLangId::Turkish, "Ağ oyununda düşman hedef bilgilerini göster"}, + {MenuLangId::Norwegian, "Vis informasjon om fiendens mål i nettverksspill"}, + {MenuLangId::Hungarian, "Ellenséges célpont adatainak megjelenítése hálózati játékban"}, + {MenuLangId::Finnish, "Näytä vihollisen kohteen tiedot verkkopelissä"}, + {MenuLangId::Vietnamese, "Hiển thị thông tin mục tiêu địch khi chơi qua mạng"}, + {MenuLangId::Polish, "Pokaż informacje o celu wroga w grze sieciowej"}, + {MenuLangId::Romanian, "Afișează informațiile despre ținta inamicului în jocul prin rețea"}, + {MenuLangId::Filipino, "Ipakita ang impormasyon ng target ng kalaban sa larong pang-network"}, + {MenuLangId::Swahili, "Onyesha taarifa ya shabaha ya adui katika mchezo wa mtandao"}, + {MenuLangId::Croatian, "Prikaži podatke o meti neprijatelja u mrežnoj igri"}, + {MenuLangId::Icelandic, "Sýna upplýsingar um skotmark óvinar í netspili"}, + {MenuLangId::Hindi, "नेटवर्क खेल में दुश्मन के लक्ष्य की जानकारी दिखाएँ"}, + {MenuLangId::Bengali, "নেটওয়ার্ক খেলায় শত্রুর লক্ষ্যের তথ্য দেখান"}, + {MenuLangId::Urdu, "نیٹ ورک کھیل میں دشمن کے ہدف کی معلومات دکھائیں"}, + {MenuLangId::Punjabi, "ਨੈੱਟਵਰਕ ਖੇਡ ਵਿੱਚ ਦੁਸ਼ਮਣ ਦੇ ਨਿਸ਼ਾਨੇ ਦੀ ਜਾਣਕਾਰੀ ਵੇਖਾਓ"}, + {MenuLangId::Telugu, "నెట్‌వర్క్ ఆటలో శత్రువు లక్ష్య సమాచారాన్ని చూపించు"}, + {MenuLangId::Persian, "نمایش اطلاعات هدف دشمن در بازی شبکه‌ای"}, + {MenuLangId::Malay, "Papar maklumat sasaran musuh dalam permainan rangkaian"}, + {MenuLangId::Marathi, "नेटवर्क खेळात शत्रूच्या लक्ष्याची माहिती दाखवा"}, + {MenuLangId::Tamil, "வலைப்பிணைப்பு விளையாட்டில் எதிரியின் இலக்கு தகவலைக் காட்டு"}, + {MenuLangId::Gujarati, "નેટવર્ક રમતમાં શત્રુના લક્ષ્યની માહિતી બતાવો"}, + {MenuLangId::Kannada, "ಜಾಲಾಟದಲ್ಲಿ ಶತ್ರುವಿನ ಗುರಿ ಮಾಹಿತಿಯನ್ನು ತೋರಿಸಿ"}, + {MenuLangId::Odia, "ନେଟୱାର୍କ ଖେଳରେ ଶତ୍ରୁର ଲକ୍ଷ୍ୟ ସୂଚନା ଦେଖାନ୍ତୁ"}, + {MenuLangId::Malayalam, "നെറ്റ്‌വർക്ക് കളിയിൽ ശത്രുവിന്റെ ലക്ഷ്യ വിവരങ്ങൾ കാണിക്കുക"}, + {MenuLangId::Burmese, "ကွန်ရက်ကစားမှုတွင် ရန်သူပစ်မှတ်အချက်အလက်ကို ပြပါ"}, + {MenuLangId::Uzbek, "Tarmoq o‘yinida dushmanning nishon ma’lumotlarini ko‘rsatish"}, + {MenuLangId::Azerbaijani, "Şəbəkə oyununda düşmənin hədəf məlumatını göstər"}, + {MenuLangId::Nepali, "नेटवर्क खेलमा शत्रुको लक्ष्य जानकारी देखाउनुहोस्"}, + {MenuLangId::Sinhala, "මාර්ගගත ක්‍රීඩාවේ සතුරාගේ ඉලක්ක තොරතුරු පෙන්වන්න"}, + {MenuLangId::Khmer, "បង្ហាញព័ត៌មានគោលដៅរបស់សត្រូវក្នុងការលេងបណ្តាញ"}, + {MenuLangId::Lao, "ສະແດງຂໍ້ມູນເປົ້າໝາຍຂອງສັດຕູໃນການຫຼິ້ນຜ່ານເຄືອຂ່າຍ"}, + {MenuLangId::Armenian, "Ցույց տալ հակառակորդի թիրախի տվյալները ցանցային խաղում"}, + {MenuLangId::Albanian, "Shfaq informacionin e objektivit të armikut në lojën në rrjet"}, + {MenuLangId::Georgian, "ქსელურ თამაშში მტრის სამიზნის ინფორმაციის ჩვენება"}, + {MenuLangId::Bosnian, "Prikaži podatke o meti neprijatelja u mrežnoj igri"}, + {MenuLangId::Serbian, "Прикажи податке о мети непријатеља у мрежној игри"}, + {MenuLangId::Macedonian, "Прикажи информации за целта на непријателот во мрежна игра"}, + {MenuLangId::Bulgarian, "Показвай информация за целта на врага в мрежова игра"}, + {MenuLangId::Belarusian, "Паказваць інфармацыю пра мэту ворага ў сеткавай гульні"}, + {MenuLangId::Maltese, "Uri l-informazzjoni tal-mira tal-għadu fil-logħba tan-netwerk"}, + {MenuLangId::Mongolian, "Сүлжээний тоглолтод дайсны байны мэдээллийг харуулах"}, + {MenuLangId::Latvian, "Rādīt informāciju par ienaidnieka mērķi tīkla spēlē"}, + {MenuLangId::Lithuanian, "Rodyti priešo taikinio informaciją tinklo žaidime"}, + {MenuLangId::Afrikaans, "Wys inligting oor die vyand se teiken in netwerkspel"}, + {MenuLangId::Irish, "Taispeáin eolas faoi sprioc an namhad i gcluiche líonra"}, + {MenuLangId::Assamese, "নেটৱৰ্ক খেলত শত্ৰুৰ লক্ষ্যৰ তথ্য দেখুৱাওক"}, + {MenuLangId::Amharic, "በአውታረመረብ ጨዋታ ውስጥ የጠላት ዒላማ መረጃ አሳይ"}, + {MenuLangId::Estonian, "Kuva vaenlase sihtmärgi teave võrgumängus"}, + {MenuLangId::Kazakh, "Желілік ойында қарсыластың нысана ақпаратын көрсету"}, + {MenuLangId::Catalan, "Mostra la informació de l’objectiu enemic en joc de xarxa"}, + {MenuLangId::Kyrgyz, "Тармак оюнунда душмандын бутасы тууралуу маалыматты көрсөтүү"}, + {MenuLangId::Slovak, "Zobraziť informácie o cieli nepriateľa v sieťovej hre"}, + {MenuLangId::Slovenian, "Prikaži informacije o tarči sovražnika v omrežni igri"}, + {MenuLangId::Zulu, "Bonisa ulwazi lwenhloso yesitha emdlalweni wenethiwekhi"}, + {MenuLangId::Basque, "Erakutsi etsaiaren helburuaren informazioa sareko jokoan"}, + {MenuLangId::Hebrew, "הצג מידע על יעד האויב במשחק רשת"}, } }, { diff --git a/src/frontend/qt_sdl/MelonPrimePatchDirectInvocationHook.inc b/src/frontend/qt_sdl/MelonPrimePatchDirectInvocationHook.inc index 4ca56a1098..ebcc69a532 100644 --- a/src/frontend/qt_sdl/MelonPrimePatchDirectInvocationHook.inc +++ b/src/frontend/qt_sdl/MelonPrimePatchDirectInvocationHook.inc @@ -454,7 +454,8 @@ if (!m_flags.test(StateFlags::BIT_IN_GAME_INIT) || !m_flags.test(StateFlags::BIT_BATTLE_RUNTIME_MODE) || !m_flags.test(StateFlags::BIT_LAST_FOCUSED) - || (m_aimBlockBits & AIMBLK_NOT_IN_GAME)) + || (m_aimBlockBits & AIMBLK_NOT_IN_GAME) + || !IsLocalPlayerAlive()) { return; } @@ -524,7 +525,8 @@ // it either. Without this a request queued during the join/countdown // could fire on the very first battle-runtime frame. if (!m_flags.test(StateFlags::BIT_IN_GAME_INIT) - || !m_flags.test(StateFlags::BIT_BATTLE_RUNTIME_MODE)) + || !m_flags.test(StateFlags::BIT_BATTLE_RUNTIME_MODE) + || !IsLocalPlayerAlive()) { m_directInvocationPending.Clear(); return false; @@ -559,6 +561,16 @@ if (localPlayer == 0 || player != localPlayer) return false; + // Spawn barrier: this is the first input hook of the update that just + // respawned the player. A pressed edge from across that boundary is + // dropped, not deferred -- replaying it on the next frame is exactly + // the behaviour to avoid. The hook returns false, so the site's own + // bl ProcessTouchInput runs untouched. + if (UNLIKELY(IsFirstPostSpawnInput(nds, player))) { + m_directInvocationPending.Clear(); + return false; + } + if (!DirectInvocation_EnsureTrampoline(nds, *site)) return false; diff --git a/src/frontend/qt_sdl/MelonPrimePatchImmediateTransformGateHook.inc b/src/frontend/qt_sdl/MelonPrimePatchImmediateTransformGateHook.inc index a06e9f9b33..d0684b72da 100644 --- a/src/frontend/qt_sdl/MelonPrimePatchImmediateTransformGateHook.inc +++ b/src/frontend/qt_sdl/MelonPrimePatchImmediateTransformGateHook.inc @@ -153,6 +153,10 @@ return false; if (m_aimBlockBits & AIMBLK_NOT_IN_GAME) return false; + if (!IsLocalPlayerAlive()) { + m_directTransformPendingFrames = 0; + return false; + } const TransformGateEntry* const entry = TransformGate_Find(m_currentRom.romGroupIndex, arm9ExecAddr); @@ -170,6 +174,14 @@ if (playerInRegs != localPlayer) return false; + // Same spawn barrier as the other native methods: drop rather than + // defer a pressed edge that crossed the respawn boundary. + if (UNLIKELY(IsFirstPostSpawnInput(nds, playerInRegs))) { + m_directTransformPendingFrames = 0; + m_input.press &= ~IB_MORPH; + return false; + } + // The request is held for a few frames by HandleRareMorph so a host // edge is not lost when the game skips this gate on the exact press // frame. Consume it here so Gate A and Gate B cannot both dispatch it. diff --git a/src/frontend/qt_sdl/MelonPrimePatchLifecycle.h b/src/frontend/qt_sdl/MelonPrimePatchLifecycle.h index b6212c03b0..da1c17c8e7 100644 --- a/src/frontend/qt_sdl/MelonPrimePatchLifecycle.h +++ b/src/frontend/qt_sdl/MelonPrimePatchLifecycle.h @@ -76,7 +76,9 @@ void RestoreOnMatchEnd(melonDS::NDS* nds, // Step 3 / Site B (see melonprime_patch_lifecycle_gateway_step3_plan.md). // Called once from HandleBattleRuntimeEnter() on the first -// mode==MODE_BATTLE_RUNTIME && flow==FLOW_ACTIVE_MATCH frame after join. +// frame after join on which the local player is in play (HP != 0), having +// already seen mode==MODE_BATTLE_RUNTIME && flow==FLOW_ACTIVE_MATCH at least +// once. The two stages need not fall on the same frame. // Applies battle-runtime static patches, activates match ARM9 hooks, and // validates/installs the guest trampoline of every enabled native path // (weapon switch Method 1, DirectInvocation Method 2/3) so the cave is diff --git a/src/frontend/qt_sdl/MelonPrimePatchNativeZoomToggleHook.inc b/src/frontend/qt_sdl/MelonPrimePatchNativeZoomToggleHook.inc index 4b7fda521f..a05630a883 100644 --- a/src/frontend/qt_sdl/MelonPrimePatchNativeZoomToggleHook.inc +++ b/src/frontend/qt_sdl/MelonPrimePatchNativeZoomToggleHook.inc @@ -211,7 +211,8 @@ if (!m_flags.test(StateFlags::BIT_IN_GAME_INIT) || !m_flags.test(StateFlags::BIT_LAST_FOCUSED) - || (m_aimBlockBits & AIMBLK_NOT_IN_GAME)) + || (m_aimBlockBits & AIMBLK_NOT_IN_GAME) + || !IsLocalPlayerAlive()) { return; } @@ -278,6 +279,11 @@ if (!nds || !m_nativeZoomPending.Pending) return false; + if (!IsLocalPlayerAlive()) { + m_nativeZoomPending.Clear(); + return false; + } + const NativeZoomToggleSite* const site = NativeZoomToggle_GetSite(m_currentRom.romGroupIndex); if (!site || arm9ExecAddr != site->WeaponActionUpdate) @@ -290,6 +296,12 @@ return false; } + // Same spawn barrier as the other native methods. + if (UNLIKELY(IsFirstPostSpawnInput(nds, m_nativeZoomPending.Player))) { + m_nativeZoomPending.Clear(); + return false; + } + if (!NativeZoomToggle_EnsureTrampoline(nds)) return false; diff --git a/src/frontend/qt_sdl/MelonPrimePatchRegistry.h b/src/frontend/qt_sdl/MelonPrimePatchRegistry.h index cfcdf13858..eb5dc5895c 100644 --- a/src/frontend/qt_sdl/MelonPrimePatchRegistry.h +++ b/src/frontend/qt_sdl/MelonPrimePatchRegistry.h @@ -50,7 +50,7 @@ namespace MelonPrime { PatchSite_GameJoin = 1u << 0, // HandleGameJoinInit (once per in-game join) PatchSite_ConfigReload = 1u << 1, // ApplyConfigReload (only when ROM detected) PatchSite_OutOfGameFrame = 1u << 2, // RunFrameHook !isInGame && focused (per frame; entries self-guard) - PatchSite_BattleRuntime = 1u << 3, // first frame with mode==0x0E && flow==0 after join + PatchSite_BattleRuntime = 1u << 3, // first frame with local HP!=0 after mode==0x0E && flow==0 was seen }; // Restore behavior flags (bitmask). Entries without flags have no RAM diff --git a/src/frontend/qt_sdl/MelonPrimePatchTouchScreenAimOnly.cpp b/src/frontend/qt_sdl/MelonPrimePatchTouchScreenAimOnly.cpp index 006b949fdd..b5a0ee2267 100644 --- a/src/frontend/qt_sdl/MelonPrimePatchTouchScreenAimOnly.cpp +++ b/src/frontend/qt_sdl/MelonPrimePatchTouchScreenAimOnly.cpp @@ -10,6 +10,7 @@ namespace MelonPrime { namespace { static constexpr const char* kCfgTouchScreenAimOnly = MelonPrime::CfgKey::TouchScreenAimOnly; +static constexpr const char* kCfgStylusMode = MelonPrime::CfgKey::StylusMode; // Battle spatial aim-only (in-match touch screen). // @@ -73,7 +74,7 @@ static const StaticWordPatch s_patch(kPatchSpans); void TouchScreenAimOnly_ApplyOnce(MelonPrimePatchState& state, melonDS::NDS* nds, Config::Table& cfg, uint8_t romGroupIndex) { - if (!cfg.GetBool(kCfgTouchScreenAimOnly)) + if (!cfg.GetBool(kCfgStylusMode) || !cfg.GetBool(kCfgTouchScreenAimOnly)) { s_patch.RestoreOnce(state.touchScreenAimOnly, nds, romGroupIndex); return; diff --git a/src/frontend/qt_sdl/MelonPrimePatchWeaponSwitchHook.inc b/src/frontend/qt_sdl/MelonPrimePatchWeaponSwitchHook.inc index af1ffff832..8f8e96e28f 100644 --- a/src/frontend/qt_sdl/MelonPrimePatchWeaponSwitchHook.inc +++ b/src/frontend/qt_sdl/MelonPrimePatchWeaponSwitchHook.inc @@ -214,6 +214,11 @@ if (!m_weaponSwitchPending.IsValid()) return false; + if (!IsLocalPlayerAlive()) { + m_weaponSwitchPending.Clear(); + return false; + } + if (!m_flags.test(StateFlags::BIT_IN_GAME_INIT)) { MP_WEAPON_SWITCH_LOG( "WeaponSwitch GateFail: inGameInit=0 pending=%u exec=%08X\n", @@ -300,6 +305,20 @@ return false; } + // Same spawn barrier as the other native methods, and the only spawn + // guard this path has: the producer no longer refuses the whole + // invulnerability window. + if (UNLIKELY(IsFirstPostSpawnInput(nds, player))) { + MP_WEAPON_SWITCH_LOG( + "WeaponSwitch SpawnBarrier: exec=%08X player=%08X pending=%u +", + arm9ExecAddr, + player, + m_weaponSwitchPending.WeaponId); + m_weaponSwitchPending.Clear(); + return false; + } + if (m_weaponSwitchPending.RetryCount == 0) { MP_WEAPON_SWITCH_LOG( "WeaponSwitch RetryExhausted: exec=%08X pending=%u\n", diff --git a/src/frontend/qt_sdl/MelonPrimeRuntimeConfig.cpp b/src/frontend/qt_sdl/MelonPrimeRuntimeConfig.cpp index 00b38b75dc..d948ffb257 100644 --- a/src/frontend/qt_sdl/MelonPrimeRuntimeConfig.cpp +++ b/src/frontend/qt_sdl/MelonPrimeRuntimeConfig.cpp @@ -109,14 +109,14 @@ RuntimeConfigSnapshot LoadRuntimeConfigSnapshot(Config::Table& cfg) noexcept #endif const int zoomInputMethod = cfg.GetInt(CfgKey::ZoomInputMethod); -#ifdef MELONPRIME_ENABLE_DEVELOPER_FEATURES - s.nativeZoomToggle = - zoomInputMethod == ZoomInputMethod::NewNativeToggle; - s.directInvocationZoom = - zoomInputMethod == ZoomInputMethod::NewDirectInvocation; -#else + // Standard (LegacyFixedR, including the retired value 1) is the normal + // zoom path in every build. Only the experimental native methods below + // are restricted to developer builds. s.nativeZoomToggle = false; s.directInvocationZoom = false; +#ifdef MELONPRIME_ENABLE_DEVELOPER_FEATURES + s.nativeZoomToggle = zoomInputMethod == ZoomInputMethod::NewNativeToggle; + s.directInvocationZoom = zoomInputMethod == ZoomInputMethod::NewDirectInvocation; #endif const int zoomAimScalePct = std::clamp(cfg.GetInt(CfgKey::ZoomAimScalePct), 10, 300); @@ -138,6 +138,9 @@ RuntimeConfigSnapshot LoadRuntimeConfigSnapshot(Config::Table& cfg) noexcept morphBoostRequiredMovement <= 0 ? 90 : morphBoostRequiredMovement); // MELONPRIME_MORPH_BOOST_MODE_CONTROLS_V14 #ifdef MELONPRIME_DS + s.touchScreenAimOnlySuspendForTransform = + cfg.GetBool(CfgKey::TouchScreenAimOnlySuspendForTransform); + s.outOfGamePatches.fixWifiEnabled = cfg.GetBool(CfgKey::WifiBitset); s.outOfGamePatches.useFirmwareLanguageEnabled = cfg.GetBool(CfgKey::UseFirmwareLanguage); diff --git a/src/frontend/qt_sdl/MelonPrimeRuntimeConfig.h b/src/frontend/qt_sdl/MelonPrimeRuntimeConfig.h index 25f9149af5..84845d0c0e 100644 --- a/src/frontend/qt_sdl/MelonPrimeRuntimeConfig.h +++ b/src/frontend/qt_sdl/MelonPrimeRuntimeConfig.h @@ -70,6 +70,9 @@ struct RuntimeConfigSnapshot { bool joy2Key = false; bool snapTap = false; bool stylusMode = false; + // Sub-option of the TouchScreenAimOnly battle patch: lift it for the few + // frames the Standard transform taps the touch-screen Transform button. + bool touchScreenAimOnlySuspendForTransform = false; bool disableMphAimSmoothing = false; bool aimAccumulator = false; diff --git a/src/frontend/qt_sdl/Screen.cpp b/src/frontend/qt_sdl/Screen.cpp index aa4df68acb..93da74ba47 100755 --- a/src/frontend/qt_sdl/Screen.cpp +++ b/src/frontend/qt_sdl/Screen.cpp @@ -707,7 +707,9 @@ void ScreenPanel::loadConfig() screenAspectBot = cfg.GetInt("ScreenAspectBot"); inGameTopScreenOnly = emuInstance->getLocalConfig().GetBool(MP_HUD_PROP_KEY_InGameTopScreenOnly); #ifdef MELONPRIME_DS - topScreenTouchEnabled = emuInstance->getLocalConfig().GetBool(MelonPrime::CfgKey::TopScreenTouch); + auto& metroidCfg = emuInstance->getLocalConfig(); + topScreenTouchEnabled = metroidCfg.GetBool(MelonPrime::CfgKey::StylusMode) + && metroidCfg.GetBool(MelonPrime::CfgKey::TopScreenTouch); loadMelonPrimeStylusCursorConfig(); #endif } @@ -715,7 +717,9 @@ void ScreenPanel::loadConfig() #ifdef MELONPRIME_DS void ScreenPanel::refreshTopScreenTouchSetting() { - const bool enabled = emuInstance->getLocalConfig().GetBool(MelonPrime::CfgKey::TopScreenTouch); + auto& cfg = emuInstance->getLocalConfig(); + const bool enabled = cfg.GetBool(MelonPrime::CfgKey::StylusMode) + && cfg.GetBool(MelonPrime::CfgKey::TopScreenTouch); if (!enabled && topScreenTouchTransform >= 0 && touching) { emuInstance->releaseScreen(); @@ -729,11 +733,13 @@ void ScreenPanel::refreshTopScreenTouchSetting() void ScreenPanel::loadMelonPrimeStylusCursorConfig() { auto& cfg = emuInstance->getLocalConfig(); - stylusHideCursorInGameEnabled = cfg.GetBool(MelonPrime::CfgKey::StylusHideCursorInGame); - stylusConfineCursorToTopScreenEnabled = - cfg.GetBool(MelonPrime::CfgKey::StylusConfineCursorToTopScreen); - stylusHoldCursorAtCenterEnabled = - cfg.GetBool(MelonPrime::CfgKey::StylusHoldCursorAtCenterWhenNotClicking); + const bool stylusModeEnabled = cfg.GetBool(MelonPrime::CfgKey::StylusMode); + stylusHideCursorInGameEnabled = stylusModeEnabled + && cfg.GetBool(MelonPrime::CfgKey::StylusHideCursorInGame); + stylusConfineCursorToTopScreenEnabled = stylusModeEnabled + && cfg.GetBool(MelonPrime::CfgKey::StylusConfineCursorToTopScreen); + stylusHoldCursorAtCenterEnabled = stylusModeEnabled + && cfg.GetBool(MelonPrime::CfgKey::StylusHoldCursorAtCenterWhenNotClicking); stylusMatchCursorOptionsEnabled = stylusHideCursorInGameEnabled || stylusConfineCursorToTopScreenEnabled || stylusHoldCursorAtCenterEnabled; diff --git a/src/frontend/qt_sdl/VideoSettingsDialog.cpp b/src/frontend/qt_sdl/VideoSettingsDialog.cpp index 8bdbd64831..641506d35c 100644 --- a/src/frontend/qt_sdl/VideoSettingsDialog.cpp +++ b/src/frontend/qt_sdl/VideoSettingsDialog.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "types.h" @@ -97,6 +98,28 @@ QString DX12HiresCoordinatesDescription() } // namespace #endif +#ifdef MELONPRIME_DS +namespace +{ + +bool RendererForcesHiresCoordinates(int renderer) +{ + if (renderer == renderer3D_OpenGLCompute) + return true; +#if defined(MELONPRIME_ENABLE_VULKAN) + if (renderer == renderer3D_Vulkan) + return true; +#endif +#if defined(_WIN32) && defined(MELONPRIME_ENABLE_DX12) + if (renderer == renderer3D_DX12) + return true; +#endif + return false; +} + +} // namespace +#endif + #if defined(MELONPRIME_DS) && defined(__APPLE__) && defined(MELONPRIME_ENABLE_METAL) namespace { @@ -231,10 +254,20 @@ void VideoSettingsDialog::setEnabled() ui->cbBetterPolygons->setWhatsThis(betterPolygonsDescription); #endif - // Every compute backend uses this directly. Metal raster also consumes it - // when its internal scale is above native resolution. + // OpenGL Compute, Vulkan and DirectX 12 always use high-resolution + // coordinates above 1x. Reflect that renderer contract in the shared + // control and configuration; their rendering paths also force the value + // independently of this UI. + const bool forceHiresCoordinates = + computeRenderer || vulkanRenderer || dx12Renderer; + if (forceHiresCoordinates) + { + const QSignalBlocker blocker(ui->cbxComputeHiResCoords); + ui->cbxComputeHiResCoords->setChecked(true); + cfg.SetBool("3D.GL.HiresCoordinates", true); + } ui->cbxComputeHiResCoords->setEnabled( - computeRenderer || metalRenderer || vulkanRenderer || dx12Renderer); + !forceHiresCoordinates && metalRenderer); #ifdef MELONPRIME_DS constexpr const char* originalHiresCoordinatesHelp = "MelonPrimeOriginalHiresCoordinatesHelp"; @@ -374,6 +407,13 @@ VideoSettingsDialog::VideoSettingsDialog(QWidget* parent) : QDialog(parent), ui( oldGLScale = cfg.GetInt("3D.GL.ScaleFactor"); oldGLBetterPolygons = cfg.GetBool("3D.GL.BetterPolygons"); oldHiresCoordinates = cfg.GetBool("3D.GL.HiresCoordinates"); +#ifdef MELONPRIME_DS + if (RendererForcesHiresCoordinates(oldRenderer)) + { + oldHiresCoordinates = true; + cfg.SetBool("3D.GL.HiresCoordinates", true); + } +#endif #if defined(MELONPRIME_DS) && (defined(MELONPRIME_ENABLE_VULKAN) \ || (defined(_WIN32) && defined(MELONPRIME_ENABLE_DX12))) oldNvidiaReflexMode = cfg.GetInt(MelonPrime::CfgKey::NvidiaReflexMode); @@ -941,7 +981,18 @@ void VideoSettingsDialog::on_cbBetterPolygons_stateChanged(int state) void VideoSettingsDialog::on_cbxComputeHiResCoords_stateChanged(int state) { auto& cfg = emuInstance->getGlobalConfig(); - cfg.SetBool("3D.GL.HiresCoordinates", (state != 0)); + const bool forced = +#ifdef MELONPRIME_DS + RendererForcesHiresCoordinates(cfg.GetInt("3D.Renderer")); +#else + false; +#endif + if (forced && state == 0) + { + const QSignalBlocker blocker(ui->cbxComputeHiResCoords); + ui->cbxComputeHiResCoords->setChecked(true); + } + cfg.SetBool("3D.GL.HiresCoordinates", forced || state != 0); emit updateVideoSettings(false); } diff --git a/tools/ci/audits/audit-raster-software-parity.py b/tools/ci/audits/audit-raster-software-parity.py index 32e87682a5..0c661067bb 100644 --- a/tools/ci/audits/audit-raster-software-parity.py +++ b/tools/ci/audits/audit-raster-software-parity.py @@ -67,6 +67,7 @@ def main() -> int: soft_header = read("src/GPU3D_Soft.h") soft_cpp = read("src/GPU3D_Soft.cpp") gl_cpp = read("src/GPU3D_Compute.cpp") + gl_wrapper = read("src/GPU_OpenGL.cpp") gl_shader = read("src/GPU3D_Compute_shaders.h") edge_vectors = read("tools/testing/raster-edge-vectors.cpp") variant_index = read("src/GPU3D_FixedVariantIndex.h") @@ -436,8 +437,25 @@ def main() -> int: require(video_settings, "MetalComputeBetterPolygonsDescription", "Metal Compute polygon-splitting UI explanation", failures) require(video_settings, - "computeRenderer || metalRenderer || vulkanRenderer || dx12Renderer", - "Metal high-resolution-coordinate UI gate", failures) + "computeRenderer || vulkanRenderer || dx12Renderer;", + "compute backend high-resolution-coordinate force", failures) + require(video_settings, "ui->cbxComputeHiResCoords->setChecked(true);", + "compute backend high-resolution-coordinate checked UI", failures) + require(video_settings, + "!forceHiresCoordinates && metalRenderer", + "compute backend high-resolution-coordinate locked UI", failures) + require(gl_wrapper, "SetRenderSettings(settings.ScaleFactor, true)", + "OpenGL Compute forced high-resolution coordinates", failures) + require(vk_wrapper, "SetRenderSettings(settings.ScaleFactor, true)", + "Vulkan forced high-resolution coordinates", failures) + require(dx_wrapper, "SetRenderSettings(settings.ScaleFactor, true)", + "DX12 forced high-resolution coordinates", failures) + require(gl_cpp, "HiresCoordinates && ScaleFactor > 1", + "OpenGL Compute native-1x coordinate bypass", failures) + require(vk_cpp, "HiresCoordinates && ScaleFactor > 1", + "Vulkan native-1x coordinate bypass", failures) + require(dx_cpp, "HiresCoordinates && ScaleFactor > 1", + "DX12 native-1x coordinate bypass", failures) require(metal_span, "swapped ? 0 : 31", "Metal swapped vertical coverage", failures) require(vk_interp, "swappedEdges", "Vulkan swapped edge path", failures)