From 598ee1a16ea355a8154d24396b2eeb6577f922c8 Mon Sep 17 00:00:00 2001 From: MaxsTechReview Date: Wed, 5 Aug 2026 15:43:33 -0400 Subject: [PATCH 1/3] Open the retro menu from the guide button in the 3D engine, and import the Stadium ROM The guide button opened the in-game menu everywhere except the voxel engine. RetroActivity, ARMSX2's MainActivityRuntime and Dolphin's EmulationActivity all handle KEYCODE_BUTTON_MODE; Gen1EngineActivity handled only BACK, and onButton drops anything that is not A, B, START or SELECT, so a physical guide press reached nothing. It now toggles the drawer the way the libretro path does, gated on a gamepad source so a TV remote cannot trip it. Dolphin's Wii branch is left alone: it maps that button to the Wiimote HOME key on purpose. STADIUM ROM is a row the mod publishes on every platform, but its import only works where LOVE has a file dialog, which on Android is nowhere -- so the row could only ever print a folder path. The mod already watches for picked_stadium.z64 in its save directory on every frame and builds from it (main.lua calls StadiumRomPick.poll for exactly this), so the row now opens the system picker, stages the file under that name and lets the mod do the rest. No engine or mod change, and no restart: the build starts within a frame and the mod shows its own progress. Once the models exist the row reads READY and opens a Keep/Delete prompt rather than importing again; Delete drops the built pack and any base ROM left behind. The ROM is checked for an N64 magic and a plausible size before it is staged, and it is written to a .part file and renamed so the mod's poll can never see a half-written file. Selecting STADIUM A or B without a ROM was not reachable to begin with: the mod gates those two rungs off the 3D-BTL ladder behind StadiumInstall.available(), so they appear on their own once the import finishes. --- .../main/feature/retro/Gen1EngineActivity.kt | 92 +++++++++++++++++++ app/src/main/feature/retro/Gen1StadiumRom.kt | 86 +++++++++++++++++ app/src/main/res/values-b+es+419/strings.xml | 13 +++ app/src/main/res/values-da/strings.xml | 13 +++ app/src/main/res/values-de/strings.xml | 13 +++ app/src/main/res/values-es/strings.xml | 13 +++ app/src/main/res/values-fi/strings.xml | 13 +++ app/src/main/res/values-fr/strings.xml | 13 +++ app/src/main/res/values-hi/strings.xml | 13 +++ app/src/main/res/values-it/strings.xml | 13 +++ app/src/main/res/values-ja/strings.xml | 13 +++ app/src/main/res/values-ko/strings.xml | 13 +++ app/src/main/res/values-no/strings.xml | 13 +++ app/src/main/res/values-pl/strings.xml | 13 +++ app/src/main/res/values-pt-rBR/strings.xml | 13 +++ app/src/main/res/values-pt/strings.xml | 13 +++ app/src/main/res/values-ro/strings.xml | 13 +++ app/src/main/res/values-ru/strings.xml | 13 +++ app/src/main/res/values-sv/strings.xml | 13 +++ app/src/main/res/values-th/strings.xml | 13 +++ app/src/main/res/values-tr/strings.xml | 13 +++ app/src/main/res/values-uk/strings.xml | 13 +++ app/src/main/res/values-zh-rCN/strings.xml | 13 +++ app/src/main/res/values-zh-rTW/strings.xml | 13 +++ app/src/main/res/values/strings.xml | 13 +++ 25 files changed, 477 insertions(+) create mode 100644 app/src/main/feature/retro/Gen1StadiumRom.kt diff --git a/app/src/main/feature/retro/Gen1EngineActivity.kt b/app/src/main/feature/retro/Gen1EngineActivity.kt index f4a71f844..b72b48970 100644 --- a/app/src/main/feature/retro/Gen1EngineActivity.kt +++ b/app/src/main/feature/retro/Gen1EngineActivity.kt @@ -20,8 +20,12 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleRegistry import androidx.lifecycle.ViewModelStore import androidx.lifecycle.ViewModelStoreOwner +import androidx.lifecycle.lifecycleScope import androidx.lifecycle.setViewTreeLifecycleOwner import androidx.lifecycle.setViewTreeViewModelStoreOwner +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import androidx.savedstate.SavedStateRegistry import androidx.savedstate.SavedStateRegistryController import androidx.savedstate.SavedStateRegistryOwner @@ -163,6 +167,12 @@ class Gen1EngineActivity : override fun dispatchKeyEvent(event: android.view.KeyEvent): Boolean { val keyCode = event.keyCode + if (keyCode == android.view.KeyEvent.KEYCODE_BUTTON_MODE && isGamepadSource(event)) { + if (event.action == android.view.KeyEvent.ACTION_UP) { + if (menu.visible) menu.close() else openMenu() + } + return true + } if (keyCode == android.view.KeyEvent.KEYCODE_BACK) { if (event.action == android.view.KeyEvent.ACTION_UP) { if (menu.visible) { @@ -225,8 +235,88 @@ class Gen1EngineActivity : else -> RetroPane.SYSTEM } + private fun isGamepadSource(event: android.view.KeyEvent): Boolean { + val source = event.device?.sources ?: return false + return source and android.view.InputDevice.SOURCE_GAMEPAD == android.view.InputDevice.SOURCE_GAMEPAD || + source and android.view.InputDevice.SOURCE_JOYSTICK == android.view.InputDevice.SOURCE_JOYSTICK + } + + private fun stadiumRomEntry(row: Gen1EngineBridge.Row): RetroMenuEntry = + RetroMenuEntry.Action( + label = row.label, + icon = RetroDrawerIcons.EditLayout, + subtitle = + when { + Gen1StadiumRom.isBuilding(row.value) -> getString(R.string.retro_stadium_building) + Gen1StadiumRom.isReady(row.value) -> getString(R.string.retro_stadium_ready) + Gen1StadiumRom.hasStagedPick(this) -> getString(R.string.retro_stadium_building) + else -> getString(R.string.retro_stadium_import) + }, + ) { + when { + Gen1StadiumRom.isBuilding(row.value) -> Unit + Gen1StadiumRom.isReady(row.value) -> promptStadiumDelete() + else -> pickStadiumRom() + } + } + + private fun pickStadiumRom() { + menu.close() + val intent = + android.content.Intent(android.content.Intent.ACTION_OPEN_DOCUMENT).apply { + addCategory(android.content.Intent.CATEGORY_OPENABLE) + type = "*/*" + } + runCatching { startActivityForResult(intent, REQUEST_STADIUM_ROM) } + .onFailure { toast(getString(R.string.retro_stadium_no_picker)) } + } + + private fun promptStadiumDelete() { + android.app.AlertDialog.Builder(this) + .setTitle(R.string.retro_stadium_row) + .setMessage(R.string.retro_stadium_delete_body) + .setPositiveButton(R.string.retro_stadium_keep) { d, _ -> d.dismiss() } + .setNegativeButton(R.string.retro_stadium_delete) { d, _ -> + d.dismiss() + val gone = Gen1StadiumRom.delete(this) + toast( + getString( + if (gone) R.string.retro_stadium_deleted else R.string.retro_stadium_delete_failed, + ), + ) + pollFaster() + } + .show() + } + + override fun onActivityResult( + requestCode: Int, + resultCode: Int, + data: android.content.Intent?, + ) { + if (requestCode != REQUEST_STADIUM_ROM) { + super.onActivityResult(requestCode, resultCode, data) + return + } + val uri = data?.data + if (resultCode != RESULT_OK || uri == null) return + toast(getString(R.string.retro_stadium_importing)) + lifecycleScope.launch(Dispatchers.IO) { + val result = Gen1StadiumRom.stage(this@Gen1EngineActivity, uri) + withContext(Dispatchers.Main) { + result + .onSuccess { + toast(getString(R.string.retro_stadium_imported)) + pollFaster() + } + .onFailure { toast(it.message ?: getString(R.string.retro_stadium_import_failed)) } + } + } + } + private fun rowEntry(row: Gen1EngineBridge.Row): RetroMenuEntry = when { + row.id == Gen1StadiumRom.ROW_ID -> stadiumRomEntry(row) row.values.isNotEmpty() -> RetroMenuEntry.Choice(row.label, row.values, row.selectedIndex) { index -> bridge.setRow(row.id, index) @@ -852,6 +942,8 @@ class Gen1EngineActivity : companion object { private const val TAG = "WnGen1Engine" + private const val REQUEST_STADIUM_ROM = 0x5D01 + const val EXTRA_ROM_PATH = "wn.engine.rom" const val EXTRA_VERSION = "wn.engine.version" const val EXTRA_GAME_NAME = "wn.engine.game_name" diff --git a/app/src/main/feature/retro/Gen1StadiumRom.kt b/app/src/main/feature/retro/Gen1StadiumRom.kt new file mode 100644 index 000000000..ff06d66b9 --- /dev/null +++ b/app/src/main/feature/retro/Gen1StadiumRom.kt @@ -0,0 +1,86 @@ +package com.winlator.cmod.feature.retro + +import android.content.Context +import android.net.Uri +import java.io.File + +object Gen1StadiumRom { + const val ROW_ID = "DRAMATIC_SHAPE:stadiumRom" + + private const val SAVE_SUBDIR = "save/pokemon-love2d" + private const val PICKED = "picked_stadium.z64" + private const val PACK_SUBDIR = "dramatic_shape/stadium" + private const val ROM_SUBDIR = "baseroms" + private const val MIN_ROM_BYTES = 4L * 1024 * 1024 + + private val MAGICS = + listOf( + byteArrayOf(0x80.toByte(), 0x37, 0x12, 0x40), + byteArrayOf(0x37, 0x80.toByte(), 0x40, 0x12), + byteArrayOf(0x40, 0x12, 0x37, 0x80.toByte()), + ) + + fun saveRoot(context: Context): File = + File(context.getExternalFilesDir(null) ?: context.filesDir, SAVE_SUBDIR) + + private fun packDir(context: Context): File = File(saveRoot(context), PACK_SUBDIR) + + private fun romDir(context: Context): File = File(saveRoot(context), ROM_SUBDIR) + + fun isReady(value: String): Boolean = value.trim().equals("READY", ignoreCase = true) + + fun isBuilding(value: String): Boolean = value.trim().equals("BUILDING", ignoreCase = true) + + fun stage( + context: Context, + uri: Uri, + ): Result = + runCatching { + val root = saveRoot(context).apply { mkdirs() } + val staging = File(root, "$PICKED.part") + staging.delete() + + val copied = + context.contentResolver.openInputStream(uri)?.use { input -> + staging.outputStream().use { output -> input.copyTo(output) } + } ?: throw IllegalStateException("Could not read that file") + + if (copied < MIN_ROM_BYTES) { + staging.delete() + throw IllegalArgumentException("That file is too small to be a Nintendo 64 ROM") + } + if (!looksLikeN64(staging)) { + staging.delete() + throw IllegalArgumentException("That is not a Nintendo 64 ROM (.z64, .v64 or .n64)") + } + + val target = File(root, PICKED) + target.delete() + if (!staging.renameTo(target)) { + staging.delete() + throw IllegalStateException("Could not hand the ROM to the engine") + } + copied + } + + private fun looksLikeN64(file: File): Boolean = + runCatching { + val head = ByteArray(4) + file.inputStream().use { if (it.read(head) != 4) return false } + MAGICS.any { magic -> magic.contentEquals(head) } + }.getOrDefault(false) + + fun hasStagedPick(context: Context): Boolean = File(saveRoot(context), PICKED).isFile + + fun delete(context: Context): Boolean = + runCatching { + var removed = packDir(context).deleteRecursively() + val roms = romDir(context) + if (roms.isDirectory) { + roms.listFiles().orEmpty().forEach { if (it.isFile && it.delete()) removed = true } + } + File(saveRoot(context), PICKED).delete() + File(saveRoot(context), "$PICKED.part").delete() + removed + }.getOrDefault(false) +} diff --git a/app/src/main/res/values-b+es+419/strings.xml b/app/src/main/res/values-b+es+419/strings.xml index 2cf95cefe..1369289ae 100644 --- a/app/src/main/res/values-b+es+419/strings.xml +++ b/app/src/main/res/values-b+es+419/strings.xml @@ -2044,6 +2044,19 @@ Ruta instalada: Preparando los datos del juego por primera vez Voxel 3D Juega este juego con el motor de vóxeles 3D en lugar del núcleo estándar + ROM de Stadium + Lista + Importar una ROM + Creando modelos de combate… + Importando… + ROM importada. Los modelos de combate se están creando. + No se pudo importar esa ROM + No hay ningún selector de archivos en este dispositivo + Conservar + Eliminar + Los modelos de combate de Stadium están instalados. ¿Eliminarlos? + Modelos de combate de Stadium eliminados + No se pudieron eliminar los modelos de Stadium Controles en pantalla Respuesta háptica AUDIO diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index d7d930f13..bd806602a 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -2046,6 +2046,19 @@ Installeret sti: Forbereder spildata for første gang Voxel 3D Spil dette spil i 3D-voxelmotoren i stedet for den almindelige kerne + Stadium-ROM + Klar + Importér en ROM + Bygger kampmodeller… + Importerer… + ROM importeret. Kampmodellerne bygges nu. + Kunne ikke importere den ROM + Der er ingen filvælger på denne enhed + Behold + Slet + Stadium-kampmodellerne er installeret. Vil du slette dem? + Stadium-kampmodeller slettet + Kunne ikke slette Stadium-modellerne Skærmknapper Haptisk feedback LYD diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 965812638..3c27b965e 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -2046,6 +2046,19 @@ Installierter Pfad: Spieldaten werden zum ersten Mal vorbereitet Voxel 3D Dieses Spiel mit der 3D-Voxel-Engine statt mit dem Standard-Core spielen + Stadium-ROM + Bereit + ROM importieren + Kampfmodelle werden erstellt… + Wird importiert… + ROM importiert. Die Kampfmodelle werden jetzt erstellt. + Diese ROM konnte nicht importiert werden + Auf diesem Gerät ist keine Dateiauswahl verfügbar + Behalten + Löschen + Die Stadium-Kampfmodelle sind installiert. Löschen? + Stadium-Kampfmodelle gelöscht + Die Stadium-Modelle konnten nicht gelöscht werden Bildschirmsteuerung Haptisches Feedback AUDIO diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index d8b8f2dbc..1846e7a1e 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -2045,6 +2045,19 @@ Ruta instalada: Preparando los datos del juego por primera vez Voxel 3D Juega a este juego con el motor de vóxeles 3D en lugar del núcleo estándar + ROM de Stadium + Lista + Importar una ROM + Creando modelos de combate… + Importando… + ROM importada. Los modelos de combate se están creando. + No se pudo importar esa ROM + No hay ningún selector de archivos en este dispositivo + Conservar + Eliminar + Los modelos de combate de Stadium están instalados. ¿Eliminarlos? + Modelos de combate de Stadium eliminados + No se pudieron eliminar los modelos de Stadium Controles en pantalla Respuesta háptica AUDIO diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index 0234bbdb9..7267cd582 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -2044,6 +2044,19 @@ Asennuspolku: Valmistellaan pelitietoja ensimmäistä kertaa Voxel 3D Pelaa tätä peliä 3D-voxelmoottorilla vakioytimen sijaan + Stadium-ROM + Valmis + Tuo ROM + Rakennetaan taistelumalleja… + Tuodaan… + ROM tuotu. Taistelumalleja rakennetaan nyt. + ROM-tiedostoa ei voitu tuoda + Tässä laitteessa ei ole tiedostonvalitsinta + Säilytä + Poista + Stadiumin taistelumallit on asennettu. Poistetaanko ne? + Stadiumin taistelumallit poistettu + Stadium-malleja ei voitu poistaa Näytön ohjaimet Haptinen palaute ÄÄNI diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 0f8daff46..2db24202b 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -2045,6 +2045,19 @@ Chemin installé : Préparation des données du jeu pour la première fois Voxel 3D Jouer à ce jeu avec le moteur voxel 3D au lieu du cœur standard + ROM Stadium + Prête + Importer une ROM + Création des modèles de combat… + Importation… + ROM importée. Les modèles de combat sont en cours de création. + Impossible d\'importer cette ROM + Aucun sélecteur de fichiers sur cet appareil + Conserver + Supprimer + Les modèles de combat Stadium sont installés. Les supprimer ? + Modèles de combat Stadium supprimés + Impossible de supprimer les modèles Stadium Commandes à l\'écran Retour haptique AUDIO diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 7ff60f316..3e68e580f 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -1981,6 +1981,19 @@ पहली बार गेम डेटा तैयार किया जा रहा है वॉक्सेल 3D इस गेम को मानक कोर के बजाय 3D वॉक्सेल इंजन में खेलें + Stadium ROM + तैयार + ROM आयात करें + बैटल मॉडल बन रहे हैं… + आयात हो रहा है… + ROM आयात हो गया। बैटल मॉडल अब बन रहे हैं। + वह ROM आयात नहीं हो सका + इस डिवाइस पर कोई फ़ाइल पिकर उपलब्ध नहीं है + रखें + हटाएँ + Stadium बैटल मॉडल इंस्टॉल हैं। उन्हें हटाएँ? + Stadium बैटल मॉडल हटाए गए + Stadium मॉडल हटाए नहीं जा सके ऑन-स्क्रीन नियंत्रण हैप्टिक फ़ीडबैक ऑडियो diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index cdadd0c61..4ccbe18cc 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -2045,6 +2045,19 @@ Percorso installato: Preparazione dei dati di gioco per la prima volta Voxel 3D Gioca a questo gioco con il motore voxel 3D invece del core standard + ROM di Stadium + Pronta + Importa una ROM + Creazione dei modelli di lotta… + Importazione… + ROM importata. I modelli di lotta si stanno creando. + Impossibile importare quella ROM + Nessun selettore di file disponibile su questo dispositivo + Mantieni + Elimina + I modelli di lotta di Stadium sono installati. Eliminarli? + Modelli di lotta di Stadium eliminati + Impossibile eliminare i modelli di Stadium Comandi a schermo Feedback aptico AUDIO diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 311c03fca..a0c6e8b79 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -2044,6 +2044,19 @@ 初回のゲームデータを準備しています ボクセル3D 標準コアの代わりに3Dボクセルエンジンでこのゲームをプレイします + スタジアムROM + 準備完了 + ROMをインポート + バトルモデルを作成中… + インポート中… + ROMをインポートしました。バトルモデルを作成しています。 + そのROMをインポートできませんでした + この端末では利用できるファイル選択画面がありません + 保持 + 削除 + スタジアムのバトルモデルがインストールされています。削除しますか? + スタジアムのバトルモデルを削除しました + スタジアムのモデルを削除できませんでした 画面上のコントロール 触覚フィードバック オーディオ diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 59a829f8d..8ba12b4e1 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -2046,6 +2046,19 @@ 게임 데이터를 처음으로 준비하는 중 복셀 3D 기본 코어 대신 3D 복셀 엔진으로 이 게임을 플레이합니다 + 스타디움 ROM + 준비됨 + ROM 가져오기 + 배틀 모델 생성 중… + 가져오는 중… + ROM을 가져왔습니다. 배틀 모델을 생성하고 있습니다. + 해당 ROM을 가져올 수 없습니다 + 이 기기에서 사용할 수 있는 파일 선택기가 없습니다 + 유지 + 삭제 + 스타디움 배틀 모델이 설치되어 있습니다. 삭제할까요? + 스타디움 배틀 모델을 삭제했습니다 + 스타디움 모델을 삭제할 수 없습니다 화면 컨트롤 햅틱 피드백 오디오 diff --git a/app/src/main/res/values-no/strings.xml b/app/src/main/res/values-no/strings.xml index 75bdff9b2..b2f240101 100644 --- a/app/src/main/res/values-no/strings.xml +++ b/app/src/main/res/values-no/strings.xml @@ -2044,6 +2044,19 @@ Installert bane: Forbereder spilldata for første gang Voxel 3D Spill dette spillet i 3D-voxelmotoren i stedet for standardkjernen + Stadium-ROM + Klar + Importer en ROM + Bygger kampmodeller… + Importerer… + ROM importert. Kampmodellene bygges nå. + Kunne ikke importere den ROM-en + Ingen filvelger er tilgjengelig på denne enheten + Behold + Slett + Stadium-kampmodellene er installert. Vil du slette dem? + Stadium-kampmodeller slettet + Kunne ikke slette Stadium-modellene Skjermkontroller Haptisk tilbakemelding LYD diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 7124a52b2..1eac55ba3 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -2051,6 +2051,19 @@ Zainstalowana ścieżka: Pierwsze przygotowywanie danych gry Voxel 3D Graj w tę grę w silniku wokselowym 3D zamiast standardowego rdzenia + ROM Stadium + Gotowe + Importuj ROM + Tworzenie modeli walki… + Importowanie… + Zaimportowano ROM. Trwa tworzenie modeli walki. + Nie udało się zaimportować tego ROM-u + Na tym urządzeniu nie ma selektora plików + Zachowaj + Usuń + Modele walki Stadium są zainstalowane. Usunąć je? + Usunięto modele walki Stadium + Nie udało się usunąć modeli Stadium Sterowanie ekranowe Wibracje dotykowe DŹWIĘK diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 2b1acbbb6..da0c84d0b 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -2045,6 +2045,19 @@ Caminho instalado: Preparando os dados do jogo pela primeira vez Voxel 3D Jogue este jogo no motor de voxels 3D em vez do núcleo padrão + ROM do Stadium + Pronta + Importar uma ROM + Criando modelos de batalha… + Importando… + ROM importada. Os modelos de batalha estão sendo criados. + Não foi possível importar essa ROM + Nenhum seletor de arquivos disponível neste dispositivo + Manter + Excluir + Os modelos de batalha do Stadium estão instalados. Excluí-los? + Modelos de batalha do Stadium excluídos + Não foi possível excluir os modelos do Stadium Controles na tela Resposta tátil ÁUDIO diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index a12861c72..4efdf3482 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -2044,6 +2044,19 @@ Caminho instalado: A preparar os dados do jogo pela primeira vez Voxel 3D Jogar este jogo no motor de voxels 3D em vez do núcleo padrão + ROM do Stadium + Pronta + Importar uma ROM + A criar modelos de combate… + A importar… + ROM importada. Os modelos de combate estão a ser criados. + Não foi possível importar essa ROM + Não há nenhum seletor de ficheiros neste dispositivo + Manter + Eliminar + Os modelos de combate do Stadium estão instalados. Eliminá-los? + Modelos de combate do Stadium eliminados + Não foi possível eliminar os modelos do Stadium Controlos no ecrã Retorno tátil ÁUDIO diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 9a4ce7cb2..a2b9a22a2 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -2044,6 +2044,19 @@ Cale instalata: Se pregătesc datele jocului pentru prima dată Voxel 3D Joacă acest joc în motorul voxel 3D în loc de nucleul standard + ROM Stadium + Pregătit + Importă un ROM + Se creează modelele de luptă… + Se importă… + ROM importat. Modelele de luptă se creează acum. + Nu s-a putut importa acel ROM + Niciun selector de fișiere disponibil pe acest dispozitiv + Păstrează + Șterge + Modelele de luptă Stadium sunt instalate. Le ștergi? + Modelele de luptă Stadium au fost șterse + Nu s-au putut șterge modelele Stadium Comenzi pe ecran Feedback haptic AUDIO diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index b0a06075b..576abf354 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -1951,6 +1951,19 @@ Первичная подготовка данных игры Воксельный 3D Играть в эту игру в воксельном 3D-движке вместо стандартного ядра + ROM Stadium + Готово + Импортировать ROM + Создание боевых моделей… + Импорт… + ROM импортирован. Боевые модели создаются. + Не удалось импортировать этот ROM + На этом устройстве нет средства выбора файлов + Оставить + Удалить + Боевые модели Stadium установлены. Удалить их? + Боевые модели Stadium удалены + Не удалось удалить модели Stadium Экранные кнопки Виброотклик ЗВУК diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 82d020fbf..e9bf80fcb 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -2044,6 +2044,19 @@ Installerad sökväg: Förbereder speldata för första gången Voxel 3D Spela det här spelet i 3D-voxelmotorn i stället för standardkärnan + Stadium-ROM + Klar + Importera en ROM + Bygger stridsmodeller… + Importerar… + ROM importerad. Stridsmodellerna byggs nu. + Det gick inte att importera den ROM-filen + Ingen filväljare är tillgänglig på den här enheten + Behåll + Ta bort + Stadium-stridsmodellerna är installerade. Vill du ta bort dem? + Stadium-stridsmodeller borttagna + Det gick inte att ta bort Stadium-modellerna Skärmkontroller Haptisk återkoppling LJUD diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml index af11128d8..3dd0f7a35 100644 --- a/app/src/main/res/values-th/strings.xml +++ b/app/src/main/res/values-th/strings.xml @@ -2044,6 +2044,19 @@ กำลังเตรียมข้อมูลเกมเป็นครั้งแรก วอกเซล 3D เล่นเกมนี้ด้วยเอนจินวอกเซล 3D แทนคอร์มาตรฐาน + ROM ของ Stadium + พร้อมแล้ว + นำเข้า ROM + กำลังสร้างโมเดลการต่อสู้… + กำลังนำเข้า… + นำเข้า ROM แล้ว กำลังสร้างโมเดลการต่อสู้ + นำเข้า ROM นั้นไม่ได้ + ไม่มีตัวเลือกไฟล์บนอุปกรณ์นี้ + เก็บไว้ + ลบ + ติดตั้งโมเดลการต่อสู้ของ Stadium แล้ว ต้องการลบหรือไม่ + ลบโมเดลการต่อสู้ของ Stadium แล้ว + ลบโมเดลของ Stadium ไม่ได้ ปุ่มควบคุมบนหน้าจอ การสั่นตอบสนอง เสียง diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index a0e1385cf..1de961479 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -2044,6 +2044,19 @@ Yüklü konum: Oyun verileri ilk kez hazırlanıyor Voxel 3D Bu oyunu standart çekirdek yerine 3D voxel motorunda oynayın + Stadium ROM\'u + Hazır + ROM içe aktar + Dövüş modelleri oluşturuluyor… + İçe aktarılıyor… + ROM içe aktarıldı. Dövüş modelleri şimdi oluşturuluyor. + Bu ROM içe aktarılamadı + Bu cihazda kullanılabilir dosya seçici yok + Sakla + Sil + Stadium dövüş modelleri yüklü. Silinsin mi? + Stadium dövüş modelleri silindi + Stadium modelleri silinemedi Ekran kontrolleri Dokunsal Geri Bildirim SES diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 10f837e21..3f06fba22 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -2051,6 +2051,19 @@ Перша підготовка даних гри Воксельний 3D Грати в цю гру у воксельному 3D-рушії замість стандартного ядра + ROM Stadium + Готово + Імпортувати ROM + Створення бойових моделей… + Імпортування… + ROM імпортовано. Бойові моделі створюються. + Не вдалося імпортувати цей ROM + На цьому пристрої немає засобу вибору файлів + Залишити + Видалити + Бойові моделі Stadium встановлено. Видалити їх? + Бойові моделі Stadium видалено + Не вдалося видалити моделі Stadium Екранне керування Тактильний відгук АУДІО diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 0201382f1..7d51a3d04 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -2045,6 +2045,19 @@ 正在首次准备游戏数据 体素 3D 使用 3D 体素引擎运行此游戏,而非标准核心 + Stadium ROM + 已就绪 + 导入 ROM + 正在生成对战模型… + 正在导入… + ROM 已导入,正在生成对战模型。 + 无法导入该 ROM + 此设备上没有可用的文件选择器 + 保留 + 删除 + Stadium 对战模型已安装。要删除吗? + 已删除 Stadium 对战模型 + 无法删除 Stadium 模型 屏幕控制 触觉反馈 音频 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 78e12d56d..7b3c28636 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -2044,6 +2044,19 @@ 正在首次準備遊戲資料 體素 3D 使用 3D 體素引擎執行此遊戲,而非標準核心 + Stadium ROM + 已就緒 + 匯入 ROM + 正在產生對戰模型… + 正在匯入… + ROM 已匯入,正在產生對戰模型。 + 無法匯入該 ROM + 此裝置上沒有可用的檔案選擇器 + 保留 + 刪除 + Stadium 對戰模型已安裝。要刪除嗎? + 已刪除 Stadium 對戰模型 + 無法刪除 Stadium 模型 螢幕控制 觸覺回饋 音訊 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a78a56807..bd7e7d997 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2160,6 +2160,19 @@ Installed path: Preparing game data for the first time Voxel 3D Play this game in the 3D voxel engine instead of the standard core + Stadium ROM + Ready + Import a ROM + Building battle models… + Importing… + ROM imported. The battle models are building now. + Could not import that ROM + No file picker is available on this device + Keep + Delete + The Stadium battle models are installed. Delete them? + Stadium battle models deleted + Could not delete the Stadium models On-screen controls Adaptive Sticks TURNIP DRIVER FLAGS From 455d1b20e88413e7e268f2501f1444ccff4847ea Mon Sep 17 00:00:00 2001 From: MaxsTechReview Date: Wed, 5 Aug 2026 16:15:22 -0400 Subject: [PATCH 2/3] Track Stadium state from disk, theme the prompt, and correct the 3D settings Deleting the Stadium models left the row reading READY and re-offering the same prompt. StadiumInstall.ready() memoises its answer in readyCache for the life of the process, so nothing WinNative removes from disk can change what the mod reports. The row now reads the pack marker itself rather than trusting the mod's cached value, and rebuilds the menu after a delete. The running engine keeps its cached answer either way, so the toast says to restart; StadiumInstall.forget() exists for this but nothing reachable calls it. The confirm prompt was a stock platform dialog sitting inside a Compose drawer that looks nothing like it. RetroConfirmPrompt and RetroConfirmDialog match RetroConflictDialog exactly. Keep sits on the left, Delete on the right in the theme's danger colour, and a tap outside the card cancels. A physical stick or d-pad could not drive the 3D engine's menu: the axis path reached the game instead. RetroActivity has a dispatchGenericMotionEvent for this and Gen1EngineActivity had none, so its handleAxis only ever ran for the on-screen pad. Joystick motion now feeds the menu while it is open and is swallowed rather than passed to the game. Shortcut Settings showed the wrong things under the 3D toggle. The video filter, SGSR and upscale rows are libretrodroid's and the engine does not use libretrodroid; the core-option group is gambatte's and the engine is not gambatte. Both are hidden, and a VOXEL 3D group takes their place with the Stadium ROM row, which works with no engine running because it is only files on disk. Two rows were lying: the engine reads neither KEY_AUDIO nor KEY_ADAPTIVE_STICKS, and its onStick and onRightStick are Unit, so it has no analog input at all. Adaptive sticks is hidden and the sound switch is replaced by a line pointing at the in-game Sound tab, which is where the engine's own per-channel volumes live. Mirroring those here would mean a second copy of state the engine owns and would drift the moment it gains an option. --- .../main/feature/retro/Gen1EngineActivity.kt | 73 ++++++--- app/src/main/feature/retro/Gen1StadiumRom.kt | 8 +- app/src/main/feature/retro/RetroDrawerMenu.kt | 98 +++++++++++ .../main/feature/retro/RetroGameSettings.kt | 152 ++++++++++++++++-- app/src/main/res/values-b+es+419/strings.xml | 4 +- app/src/main/res/values-da/strings.xml | 4 +- app/src/main/res/values-de/strings.xml | 4 +- app/src/main/res/values-es/strings.xml | 4 +- app/src/main/res/values-fi/strings.xml | 4 +- app/src/main/res/values-fr/strings.xml | 4 +- app/src/main/res/values-hi/strings.xml | 4 +- app/src/main/res/values-it/strings.xml | 4 +- app/src/main/res/values-ja/strings.xml | 4 +- app/src/main/res/values-ko/strings.xml | 4 +- app/src/main/res/values-no/strings.xml | 4 +- app/src/main/res/values-pl/strings.xml | 4 +- app/src/main/res/values-pt-rBR/strings.xml | 4 +- app/src/main/res/values-pt/strings.xml | 4 +- app/src/main/res/values-ro/strings.xml | 4 +- app/src/main/res/values-ru/strings.xml | 4 +- app/src/main/res/values-sv/strings.xml | 4 +- app/src/main/res/values-th/strings.xml | 4 +- app/src/main/res/values-tr/strings.xml | 4 +- app/src/main/res/values-uk/strings.xml | 4 +- app/src/main/res/values-zh-rCN/strings.xml | 4 +- app/src/main/res/values-zh-rTW/strings.xml | 4 +- app/src/main/res/values/strings.xml | 4 +- 27 files changed, 364 insertions(+), 59 deletions(-) diff --git a/app/src/main/feature/retro/Gen1EngineActivity.kt b/app/src/main/feature/retro/Gen1EngineActivity.kt index b72b48970..c33074dc4 100644 --- a/app/src/main/feature/retro/Gen1EngineActivity.kt +++ b/app/src/main/feature/retro/Gen1EngineActivity.kt @@ -190,6 +190,24 @@ class Gen1EngineActivity : return super.dispatchKeyEvent(event) } + override fun dispatchGenericMotionEvent(event: android.view.MotionEvent): Boolean { + val joystick = + event.source and android.view.InputDevice.SOURCE_JOYSTICK == + android.view.InputDevice.SOURCE_JOYSTICK + if (menu.visible && joystick) { + val hatX = event.getAxisValue(android.view.MotionEvent.AXIS_HAT_X) + val hatY = event.getAxisValue(android.view.MotionEvent.AXIS_HAT_Y) + val x = + if (kotlin.math.abs(hatX) > 0.5f) hatX else event.getAxisValue(android.view.MotionEvent.AXIS_X) + val y = + if (kotlin.math.abs(hatY) > 0.5f) hatY else event.getAxisValue(android.view.MotionEvent.AXIS_Y) + menu.handleAxis(x, y) + return true + } + if (menu.visible) return true + return super.dispatchGenericMotionEvent(event) + } + private fun buildTabs(): List = listOf( RetroTabSpec(null, RetroDrawerIcons.Play, getString(R.string.retro_tab_menu)), @@ -241,24 +259,27 @@ class Gen1EngineActivity : source and android.view.InputDevice.SOURCE_JOYSTICK == android.view.InputDevice.SOURCE_JOYSTICK } - private fun stadiumRomEntry(row: Gen1EngineBridge.Row): RetroMenuEntry = - RetroMenuEntry.Action( + private fun stadiumRomEntry(row: Gen1EngineBridge.Row): RetroMenuEntry { + val building = Gen1StadiumRom.isBuilding(row.value) || Gen1StadiumRom.hasStagedPick(this) + val installed = Gen1StadiumRom.isInstalled(this) + return RetroMenuEntry.Action( label = row.label, icon = RetroDrawerIcons.EditLayout, + danger = installed && !building, subtitle = when { - Gen1StadiumRom.isBuilding(row.value) -> getString(R.string.retro_stadium_building) - Gen1StadiumRom.isReady(row.value) -> getString(R.string.retro_stadium_ready) - Gen1StadiumRom.hasStagedPick(this) -> getString(R.string.retro_stadium_building) + building -> getString(R.string.retro_stadium_building) + installed -> getString(R.string.retro_stadium_ready) else -> getString(R.string.retro_stadium_import) }, ) { when { - Gen1StadiumRom.isBuilding(row.value) -> Unit - Gen1StadiumRom.isReady(row.value) -> promptStadiumDelete() + building -> Unit + installed -> promptStadiumDelete() else -> pickStadiumRom() } } + } private fun pickStadiumRom() { menu.close() @@ -272,21 +293,29 @@ class Gen1EngineActivity : } private fun promptStadiumDelete() { - android.app.AlertDialog.Builder(this) - .setTitle(R.string.retro_stadium_row) - .setMessage(R.string.retro_stadium_delete_body) - .setPositiveButton(R.string.retro_stadium_keep) { d, _ -> d.dismiss() } - .setNegativeButton(R.string.retro_stadium_delete) { d, _ -> - d.dismiss() - val gone = Gen1StadiumRom.delete(this) - toast( - getString( - if (gone) R.string.retro_stadium_deleted else R.string.retro_stadium_delete_failed, - ), - ) - pollFaster() - } - .show() + menu.confirmPrompt = + RetroConfirmPrompt( + title = getString(R.string.retro_stadium_row), + message = getString(R.string.retro_stadium_delete_body), + confirmLabel = getString(R.string.retro_stadium_delete), + dismissLabel = getString(R.string.retro_stadium_keep), + onConfirm = { + menu.confirmPrompt = null + val gone = Gen1StadiumRom.delete(this) + toast( + getString( + if (gone) { + R.string.retro_stadium_deleted + } else { + R.string.retro_stadium_delete_failed + }, + ), + ) + menu.rebuild() + pollFaster() + }, + onDismiss = { menu.confirmPrompt = null }, + ) } override fun onActivityResult( diff --git a/app/src/main/feature/retro/Gen1StadiumRom.kt b/app/src/main/feature/retro/Gen1StadiumRom.kt index ff06d66b9..02c018783 100644 --- a/app/src/main/feature/retro/Gen1StadiumRom.kt +++ b/app/src/main/feature/retro/Gen1StadiumRom.kt @@ -27,10 +27,14 @@ object Gen1StadiumRom { private fun romDir(context: Context): File = File(saveRoot(context), ROM_SUBDIR) - fun isReady(value: String): Boolean = value.trim().equals("READY", ignoreCase = true) - fun isBuilding(value: String): Boolean = value.trim().equals("BUILDING", ignoreCase = true) + fun isInstalled(context: Context): Boolean { + val marker = File(packDir(context), "pack.info") + if (!marker.isFile) return false + return runCatching { marker.readText().trim().isNotEmpty() }.getOrDefault(false) + } + fun stage( context: Context, uri: Uri, diff --git a/app/src/main/feature/retro/RetroDrawerMenu.kt b/app/src/main/feature/retro/RetroDrawerMenu.kt index e951a6394..b57fa8e3f 100644 --- a/app/src/main/feature/retro/RetroDrawerMenu.kt +++ b/app/src/main/feature/retro/RetroDrawerMenu.kt @@ -92,6 +92,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.winlator.cmod.R import com.winlator.cmod.shared.theme.SessionDrawerStyle +import com.winlator.cmod.shared.theme.WinNativeDanger import com.winlator.cmod.shared.theme.WinNativeOutline import com.winlator.cmod.shared.theme.WinNativeSurface import com.winlator.cmod.shared.ui.outlinedSwitchColors @@ -128,6 +129,15 @@ class RetroRenamePrompt( val onConfirm: (String?) -> Unit, ) +class RetroConfirmPrompt( + val title: String, + val message: String, + val confirmLabel: String, + val dismissLabel: String, + val onConfirm: () -> Unit, + val onDismiss: () -> Unit, +) + class RetroConflictPrompt( val message: String, val options: List, @@ -251,6 +261,7 @@ class RetroMenuController { var bottomProvider: (() -> List)? = null var renamePrompt by mutableStateOf(null) var conflictPrompt by mutableStateOf(null) + var confirmPrompt by mutableStateOf(null) val gridColumns: Int get() = if (pane == null) 3 else 1 @@ -495,6 +506,9 @@ fun RetroDrawerMenu(controller: RetroMenuController) { controller.conflictPrompt?.let { prompt -> RetroConflictDialog(prompt) } + controller.confirmPrompt?.let { prompt -> + RetroConfirmDialog(prompt) + } } } @@ -1523,6 +1537,90 @@ internal fun RetroRenameDialog( } } +@Composable +internal fun RetroConfirmDialog(prompt: RetroConfirmPrompt) { + Box( + modifier = + Modifier + .fillMaxSize() + .background(Color(0xCC000000)) + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + ) { prompt.onDismiss() }, + contentAlignment = Alignment.Center, + ) { + Column( + modifier = + Modifier + .width(340.dp) + .clip(RoundedCornerShape(16.dp)) + .background(WinNativeSurface) + .border(1.dp, WinNativeOutline, RoundedCornerShape(16.dp)) + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + ) {} + .padding(16.dp), + ) { + Text( + text = prompt.title, + color = DrawerTextPrimary, + fontSize = 15.sp, + fontWeight = FontWeight.SemiBold, + ) + Spacer(Modifier.height(6.dp)) + Text( + text = prompt.message, + color = DrawerTextSecondary, + fontSize = 12.sp, + ) + Spacer(Modifier.height(14.dp)) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(8.dp), + ) { + Row( + modifier = + Modifier + .weight(1f) + .clip(RoundedCornerShape(10.dp)) + .background(DrawerFocusFill) + .border(1.dp, DrawerAccent, RoundedCornerShape(10.dp)) + .clickable { prompt.onDismiss() } + .padding(horizontal = 12.dp, vertical = 10.dp), + horizontalArrangement = Arrangement.Center, + ) { + Text( + text = prompt.dismissLabel, + color = DrawerActiveAccent, + fontSize = 13.sp, + fontWeight = FontWeight.SemiBold, + ) + } + Row( + modifier = + Modifier + .weight(1f) + .clip(RoundedCornerShape(10.dp)) + .background(PaneInnerResting) + .border(1.dp, RestingCardBorder, RoundedCornerShape(10.dp)) + .clickable { prompt.onConfirm() } + .padding(horizontal = 12.dp, vertical = 10.dp), + horizontalArrangement = Arrangement.Center, + ) { + Text( + text = prompt.confirmLabel, + color = WinNativeDanger, + fontSize = 13.sp, + fontWeight = FontWeight.SemiBold, + ) + } + } + } + } +} + @Composable internal fun RetroConflictDialog(prompt: RetroConflictPrompt) { Box( diff --git a/app/src/main/feature/retro/RetroGameSettings.kt b/app/src/main/feature/retro/RetroGameSettings.kt index bf1bae663..e36aef8f8 100644 --- a/app/src/main/feature/retro/RetroGameSettings.kt +++ b/app/src/main/feature/retro/RetroGameSettings.kt @@ -77,6 +77,7 @@ import com.winlator.cmod.shared.ui.nav.paneHighlight import com.winlator.cmod.shared.ui.nav.paneNavItem import com.winlator.cmod.shared.ui.outlinedSwitchColors import com.winlator.cmod.shared.ui.widget.chasingBorder +import kotlinx.coroutines.launch private val BgDeep = GameSettingsStyle.BgDeep private val SidebarBg = GameSettingsStyle.SidebarBg @@ -1113,6 +1114,16 @@ private fun RetroGraphicsSection(state: RetroSettingsState) { val embeddedDolphin = RetroCoreManager.usesDolphinCore(state.system) && RetroShortcuts.embeddedDolphinEnabled(embeddedDolphinContext) + val voxelEngine = state.engine3d + if (voxelEngine) { + Spacer(Modifier.height(12.dp)) + RetroSettingGroup { + RetroGroupTitle(stringResource(R.string.retro_gs_engine_3d).uppercase()) + RetroStadiumRomSetting() + RetroSettingNote(stringResource(R.string.retro_gs_engine_3d_note)) + } + } + if (!voxelEngine) { RetroSettingGroup { RetroGroupTitle(stringResource(R.string.retro_gs_group_video)) if (embeddedDolphin) { @@ -1140,7 +1151,8 @@ private fun RetroGraphicsSection(state: RetroSettingsState) { } } } - if (state.coreOptions.isNotEmpty()) { + } + if (state.coreOptions.isNotEmpty() && !voxelEngine) { Spacer(Modifier.height(12.dp)) RetroSettingGroup { RetroGroupTitle((state.system?.shortName ?: stringResource(R.string.retro_gs_group_core)).uppercase()) @@ -1160,6 +1172,116 @@ private fun RetroGraphicsSection(state: RetroSettingsState) { } } +@Composable +private fun RetroSettingNote(text: String) { + Text( + text = text, + color = TextDim, + fontSize = 11.sp, + modifier = Modifier.padding(top = 6.dp), + ) +} + +@Composable +private fun RetroStadiumRomSetting() { + val context = androidx.compose.ui.platform.LocalContext.current + val scope = androidx.compose.runtime.rememberCoroutineScope() + var refresh by remember { mutableIntStateOf(0) } + var confirmDelete by remember { mutableStateOf(false) } + val installed = remember(refresh) { Gen1StadiumRom.isInstalled(context) } + val staged = remember(refresh) { Gen1StadiumRom.hasStagedPick(context) } + + val picker = + androidx.activity.compose.rememberLauncherForActivityResult( + androidx.activity.result.contract.ActivityResultContracts.OpenDocument(), + ) { uri -> + if (uri != null) { + scope.launch { + val result = + kotlinx.coroutines.withContext(kotlinx.coroutines.Dispatchers.IO) { + Gen1StadiumRom.stage(context, uri) + } + result + .onSuccess { + android.widget.Toast.makeText( + context, + context.getString(R.string.retro_stadium_imported), + android.widget.Toast.LENGTH_LONG, + ).show() + } + .onFailure { + android.widget.Toast.makeText( + context, + it.message ?: context.getString(R.string.retro_stadium_import_failed), + android.widget.Toast.LENGTH_LONG, + ).show() + } + refresh++ + } + } + } + + val status = + when { + staged -> stringResource(R.string.retro_stadium_building) + installed -> stringResource(R.string.retro_stadium_ready) + else -> stringResource(R.string.retro_stadium_import) + } + + Row( + modifier = + Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(FieldCorner)) + .background(InputSurface) + .border(1.dp, InputBorder, RoundedCornerShape(FieldCorner)) + .clickable { + when { + staged -> Unit + installed -> confirmDelete = true + else -> picker.launch(arrayOf("*/*")) + } + } + .padding(horizontal = 12.dp, vertical = 8.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + stringResource(R.string.retro_stadium_row), + color = TextPrimary, + fontSize = ValueSize, + modifier = Modifier.weight(1f), + ) + Text(status, color = if (installed) TextPrimary else TextDim, fontSize = ValueSize) + } + + if (confirmDelete) { + androidx.compose.material3.AlertDialog( + onDismissRequest = { confirmDelete = false }, + title = { Text(stringResource(R.string.retro_stadium_row)) }, + text = { Text(stringResource(R.string.retro_stadium_delete_body)) }, + confirmButton = { + androidx.compose.material3.TextButton(onClick = { + confirmDelete = false + val gone = Gen1StadiumRom.delete(context) + android.widget.Toast.makeText( + context, + context.getString( + if (gone) R.string.retro_stadium_deleted else R.string.retro_stadium_delete_failed, + ), + android.widget.Toast.LENGTH_LONG, + ).show() + refresh++ + }) { Text(stringResource(R.string.retro_stadium_delete)) } + }, + dismissButton = { + androidx.compose.material3.TextButton(onClick = { confirmDelete = false }) { + Text(stringResource(R.string.retro_stadium_keep)) + } + }, + ) + } +} + @Composable private fun DolphinGpuDriverDropdown() { val context = androidx.compose.ui.platform.LocalContext.current @@ -1900,12 +2022,14 @@ private fun RetroInputSection(state: RetroSettingsState) { checked = state.touchControls, onCheckedChange = { state.touchControls = it }, ) - RetroSettingSwitch( - label = stringResource(R.string.retro_gs_adaptive_sticks), - checked = state.adaptiveSticks, - subtitle = stringResource(R.string.retro_gs_adaptive_sticks_subtitle), - onCheckedChange = { state.adaptiveSticks = it }, - ) + if (!state.engine3d) { + RetroSettingSwitch( + label = stringResource(R.string.retro_gs_adaptive_sticks), + checked = state.adaptiveSticks, + subtitle = stringResource(R.string.retro_gs_adaptive_sticks_subtitle), + onCheckedChange = { state.adaptiveSticks = it }, + ) + } val sysId = state.system?.id if (sysId == RetroSystems.PSX.id || RetroCoreManager.usesDolphinCore(state.system)) { var invVer by remember { androidx.compose.runtime.mutableIntStateOf(0) } @@ -2006,10 +2130,14 @@ private fun RetroAudioSection(state: RetroSettingsState) { } RetroSettingGroup { RetroGroupTitle(stringResource(R.string.retro_gs_group_audio)) - RetroSettingSwitch( - label = stringResource(R.string.retro_gs_sound), - checked = state.audio, - onCheckedChange = { state.audio = it }, - ) + if (state.engine3d) { + RetroSettingNote(stringResource(R.string.retro_gs_engine_3d_audio_note)) + } else { + RetroSettingSwitch( + label = stringResource(R.string.retro_gs_sound), + checked = state.audio, + onCheckedChange = { state.audio = it }, + ) + } } } diff --git a/app/src/main/res/values-b+es+419/strings.xml b/app/src/main/res/values-b+es+419/strings.xml index 1369289ae..f7b56e580 100644 --- a/app/src/main/res/values-b+es+419/strings.xml +++ b/app/src/main/res/values-b+es+419/strings.xml @@ -2044,6 +2044,8 @@ Ruta instalada: Preparando los datos del juego por primera vez Voxel 3D Juega este juego con el motor de vóxeles 3D en lugar del núcleo estándar + Los ajustes propios del motor 3D están en el menú del juego. + El sonido lo gestiona el motor 3D. Usa la pestaña Sonido del menú del juego. ROM de Stadium Lista Importar una ROM @@ -2055,7 +2057,7 @@ Ruta instalada: Conservar Eliminar Los modelos de combate de Stadium están instalados. ¿Eliminarlos? - Modelos de combate de Stadium eliminados + Modelos de combate de Stadium eliminados. Reinicia el juego para terminar de quitarlos. No se pudieron eliminar los modelos de Stadium Controles en pantalla Respuesta háptica diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index bd806602a..30c32a3b7 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -2046,6 +2046,8 @@ Installeret sti: Forbereder spildata for første gang Voxel 3D Spil dette spil i 3D-voxelmotoren i stedet for den almindelige kerne + 3D-motorens egne indstillinger findes i menuen i spillet. + Lyden styres af 3D-motoren. Brug fanen Lyd i menuen i spillet. Stadium-ROM Klar Importér en ROM @@ -2057,7 +2059,7 @@ Installeret sti: Behold Slet Stadium-kampmodellerne er installeret. Vil du slette dem? - Stadium-kampmodeller slettet + Stadium-kampmodeller slettet. Genstart spillet for at fjerne dem helt. Kunne ikke slette Stadium-modellerne Skærmknapper Haptisk feedback diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 3c27b965e..c33cb6287 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -2046,6 +2046,8 @@ Installierter Pfad: Spieldaten werden zum ersten Mal vorbereitet Voxel 3D Dieses Spiel mit der 3D-Voxel-Engine statt mit dem Standard-Core spielen + Die eigenen Einstellungen der 3D-Engine stehen im Spielmenü. + Der Ton wird von der 3D-Engine verwaltet. Nutze den Tab „Ton“ im Spielmenü. Stadium-ROM Bereit ROM importieren @@ -2057,7 +2059,7 @@ Installierter Pfad: Behalten Löschen Die Stadium-Kampfmodelle sind installiert. Löschen? - Stadium-Kampfmodelle gelöscht + Stadium-Kampfmodelle gelöscht. Starte das Spiel neu, um sie vollständig zu entfernen. Die Stadium-Modelle konnten nicht gelöscht werden Bildschirmsteuerung Haptisches Feedback diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 1846e7a1e..67362428c 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -2045,6 +2045,8 @@ Ruta instalada: Preparando los datos del juego por primera vez Voxel 3D Juega a este juego con el motor de vóxeles 3D en lugar del núcleo estándar + Los ajustes propios del motor 3D están en el menú del juego. + El sonido lo gestiona el motor 3D. Usa la pestaña Sonido del menú del juego. ROM de Stadium Lista Importar una ROM @@ -2056,7 +2058,7 @@ Ruta instalada: Conservar Eliminar Los modelos de combate de Stadium están instalados. ¿Eliminarlos? - Modelos de combate de Stadium eliminados + Modelos de combate de Stadium eliminados. Reinicia el juego para terminar de quitarlos. No se pudieron eliminar los modelos de Stadium Controles en pantalla Respuesta háptica diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index 7267cd582..74d0dcdde 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -2044,6 +2044,8 @@ Asennuspolku: Valmistellaan pelitietoja ensimmäistä kertaa Voxel 3D Pelaa tätä peliä 3D-voxelmoottorilla vakioytimen sijaan + 3D-moottorin omat asetukset ovat pelin sisäisessä valikossa. + Äänestä vastaa 3D-moottori. Käytä pelin valikon Ääni-välilehteä. Stadium-ROM Valmis Tuo ROM @@ -2055,7 +2057,7 @@ Asennuspolku: Säilytä Poista Stadiumin taistelumallit on asennettu. Poistetaanko ne? - Stadiumin taistelumallit poistettu + Stadiumin taistelumallit poistettu. Käynnistä peli uudelleen viimeistelläksesi poiston. Stadium-malleja ei voitu poistaa Näytön ohjaimet Haptinen palaute diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 2db24202b..bce29de89 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -2045,6 +2045,8 @@ Chemin installé : Préparation des données du jeu pour la première fois Voxel 3D Jouer à ce jeu avec le moteur voxel 3D au lieu du cœur standard + Les réglages propres au moteur 3D se trouvent dans le menu en jeu. + Le son est géré par le moteur 3D. Utilisez l\'onglet Son du menu en jeu. ROM Stadium Prête Importer une ROM @@ -2056,7 +2058,7 @@ Chemin installé : Conserver Supprimer Les modèles de combat Stadium sont installés. Les supprimer ? - Modèles de combat Stadium supprimés + Modèles de combat Stadium supprimés. Redémarrez le jeu pour terminer la suppression. Impossible de supprimer les modèles Stadium Commandes à l\'écran Retour haptique diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 3e68e580f..af45fc214 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -1981,6 +1981,8 @@ पहली बार गेम डेटा तैयार किया जा रहा है वॉक्सेल 3D इस गेम को मानक कोर के बजाय 3D वॉक्सेल इंजन में खेलें + 3D इंजन की अपनी सेटिंग्स इन-गेम मेन्यू में हैं। + ध्वनि 3D इंजन द्वारा नियंत्रित होती है। इन-गेम मेन्यू में ध्वनि टैब का उपयोग करें। Stadium ROM तैयार ROM आयात करें @@ -1992,7 +1994,7 @@ रखें हटाएँ Stadium बैटल मॉडल इंस्टॉल हैं। उन्हें हटाएँ? - Stadium बैटल मॉडल हटाए गए + Stadium बैटल मॉडल हटाए गए। उन्हें पूरी तरह हटाने के लिए गेम पुनः आरंभ करें। Stadium मॉडल हटाए नहीं जा सके ऑन-स्क्रीन नियंत्रण हैप्टिक फ़ीडबैक diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 4ccbe18cc..45e73b759 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -2045,6 +2045,8 @@ Percorso installato: Preparazione dei dati di gioco per la prima volta Voxel 3D Gioca a questo gioco con il motore voxel 3D invece del core standard + Le impostazioni del motore 3D si trovano nel menu di gioco. + L\'audio è gestito dal motore 3D. Usa la scheda Audio nel menu di gioco. ROM di Stadium Pronta Importa una ROM @@ -2056,7 +2058,7 @@ Percorso installato: Mantieni Elimina I modelli di lotta di Stadium sono installati. Eliminarli? - Modelli di lotta di Stadium eliminati + Modelli di lotta di Stadium eliminati. Riavvia il gioco per completare la rimozione. Impossibile eliminare i modelli di Stadium Comandi a schermo Feedback aptico diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index a0c6e8b79..39d9a5d98 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -2044,6 +2044,8 @@ 初回のゲームデータを準備しています ボクセル3D 標準コアの代わりに3Dボクセルエンジンでこのゲームをプレイします + 3Dエンジン独自の設定はゲーム内メニューにあります。 + サウンドは3Dエンジンが管理します。ゲーム内メニューのサウンドタブを使用してください。 スタジアムROM 準備完了 ROMをインポート @@ -2055,7 +2057,7 @@ 保持 削除 スタジアムのバトルモデルがインストールされています。削除しますか? - スタジアムのバトルモデルを削除しました + スタジアムのバトルモデルを削除しました。完全に削除するにはゲームを再起動してください。 スタジアムのモデルを削除できませんでした 画面上のコントロール 触覚フィードバック diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 8ba12b4e1..2baf6229f 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -2046,6 +2046,8 @@ 게임 데이터를 처음으로 준비하는 중 복셀 3D 기본 코어 대신 3D 복셀 엔진으로 이 게임을 플레이합니다 + 3D 엔진의 자체 설정은 게임 내 메뉴에 있습니다. + 사운드는 3D 엔진이 관리합니다. 게임 내 메뉴의 사운드 탭을 사용하세요. 스타디움 ROM 준비됨 ROM 가져오기 @@ -2057,7 +2059,7 @@ 유지 삭제 스타디움 배틀 모델이 설치되어 있습니다. 삭제할까요? - 스타디움 배틀 모델을 삭제했습니다 + 스타디움 배틀 모델을 삭제했습니다. 완전히 제거하려면 게임을 다시 시작하세요. 스타디움 모델을 삭제할 수 없습니다 화면 컨트롤 햅틱 피드백 diff --git a/app/src/main/res/values-no/strings.xml b/app/src/main/res/values-no/strings.xml index b2f240101..fa63d8670 100644 --- a/app/src/main/res/values-no/strings.xml +++ b/app/src/main/res/values-no/strings.xml @@ -2044,6 +2044,8 @@ Installert bane: Forbereder spilldata for første gang Voxel 3D Spill dette spillet i 3D-voxelmotoren i stedet for standardkjernen + 3D-motorens egne innstillinger finnes i menyen i spillet. + Lyden styres av 3D-motoren. Bruk Lyd-fanen i menyen i spillet. Stadium-ROM Klar Importer en ROM @@ -2055,7 +2057,7 @@ Installert bane: Behold Slett Stadium-kampmodellene er installert. Vil du slette dem? - Stadium-kampmodeller slettet + Stadium-kampmodeller slettet. Start spillet på nytt for å fullføre fjerningen. Kunne ikke slette Stadium-modellene Skjermkontroller Haptisk tilbakemelding diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 1eac55ba3..662b6910f 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -2051,6 +2051,8 @@ Zainstalowana ścieżka: Pierwsze przygotowywanie danych gry Voxel 3D Graj w tę grę w silniku wokselowym 3D zamiast standardowego rdzenia + Własne ustawienia silnika 3D znajdują się w menu w grze. + Dźwiękiem zarządza silnik 3D. Użyj karty Dźwięk w menu w grze. ROM Stadium Gotowe Importuj ROM @@ -2062,7 +2064,7 @@ Zainstalowana ścieżka: Zachowaj Usuń Modele walki Stadium są zainstalowane. Usunąć je? - Usunięto modele walki Stadium + Usunięto modele walki Stadium. Uruchom grę ponownie, aby zakończyć ich usuwanie. Nie udało się usunąć modeli Stadium Sterowanie ekranowe Wibracje dotykowe diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index da0c84d0b..c8c140699 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -2045,6 +2045,8 @@ Caminho instalado: Preparando os dados do jogo pela primeira vez Voxel 3D Jogue este jogo no motor de voxels 3D em vez do núcleo padrão + As configurações do motor 3D ficam no menu do jogo. + O som é gerenciado pelo motor 3D. Use a aba Som no menu do jogo. ROM do Stadium Pronta Importar uma ROM @@ -2056,7 +2058,7 @@ Caminho instalado: Manter Excluir Os modelos de batalha do Stadium estão instalados. Excluí-los? - Modelos de batalha do Stadium excluídos + Modelos de batalha do Stadium excluídos. Reinicie o jogo para concluir a remoção. Não foi possível excluir os modelos do Stadium Controles na tela Resposta tátil diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 4efdf3482..831e78cba 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -2044,6 +2044,8 @@ Caminho instalado: A preparar os dados do jogo pela primeira vez Voxel 3D Jogar este jogo no motor de voxels 3D em vez do núcleo padrão + As definições do motor 3D estão no menu do jogo. + O som é gerido pelo motor 3D. Usa o separador Som no menu do jogo. ROM do Stadium Pronta Importar uma ROM @@ -2055,7 +2057,7 @@ Caminho instalado: Manter Eliminar Os modelos de combate do Stadium estão instalados. Eliminá-los? - Modelos de combate do Stadium eliminados + Modelos de combate do Stadium eliminados. Reinicie o jogo para concluir a remoção. Não foi possível eliminar os modelos do Stadium Controlos no ecrã Retorno tátil diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index a2b9a22a2..2f858d97e 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -2044,6 +2044,8 @@ Cale instalata: Se pregătesc datele jocului pentru prima dată Voxel 3D Joacă acest joc în motorul voxel 3D în loc de nucleul standard + Setările proprii ale motorului 3D se află în meniul din joc. + Sunetul este gestionat de motorul 3D. Folosește fila Sunet din meniul din joc. ROM Stadium Pregătit Importă un ROM @@ -2055,7 +2057,7 @@ Cale instalata: Păstrează Șterge Modelele de luptă Stadium sunt instalate. Le ștergi? - Modelele de luptă Stadium au fost șterse + Modelele de luptă Stadium au fost șterse. Repornește jocul pentru a finaliza eliminarea. Nu s-au putut șterge modelele Stadium Comenzi pe ecran Feedback haptic diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 576abf354..b806d890f 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -1951,6 +1951,8 @@ Первичная подготовка данных игры Воксельный 3D Играть в эту игру в воксельном 3D-движке вместо стандартного ядра + Собственные настройки 3D-движка находятся в игровом меню. + Звуком управляет 3D-движок. Используйте вкладку «Звук» в игровом меню. ROM Stadium Готово Импортировать ROM @@ -1962,7 +1964,7 @@ Оставить Удалить Боевые модели Stadium установлены. Удалить их? - Боевые модели Stadium удалены + Боевые модели Stadium удалены. Перезапустите игру, чтобы завершить удаление. Не удалось удалить модели Stadium Экранные кнопки Виброотклик diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index e9bf80fcb..8e983ea87 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -2044,6 +2044,8 @@ Installerad sökväg: Förbereder speldata för första gången Voxel 3D Spela det här spelet i 3D-voxelmotorn i stället för standardkärnan + 3D-motorns egna inställningar finns i menyn i spelet. + Ljudet hanteras av 3D-motorn. Använd fliken Ljud i menyn i spelet. Stadium-ROM Klar Importera en ROM @@ -2055,7 +2057,7 @@ Installerad sökväg: Behåll Ta bort Stadium-stridsmodellerna är installerade. Vill du ta bort dem? - Stadium-stridsmodeller borttagna + Stadium-stridsmodeller borttagna. Starta om spelet för att slutföra borttagningen. Det gick inte att ta bort Stadium-modellerna Skärmkontroller Haptisk återkoppling diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml index 3dd0f7a35..35b101840 100644 --- a/app/src/main/res/values-th/strings.xml +++ b/app/src/main/res/values-th/strings.xml @@ -2044,6 +2044,8 @@ กำลังเตรียมข้อมูลเกมเป็นครั้งแรก วอกเซล 3D เล่นเกมนี้ด้วยเอนจินวอกเซล 3D แทนคอร์มาตรฐาน + การตั้งค่าของเอนจิน 3D อยู่ในเมนูในเกม + เสียงจัดการโดยเอนจิน 3D ใช้แท็บเสียงในเมนูในเกม ROM ของ Stadium พร้อมแล้ว นำเข้า ROM @@ -2055,7 +2057,7 @@ เก็บไว้ ลบ ติดตั้งโมเดลการต่อสู้ของ Stadium แล้ว ต้องการลบหรือไม่ - ลบโมเดลการต่อสู้ของ Stadium แล้ว + ลบโมเดลการต่อสู้ของ Stadium แล้ว รีสตาร์ทเกมเพื่อลบให้เสร็จสมบูรณ์ ลบโมเดลของ Stadium ไม่ได้ ปุ่มควบคุมบนหน้าจอ การสั่นตอบสนอง diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 1de961479..18a106ab2 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -2044,6 +2044,8 @@ Yüklü konum: Oyun verileri ilk kez hazırlanıyor Voxel 3D Bu oyunu standart çekirdek yerine 3D voxel motorunda oynayın + 3D motorun kendi ayarları oyun içi menüdedir. + Ses, 3D motor tarafından yönetilir. Oyun içi menüdeki Ses sekmesini kullanın. Stadium ROM\'u Hazır ROM içe aktar @@ -2055,7 +2057,7 @@ Yüklü konum: Sakla Sil Stadium dövüş modelleri yüklü. Silinsin mi? - Stadium dövüş modelleri silindi + Stadium dövüş modelleri silindi. Kaldırma işlemini tamamlamak için oyunu yeniden başlatın. Stadium modelleri silinemedi Ekran kontrolleri Dokunsal Geri Bildirim diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 3f06fba22..df571d503 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -2051,6 +2051,8 @@ Перша підготовка даних гри Воксельний 3D Грати в цю гру у воксельному 3D-рушії замість стандартного ядра + Власні налаштування 3D-рушія містяться в ігровому меню. + Звуком керує 3D-рушій. Скористайтеся вкладкою «Звук» в ігровому меню. ROM Stadium Готово Імпортувати ROM @@ -2062,7 +2064,7 @@ Залишити Видалити Бойові моделі Stadium встановлено. Видалити їх? - Бойові моделі Stadium видалено + Бойові моделі Stadium видалено. Перезапустіть гру, щоб завершити видалення. Не вдалося видалити моделі Stadium Екранне керування Тактильний відгук diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 7d51a3d04..c91d00c73 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -2045,6 +2045,8 @@ 正在首次准备游戏数据 体素 3D 使用 3D 体素引擎运行此游戏,而非标准核心 + 3D 引擎自身的设置位于游戏内菜单中。 + 声音由 3D 引擎控制,请使用游戏内菜单的“声音”标签页。 Stadium ROM 已就绪 导入 ROM @@ -2056,7 +2058,7 @@ 保留 删除 Stadium 对战模型已安装。要删除吗? - 已删除 Stadium 对战模型 + 已删除 Stadium 对战模型。请重启游戏以完成移除。 无法删除 Stadium 模型 屏幕控制 触觉反馈 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 7b3c28636..e358ba4b0 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -2044,6 +2044,8 @@ 正在首次準備遊戲資料 體素 3D 使用 3D 體素引擎執行此遊戲,而非標準核心 + 3D 引擎本身的設定位於遊戲內選單中。 + 聲音由 3D 引擎控制,請使用遊戲內選單的「聲音」分頁。 Stadium ROM 已就緒 匯入 ROM @@ -2055,7 +2057,7 @@ 保留 刪除 Stadium 對戰模型已安裝。要刪除嗎? - 已刪除 Stadium 對戰模型 + 已刪除 Stadium 對戰模型。請重新啟動遊戲以完成移除。 無法刪除 Stadium 模型 螢幕控制 觸覺回饋 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bd7e7d997..44877f0ae 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2160,6 +2160,8 @@ Installed path: Preparing game data for the first time Voxel 3D Play this game in the 3D voxel engine instead of the standard core + The 3D engine\'s own settings live in the in-game menu. + Sound is handled by the 3D engine. Use the Sound tab in the in-game menu. Stadium ROM Ready Import a ROM @@ -2171,7 +2173,7 @@ Installed path: Keep Delete The Stadium battle models are installed. Delete them? - Stadium battle models deleted + Stadium battle models deleted. Restart the game to finish removing them. Could not delete the Stadium models On-screen controls Adaptive Sticks From 82e64e77a9d47881e61772ddd0019fe1af1e52bf Mon Sep 17 00:00:00 2001 From: MaxsTechReview Date: Wed, 5 Aug 2026 16:38:52 -0400 Subject: [PATCH 3/3] Give the 3D engine's own settings a home in Shortcut Settings Shortcut Settings showed nothing the engine actually runs on. The engine publishes fourteen rows over the bridge -- colors, tilt, gbcfx, zoom, voidFill, videoMode, animations, the three volumes and the music filter, fpsCap, speed, controls -- plus whatever the mod adds, and none of them reached the screen. Embedded emulators already have this: RetroCoreOptions carries GAMECUBE_OPTIONS and WII_OPTIONS for standalone Dolphin, and DolphinEmbedLaunch resolves them into EXTRA_VARIABLES at launch. The 3D engine had no equivalent. A hand-written catalogue would not survive here. Several ladders are built at runtime -- zoom's legal range follows the window's fit scale and changes on rotation, colors comes from PaletteFX.MODES, controls from the ruleset registry -- so a copy in Kotlin would be wrong the moment the engine moved. Instead the rows the engine already publishes are cached as it runs, and that cache is what the screen renders. The labels come from the engine, so there is no second list to maintain and a new option appears on its own after one launch. Choices are stored as the retro_var_ extras the libretro path already uses, resolved at launch, and applied through the bridge once the engine reports booted. Every row keeps a leave-as-set entry so a shortcut only pins what the player actually chose, and a game that has never run says so rather than showing an empty screen. --- app/src/main/feature/retro/Gen1EmbedLaunch.kt | 4 + .../main/feature/retro/Gen1EngineActivity.kt | 12 ++ .../main/feature/retro/Gen1EngineSettings.kt | 111 ++++++++++++++++++ .../main/feature/retro/RetroGameSettings.kt | 60 +++++++++- app/src/main/res/values-b+es+419/strings.xml | 2 + app/src/main/res/values-da/strings.xml | 2 + app/src/main/res/values-de/strings.xml | 2 + app/src/main/res/values-es/strings.xml | 2 + app/src/main/res/values-fi/strings.xml | 2 + app/src/main/res/values-fr/strings.xml | 2 + app/src/main/res/values-hi/strings.xml | 2 + app/src/main/res/values-it/strings.xml | 2 + app/src/main/res/values-ja/strings.xml | 2 + app/src/main/res/values-ko/strings.xml | 2 + app/src/main/res/values-no/strings.xml | 2 + app/src/main/res/values-pl/strings.xml | 2 + app/src/main/res/values-pt-rBR/strings.xml | 2 + app/src/main/res/values-pt/strings.xml | 2 + app/src/main/res/values-ro/strings.xml | 2 + app/src/main/res/values-ru/strings.xml | 2 + app/src/main/res/values-sv/strings.xml | 2 + app/src/main/res/values-th/strings.xml | 2 + app/src/main/res/values-tr/strings.xml | 2 + app/src/main/res/values-uk/strings.xml | 2 + app/src/main/res/values-zh-rCN/strings.xml | 2 + app/src/main/res/values-zh-rTW/strings.xml | 2 + app/src/main/res/values/strings.xml | 2 + 27 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 app/src/main/feature/retro/Gen1EngineSettings.kt diff --git a/app/src/main/feature/retro/Gen1EmbedLaunch.kt b/app/src/main/feature/retro/Gen1EmbedLaunch.kt index 6e3688f0d..e9153e714 100644 --- a/app/src/main/feature/retro/Gen1EmbedLaunch.kt +++ b/app/src/main/feature/retro/Gen1EmbedLaunch.kt @@ -151,6 +151,10 @@ object Gen1EmbedLaunch { Gen1EngineActivity.EXTRA_ARTWORK_PATH, shortcut.getExtra("customCoverArtPath"), ) + putExtra( + Gen1EngineActivity.EXTRA_ENGINE_VARS, + Gen1EngineSettings.resolve(context, shortcut), + ) } } } diff --git a/app/src/main/feature/retro/Gen1EngineActivity.kt b/app/src/main/feature/retro/Gen1EngineActivity.kt index c33074dc4..713af01c0 100644 --- a/app/src/main/feature/retro/Gen1EngineActivity.kt +++ b/app/src/main/feature/retro/Gen1EngineActivity.kt @@ -49,6 +49,7 @@ class Gen1EngineActivity : private lateinit var bridge: Gen1EngineBridge private var touchControls = true + private var engineVarsApplied = false private var persistShortcut: Shortcut? = null @@ -750,6 +751,16 @@ class Gen1EngineActivity : private fun onEngineState(state: Gen1EngineBridge.State, menuChanged: Boolean) { importState = state.import if (loadingVisible && state.booted) loadingVisible = false + if (state.booted && state.rows.isNotEmpty()) { + if (!engineVarsApplied) { + engineVarsApplied = true + @Suppress("UNCHECKED_CAST") + val wanted = + intent.getSerializableExtra(EXTRA_ENGINE_VARS) as? HashMap + if (wanted != null) Gen1EngineSettings.applyTo(bridge, wanted) + } + Gen1EngineSettings.cache(this, state.rows) + } if (menuChanged && menu.visible) menu.rebuild() } @@ -977,6 +988,7 @@ class Gen1EngineActivity : const val EXTRA_VERSION = "wn.engine.version" const val EXTRA_GAME_NAME = "wn.engine.game_name" const val EXTRA_SHORTCUT_PATH = "wn.engine.shortcut" + const val EXTRA_ENGINE_VARS = "wn.engine.vars" const val EXTRA_ARTWORK_PATH = "wn.engine.artwork" private const val DPAD_DEADZONE = 0.35f diff --git a/app/src/main/feature/retro/Gen1EngineSettings.kt b/app/src/main/feature/retro/Gen1EngineSettings.kt new file mode 100644 index 000000000..e1b85b7dd --- /dev/null +++ b/app/src/main/feature/retro/Gen1EngineSettings.kt @@ -0,0 +1,111 @@ +package com.winlator.cmod.feature.retro + +import android.content.Context +import androidx.preference.PreferenceManager +import com.winlator.cmod.runtime.container.Shortcut +import org.json.JSONArray +import org.json.JSONObject + +object Gen1EngineSettings { + private const val CACHE_KEY = "gen1_engine_rows" + + data class CachedRow( + val id: String, + val label: String, + val values: List, + val pane: String, + ) + + fun cache( + context: Context, + rows: List, + ) { + val usable = rows.filter { it.values.size > 1 && it.id != Gen1StadiumRom.ROW_ID } + if (usable.isEmpty()) return + val array = JSONArray() + usable.forEach { row -> + array.put( + JSONObject() + .put("id", row.id) + .put("label", row.label) + .put("pane", paneOf(row.id)) + .put("values", JSONArray(row.values)), + ) + } + PreferenceManager.getDefaultSharedPreferences(context) + .edit().putString(CACHE_KEY, array.toString()).apply() + } + + fun cached(context: Context): List = + runCatching { + val raw = + PreferenceManager.getDefaultSharedPreferences(context) + .getString(CACHE_KEY, null) ?: return emptyList() + val array = JSONArray(raw) + (0 until array.length()).mapNotNull { i -> + val o = array.optJSONObject(i) ?: return@mapNotNull null + val values = o.optJSONArray("values") ?: return@mapNotNull null + val list = (0 until values.length()).map { values.optString(it) } + if (list.size < 2) return@mapNotNull null + CachedRow( + id = o.optString("id"), + label = o.optString("label"), + values = list, + pane = o.optString("pane", PANE_SYSTEM), + ) + } + }.getOrDefault(emptyList()) + + fun selection( + shortcut: Shortcut, + row: CachedRow, + ): String? = + shortcut.getExtra(RetroShortcuts.VAR_PREFIX + row.id) + .takeIf { it.isNotEmpty() && it in row.values } + + fun resolve( + context: Context, + shortcut: Shortcut, + ): HashMap { + val out = HashMap() + cached(context).forEach { row -> + selection(shortcut, row)?.let { out[row.id] = it } + } + return out + } + + fun applyTo( + bridge: Gen1EngineBridge, + wanted: Map, + ) { + if (wanted.isEmpty()) return + bridge.state.rows.forEach { row -> + val target = wanted[row.id] ?: return@forEach + if (row.values.isEmpty()) return@forEach + val index = row.values.indexOf(target) + if (index >= 0 && index != row.selectedIndex) bridge.setRow(row.id, index) + } + } + + const val PANE_DISPLAY = "display" + const val PANE_SOUND = "sound" + const val PANE_PERFORMANCE = "performance" + const val PANE_CONTROLS = "controls" + const val PANE_SYSTEM = "system" + + private val SOUND_ROWS = setOf("musicVol", "sfxVol", "pikaVol", "musicFilter") + private val DISPLAY_ROWS = + setOf("colors", "tilt", "gbcfx", "zoom", "voidFill", "videoMode", "animations") + private val PERFORMANCE_ROWS = setOf("fpsCap", "speed") + private val CONTROL_ROWS = setOf("controls") + + private fun paneOf(id: String): String = + when { + Gen1EngineBridge.isModRow(id) -> PANE_DISPLAY + id in SOUND_ROWS -> PANE_SOUND + id in DISPLAY_ROWS -> PANE_DISPLAY + id in PERFORMANCE_ROWS -> PANE_PERFORMANCE + id in CONTROL_ROWS -> PANE_CONTROLS + else -> PANE_SYSTEM + } +} diff --git a/app/src/main/feature/retro/RetroGameSettings.kt b/app/src/main/feature/retro/RetroGameSettings.kt index e36aef8f8..a0193514c 100644 --- a/app/src/main/feature/retro/RetroGameSettings.kt +++ b/app/src/main/feature/retro/RetroGameSettings.kt @@ -135,6 +135,15 @@ class RetroSettingsState( .lowercase().let { if (it in UPSCALE_KEYS) it else "native" }, ) var engine3d by mutableStateOf(shortcut.getExtra(Gen1EmbedLaunch.KEY_ENGINE_3D) == "1") + + val engineValues: androidx.compose.runtime.snapshots.SnapshotStateMap = + androidx.compose.runtime.mutableStateMapOf().apply { + if (context != null) { + Gen1EngineSettings.cached(context).forEach { row -> + Gen1EngineSettings.selection(shortcut, row)?.let { put(row.id, it) } + } + } + } var touchControls by mutableStateOf( shortcut.getExtra(RetroShortcuts.KEY_TOUCH_CONTROLS) .ifEmpty { if (context != null && sysId != null) (if (RetroDefaults.touchControls(context, sysId)) "1" else "0") else "1" } != "0", @@ -206,6 +215,11 @@ class RetroSettingsState( shortcut.putExtra(RetroShortcuts.KEY_SGSR, if (sgsr) "1" else "0") shortcut.putExtra(RetroShortcuts.KEY_UPSCALE, upscale) shortcut.putExtra(Gen1EmbedLaunch.KEY_ENGINE_3D, if (engine3d) "1" else "0") + if (context != null) { + Gen1EngineSettings.cached(context).forEach { row -> + shortcut.putExtra(RetroShortcuts.VAR_PREFIX + row.id, engineValues[row.id]) + } + } shortcut.putExtra(RetroShortcuts.KEY_TOUCH_CONTROLS, if (touchControls) "1" else "0") shortcut.putExtra(RetroShortcuts.KEY_ADAPTIVE_STICKS, if (adaptiveSticks) "1" else "0") shortcut.putExtra(RetroShortcuts.KEY_HDD_IMAGE, hddImage) @@ -1120,8 +1134,8 @@ private fun RetroGraphicsSection(state: RetroSettingsState) { RetroSettingGroup { RetroGroupTitle(stringResource(R.string.retro_gs_engine_3d).uppercase()) RetroStadiumRomSetting() - RetroSettingNote(stringResource(R.string.retro_gs_engine_3d_note)) } + RetroEngineRowSettings(state) } if (!voxelEngine) { RetroSettingGroup { @@ -1172,6 +1186,50 @@ private fun RetroGraphicsSection(state: RetroSettingsState) { } } +@Composable +private fun RetroEngineRowSettings(state: RetroSettingsState) { + val context = androidx.compose.ui.platform.LocalContext.current + val rows = remember(context) { Gen1EngineSettings.cached(context) } + if (rows.isEmpty()) { + RetroSettingGroup { + RetroSettingNote(stringResource(R.string.retro_gs_engine_3d_uncached)) + } + return + } + val panes = + listOf( + Gen1EngineSettings.PANE_DISPLAY to R.string.retro_gs_section_graphics, + Gen1EngineSettings.PANE_SOUND to R.string.retro_gs_group_audio, + Gen1EngineSettings.PANE_PERFORMANCE to R.string.retro_gs_section_performance, + Gen1EngineSettings.PANE_CONTROLS to R.string.retro_gs_group_input, + Gen1EngineSettings.PANE_SYSTEM to R.string.retro_gs_section_general, + ) + panes.forEach { (pane, titleRes) -> + val paneRows = rows.filter { it.pane == pane } + if (paneRows.isEmpty()) return@forEach + Spacer(Modifier.height(12.dp)) + RetroSettingGroup { + RetroGroupTitle(stringResource(titleRes).uppercase()) + paneRows.forEach { row -> + val current = state.engineValues[row.id] + RetroSettingDropdown( + label = row.label, + entries = listOf(stringResource(R.string.retro_gs_engine_3d_leave)) + row.values, + selectedIndex = (row.values.indexOf(current) + 1).coerceAtLeast(0), + onSelected = { index -> + if (index == 0) { + state.engineValues.remove(row.id) + } else { + state.engineValues[row.id] = row.values[index - 1] + } + }, + ) + } + } + } + RetroSettingNote(stringResource(R.string.retro_gs_engine_3d_note)) +} + @Composable private fun RetroSettingNote(text: String) { Text( diff --git a/app/src/main/res/values-b+es+419/strings.xml b/app/src/main/res/values-b+es+419/strings.xml index f7b56e580..c5a608a85 100644 --- a/app/src/main/res/values-b+es+419/strings.xml +++ b/app/src/main/res/values-b+es+419/strings.xml @@ -2045,6 +2045,8 @@ Ruta instalada: Voxel 3D Juega este juego con el motor de vóxeles 3D en lugar del núcleo estándar Los ajustes propios del motor 3D están en el menú del juego. + Inicia el juego una vez para que sus ajustes del motor 3D aparezcan aquí. + Dejar como en el juego El sonido lo gestiona el motor 3D. Usa la pestaña Sonido del menú del juego. ROM de Stadium Lista diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index 30c32a3b7..7bce152eb 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -2047,6 +2047,8 @@ Installeret sti: Voxel 3D Spil dette spil i 3D-voxelmotoren i stedet for den almindelige kerne 3D-motorens egne indstillinger findes i menuen i spillet. + Start spillet én gang, så 3D-motorens indstillinger kan vises her. + Behold som i spillet Lyden styres af 3D-motoren. Brug fanen Lyd i menuen i spillet. Stadium-ROM Klar diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index c33cb6287..b63c7a88f 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -2047,6 +2047,8 @@ Installierter Pfad: Voxel 3D Dieses Spiel mit der 3D-Voxel-Engine statt mit dem Standard-Core spielen Die eigenen Einstellungen der 3D-Engine stehen im Spielmenü. + Starte das Spiel einmal, damit die Einstellungen der 3D-Engine hier erscheinen. + Wie im Spiel belassen Der Ton wird von der 3D-Engine verwaltet. Nutze den Tab „Ton“ im Spielmenü. Stadium-ROM Bereit diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 67362428c..891826815 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -2046,6 +2046,8 @@ Ruta instalada: Voxel 3D Juega a este juego con el motor de vóxeles 3D en lugar del núcleo estándar Los ajustes propios del motor 3D están en el menú del juego. + Inicia el juego una vez para que sus ajustes del motor 3D aparezcan aquí. + Dejar como en el juego El sonido lo gestiona el motor 3D. Usa la pestaña Sonido del menú del juego. ROM de Stadium Lista diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index 74d0dcdde..9259f8ab3 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -2045,6 +2045,8 @@ Asennuspolku: Voxel 3D Pelaa tätä peliä 3D-voxelmoottorilla vakioytimen sijaan 3D-moottorin omat asetukset ovat pelin sisäisessä valikossa. + Käynnistä peli kerran, jotta 3D-moottorin asetukset näkyvät täällä. + Jätä pelin mukaiseksi Äänestä vastaa 3D-moottori. Käytä pelin valikon Ääni-välilehteä. Stadium-ROM Valmis diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index bce29de89..aa9e2a313 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -2046,6 +2046,8 @@ Chemin installé : Voxel 3D Jouer à ce jeu avec le moteur voxel 3D au lieu du cœur standard Les réglages propres au moteur 3D se trouvent dans le menu en jeu. + Lancez le jeu une fois pour que les réglages du moteur 3D apparaissent ici. + Laisser comme dans le jeu Le son est géré par le moteur 3D. Utilisez l\'onglet Son du menu en jeu. ROM Stadium Prête diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index af45fc214..57ee71630 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -1982,6 +1982,8 @@ वॉक्सेल 3D इस गेम को मानक कोर के बजाय 3D वॉक्सेल इंजन में खेलें 3D इंजन की अपनी सेटिंग्स इन-गेम मेन्यू में हैं। + 3D इंजन की सेटिंग्स यहाँ दिखाने के लिए गेम एक बार चलाएँ। + गेम में सेट अनुसार छोड़ें ध्वनि 3D इंजन द्वारा नियंत्रित होती है। इन-गेम मेन्यू में ध्वनि टैब का उपयोग करें। Stadium ROM तैयार diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 45e73b759..e5ed7beaa 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -2046,6 +2046,8 @@ Percorso installato: Voxel 3D Gioca a questo gioco con il motore voxel 3D invece del core standard Le impostazioni del motore 3D si trovano nel menu di gioco. + Avvia il gioco una volta perché le impostazioni del motore 3D compaiano qui. + Lascia come nel gioco L\'audio è gestito dal motore 3D. Usa la scheda Audio nel menu di gioco. ROM di Stadium Pronta diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 39d9a5d98..5457505ed 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -2045,6 +2045,8 @@ ボクセル3D 標準コアの代わりに3Dボクセルエンジンでこのゲームをプレイします 3Dエンジン独自の設定はゲーム内メニューにあります。 + 3Dエンジンの設定をここに表示するには、ゲームを一度起動してください。 + ゲーム内の設定のまま サウンドは3Dエンジンが管理します。ゲーム内メニューのサウンドタブを使用してください。 スタジアムROM 準備完了 diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 2baf6229f..a9a07ac71 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -2047,6 +2047,8 @@ 복셀 3D 기본 코어 대신 3D 복셀 엔진으로 이 게임을 플레이합니다 3D 엔진의 자체 설정은 게임 내 메뉴에 있습니다. + 3D 엔진 설정을 여기에 표시하려면 게임을 한 번 실행하세요. + 게임 설정 그대로 사운드는 3D 엔진이 관리합니다. 게임 내 메뉴의 사운드 탭을 사용하세요. 스타디움 ROM 준비됨 diff --git a/app/src/main/res/values-no/strings.xml b/app/src/main/res/values-no/strings.xml index fa63d8670..821f184a6 100644 --- a/app/src/main/res/values-no/strings.xml +++ b/app/src/main/res/values-no/strings.xml @@ -2045,6 +2045,8 @@ Installert bane: Voxel 3D Spill dette spillet i 3D-voxelmotoren i stedet for standardkjernen 3D-motorens egne innstillinger finnes i menyen i spillet. + Start spillet én gang så innstillingene for 3D-motoren vises her. + Behold som i spillet Lyden styres av 3D-motoren. Bruk Lyd-fanen i menyen i spillet. Stadium-ROM Klar diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 662b6910f..e8d042b42 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -2052,6 +2052,8 @@ Zainstalowana ścieżka: Voxel 3D Graj w tę grę w silniku wokselowym 3D zamiast standardowego rdzenia Własne ustawienia silnika 3D znajdują się w menu w grze. + Uruchom grę raz, aby ustawienia silnika 3D pojawiły się tutaj. + Pozostaw jak w grze Dźwiękiem zarządza silnik 3D. Użyj karty Dźwięk w menu w grze. ROM Stadium Gotowe diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index c8c140699..2b6df0eb6 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -2046,6 +2046,8 @@ Caminho instalado: Voxel 3D Jogue este jogo no motor de voxels 3D em vez do núcleo padrão As configurações do motor 3D ficam no menu do jogo. + Inicie o jogo uma vez para que as configurações do motor 3D apareçam aqui. + Manter como no jogo O som é gerenciado pelo motor 3D. Use a aba Som no menu do jogo. ROM do Stadium Pronta diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 831e78cba..50b5cbc68 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -2045,6 +2045,8 @@ Caminho instalado: Voxel 3D Jogar este jogo no motor de voxels 3D em vez do núcleo padrão As definições do motor 3D estão no menu do jogo. + Inicia o jogo uma vez para que as definições do motor 3D apareçam aqui. + Manter como no jogo O som é gerido pelo motor 3D. Usa o separador Som no menu do jogo. ROM do Stadium Pronta diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 2f858d97e..613511f62 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -2045,6 +2045,8 @@ Cale instalata: Voxel 3D Joacă acest joc în motorul voxel 3D în loc de nucleul standard Setările proprii ale motorului 3D se află în meniul din joc. + Pornește jocul o dată pentru ca setările motorului 3D să apară aici. + Lasă ca în joc Sunetul este gestionat de motorul 3D. Folosește fila Sunet din meniul din joc. ROM Stadium Pregătit diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index b806d890f..808fb698a 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -1952,6 +1952,8 @@ Воксельный 3D Играть в эту игру в воксельном 3D-движке вместо стандартного ядра Собственные настройки 3D-движка находятся в игровом меню. + Запустите игру один раз, чтобы настройки 3D-движка появились здесь. + Оставить как в игре Звуком управляет 3D-движок. Используйте вкладку «Звук» в игровом меню. ROM Stadium Готово diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 8e983ea87..4ab8e1cde 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -2045,6 +2045,8 @@ Installerad sökväg: Voxel 3D Spela det här spelet i 3D-voxelmotorn i stället för standardkärnan 3D-motorns egna inställningar finns i menyn i spelet. + Starta spelet en gång så att 3D-motorns inställningar visas här. + Behåll som i spelet Ljudet hanteras av 3D-motorn. Använd fliken Ljud i menyn i spelet. Stadium-ROM Klar diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml index 35b101840..980740169 100644 --- a/app/src/main/res/values-th/strings.xml +++ b/app/src/main/res/values-th/strings.xml @@ -2045,6 +2045,8 @@ วอกเซล 3D เล่นเกมนี้ด้วยเอนจินวอกเซล 3D แทนคอร์มาตรฐาน การตั้งค่าของเอนจิน 3D อยู่ในเมนูในเกม + เปิดเกมหนึ่งครั้งเพื่อให้การตั้งค่าเอนจิน 3D แสดงที่นี่ + คงค่าตามในเกม เสียงจัดการโดยเอนจิน 3D ใช้แท็บเสียงในเมนูในเกม ROM ของ Stadium พร้อมแล้ว diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 18a106ab2..445fe681e 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -2045,6 +2045,8 @@ Yüklü konum: Voxel 3D Bu oyunu standart çekirdek yerine 3D voxel motorunda oynayın 3D motorun kendi ayarları oyun içi menüdedir. + 3D motor ayarlarının burada listelenmesi için oyunu bir kez başlatın. + Oyundaki gibi bırak Ses, 3D motor tarafından yönetilir. Oyun içi menüdeki Ses sekmesini kullanın. Stadium ROM\'u Hazır diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index df571d503..e64edb25c 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -2052,6 +2052,8 @@ Воксельний 3D Грати в цю гру у воксельному 3D-рушії замість стандартного ядра Власні налаштування 3D-рушія містяться в ігровому меню. + Запустіть гру один раз, щоб налаштування 3D-рушія з’явилися тут. + Залишити як у грі Звуком керує 3D-рушій. Скористайтеся вкладкою «Звук» в ігровому меню. ROM Stadium Готово diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index c91d00c73..c91f65211 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -2046,6 +2046,8 @@ 体素 3D 使用 3D 体素引擎运行此游戏,而非标准核心 3D 引擎自身的设置位于游戏内菜单中。 + 先启动一次游戏,其 3D 引擎设置才会显示在这里。 + 保持游戏内设置 声音由 3D 引擎控制,请使用游戏内菜单的“声音”标签页。 Stadium ROM 已就绪 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index e358ba4b0..1a26b4301 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -2045,6 +2045,8 @@ 體素 3D 使用 3D 體素引擎執行此遊戲,而非標準核心 3D 引擎本身的設定位於遊戲內選單中。 + 先啟動一次遊戲,其 3D 引擎設定才會顯示在這裡。 + 保持遊戲內設定 聲音由 3D 引擎控制,請使用遊戲內選單的「聲音」分頁。 Stadium ROM 已就緒 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 44877f0ae..98e0f9f37 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2161,6 +2161,8 @@ Installed path: Voxel 3D Play this game in the 3D voxel engine instead of the standard core The 3D engine\'s own settings live in the in-game menu. + Launch this game once so its 3D engine settings can be listed here. + Leave as set in game Sound is handled by the 3D engine. Use the Sound tab in the in-game menu. Stadium ROM Ready