Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
c59dbcc35c | |||
91d38b58c4 | |||
240f60b283 | |||
6a32ad65a5 | |||
6cc7a537b6 | |||
bf4c06ee2d | |||
f26d83f291 | |||
8b2c1a04ee |
12
CHANGELOG.md
12
CHANGELOG.md
@ -1,3 +1,15 @@
|
|||||||
|
## 0.16.0
|
||||||
|
|
||||||
|
- Fixed the clear cache button not working
|
||||||
|
- Fixed Linux builds
|
||||||
|
- Moved the store tab to the left
|
||||||
|
- "Reapply mods and start" renamed from "Refresh and start" to better convey the meaning
|
||||||
|
- "Reapply mods and start" is no longer necessary when enabling packages from the `local` namespace
|
||||||
|
- Various internationalization additions
|
||||||
|
- STARTLINER now remembers the recently open tab and re-opens it on the next session
|
||||||
|
- Added "Beta" to the title as STARTLINER is approaching feature-completeness
|
||||||
|
- Added full Polish localization :smciota:
|
||||||
|
|
||||||
## 0.15.0
|
## 0.15.0
|
||||||
|
|
||||||
- Added internationalization
|
- Added internationalization
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
If you're stuck on this screen, restart the game.
|
|
||||||
|
|
||||||
If the problem persists, <a href="https://gitea.tendokyu.moe/Dniel97/SEGAguide/wiki/FAQ#game-is-stuck-at-checking-distribution-server" target="_blank">check your network configuration</a>
|
|
@ -1,8 +0,0 @@
|
|||||||
You can access this page any time by right-clicking the START button.
|
|
||||||
|
|
||||||
Additional resources:
|
|
||||||
|
|
||||||
- <a href="https://gitea.tendokyu.moe/Dniel97/SEGAguide/wiki/FAQ" target="_blank">SEGAguide</a>
|
|
||||||
- <a href="https://two-torial.xyz/" target="_blank">two-torial</a>
|
|
||||||
|
|
||||||
## Have fun
|
|
@ -1,3 +0,0 @@
|
|||||||
You also have to calibrate the lever, or you may get the error 3301.
|
|
||||||
|
|
||||||
Go to lever settings (<span class="bg-black text-white">レバー設定</span>), move the lever to both edges, then press "end" (<span class="bg-black text-white">終了</span>) and "save" (<span class="bg-black text-white">保存する</span>).
|
|
@ -1,3 +0,0 @@
|
|||||||
You might get stuck on this screen for several minutes. _This is normal_. The game just takes a long time to load data.
|
|
||||||
|
|
||||||
If you install <code>7EVENDAYSHOLIDAYS/LoadBoost</code>, subsequent launches will be much faster.
|
|
@ -1,7 +0,0 @@
|
|||||||
You might get stuck on the following screen:
|
|
||||||
|
|
||||||
<div class="p-2 mt-1 mb-1 bg-black text-white">Aグループの基準機から設定を取得</div>
|
|
||||||
|
|
||||||
In which case, you should go to the test menu, and in game settings <span class="bg-black text-white">ゲーム設定</span> switch from "follow the standard machine" <span class="bg-black text-white">基準機に従う</span> to "standard machine" <span class="bg-black text-white">基準機</span>.
|
|
||||||
|
|
||||||
The test menu can be accessed with %TESTMENU%.
|
|
@ -75,6 +75,7 @@ pub async fn startline(app: AppHandle, refresh: bool) -> Result<(), String> {
|
|||||||
&p.data.sgt.target.parent().unwrap().join("amdaemon.exe")
|
&p.data.sgt.target.parent().unwrap().join("amdaemon.exe")
|
||||||
).map_err(|e| e.to_string())?;
|
).map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
let info = p.prepare_display()
|
let info = p.prepare_display()
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
let lineup_res = p.line_up(hash, refresh, patches_enabled).await
|
let lineup_res = p.line_up(hash, refresh, patches_enabled).await
|
||||||
@ -190,12 +191,16 @@ pub async fn get_all_packages(state: State<'_, Mutex<AppData>>) -> Result<HashMa
|
|||||||
|
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_game_packages(state: State<'_, Mutex<AppData>>, game: Game) -> Result<Vec<PkgKey>, ()> {
|
pub async fn get_game_packages(state: State<'_, Mutex<AppData>>, game: Option<Game>) -> Result<Vec<PkgKey>, ()> {
|
||||||
log::debug!("invoke: get_game_packages {game}");
|
log::debug!("invoke: get_game_packages {game:?}");
|
||||||
|
|
||||||
let appd = state.lock().await;
|
let appd = state.lock().await;
|
||||||
|
|
||||||
|
if let Some(game) = game {
|
||||||
Ok(appd.pkgs.get_game_list(game))
|
Ok(appd.pkgs.get_game_list(game))
|
||||||
|
} else {
|
||||||
|
Ok(Vec::new())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@ -404,10 +409,14 @@ pub async fn load_segatools_ini(state: State<'_, Mutex<AppData>>, path: PathBuf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn create_shortcut(app: AppHandle, profile_meta: ProfileMeta) -> Result<(), String> {
|
pub async fn create_shortcut(_app: AppHandle, profile_meta: ProfileMeta) -> Result<(), String> {
|
||||||
log::debug!("invoke: create_shortcut({:?})", profile_meta);
|
log::debug!("invoke: create_shortcut({:?})", profile_meta);
|
||||||
|
|
||||||
util::create_shortcut(app, &profile_meta).map_err(|e| e.to_string())
|
#[cfg(target_os = "windows")]
|
||||||
|
return util::create_shortcut(_app, &profile_meta).map_err(|e| e.to_string());
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
return Err("unsupported".to_owned());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@ -437,12 +446,32 @@ pub async fn import_profile(path: PathBuf) -> Result<(), String> {
|
|||||||
Profile::import(path).map_err(|e| e.to_string())
|
Profile::import(path).map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn clear_cache(state: State<'_, Mutex<AppData>>) -> Result<(), String> {
|
||||||
|
log::debug!("invoke: clear_cache");
|
||||||
|
|
||||||
|
let appd = state.lock().await;
|
||||||
|
if let Some(p) = &appd.profile {
|
||||||
|
let dir = p.data_dir().join("mu3-mods-cache");
|
||||||
|
let path = dir.join("data_cache.bin");
|
||||||
|
if path.exists() {
|
||||||
|
std::fs::remove_file(path).map_err(|e| e.to_string())?;
|
||||||
|
}
|
||||||
|
let path = dir.join("data_fumen_analysis_cache.bin");
|
||||||
|
if path.exists() {
|
||||||
|
std::fs::remove_file(path).map_err(|e| e.to_string())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn list_platform_capabilities() -> Result<Vec<String>, ()> {
|
pub async fn list_platform_capabilities() -> Result<Vec<String>, ()> {
|
||||||
log::debug!("invoke: list_platform_capabilities");
|
log::debug!("invoke: list_platform_capabilities");
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
return Ok(vec!["display".to_owned()]);
|
return Ok(vec!["display".to_owned(), "shortcut".to_owned(), "chunithm".to_owned()]);
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
return Ok(vec!["wine".to_owned()]);
|
return Ok(vec!["wine".to_owned()]);
|
||||||
|
@ -207,6 +207,7 @@ pub async fn run(_args: Vec<String>) {
|
|||||||
cmd::create_shortcut,
|
cmd::create_shortcut,
|
||||||
cmd::export_profile,
|
cmd::export_profile,
|
||||||
cmd::import_profile,
|
cmd::import_profile,
|
||||||
|
cmd::clear_cache,
|
||||||
|
|
||||||
cmd::get_global_config,
|
cmd::get_global_config,
|
||||||
cmd::set_global_config,
|
cmd::set_global_config,
|
||||||
@ -335,7 +336,7 @@ async fn update(app: tauri::AppHandle) -> tauri_plugin_updater::Result<()> {
|
|||||||
fn open_window(apph: AppHandle) -> anyhow::Result<()> {
|
fn open_window(apph: AppHandle) -> anyhow::Result<()> {
|
||||||
let config = apph.config().clone();
|
let config = apph.config().clone();
|
||||||
tauri::WebviewWindowBuilder::new(&apph, "main", tauri::WebviewUrl::App("index.html".into()))
|
tauri::WebviewWindowBuilder::new(&apph, "main", tauri::WebviewUrl::App("index.html".into()))
|
||||||
.title(format!("STARTLINER {}", config.version.unwrap_or_default()))
|
.title(format!("STARTLINER {} Beta", config.version.unwrap_or_default()))
|
||||||
.inner_size(900f64, 600f64)
|
.inner_size(900f64, 600f64)
|
||||||
.min_inner_size(900f64, 600f64)
|
.min_inner_size(900f64, 600f64)
|
||||||
.build()?;
|
.build()?;
|
||||||
|
@ -108,7 +108,10 @@ impl Display {
|
|||||||
Game::Ongeki => 60,
|
Game::Ongeki => 60,
|
||||||
},
|
},
|
||||||
borderless_fullscreen: true,
|
borderless_fullscreen: true,
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
dont_switch_primary: false,
|
dont_switch_primary: false,
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
dont_switch_primary: true,
|
||||||
monitor_index_override: None,
|
monitor_index_override: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -141,7 +144,7 @@ pub struct BepInEx {
|
|||||||
pub console: bool,
|
pub console: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Clone)]
|
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct Wine {
|
pub struct Wine {
|
||||||
pub runtime: PathBuf,
|
pub runtime: PathBuf,
|
||||||
|
8
rust/src/modules/display_linux.rs
Normal file
8
rust/src/modules/display_linux.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
use ini::Ini;
|
||||||
|
use crate::model::{misc::Game, profile::Display};
|
||||||
|
|
||||||
|
impl Display {
|
||||||
|
pub fn line_up(&self, _game: Game, _ini: &mut Ini) {
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
}
|
@ -8,3 +8,6 @@ pub mod mempatcher;
|
|||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub mod display_windows;
|
pub mod display_windows;
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub mod display_linux;
|
@ -7,12 +7,20 @@ use crate::pkg_store::PackageStore;
|
|||||||
use crate::util;
|
use crate::util;
|
||||||
use crate::profiles::types::ProfilePaths;
|
use crate::profiles::types::ProfilePaths;
|
||||||
|
|
||||||
pub async fn prepare_packages<'a>(p: &'a impl ProfilePaths, pkgs: &BTreeSet<PkgKey>, redo_bepinex: bool) -> Result<()> {
|
pub async fn prepare_packages<'a>(p: &'a impl ProfilePaths, pkgs: &BTreeSet<PkgKey>, mut redo_bepinex: bool) -> Result<()> {
|
||||||
log::debug!("begin prepare packages");
|
log::debug!("begin prepare packages");
|
||||||
|
|
||||||
let pfx_dir = p.data_dir();
|
let pfx_dir = p.data_dir();
|
||||||
let opt_dir = pfx_dir.join("option");
|
let opt_dir = pfx_dir.join("option");
|
||||||
|
|
||||||
|
for m in pkgs {
|
||||||
|
let (namespace, _) = m.split()?;
|
||||||
|
if namespace == "local" {
|
||||||
|
log::info!("package with the 'local' namespace enabled -- force refreshing");
|
||||||
|
redo_bepinex = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if redo_bepinex {
|
if redo_bepinex {
|
||||||
if pfx_dir.join("BepInEx").exists() {
|
if pfx_dir.join("BepInEx").exists() {
|
||||||
util::remove_dir_all(pfx_dir.join("BepInEx")).await?;
|
util::remove_dir_all(pfx_dir.join("BepInEx")).await?;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
pub use types::{Profile, ProfileData, ProfileMeta, ProfilePaths, StartPayload};
|
pub use types::{Profile, ProfileData, ProfileMeta, ProfilePaths, StartPayload};
|
||||||
use std::{collections::{BTreeMap, BTreeSet}, path::{Path, PathBuf}};
|
use std::{collections::{BTreeMap, BTreeSet}, path::{Path, PathBuf}};
|
||||||
use crate::{model::{misc::Game, patch::{PatchList, PatchSelection}, profile::{Aime, ChunithmKeyboard, IOSelection, Keyboard, Mu3Ini, OngekiKeyboard, ProfileModule}}, modules::{display_windows::DisplayInfo, package::prepare_packages}, pkg::PkgKey, pkg_store::PackageStore, util};
|
use crate::{model::{misc::Game, patch::{PatchList, PatchSelection}, profile::{Aime, ChunithmKeyboard, IOSelection, Keyboard, Mu3Ini, OngekiKeyboard, ProfileModule}}, modules::package::prepare_packages, pkg::PkgKey, pkg_store::PackageStore, util};
|
||||||
use tauri::Emitter;
|
use tauri::Emitter;
|
||||||
use std::process::Stdio;
|
use std::process::Stdio;
|
||||||
use crate::model::profile::BepInEx;
|
use crate::model::profile::BepInEx;
|
||||||
@ -10,9 +10,23 @@ use std::fs::File;
|
|||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
use tokio::task::JoinSet;
|
use tokio::task::JoinSet;
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
use crate::modules::display_windows::DisplayInfo;
|
||||||
|
|
||||||
pub mod template;
|
pub mod template;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub trait RawArg {
|
||||||
|
fn raw_arg<S: AsRef<std::ffi::OsStr>>(&mut self, arg: S) -> &mut Command;
|
||||||
|
}
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
impl RawArg for Command {
|
||||||
|
fn raw_arg<S: AsRef<std::ffi::OsStr>>(&mut self, arg: S) -> &mut Command {
|
||||||
|
return self.arg::<S>(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Profile {
|
impl Profile {
|
||||||
pub fn new(mut meta: ProfileMeta) -> Result<Self> {
|
pub fn new(mut meta: ProfileMeta) -> Result<Self> {
|
||||||
meta.name = fixed_name(&meta, true);
|
meta.name = fixed_name(&meta, true);
|
||||||
@ -176,6 +190,7 @@ impl Profile {
|
|||||||
self.data.patches = source.patches;
|
self.data.patches = source.patches;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
pub fn prepare_display(&self) -> Result<Option<DisplayInfo>> {
|
pub fn prepare_display(&self) -> Result<Option<DisplayInfo>> {
|
||||||
let info = match &self.data.display {
|
let info = match &self.data.display {
|
||||||
None => None,
|
None => None,
|
||||||
@ -252,8 +267,8 @@ impl Profile {
|
|||||||
}
|
}
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
game_builder = Command::new(&self.wine.runtime);
|
game_builder = Command::new(&self.data.wine.runtime);
|
||||||
amd_builder = Command::new(&self.wine.runtime);
|
amd_builder = Command::new(&self.data.wine.runtime);
|
||||||
|
|
||||||
game_builder.arg(sgt_dir.join(self.meta.game.inject_exe()));
|
game_builder.arg(sgt_dir.join(self.meta.game.inject_exe()));
|
||||||
amd_builder.arg("cmd.exe");
|
amd_builder.arg("cmd.exe");
|
||||||
@ -349,8 +364,8 @@ impl Profile {
|
|||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
amd_builder.env("WINEPREFIX", &self.wine.prefix);
|
amd_builder.env("WINEPREFIX", &self.data.wine.prefix);
|
||||||
game_builder.env("WINEPREFIX", &self.wine.prefix);
|
game_builder.env("WINEPREFIX", &self.data.wine.prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
let amd_log = File::create(self.data_dir().join("amdaemon.exe.log"))?;
|
let amd_log = File::create(self.data_dir().join("amdaemon.exe.log"))?;
|
||||||
|
@ -152,6 +152,7 @@ impl PathStr for PathBuf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn bool_to_01(val: bool) -> &'static str {
|
pub fn bool_to_01(val: bool) -> &'static str {
|
||||||
return if val { "1" } else { "0" }
|
return if val { "1" } else { "0" }
|
||||||
}
|
}
|
||||||
|
@ -65,18 +65,3 @@ controllerLedOutputOpeNITHM=0
|
|||||||
;
|
;
|
||||||
; Board 2 is the slider and has 31 LEDs:
|
; Board 2 is the slider and has 31 LEDs:
|
||||||
; [0]-[31]: slider LEDs right to left BRG, alternating between keys and dividers
|
; [0]-[31]: slider LEDs right to left BRG, alternating between keys and dividers
|
||||||
|
|
||||||
|
|
||||||
; -----------------------------------------------------------------------------
|
|
||||||
; Custom IO settings
|
|
||||||
; -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
[chuniio]
|
|
||||||
; Uncomment this if you have custom chuniio implementation comprised of a single 32bit DLL.
|
|
||||||
; (will use chu2to3 engine internally)
|
|
||||||
;path=
|
|
||||||
|
|
||||||
; Uncomment both of these if you have custom chuniio implementation comprised of two DLLs.
|
|
||||||
; x86 chuniio to path32, x64 to path64. Both are necessary.
|
|
||||||
;path32=
|
|
||||||
;path64=
|
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "STARTLINER",
|
"productName": "STARTLINER",
|
||||||
"version": "0.15.0",
|
"version": "0.16.0",
|
||||||
"identifier": "zip.patafour.startliner",
|
"identifier": "zip.patafour.startliner",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "bun run dev",
|
"beforeDevCommand": "bun run dev",
|
||||||
|
@ -20,15 +20,16 @@ import OptionList from './OptionList.vue';
|
|||||||
import PatchList from './PatchList.vue';
|
import PatchList from './PatchList.vue';
|
||||||
import ProfileList from './ProfileList.vue';
|
import ProfileList from './ProfileList.vue';
|
||||||
import StartButton from './StartButton.vue';
|
import StartButton from './StartButton.vue';
|
||||||
import { invoke } from '../invoke';
|
|
||||||
import {
|
import {
|
||||||
useClientStore,
|
useClientStore,
|
||||||
useGeneralStore,
|
useGeneralStore,
|
||||||
usePkgStore,
|
usePkgStore,
|
||||||
usePrfStore,
|
usePrfStore,
|
||||||
} from '../stores';
|
} from '../stores';
|
||||||
import { Dirs } from '../types';
|
|
||||||
import { messageSplit, shouldPreferDark } from '../util';
|
import { messageSplit, shouldPreferDark } from '../util';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
document.documentElement.classList.toggle('use-dark-mode', shouldPreferDark());
|
document.documentElement.classList.toggle('use-dark-mode', shouldPreferDark());
|
||||||
|
|
||||||
@ -37,10 +38,10 @@ const prf = usePrfStore();
|
|||||||
const general = useGeneralStore();
|
const general = useGeneralStore();
|
||||||
const client = useClientStore();
|
const client = useClientStore();
|
||||||
|
|
||||||
|
client.load();
|
||||||
|
|
||||||
pkg.setupListeners();
|
pkg.setupListeners();
|
||||||
|
|
||||||
const currentTab: Ref<'users' | 'loc' | 'patches' | 'rmt' | 'cfg' | 'info'> =
|
|
||||||
ref('users');
|
|
||||||
const pkgSearchTerm = ref('');
|
const pkgSearchTerm = ref('');
|
||||||
|
|
||||||
const isProfileDisabled = computed(() => prf.current === null);
|
const isProfileDisabled = computed(() => prf.current === null);
|
||||||
@ -56,17 +57,11 @@ listen<undefined>('update-end', (_) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
invoke('list_directories').then((d) => {
|
|
||||||
general.dirs = d as Dirs;
|
|
||||||
client.load();
|
|
||||||
});
|
|
||||||
|
|
||||||
const fetch_promise = pkg.fetch(true);
|
const fetch_promise = pkg.fetch(true);
|
||||||
|
|
||||||
await Promise.all([prf.reloadList(), prf.reload()]);
|
await Promise.all([prf.reloadList(), prf.reload()]);
|
||||||
|
|
||||||
if (prf.current !== null) {
|
if (prf.current !== null) {
|
||||||
currentTab.value = 'loc';
|
|
||||||
await pkg.reloadAll();
|
await pkg.reloadAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,10 +206,11 @@ listen<DownloadingStatus>('download-progress', (event) => {
|
|||||||
|
|
||||||
<Tabs
|
<Tabs
|
||||||
lazy
|
lazy
|
||||||
:value="currentTab"
|
:value="client.currentTab"
|
||||||
v-on:update:value="
|
v-on:update:value="
|
||||||
(value) => {
|
(value) => {
|
||||||
currentTab = value as any;
|
client.currentTab = value as string;
|
||||||
|
client.save();
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
class="h-screen"
|
class="h-screen"
|
||||||
@ -222,6 +218,13 @@ listen<DownloadingStatus>('download-progress', (event) => {
|
|||||||
<div class="fixed w-full flex z-100">
|
<div class="fixed w-full flex z-100">
|
||||||
<TabList class="grow" :show-navigators="false">
|
<TabList class="grow" :show-navigators="false">
|
||||||
<Tab value="users"><div class="pi pi-home"></div></Tab>
|
<Tab value="users"><div class="pi pi-home"></div></Tab>
|
||||||
|
<Tab
|
||||||
|
:disabled="
|
||||||
|
isProfileDisabled || pkg.networkStatus !== 'online'
|
||||||
|
"
|
||||||
|
value="rmt"
|
||||||
|
><div class="pi pi-download"></div
|
||||||
|
></Tab>
|
||||||
<Tab :disabled="isProfileDisabled" value="loc"
|
<Tab :disabled="isProfileDisabled" value="loc"
|
||||||
><div class="pi pi-box"></div
|
><div class="pi pi-box"></div
|
||||||
></Tab>
|
></Tab>
|
||||||
@ -230,12 +233,7 @@ listen<DownloadingStatus>('download-progress', (event) => {
|
|||||||
value="patches"
|
value="patches"
|
||||||
><div class="pi pi-ticket"></div
|
><div class="pi pi-ticket"></div
|
||||||
></Tab>
|
></Tab>
|
||||||
<Tab
|
|
||||||
v-if="pkg.networkStatus === 'online'"
|
|
||||||
:disabled="isProfileDisabled"
|
|
||||||
value="rmt"
|
|
||||||
><div class="pi pi-download"></div
|
|
||||||
></Tab>
|
|
||||||
<Tab :disabled="isProfileDisabled" value="cfg"
|
<Tab :disabled="isProfileDisabled" value="cfg"
|
||||||
><div class="pi pi-cog"></div
|
><div class="pi pi-cog"></div
|
||||||
></Tab>
|
></Tab>
|
||||||
@ -248,17 +246,21 @@ listen<DownloadingStatus>('download-progress', (event) => {
|
|||||||
<div class="flex gap-4">
|
<div class="flex gap-4">
|
||||||
<div
|
<div
|
||||||
class="flex"
|
class="flex"
|
||||||
v-if="['loc', 'rmt', 'cfg'].includes(currentTab)"
|
v-if="
|
||||||
|
['loc', 'rmt', 'cfg'].includes(
|
||||||
|
client.currentTab
|
||||||
|
)
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<InputIcon class="self-center mr-2">
|
<InputIcon class="self-center mr-2">
|
||||||
<i class="pi pi-search" />
|
<i class="pi pi-search" />
|
||||||
</InputIcon>
|
</InputIcon>
|
||||||
<InputText
|
<InputText
|
||||||
v-if="currentTab === 'cfg'"
|
v-if="client.currentTab === 'cfg'"
|
||||||
style="min-width: 0; width: 25dvw"
|
style="min-width: 0; width: 25dvw"
|
||||||
class="self-center"
|
class="self-center"
|
||||||
size="small"
|
size="small"
|
||||||
placeholder="Search"
|
:placeholder="t('search')"
|
||||||
v-model="general.cfgSearchTerm"
|
v-model="general.cfgSearchTerm"
|
||||||
/>
|
/>
|
||||||
<InputText
|
<InputText
|
||||||
@ -266,7 +268,7 @@ listen<DownloadingStatus>('download-progress', (event) => {
|
|||||||
style="min-width: 0; width: 25dvw"
|
style="min-width: 0; width: 25dvw"
|
||||||
class="self-center"
|
class="self-center"
|
||||||
size="small"
|
size="small"
|
||||||
placeholder="Search"
|
:placeholder="t('search')"
|
||||||
v-model="pkgSearchTerm"
|
v-model="pkgSearchTerm"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -304,19 +306,19 @@ listen<DownloadingStatus>('download-progress', (event) => {
|
|||||||
</TabList>
|
</TabList>
|
||||||
</div>
|
</div>
|
||||||
<TabPanels class="w-full grow mt-[3rem]">
|
<TabPanels class="w-full grow mt-[3rem]">
|
||||||
<TabPanel value="loc">
|
<TabPanel value="loc" v-if="!isProfileDisabled">
|
||||||
<ModList :search="pkgSearchTerm" />
|
<ModList :search="pkgSearchTerm" />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel value="rmt">
|
<TabPanel value="rmt" v-if="!isProfileDisabled">
|
||||||
<ModStore :search="pkgSearchTerm" />
|
<ModStore :search="pkgSearchTerm" />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel value="cfg">
|
<TabPanel value="cfg" v-if="!isProfileDisabled">
|
||||||
<OptionList />
|
<OptionList />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel value="users">
|
<TabPanel value="users">
|
||||||
<ProfileList />
|
<ProfileList />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel value="patches">
|
<TabPanel value="patches" v-if="!isProfileDisabled">
|
||||||
<PatchList
|
<PatchList
|
||||||
v-if="
|
v-if="
|
||||||
pkg.hasLocal('mempatcher-mempatcher') &&
|
pkg.hasLocal('mempatcher-mempatcher') &&
|
||||||
@ -347,7 +349,12 @@ listen<DownloadingStatus>('download-progress', (event) => {
|
|||||||
<InfoPage />
|
<InfoPage />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
</TabPanels>
|
</TabPanels>
|
||||||
<div v-if="currentTab === 'users' || currentTab === 'info'">
|
<div
|
||||||
|
v-if="
|
||||||
|
client.currentTab === 'users' ||
|
||||||
|
client.currentTab === 'info'
|
||||||
|
"
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
v-if="prf.current?.meta.game === 'ongeki'"
|
v-if="prf.current?.meta.game === 'ongeki'"
|
||||||
src="/sticker-ongeki.svg"
|
src="/sticker-ongeki.svg"
|
||||||
|
@ -22,7 +22,7 @@ const empty = ref(false);
|
|||||||
const gameSublist: Ref<string[]> = ref([]);
|
const gameSublist: Ref<string[]> = ref([]);
|
||||||
|
|
||||||
invoke('get_game_packages', {
|
invoke('get_game_packages', {
|
||||||
game: prf.current?.meta.game,
|
game: prf.current?.meta.game ?? null,
|
||||||
}).then((list) => {
|
}).then((list) => {
|
||||||
gameSublist.value = list as string[];
|
gameSublist.value = list as string[];
|
||||||
});
|
});
|
||||||
@ -55,6 +55,9 @@ const group = computed(() => {
|
|||||||
const missing = computed(() => {
|
const missing = computed(() => {
|
||||||
return prf.current?.data.mods.filter((m) => !pkgs.hasLocal(m)) ?? [];
|
return prf.current?.data.mods.filter((m) => !pkgs.hasLocal(m)) ?? [];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const emptyVisible = ref(false);
|
||||||
|
setTimeout(() => (emptyVisible.value = true), 500);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -84,5 +87,7 @@ const missing = computed(() => {
|
|||||||
<Fieldset v-for="(namespace, key) in group" :legend="key.toString()">
|
<Fieldset v-for="(namespace, key) in group" :legend="key.toString()">
|
||||||
<ModListEntry v-for="p in namespace" :pkg="p" />
|
<ModListEntry v-for="p in namespace" :pkg="p" />
|
||||||
</Fieldset>
|
</Fieldset>
|
||||||
<div v-if="empty === true" class="text-3xl fadein">∅</div>
|
<div v-if="empty === true && emptyVisible === true" class="text-3xl fadein">
|
||||||
|
∅
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -23,7 +23,7 @@ const props = defineProps({
|
|||||||
const gameSublist: Ref<string[]> = ref([]);
|
const gameSublist: Ref<string[]> = ref([]);
|
||||||
|
|
||||||
invoke('get_game_packages', {
|
invoke('get_game_packages', {
|
||||||
game: prf.current?.meta.game,
|
game: prf.current?.meta.game ?? null,
|
||||||
}).then((list) => {
|
}).then((list) => {
|
||||||
gameSublist.value = list as string[];
|
gameSublist.value = list as string[];
|
||||||
});
|
});
|
||||||
@ -46,10 +46,10 @@ const list = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const shouldShowRecommended = computed(() => {
|
const shouldShowRecommended = computed(() => {
|
||||||
if (prf.current!.meta.game === 'ongeki') {
|
if (prf.current?.meta.game === 'ongeki') {
|
||||||
return !pkgs.allLocal.some((p) => pkgKey(p) === 'segatools-mu3hook');
|
return !pkgs.allLocal.some((p) => pkgKey(p) === 'segatools-mu3hook');
|
||||||
}
|
}
|
||||||
if (prf.current!.meta.game === 'chunithm') {
|
if (prf.current?.meta.game === 'chunithm') {
|
||||||
return (
|
return (
|
||||||
!pkgs.allLocal.some((p) => pkgKey(p) === 'segatools-chusanhook') ||
|
!pkgs.allLocal.some((p) => pkgKey(p) === 'segatools-chusanhook') ||
|
||||||
!pkgs.allLocal.some((p) => pkgKey(p) === 'mempatcher-mempatcher')
|
!pkgs.allLocal.some((p) => pkgKey(p) === 'mempatcher-mempatcher')
|
||||||
@ -58,21 +58,21 @@ const shouldShowRecommended = computed(() => {
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
const getRecommendedTooltip = () => {
|
const recommendedTooltip = computed(() => {
|
||||||
if (prf.current!.meta.game === 'ongeki') {
|
if (prf.current?.meta.game === 'ongeki') {
|
||||||
return 'segatools-mu3hook';
|
return 'segatools-mu3hook';
|
||||||
}
|
}
|
||||||
if (prf.current!.meta.game === 'chunithm') {
|
if (prf.current?.meta.game === 'chunithm') {
|
||||||
return 'segatools-chusanhook + mempatcher';
|
return 'segatools-chusanhook + mempatcher';
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
};
|
});
|
||||||
|
|
||||||
const installRecommended = () => {
|
const installRecommended = () => {
|
||||||
if (prf.current!.meta.game === 'ongeki') {
|
if (prf.current?.meta.game === 'ongeki') {
|
||||||
pkgs.installFromKey('segatools-mu3hook');
|
pkgs.installFromKey('segatools-mu3hook');
|
||||||
}
|
}
|
||||||
if (prf.current!.meta.game === 'chunithm') {
|
if (prf.current?.meta.game === 'chunithm') {
|
||||||
pkgs.installFromKey('segatools-chusanhook');
|
pkgs.installFromKey('segatools-chusanhook');
|
||||||
pkgs.installFromKey('mempatcher-mempatcher');
|
pkgs.installFromKey('mempatcher-mempatcher');
|
||||||
}
|
}
|
||||||
@ -101,7 +101,7 @@ const installRecommended = () => {
|
|||||||
<MultiSelect
|
<MultiSelect
|
||||||
size="small"
|
size="small"
|
||||||
:showToggleAll="false"
|
:showToggleAll="false"
|
||||||
placeholder="Include categories"
|
:placeholder="t('store.includeCategories')"
|
||||||
v-model="pkgs.includeCategories"
|
v-model="pkgs.includeCategories"
|
||||||
:options="[...pkgs.availableCategories]"
|
:options="[...pkgs.availableCategories]"
|
||||||
class="w-full"
|
class="w-full"
|
||||||
@ -109,7 +109,7 @@ const installRecommended = () => {
|
|||||||
<MultiSelect
|
<MultiSelect
|
||||||
size="small"
|
size="small"
|
||||||
:showToggleAll="false"
|
:showToggleAll="false"
|
||||||
placeholder="Exclude categories"
|
:placeholder="t('store.excludeCategories')"
|
||||||
v-model="pkgs.excludeCategories"
|
v-model="pkgs.excludeCategories"
|
||||||
:options="[...pkgs.availableCategories]"
|
:options="[...pkgs.availableCategories]"
|
||||||
class="w-full"
|
class="w-full"
|
||||||
@ -120,7 +120,7 @@ const installRecommended = () => {
|
|||||||
<Button
|
<Button
|
||||||
v-if="shouldShowRecommended"
|
v-if="shouldShowRecommended"
|
||||||
:label="t('store.installRecommended')"
|
:label="t('store.installRecommended')"
|
||||||
v-tooltip="getRecommendedTooltip"
|
v-tooltip="recommendedTooltip"
|
||||||
icon="pi pi-plus"
|
icon="pi pi-plus"
|
||||||
class="mb-3"
|
class="mb-3"
|
||||||
@click="installRecommended"
|
@click="installRecommended"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ComputedRef, computed, onMounted, ref } from 'vue';
|
import { ComputedRef, computed, ref } from 'vue';
|
||||||
import Button from 'primevue/button';
|
import Button from 'primevue/button';
|
||||||
import Carousel from 'primevue/carousel';
|
import Carousel from 'primevue/carousel';
|
||||||
import Dialog from 'primevue/dialog';
|
import Dialog from 'primevue/dialog';
|
||||||
@ -7,6 +7,9 @@ import { fromKeycode } from '../keyboard';
|
|||||||
import { useClientStore, usePrfStore } from '../stores';
|
import { useClientStore, usePrfStore } from '../stores';
|
||||||
import { prettyPrint } from '../util';
|
import { prettyPrint } from '../util';
|
||||||
import { VueMarkdownIt } from '@f3ve/vue-markdown-it';
|
import { VueMarkdownIt } from '@f3ve/vue-markdown-it';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
const prf = usePrfStore();
|
const prf = usePrfStore();
|
||||||
const client = useClientStore();
|
const client = useClientStore();
|
||||||
@ -24,38 +27,73 @@ interface Datum {
|
|||||||
|
|
||||||
const game = computed(() => prf.current?.meta.game);
|
const game = computed(() => prf.current?.meta.game);
|
||||||
|
|
||||||
const processText = (s: string) => {
|
const processText = computed(() => (s: string) => {
|
||||||
|
// Why do I have to do this
|
||||||
|
s = s
|
||||||
|
.split('\n')
|
||||||
|
.map((l) => l.trim())
|
||||||
|
.join('\n');
|
||||||
if (prf.current!.data.keyboard?.data.enabled) {
|
if (prf.current!.data.keyboard?.data.enabled) {
|
||||||
const testKey = prf.current!.data.keyboard?.data.test;
|
const testKey = prf.current!.data.keyboard?.data.test;
|
||||||
const readable = fromKeycode(testKey);
|
const readable = fromKeycode(testKey);
|
||||||
if (readable !== null) {
|
if (readable !== null) {
|
||||||
return s.replace(
|
return s.replace(
|
||||||
'%TESTMENU%',
|
'%TESTMENU%',
|
||||||
`${readable} or a button on the back of the controller`
|
`${readable} ${t('onboarding.or')} ${t('onboarding.backButton')}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s.replace('%TESTMENU%', 'a button on the back of the controller');
|
return s.replace('%TESTMENU%', t('onboarding.backButton'));
|
||||||
};
|
});
|
||||||
|
|
||||||
const loadPage = async (title: string) => {
|
const loadPage = computed(() => (title: string, messages?: object) => {
|
||||||
return {
|
return {
|
||||||
text: await (await fetch(`/help-${title}.md`)).text(),
|
text: t(`onboarding.${title}`, {
|
||||||
|
endlink: '</a>',
|
||||||
|
black: '<span class="bg-black text-white">',
|
||||||
|
end: '</span>',
|
||||||
|
...messages,
|
||||||
|
}),
|
||||||
image: `help-${title}.png`,
|
image: `help-${title}.png`,
|
||||||
};
|
};
|
||||||
};
|
});
|
||||||
|
|
||||||
let systemProcessing: Datum;
|
|
||||||
let standardOngeki: Datum;
|
|
||||||
let standardChunithm: Datum;
|
|
||||||
let lever: Datum;
|
|
||||||
let server: Datum;
|
|
||||||
let finaleOngeki: Datum;
|
|
||||||
let finaleChunithm: Datum;
|
|
||||||
|
|
||||||
const data: ComputedRef<Datum[]> = computed(() => {
|
const data: ComputedRef<Datum[]> = computed(() => {
|
||||||
const res = [];
|
const res = [];
|
||||||
|
|
||||||
|
const [standard, systemProcessing, lever, server, finale] = [
|
||||||
|
loadPage.value('standard', {
|
||||||
|
bigblack: '<div class="p-2 mt-1 mb-1 bg-black text-white">',
|
||||||
|
endbig: '</div>',
|
||||||
|
}),
|
||||||
|
loadPage.value('ongeki-system-processing'),
|
||||||
|
loadPage.value('ongeki-lever'),
|
||||||
|
loadPage.value('chunithm-server', {
|
||||||
|
link: '<a href="https://gitea.tendokyu.moe/Dniel97/SEGAguide/wiki/FAQ#game-is-stuck-at-checking-distribution-server" target="_blank">',
|
||||||
|
}),
|
||||||
|
loadPage.value('finale', {
|
||||||
|
segaguide:
|
||||||
|
'<a href="https://gitea.tendokyu.moe/Dniel97/SEGAguide/wiki/FAQ" target="_blank">',
|
||||||
|
twotorial: '<a href="https://two-torial.xyz/" target="_blank">',
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
const standardOngeki = {
|
||||||
|
...standard,
|
||||||
|
image: '/help-standard-ongeki.png',
|
||||||
|
};
|
||||||
|
const standardChunithm = {
|
||||||
|
...standard,
|
||||||
|
image: '/help-standard-chunithm.png',
|
||||||
|
};
|
||||||
|
const finaleOngeki = {
|
||||||
|
...finale,
|
||||||
|
image: '/help-finale-ongeki.png',
|
||||||
|
};
|
||||||
|
const finaleChunithm = {
|
||||||
|
...finale,
|
||||||
|
image: '/help-finale-chunithm.png',
|
||||||
|
};
|
||||||
|
|
||||||
switch (prf.current?.meta.game) {
|
switch (prf.current?.meta.game) {
|
||||||
case 'ongeki':
|
case 'ongeki':
|
||||||
res.push(systemProcessing);
|
res.push(systemProcessing);
|
||||||
@ -75,40 +113,18 @@ const data: ComputedRef<Datum[]> = computed(() => {
|
|||||||
return res;
|
return res;
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
const context = ref({
|
||||||
[standardOngeki, systemProcessing, lever, server, finaleOngeki] =
|
index: 0,
|
||||||
await Promise.all([
|
|
||||||
loadPage('standard'),
|
|
||||||
loadPage('ongeki-system-processing'),
|
|
||||||
loadPage('ongeki-lever'),
|
|
||||||
loadPage('chunithm-server'),
|
|
||||||
loadPage('finale'),
|
|
||||||
]);
|
|
||||||
standardOngeki = {
|
|
||||||
...standardOngeki,
|
|
||||||
image: '/help-standard-ongeki.png',
|
|
||||||
};
|
|
||||||
standardChunithm = {
|
|
||||||
...standardOngeki,
|
|
||||||
image: '/help-standard-chunithm.png',
|
|
||||||
};
|
|
||||||
finaleOngeki = {
|
|
||||||
...finaleOngeki,
|
|
||||||
image: '/help-finale-ongeki.png',
|
|
||||||
};
|
|
||||||
finaleChunithm = {
|
|
||||||
...finaleOngeki,
|
|
||||||
image: '/help-finale-chunithm.png',
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const counter = ref(0);
|
|
||||||
|
|
||||||
const exitLabel = computed(() => {
|
const exitLabel = computed(() => {
|
||||||
return props.firstTime === true && counter.value < data.value.length - 1
|
return props.firstTime === true &&
|
||||||
? 'Skip'
|
context.value.index < data.value.length - 1
|
||||||
: 'Close';
|
? t('skip')
|
||||||
|
: t('close');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const page = ref(0);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -122,13 +138,15 @@ const exitLabel = computed(() => {
|
|||||||
: `${game ? prettyPrint(game) : '<game>'} help`
|
: `${game ? prettyPrint(game) : '<game>'} help`
|
||||||
"
|
"
|
||||||
:style="{ width: '760px', scale: client.scaleValue }"
|
:style="{ width: '760px', scale: client.scaleValue }"
|
||||||
|
v-on:show="() => ((context.index = 0), (page = 0))"
|
||||||
>
|
>
|
||||||
<Carousel
|
<Carousel
|
||||||
:value="data"
|
:value="data"
|
||||||
:num-visible="1"
|
:num-visible="1"
|
||||||
:num-scroll="1"
|
:num-scroll="1"
|
||||||
:page="counter"
|
:context="context"
|
||||||
v-on:update:page="(p) => (counter = p)"
|
:page="page"
|
||||||
|
v-on:update:page="(p) => ((context.index = p), (page = p))"
|
||||||
>
|
>
|
||||||
<template #item="slotProps">
|
<template #item="slotProps">
|
||||||
<div class="md-container markdown">
|
<div class="md-container markdown">
|
||||||
@ -150,10 +168,10 @@ const exitLabel = computed(() => {
|
|||||||
</Carousel>
|
</Carousel>
|
||||||
<div style="width: 100%; text-align: center">
|
<div style="width: 100%; text-align: center">
|
||||||
<Button
|
<Button
|
||||||
v-if="counter < data.length - 1"
|
v-if="context.index < data.length - 1"
|
||||||
class="m-auto mr-4"
|
class="m-auto mr-4"
|
||||||
label="Next"
|
:label="t('next')"
|
||||||
@click="() => (counter += 1)"
|
@click="() => (page += 1)"
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
class="m-auto"
|
class="m-auto"
|
||||||
|
@ -61,7 +61,7 @@ prf.reload();
|
|||||||
<MiscOptions />
|
<MiscOptions />
|
||||||
<OptionCategory
|
<OptionCategory
|
||||||
title="Extensions"
|
title="Extensions"
|
||||||
v-if="prf.current!.meta.game === 'chunithm'"
|
v-if="prf.current?.meta.game === 'chunithm'"
|
||||||
>
|
>
|
||||||
<OptionRow :title="t('cfg.extensions.saekawa')">
|
<OptionRow :title="t('cfg.extensions.saekawa')">
|
||||||
<FileEditor
|
<FileEditor
|
||||||
@ -72,7 +72,7 @@ prf.reload();
|
|||||||
></OptionCategory>
|
></OptionCategory>
|
||||||
<OptionCategory
|
<OptionCategory
|
||||||
:title="t('cfg.extensions.title')"
|
:title="t('cfg.extensions.title')"
|
||||||
v-if="prf.current!.meta.game === 'ongeki'"
|
v-if="prf.current?.meta.game === 'ongeki'"
|
||||||
>
|
>
|
||||||
<OptionRow :title="t('cfg.extensions.inohara')">
|
<OptionRow :title="t('cfg.extensions.inohara')">
|
||||||
<FileEditor
|
<FileEditor
|
||||||
|
@ -8,7 +8,7 @@ import { usePrfStore } from '../stores';
|
|||||||
import { Patch } from '../types';
|
import { Patch } from '../types';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t, te } = useI18n();
|
||||||
|
|
||||||
const prf = usePrfStore();
|
const prf = usePrfStore();
|
||||||
|
|
||||||
@ -51,14 +51,14 @@ const hexModel = computed({
|
|||||||
|
|
||||||
// Doesn't need to be reactive
|
// Doesn't need to be reactive
|
||||||
const nameKey = `patch.${props.patch?.id}`;
|
const nameKey = `patch.${props.patch?.id}`;
|
||||||
let name = t(nameKey);
|
const name = te(nameKey) ? t(nameKey) : props.patch?.name;
|
||||||
if (name === nameKey) {
|
|
||||||
name = props.patch?.name ?? 'No name';
|
const tooltipKey = `patch.${props.patch?.id}-tooltip`;
|
||||||
}
|
const tooltip = te(tooltipKey) ? t(tooltipKey) : props.patch?.tooltip;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<OptionRow :title="name" :tooltip="patch?.tooltip" :greytext="patch?.id">
|
<OptionRow :title="name" :tooltip="tooltip" :greytext="patch?.id">
|
||||||
<ToggleSwitch
|
<ToggleSwitch
|
||||||
v-if="patch?.type === undefined"
|
v-if="patch?.type === undefined"
|
||||||
:model-value="prf.current!.data.patches?.[patch!.id!] !== undefined"
|
:model-value="prf.current!.data.patches?.[patch!.id!] !== undefined"
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Ref, ref } from 'vue';
|
import { Ref, ref } from 'vue';
|
||||||
|
// import Select from 'primevue/select';
|
||||||
import * as path from '@tauri-apps/api/path';
|
import * as path from '@tauri-apps/api/path';
|
||||||
import OptionCategory from './OptionCategory.vue';
|
import OptionCategory from './OptionCategory.vue';
|
||||||
import PatchEntry from './PatchEntry.vue';
|
import PatchEntry from './PatchEntry.vue';
|
||||||
@ -32,8 +33,6 @@ invoke('list_patches', { target: prf.current!.data.sgt.target }).then(
|
|||||||
target: amd,
|
target: amd,
|
||||||
})) as Patch[];
|
})) as Patch[];
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const errorMessage = t('patch.noneFound');
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -49,7 +48,7 @@ const errorMessage = t('patch.noneFound');
|
|||||||
/>
|
/>
|
||||||
<div v-if="gamePatches === null">{{ t('patch.loading') }}</div>
|
<div v-if="gamePatches === null">{{ t('patch.loading') }}</div>
|
||||||
<div v-if="gamePatches !== null && gamePatches.length === 0">
|
<div v-if="gamePatches !== null && gamePatches.length === 0">
|
||||||
{{ errorMessage }}
|
{{ t('patch.noneFound') }}
|
||||||
</div>
|
</div>
|
||||||
</OptionCategory>
|
</OptionCategory>
|
||||||
<OptionCategory title="amdaemon.exe" always-found>
|
<OptionCategory title="amdaemon.exe" always-found>
|
||||||
@ -58,9 +57,22 @@ const errorMessage = t('patch.noneFound');
|
|||||||
v-for="p in amdPatches"
|
v-for="p in amdPatches"
|
||||||
:patch="p"
|
:patch="p"
|
||||||
/>
|
/>
|
||||||
<div v-if="gamePatches === null">Loading...</div>
|
<div v-if="gamePatches === null">{{ t('patch.loading') }}</div>
|
||||||
<div v-if="amdPatches !== null && amdPatches.length === 0">
|
<div v-if="amdPatches !== null && amdPatches.length === 0">
|
||||||
{{ errorMessage }}
|
{{ t('patch.noneFound') }}
|
||||||
|
<!-- <br />
|
||||||
|
<Select
|
||||||
|
class="mt-3"
|
||||||
|
style="width: 400px"
|
||||||
|
:options="[
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
]"
|
||||||
|
:placeholder="t('patch.forceLoad')"
|
||||||
|
size="small"
|
||||||
|
option-label="title"
|
||||||
|
option-value="value"
|
||||||
|
></Select> -->
|
||||||
</div>
|
</div>
|
||||||
</OptionCategory>
|
</OptionCategory>
|
||||||
</template>
|
</template>
|
||||||
|
@ -18,10 +18,17 @@ const prf = usePrfStore();
|
|||||||
const client = useClientStore();
|
const client = useClientStore();
|
||||||
const general = useGeneralStore();
|
const general = useGeneralStore();
|
||||||
|
|
||||||
|
const hasChunithm = ref(false);
|
||||||
const exportVisible = ref(false);
|
const exportVisible = ref(false);
|
||||||
const exportKeychip = ref(false);
|
const exportKeychip = ref(false);
|
||||||
const files = new Set<string>();
|
const files = new Set<string>();
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
hasChunithm.value = (
|
||||||
|
(await invoke('list_platform_capabilities')) as string[]
|
||||||
|
).includes('chunithm');
|
||||||
|
})();
|
||||||
|
|
||||||
const exportTemplate = async () => {
|
const exportTemplate = async () => {
|
||||||
const fl = [...files.values()];
|
const fl = [...files.values()];
|
||||||
exportVisible.value = false;
|
exportVisible.value = false;
|
||||||
@ -30,7 +37,7 @@ const exportTemplate = async () => {
|
|||||||
files: fl,
|
files: fl,
|
||||||
});
|
});
|
||||||
await invoke('open_file', {
|
await invoke('open_file', {
|
||||||
path: await path.join(general.configDir, 'exports'),
|
path: await path.join(await general.configDir, 'exports'),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -83,16 +90,16 @@ const importPick = async () => {
|
|||||||
modal
|
modal
|
||||||
:visible="exportVisible"
|
:visible="exportVisible"
|
||||||
:closable="false /*this shit doesn't work */"
|
:closable="false /*this shit doesn't work */"
|
||||||
:header="`Export ${prf.current?.meta.name}`"
|
:header="`${t('profile.export')} ${prf.current?.meta.name}`"
|
||||||
:style="{ width: '300px', scale: client.scaleValue }"
|
:style="{ width: '300px', scale: client.scaleValue }"
|
||||||
>
|
>
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="flex flex-row">
|
<div class="flex flex-row">
|
||||||
<div class="grow">Export keychip</div>
|
<div class="grow">{{ t('profile.export') }} keychip</div>
|
||||||
<ToggleSwitch v-model="exportKeychip" />
|
<ToggleSwitch v-model="exportKeychip" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-row" v-for="f in fileListCurrent">
|
<div class="flex flex-row" v-for="f in fileListCurrent">
|
||||||
<div class="grow">Export {{ f }}</div>
|
<div class="grow">{{ t('profile.export') }} {{ f }}</div>
|
||||||
<ToggleSwitch
|
<ToggleSwitch
|
||||||
:model-value="true"
|
:model-value="true"
|
||||||
@update:model-value="
|
@update:model-value="
|
||||||
@ -134,6 +141,7 @@ const importPick = async () => {
|
|||||||
@click="() => prf.create('ongeki')"
|
@click="() => prf.create('ongeki')"
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
|
v-if="hasChunithm"
|
||||||
:label="t('profile.create', { game: t('game.chunithm') })"
|
:label="t('profile.create', { game: t('game.chunithm') })"
|
||||||
icon="pi pi-file-plus"
|
icon="pi pi-file-plus"
|
||||||
class="chunithm-button profile-button"
|
class="chunithm-button profile-button"
|
||||||
@ -142,14 +150,14 @@ const importPick = async () => {
|
|||||||
</div>
|
</div>
|
||||||
<div class="mt-4 flex flex-row flex-wrap align-middle gap-4">
|
<div class="mt-4 flex flex-row flex-wrap align-middle gap-4">
|
||||||
<Button
|
<Button
|
||||||
label="Import template"
|
:label="t('profile.importTemplate')"
|
||||||
icon="pi pi-file-import"
|
icon="pi pi-file-import"
|
||||||
class="import-button profile-button"
|
class="import-button profile-button"
|
||||||
@click="() => importPick()"
|
@click="() => importPick()"
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
:disabled="prf.current === null"
|
:disabled="prf.current === null"
|
||||||
label="Export template"
|
:label="t('profile.exportTemplate')"
|
||||||
icon="pi pi-file-export"
|
icon="pi pi-file-export"
|
||||||
class="profile-button"
|
class="profile-button"
|
||||||
@click="() => openExportDialog()"
|
@click="() => openExportDialog()"
|
||||||
@ -171,6 +179,7 @@ const importPick = async () => {
|
|||||||
:options="[
|
:options="[
|
||||||
{ title: 'English', value: 'en' },
|
{ title: 'English', value: 'en' },
|
||||||
// { title: '日本語', value: 'ja' },
|
// { title: '日本語', value: 'ja' },
|
||||||
|
{ title: 'Polski', value: 'pl' },
|
||||||
]"
|
]"
|
||||||
size="small"
|
size="small"
|
||||||
option-label="title"
|
option-label="title"
|
||||||
|
@ -73,10 +73,12 @@ const promptDeleteProfile = async () => {
|
|||||||
|
|
||||||
const dataExists = ref(false);
|
const dataExists = ref(false);
|
||||||
|
|
||||||
path.join(general.dataDir, `profile-${props.p!.game}-${props.p!.name}`).then(
|
general.dataDir.then((dataDir) =>
|
||||||
async (p) => {
|
path
|
||||||
|
.join(dataDir, `profile-${props.p!.game}-${props.p!.name}`)
|
||||||
|
.then(async (p) => {
|
||||||
dataExists.value = await invoke('file_exists', { path: p });
|
dataExists.value = await invoke('file_exists', { path: p });
|
||||||
}
|
})
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -145,8 +147,12 @@ path.join(general.dataDir, `profile-${props.p!.game}-${props.p!.name}`).then(
|
|||||||
class="self-center"
|
class="self-center"
|
||||||
style="width: 2rem; height: 2rem"
|
style="width: 2rem; height: 2rem"
|
||||||
@click="
|
@click="
|
||||||
|
async () =>
|
||||||
path
|
path
|
||||||
.join(general.configDir, `profile-${p!.game}-${p!.name}`)
|
.join(
|
||||||
|
await general.configDir,
|
||||||
|
`profile-${p!.game}-${p!.name}`
|
||||||
|
)
|
||||||
.then(async (path) => {
|
.then(async (path) => {
|
||||||
await invoke('open_file', { path });
|
await invoke('open_file', { path });
|
||||||
})
|
})
|
||||||
@ -162,8 +168,12 @@ path.join(general.dataDir, `profile-${props.p!.game}-${props.p!.name}`).then(
|
|||||||
class="self-center"
|
class="self-center"
|
||||||
style="width: 2rem; height: 2rem"
|
style="width: 2rem; height: 2rem"
|
||||||
@click="
|
@click="
|
||||||
|
async () =>
|
||||||
path
|
path
|
||||||
.join(general.dataDir, `profile-${p!.game}-${p!.name}`)
|
.join(
|
||||||
|
await general.dataDir,
|
||||||
|
`profile-${p!.game}-${p!.name}`
|
||||||
|
)
|
||||||
.then(async (path) => {
|
.then(async (path) => {
|
||||||
await invoke('open_file', { path });
|
await invoke('open_file', { path });
|
||||||
})
|
})
|
||||||
|
@ -99,18 +99,23 @@ const createShortcut = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const hasShortcut = ref(false);
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
hasShortcut.value = (
|
||||||
|
(await invoke('list_platform_capabilities')) as string[]
|
||||||
|
).includes('shortcut');
|
||||||
|
})();
|
||||||
|
|
||||||
const menuItems = computed(() => {
|
const menuItems = computed(() => {
|
||||||
const base = [
|
let base = [
|
||||||
{
|
{
|
||||||
label: t('start.button.unchecked'),
|
label: t('start.button.unchecked'),
|
||||||
icon: 'pi pi-exclamation-circle',
|
icon: 'pi pi-exclamation-circle',
|
||||||
command: async () => await startline(true, false),
|
command: async () => await startline(true, false),
|
||||||
},
|
},
|
||||||
{
|
];
|
||||||
label: t('start.button.shortcut'),
|
let baseTail = [
|
||||||
icon: 'pi pi-link',
|
|
||||||
command: createShortcut,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: t('start.button.help'),
|
label: t('start.button.help'),
|
||||||
icon: 'pi pi-question-circle',
|
icon: 'pi pi-question-circle',
|
||||||
@ -123,8 +128,18 @@ const menuItems = computed(() => {
|
|||||||
if (prf.current === null) {
|
if (prf.current === null) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
if (hasShortcut.value === true) {
|
||||||
|
base = [
|
||||||
|
...base,
|
||||||
|
{
|
||||||
|
label: t('start.button.shortcut'),
|
||||||
|
icon: 'pi pi-link',
|
||||||
|
command: createShortcut,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
if (prf.current.meta.game === 'chunithm') {
|
if (prf.current.meta.game === 'chunithm') {
|
||||||
return base;
|
return [...base, ...baseTail];
|
||||||
}
|
}
|
||||||
if (prf.current.meta.game === 'ongeki') {
|
if (prf.current.meta.game === 'ongeki') {
|
||||||
return [
|
return [
|
||||||
@ -137,8 +152,9 @@ const menuItems = computed(() => {
|
|||||||
{
|
{
|
||||||
label: t('start.button.cache'),
|
label: t('start.button.cache'),
|
||||||
icon: 'pi pi-trash',
|
icon: 'pi pi-trash',
|
||||||
command: async () => {},
|
command: async () => await invoke('clear_cache'),
|
||||||
},
|
},
|
||||||
|
...baseTail,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Ref, computed, ref } from 'vue';
|
import { Ref, computed, onMounted, ref } from 'vue';
|
||||||
import InputNumber from 'primevue/inputnumber';
|
import InputNumber from 'primevue/inputnumber';
|
||||||
import Select from 'primevue/select';
|
import Select from 'primevue/select';
|
||||||
import SelectButton from 'primevue/selectbutton';
|
import SelectButton from 'primevue/selectbutton';
|
||||||
@ -65,16 +65,20 @@ const loadDisplays = () => {
|
|||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
loadDisplays();
|
loadDisplays();
|
||||||
|
});
|
||||||
|
|
||||||
const game = prf.current!.meta.game;
|
const game = computed(() => prf.current!.meta.game);
|
||||||
const isVertical = game === 'ongeki';
|
const isVertical = computed(() => prf.current!.meta.game === 'ongeki');
|
||||||
const adjustableRez = game === 'ongeki';
|
const adjustableRez = computed(() => prf.current!.meta.game === 'ongeki');
|
||||||
const canSkipPrimarySwitch = game === 'ongeki';
|
const canSkipPrimarySwitch = computed(
|
||||||
|
() => prf.current!.meta.game === 'ongeki'
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<OptionCategory title="Display">
|
<OptionCategory :title="t('cfg.display.title')">
|
||||||
<OptionRow
|
<OptionRow
|
||||||
v-if="capabilities.includes('display')"
|
v-if="capabilities.includes('display')"
|
||||||
:title="t('cfg.display.target')"
|
:title="t('cfg.display.target')"
|
||||||
@ -90,7 +94,7 @@ const canSkipPrimarySwitch = game === 'ongeki';
|
|||||||
</OptionRow>
|
</OptionRow>
|
||||||
<OptionRow
|
<OptionRow
|
||||||
class="number-input"
|
class="number-input"
|
||||||
title="Game resolution"
|
:title="t('cfg.display.resolution')"
|
||||||
v-if="adjustableRez"
|
v-if="adjustableRez"
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
@ -115,9 +119,9 @@ const canSkipPrimarySwitch = game === 'ongeki';
|
|||||||
<SelectButton
|
<SelectButton
|
||||||
v-model="prf.current!.data.display.mode"
|
v-model="prf.current!.data.display.mode"
|
||||||
:options="[
|
:options="[
|
||||||
{ title: 'Window', value: 'Window' },
|
{ title: t('cfg.display.window'), value: 'Window' },
|
||||||
{ title: 'Borderless window', value: 'Borderless' },
|
{ title: t('cfg.display.borderless'), value: 'Borderless' },
|
||||||
{ title: 'Fullscreen', value: 'Fullscreen' },
|
{ title: t('cfg.display.fullscreen'), value: 'Fullscreen' },
|
||||||
]"
|
]"
|
||||||
:allow-empty="false"
|
:allow-empty="false"
|
||||||
option-label="title"
|
option-label="title"
|
||||||
@ -197,16 +201,19 @@ const canSkipPrimarySwitch = game === 'ongeki';
|
|||||||
<OptionRow
|
<OptionRow
|
||||||
:title="t('cfg.display.dontSwitchPrimary')"
|
:title="t('cfg.display.dontSwitchPrimary')"
|
||||||
v-if="
|
v-if="
|
||||||
capabilities.includes('display') &&
|
!capabilities.includes('display') ||
|
||||||
prf.current?.data.display.target !== 'default' &&
|
(prf.current?.data.display.target !== 'default' &&
|
||||||
(prf.current!.data.display.dont_switch_primary ||
|
(prf.current!.data.display.dont_switch_primary ||
|
||||||
displayList.length > 2) &&
|
displayList.length > 2) &&
|
||||||
canSkipPrimarySwitch
|
canSkipPrimarySwitch)
|
||||||
"
|
"
|
||||||
:dangerous-tooltip="t('cfg.display.dontSwitchPrimaryTooltip')"
|
:dangerous-tooltip="t('cfg.display.dontSwitchPrimaryTooltip')"
|
||||||
>
|
>
|
||||||
<ToggleSwitch
|
<ToggleSwitch
|
||||||
:disabled="extraDisplayOptionsDisabled"
|
:disabled="
|
||||||
|
extraDisplayOptionsDisabled &&
|
||||||
|
capabilities.includes('display')
|
||||||
|
"
|
||||||
v-model="prf.current!.data.display.dont_switch_primary"
|
v-model="prf.current!.data.display.dont_switch_primary"
|
||||||
/>
|
/>
|
||||||
</OptionRow>
|
</OptionRow>
|
||||||
@ -214,9 +221,9 @@ const canSkipPrimarySwitch = game === 'ongeki';
|
|||||||
:title="t('cfg.display.index')"
|
:title="t('cfg.display.index')"
|
||||||
class="number-input"
|
class="number-input"
|
||||||
v-if="
|
v-if="
|
||||||
capabilities.includes('display') &&
|
!capabilities.includes('display') ||
|
||||||
prf.current?.data.display.target !== 'default' &&
|
(prf.current?.data.display.target !== 'default' &&
|
||||||
prf.current!.data.display.dont_switch_primary
|
prf.current!.data.display.dont_switch_primary)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
@ -225,8 +232,12 @@ const canSkipPrimarySwitch = game === 'ongeki';
|
|||||||
:min="game === 'chunithm' ? 0 : 1"
|
:min="game === 'chunithm' ? 0 : 1"
|
||||||
:max="32"
|
:max="32"
|
||||||
:use-grouping="false"
|
:use-grouping="false"
|
||||||
|
placeholder="1"
|
||||||
v-model="prf.current!.data.display.monitor_index_override"
|
v-model="prf.current!.data.display.monitor_index_override"
|
||||||
:disabled="extraDisplayOptionsDisabled"
|
:disabled="
|
||||||
|
extraDisplayOptionsDisabled &&
|
||||||
|
capabilities.includes('display')
|
||||||
|
"
|
||||||
:allow-empty="true"
|
:allow-empty="true"
|
||||||
/>
|
/>
|
||||||
</OptionRow>
|
</OptionRow>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue';
|
import { Ref, computed, ref } from 'vue';
|
||||||
import Select from 'primevue/select';
|
import Select from 'primevue/select';
|
||||||
import { useConfirm } from 'primevue/useconfirm';
|
import { useConfirm } from 'primevue/useconfirm';
|
||||||
import { emit } from '@tauri-apps/api/event';
|
import { emit } from '@tauri-apps/api/event';
|
||||||
@ -19,6 +19,14 @@ const prf = usePrfStore();
|
|||||||
const pkgs = usePkgStore();
|
const pkgs = usePkgStore();
|
||||||
const confirmDialog = useConfirm();
|
const confirmDialog = useConfirm();
|
||||||
|
|
||||||
|
const capabilities: Ref<string[]> = ref([]);
|
||||||
|
|
||||||
|
invoke('list_platform_capabilities').then(async (v: unknown) => {
|
||||||
|
if (Array.isArray(v)) {
|
||||||
|
capabilities.value.push(...v);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const names = computed(() => {
|
const names = computed(() => {
|
||||||
switch (prf.current?.meta.game) {
|
switch (prf.current?.meta.game) {
|
||||||
case 'ongeki': {
|
case 'ongeki': {
|
||||||
@ -35,8 +43,6 @@ const names = computed(() => {
|
|||||||
io: 'chuniio',
|
io: 'chuniio',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case undefined:
|
|
||||||
throw new Error('Option tab without a profile');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -59,14 +65,14 @@ const checkSegatoolsIni = async (target: string) => {
|
|||||||
<template>
|
<template>
|
||||||
<OptionCategory :title="t('cfg.segatools.general')">
|
<OptionCategory :title="t('cfg.segatools.general')">
|
||||||
<OptionRow
|
<OptionRow
|
||||||
:title="names.exe"
|
:title="names?.exe"
|
||||||
:tooltip="t('cfg.segatools.targetTooltip')"
|
:tooltip="t('cfg.segatools.targetTooltip')"
|
||||||
>
|
>
|
||||||
<FilePicker
|
<FilePicker
|
||||||
:directory="false"
|
:directory="false"
|
||||||
:promptname="names.exe"
|
:promptname="names?.exe"
|
||||||
extension="exe"
|
extension="exe"
|
||||||
:value="prf.current!.data.sgt.target"
|
:value="prf.current?.data.sgt.target"
|
||||||
:callback="
|
:callback="
|
||||||
(value: string) => (
|
(value: string) => (
|
||||||
(prf.current!.data.sgt.target = value),
|
(prf.current!.data.sgt.target = value),
|
||||||
@ -80,7 +86,7 @@ const checkSegatoolsIni = async (target: string) => {
|
|||||||
<FilePicker
|
<FilePicker
|
||||||
:directory="true"
|
:directory="true"
|
||||||
placeholder="amfs"
|
placeholder="amfs"
|
||||||
:value="prf.current!.data.sgt.amfs"
|
:value="prf.current?.data.sgt.amfs"
|
||||||
:callback="
|
:callback="
|
||||||
(value: string) => (prf.current!.data.sgt.amfs = value)
|
(value: string) => (prf.current!.data.sgt.amfs = value)
|
||||||
"
|
"
|
||||||
@ -106,7 +112,7 @@ const checkSegatoolsIni = async (target: string) => {
|
|||||||
></FilePicker>
|
></FilePicker>
|
||||||
</OptionRow>
|
</OptionRow>
|
||||||
<OptionRow
|
<OptionRow
|
||||||
:title="names.hook"
|
:title="names?.hook"
|
||||||
:tooltip="
|
:tooltip="
|
||||||
t('cfg.segatools.installTooltip', {
|
t('cfg.segatools.installTooltip', {
|
||||||
thing: t('cfg.segatools.hooks'),
|
thing: t('cfg.segatools.hooks'),
|
||||||
@ -132,19 +138,18 @@ const checkSegatoolsIni = async (target: string) => {
|
|||||||
></Select>
|
></Select>
|
||||||
</OptionRow>
|
</OptionRow>
|
||||||
<OptionRow
|
<OptionRow
|
||||||
:title="names.io"
|
:title="names?.io"
|
||||||
:tooltip="
|
:tooltip="`${t('cfg.segatools.ioModulesDesc')}
|
||||||
t('cfg.segatools.installTooltip', {
|
${t('cfg.segatools.installTooltip', {
|
||||||
thing: t('cfg.segatools.ioModules'),
|
thing: t('cfg.segatools.ioModules'),
|
||||||
})
|
})}`"
|
||||||
"
|
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
v-model="prf.current!.data.sgt.io2"
|
v-model="prf.current!.data.sgt.io2"
|
||||||
:options="[
|
:options="[
|
||||||
{ title: 'native io4', value: 'hardware' },
|
{ title: t('cfg.segatools.io4'), value: 'hardware' },
|
||||||
{
|
{
|
||||||
title: 'segatools built-in (keyboard)',
|
title: t('cfg.segatools.ioBuiltIn'),
|
||||||
value: 'segatools_built_in',
|
value: 'segatools_built_in',
|
||||||
},
|
},
|
||||||
...pkgs
|
...pkgs
|
||||||
@ -164,5 +169,29 @@ const checkSegatoolsIni = async (target: string) => {
|
|||||||
option-value="value"
|
option-value="value"
|
||||||
></Select>
|
></Select>
|
||||||
</OptionRow>
|
</OptionRow>
|
||||||
|
<OptionRow
|
||||||
|
v-if="capabilities.includes('wine')"
|
||||||
|
:title="t('cfg.wine.runtime')"
|
||||||
|
>
|
||||||
|
<FilePicker
|
||||||
|
:directory="false"
|
||||||
|
:value="prf.current!.data.wine.runtime"
|
||||||
|
:callback="
|
||||||
|
(value: string) => (prf.current!.data.wine.runtime = value)
|
||||||
|
"
|
||||||
|
></FilePicker>
|
||||||
|
</OptionRow>
|
||||||
|
<OptionRow
|
||||||
|
v-if="capabilities.includes('wine')"
|
||||||
|
:title="t('cfg.wine.prefix')"
|
||||||
|
>
|
||||||
|
<FilePicker
|
||||||
|
:directory="true"
|
||||||
|
:value="prf.current!.data.wine.prefix"
|
||||||
|
:callback="
|
||||||
|
(value: string) => (prf.current!.data.wine.prefix = value)
|
||||||
|
"
|
||||||
|
></FilePicker>
|
||||||
|
</OptionRow>
|
||||||
</OptionCategory>
|
</OptionCategory>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import en from './i18n/en';
|
import en from './i18n/en';
|
||||||
import ja from './i18n/ja';
|
|
||||||
import { createI18n } from 'vue-i18n';
|
import { createI18n } from 'vue-i18n';
|
||||||
|
|
||||||
export type Locale = 'en' | 'ja';
|
export type Locale = 'en' | 'ja' | 'pl';
|
||||||
|
|
||||||
const loadLocaleMessages = async (locale: Locale) => {
|
const loadLocaleMessages = async (locale: Locale) => {
|
||||||
return (await import(`./i18n/${locale}.ts`)).default;
|
return (await import(`./i18n/${locale}.ts`)).default;
|
||||||
@ -12,7 +11,9 @@ const i18n = createI18n({
|
|||||||
legacy: false,
|
legacy: false,
|
||||||
locale: 'en',
|
locale: 'en',
|
||||||
fallbackLocale: 'en',
|
fallbackLocale: 'en',
|
||||||
messages: { en, ja },
|
warnHtmlInMessage: false,
|
||||||
|
warnHtmlMessage: false,
|
||||||
|
messages: { en, ja: {}, pl: {} },
|
||||||
});
|
});
|
||||||
|
|
||||||
const setLocale = async (locale: Locale) => {
|
const setLocale = async (locale: Locale) => {
|
||||||
|
@ -4,6 +4,10 @@ export default {
|
|||||||
enable: 'Enable',
|
enable: 'Enable',
|
||||||
disable: 'Disable',
|
disable: 'Disable',
|
||||||
default: 'Default',
|
default: 'Default',
|
||||||
|
search: 'Search',
|
||||||
|
next: 'Next',
|
||||||
|
skip: 'Skip',
|
||||||
|
close: 'Close',
|
||||||
start: {
|
start: {
|
||||||
failed: 'Start check failed',
|
failed: 'Start check failed',
|
||||||
accept: 'Run anyway',
|
accept: 'Run anyway',
|
||||||
@ -21,11 +25,11 @@ export default {
|
|||||||
button: {
|
button: {
|
||||||
start: 'START',
|
start: 'START',
|
||||||
stop: 'STOP',
|
stop: 'STOP',
|
||||||
unchecked: 'Start unchecked',
|
unchecked: 'Skip checks and start',
|
||||||
shortcut: 'Create desktop shortcut',
|
shortcut: 'Create desktop shortcut',
|
||||||
help: 'Help',
|
help: 'Help',
|
||||||
refresh: 'Refresh and start',
|
refresh: 'Reapply mods and start',
|
||||||
cache: 'Clear cache',
|
cache: 'Clear mod cache',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
game: {
|
game: {
|
||||||
@ -38,6 +42,9 @@ export default {
|
|||||||
delete: 'Delete profile',
|
delete: 'Delete profile',
|
||||||
reallyDelete: 'Are you sure you want to delete {profile}?',
|
reallyDelete: 'Are you sure you want to delete {profile}?',
|
||||||
template: 'STARTLINER template',
|
template: 'STARTLINER template',
|
||||||
|
importTemplate: 'Import template',
|
||||||
|
exportTemplate: 'Export template',
|
||||||
|
export: 'Export',
|
||||||
},
|
},
|
||||||
store: {
|
store: {
|
||||||
installRecommended: 'Install recommended packages',
|
installRecommended: 'Install recommended packages',
|
||||||
@ -46,13 +53,20 @@ export default {
|
|||||||
nsfw: 'Show NSFW',
|
nsfw: 'Show NSFW',
|
||||||
incompatible: 'This package is currently incompatible with STARTLINER.',
|
incompatible: 'This package is currently incompatible with STARTLINER.',
|
||||||
missing: 'Missing',
|
missing: 'Missing',
|
||||||
|
includeCategories: 'Include categories',
|
||||||
|
excludeCategories: 'Exclude categories',
|
||||||
},
|
},
|
||||||
patch: {
|
patch: {
|
||||||
loading: 'Loading...',
|
loading: 'Loading...',
|
||||||
noneFound:
|
noneFound:
|
||||||
"No compatible patches found. Make sure you're using unpacked and unpatched files.",
|
"No compatible patches found. Make sure you're using unpacked and unpatched files.",
|
||||||
|
forceLoad: 'Force load',
|
||||||
// Example patch name override
|
// Example patch name override
|
||||||
'standard-no-encryption': 'No encryption',
|
// 'standard-no-encryption': 'No encryption',
|
||||||
|
// 'standard-no-encryption-tooltip': 'Will also disable TLS',
|
||||||
|
// It is also possible to add a tooltip where there normally is none
|
||||||
|
// 'standard-maximum-tracks-tooltip': 'The number of tracks per credit',
|
||||||
|
// For more info check https://gitea.tendokyu.moe/akanyan/STARTLINER/wiki/Translation-%26-Localization
|
||||||
},
|
},
|
||||||
cfg: {
|
cfg: {
|
||||||
afterRestart: 'Applied after a restart',
|
afterRestart: 'Applied after a restart',
|
||||||
@ -64,9 +78,14 @@ export default {
|
|||||||
'STARTLINER expects unpacked executables put into otherwise clean data.',
|
'STARTLINER expects unpacked executables put into otherwise clean data.',
|
||||||
hooks: 'Hooks',
|
hooks: 'Hooks',
|
||||||
ioModules: 'IO modules',
|
ioModules: 'IO modules',
|
||||||
|
ioModulesDesc: 'This should match your desired input method.',
|
||||||
|
ioBuiltIn: 'segatools built-in (keyboard)',
|
||||||
|
io4: 'Native IO4',
|
||||||
installTooltip: '{thing} can be downloaded from the package store.',
|
installTooltip: '{thing} can be downloaded from the package store.',
|
||||||
},
|
},
|
||||||
display: {
|
display: {
|
||||||
|
title: 'Display',
|
||||||
|
resolution: 'Game resolution',
|
||||||
primary: 'Primary',
|
primary: 'Primary',
|
||||||
target: 'Target display',
|
target: 'Target display',
|
||||||
mode: 'Mode',
|
mode: 'Mode',
|
||||||
@ -82,6 +101,9 @@ export default {
|
|||||||
portrait: 'Portrait',
|
portrait: 'Portrait',
|
||||||
landscape: 'Landscape',
|
landscape: 'Landscape',
|
||||||
flipped: 'flipped',
|
flipped: 'flipped',
|
||||||
|
window: 'Window',
|
||||||
|
borderless: 'Borderless window',
|
||||||
|
fullscreen: 'Fullscreen',
|
||||||
},
|
},
|
||||||
network: {
|
network: {
|
||||||
title: 'Network',
|
title: 'Network',
|
||||||
@ -142,7 +164,10 @@ export default {
|
|||||||
leverMode: 'Lever mode',
|
leverMode: 'Lever mode',
|
||||||
mouse: 'Mouse',
|
mouse: 'Mouse',
|
||||||
},
|
},
|
||||||
|
wine: {
|
||||||
|
prefix: 'Wine prefix',
|
||||||
|
runtime: 'Wine runtime',
|
||||||
|
},
|
||||||
startliner: {
|
startliner: {
|
||||||
offlineMode: 'Offline mode',
|
offlineMode: 'Offline mode',
|
||||||
offlineModeTooltip: 'Disables the package store.',
|
offlineModeTooltip: 'Disables the package store.',
|
||||||
@ -150,4 +175,46 @@ export default {
|
|||||||
verbose: 'Detailed logs',
|
verbose: 'Detailed logs',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
onboarding: {
|
||||||
|
or: 'or',
|
||||||
|
backButton: 'a button on the back of the controller',
|
||||||
|
standard: `
|
||||||
|
You might get stuck on the following screen:
|
||||||
|
|
||||||
|
{bigblack}Aグループの基準機から設定を取得{endbig}
|
||||||
|
|
||||||
|
In which case, you should go to the test menu, and in game settings {black}ゲーム設定{end} switch from "follow the standard machine" {black}基準機に従う{end} to "standard machine" {black}基準機{end}.
|
||||||
|
|
||||||
|
The test menu can be accessed with %TESTMENU%.
|
||||||
|
`,
|
||||||
|
|
||||||
|
'ongeki-system-processing': `
|
||||||
|
You might get stuck on this screen for several minutes. _This is normal_. The game just takes a long time to load data.
|
||||||
|
|
||||||
|
If you install <code>7EVENDAYSHOLIDAYS/LoadBoost</code>, subsequent launches will be much faster.
|
||||||
|
`,
|
||||||
|
|
||||||
|
'ongeki-lever': `
|
||||||
|
You also have to calibrate the lever, or you may get the error 3301.
|
||||||
|
|
||||||
|
Go to lever settings ({black}レバー設定{end}), move the lever to both edges, then press "end" ({black}終了{end}) and "save" ({black}保存する{end}).
|
||||||
|
`,
|
||||||
|
|
||||||
|
'chunithm-server': `
|
||||||
|
If you're stuck on this screen, restart the game.
|
||||||
|
|
||||||
|
If the problem persists, {link}check your network configuration{endlink}
|
||||||
|
`,
|
||||||
|
|
||||||
|
finale: `
|
||||||
|
You can access this page any time by right-clicking the START button.
|
||||||
|
|
||||||
|
Additional resources:
|
||||||
|
|
||||||
|
- {segaguide}SEGAguide{endlink}
|
||||||
|
- {twotorial}two-torial{endlink}
|
||||||
|
|
||||||
|
## Have fun
|
||||||
|
`,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
261
src/i18n/pl.ts
Normal file
261
src/i18n/pl.ts
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
export default {
|
||||||
|
ok: 'OK',
|
||||||
|
cancel: 'Anuluj',
|
||||||
|
enable: 'Włącz',
|
||||||
|
disable: 'Wyłącz',
|
||||||
|
default: 'Domyślne',
|
||||||
|
search: 'Wyszukaj',
|
||||||
|
next: 'Dalej',
|
||||||
|
skip: 'Pomiń',
|
||||||
|
close: 'Zamknij',
|
||||||
|
start: {
|
||||||
|
failed: 'Uruchomienie nie powiodło się',
|
||||||
|
accept: 'Uruchom mimo to',
|
||||||
|
error: {
|
||||||
|
package: 'Brakujący pakiet',
|
||||||
|
dependency: 'Brakująca dependencja',
|
||||||
|
tool: 'Brakujące narzędzie',
|
||||||
|
unknown: 'Nieznany błąd',
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
game: 'Należy najpierw wskazać lokalizację gry',
|
||||||
|
amfs: 'Należy najpierw wskazać lokalizację amfs',
|
||||||
|
segatools: 'Należy dodać hook segatools',
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
start: 'START',
|
||||||
|
stop: 'STOP',
|
||||||
|
unchecked: 'Uruchom bez sprawdzania',
|
||||||
|
shortcut: 'Utwórz skrót',
|
||||||
|
help: 'Pomoc',
|
||||||
|
refresh: 'Uruchom po re-aplikacji modów',
|
||||||
|
cache: 'Wyczyść mod cache',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
game: {
|
||||||
|
ongeki: 'O.N.G.E.K.I.',
|
||||||
|
chunithm: 'CHUNITHM',
|
||||||
|
},
|
||||||
|
profile: {
|
||||||
|
welcome: 'Witaj w STARTLINERZE! Zacznij od utworzenia profilu',
|
||||||
|
create: 'Profil {game}',
|
||||||
|
delete: 'Usuń profil',
|
||||||
|
reallyDelete: 'Czy na pewno chcesz usunąć {profile}?',
|
||||||
|
template: 'Szablon',
|
||||||
|
importTemplate: 'Importuj szablon',
|
||||||
|
exportTemplate: 'Eksportuj szablon',
|
||||||
|
export: 'Eksportuj',
|
||||||
|
},
|
||||||
|
store: {
|
||||||
|
installRecommended: 'Dodaj zalecane pakiety',
|
||||||
|
installed: 'Pokaż zainstalowane',
|
||||||
|
deprecated: 'Pokaż przestarzałe',
|
||||||
|
nsfw: 'Pokaż mityczny O.N.G.E.K.I. Sex Mod dlaczego ta opcja w ogóle tu jest',
|
||||||
|
incompatible:
|
||||||
|
'Ten pakiet jest obecnie niekompatybilny ze STARTLINEREM.',
|
||||||
|
missing: 'Niedostępne',
|
||||||
|
includeCategories: 'Włącz kategorie',
|
||||||
|
excludeCategories: 'Wyłącz kategorie',
|
||||||
|
},
|
||||||
|
patch: {
|
||||||
|
loading: 'Wczytuję...',
|
||||||
|
noneFound:
|
||||||
|
'Brak kompatybilnych łatek. Upewnij się, że używasz czystych odpakowanych plików.',
|
||||||
|
forceLoad: 'Wymuś załadowanie',
|
||||||
|
'standard-shared-audio':
|
||||||
|
'Wymuś współdzielony tryb dźwięku; częstotliwość w systemie musi wynosić 48kHz',
|
||||||
|
'standard-shared-audio-tooltip':
|
||||||
|
'Poprawia kompatybilność, ale może zwiększyć opóźnienie',
|
||||||
|
'standard-2ch': 'Wymuś stereo',
|
||||||
|
'standard-2ch-tooltip': 'Może powodować bass overload',
|
||||||
|
'standard-song-timer': 'Wyłącz timer wyboru utworu',
|
||||||
|
'standard-map-timer': 'Timer wyboru mapy',
|
||||||
|
'standard-map-timer-tooltip':
|
||||||
|
'Jeśli ustawiony na wartość ujemną, timer wyniesie 968 + wartość (np. 968 + -1 = 967)',
|
||||||
|
'standard-ticket-timer': 'Timer wyboru biletu',
|
||||||
|
'standard-ticket-timer-tooltip':
|
||||||
|
'Jeśli ustawiony na wartość ujemną, timer wyniesie 968 + wartość (np. 968 + -1 = 967)',
|
||||||
|
'standard-course-timer': 'Timer wyboru dana',
|
||||||
|
'standard-course-timer-tooltip':
|
||||||
|
'Jeśli ustawiony na wartość ujemną, timer wyniesie 968 + wartość (np. 968 + -1 = 967)',
|
||||||
|
'standard-unlimited-tracks': 'Nieograniczona maksymalna liczba utworów',
|
||||||
|
'standard-unlimited-tracks-tooltip':
|
||||||
|
'Konieczne do grania więcej niż 7 utworów na kredyt',
|
||||||
|
'standard-maximum-tracks': 'Maksymalna liczba utworów',
|
||||||
|
'standard-no-encryption': 'Wyłącz szyfrowanie',
|
||||||
|
'standard-no-encryption-tooltip': 'Wyłączy również TLS',
|
||||||
|
'standard-no-tls': 'Wyłącz TLS',
|
||||||
|
'standard-no-tls-tooltip': 'Obejście problemów z serwerem tytułowym',
|
||||||
|
'standard-head-to-head': 'Napraw head to head',
|
||||||
|
'standard-head-to-head-tooltip':
|
||||||
|
'Naprawia nieskończoną synchronizację podczas próby połączenia w trybie head to head',
|
||||||
|
'standard-bypass-1080p': 'Obejdź sprawdzenie 1080p',
|
||||||
|
'standard-bypass-120hz': 'Obejdź sprawdzenie 120Hz',
|
||||||
|
'standard-force-free-play-text': 'Wymuś tekst kredytu FREE PLAY',
|
||||||
|
'standard-force-free-play-text-tooltip':
|
||||||
|
'Zastępuje liczbę kredytów tekstem FREE PLAY',
|
||||||
|
'standard-custom-free-play-length': 'Długość tekstu FREE PLAY',
|
||||||
|
'standard-custom-free-play-length-tooltip':
|
||||||
|
'Zmienia długość tekstu wyświetlanego, gdy włączony jest wymuszony tekst kredytu FREE PLAY',
|
||||||
|
'standard-custom-free-play-text': 'Customowy tekst FREE PLAY',
|
||||||
|
'standard-custom-free-play-text-tooltip': 'Zastąp tekst FREE PLAY',
|
||||||
|
'standard-localhost':
|
||||||
|
'Zezwól na serwer pod adresem 127.0.0.1/localhost',
|
||||||
|
'standard-credit-freeze': 'Zamroź kredyty',
|
||||||
|
'standard-credit-freeze-tooltip':
|
||||||
|
'Zapobiega używaniu kredytów. Co najmniej jeden kredyt musi być dostępny, aby rozpocząć grę lub zakupić bilety premium.',
|
||||||
|
'standard-openssl-fix': 'Napraw błąd OpenSSL SHA',
|
||||||
|
'standard-openssl-fix-tooltip':
|
||||||
|
'Naprawia crash na procesorach Intel 10. generacji i nowszych',
|
||||||
|
},
|
||||||
|
cfg: {
|
||||||
|
afterRestart: 'Wymaga restartu.',
|
||||||
|
hardware: 'Prawdziwy czytnik',
|
||||||
|
segatools: {
|
||||||
|
general: 'Ogólne',
|
||||||
|
builtIn: 'Wbudowany emulator',
|
||||||
|
targetTooltip:
|
||||||
|
'STARTLINER oczekuje czystych danych, pomijając odpakowane exe.',
|
||||||
|
hooks: 'Hooki',
|
||||||
|
ioModules: 'Moduły IO',
|
||||||
|
ioModulesDesc:
|
||||||
|
'Powinien odpowiadać twojej preferowanej metodzie wejścia.',
|
||||||
|
ioBuiltIn: 'Wbudowany emulator (klawiatura)',
|
||||||
|
io4: 'Natywne IO4',
|
||||||
|
installTooltip: '{thing} można pobrać z pobierajki pakietów.',
|
||||||
|
},
|
||||||
|
display: {
|
||||||
|
title: 'Ekran',
|
||||||
|
resolution: 'Rozdzielczość',
|
||||||
|
primary: 'Główny',
|
||||||
|
target: 'Docelowy wyświetlacz',
|
||||||
|
mode: 'Tryb',
|
||||||
|
rotation: 'Obrót',
|
||||||
|
refreshRate: 'Częstotliwość odświeżania',
|
||||||
|
borderlessFullscreen: 'Bezramkowy tryb pełnoekranowy',
|
||||||
|
borderlessFullscreenTooltip:
|
||||||
|
'Dopasuj rozdzielczość wyświetlacza do gry.',
|
||||||
|
dontSwitchPrimary: 'Pomiń przełączanie głównego wyświetlacza',
|
||||||
|
dontSwitchPrimaryTooltip:
|
||||||
|
'Włącz tę opcję tylko wtedy, gdy przełączanie głównego wyświetlacza powoduje problemy. Monitory muszą mieć dopasowaną częstotliwość odświeżania.',
|
||||||
|
index: 'Indeks wyświetlacza',
|
||||||
|
portrait: 'Pion',
|
||||||
|
landscape: 'Poziom',
|
||||||
|
flipped: 'Odwrócony',
|
||||||
|
window: 'Okno',
|
||||||
|
borderless: 'Okno bez ramki',
|
||||||
|
fullscreen: 'Pełny ekran',
|
||||||
|
},
|
||||||
|
network: {
|
||||||
|
title: 'Sieć',
|
||||||
|
type: 'Typ sieci',
|
||||||
|
remote: 'Zdalny',
|
||||||
|
localArtemis: 'Lokalny (ARTEMiS)',
|
||||||
|
artemisPath: 'Lokalizacja ARTEMiSa',
|
||||||
|
address: 'Adres serwera',
|
||||||
|
keychip: 'Keychip',
|
||||||
|
subnet: 'Podsieć',
|
||||||
|
addrSuffix: 'Sufiks adresu',
|
||||||
|
},
|
||||||
|
aime: {
|
||||||
|
type: 'Typ Aime',
|
||||||
|
modules: 'Moduły Aime',
|
||||||
|
code: 'Kod Aime',
|
||||||
|
codeTooltip:
|
||||||
|
'Dotyczy tylko wbudowanej emulacji lub zgodnych pakietów',
|
||||||
|
aimedb: 'Użyj AiMeDB dla kart fizycznych',
|
||||||
|
aimedbTooltip:
|
||||||
|
'Decyduje czy karty fizyczne powinny używać AiMeDB do pobierania kodów dostępu. Jeśli łączysz się z hostowaną siecią, włącz tę opcję, aby załadować te same dane konta, jakie uzyskałxbyś na fizycznym cabie.',
|
||||||
|
serialPort: 'Port szeregowy Aime',
|
||||||
|
serialPortTooltip: `Porty można sprawdzić w Urządzeniach i drukarkach lub na googlechromelabs.github.io/serial-terminal
|
||||||
|
Dla AIC Pico powinien być wybrany port AIME.`,
|
||||||
|
serverName: 'Nazwa serwera',
|
||||||
|
},
|
||||||
|
misc: {
|
||||||
|
title: 'Różne',
|
||||||
|
intel: 'Obejście buga OpenSSL dla procesorów Intel ≥10 generacji',
|
||||||
|
intelTooltip: 'Zaleca się zamiast tego załatać amdaemon.',
|
||||||
|
other: 'Inne opcje segatools',
|
||||||
|
otherTooltip:
|
||||||
|
'Zaawansowane lub sytuacyjne opcje, które nie są objęte przez STARTLINERA',
|
||||||
|
},
|
||||||
|
extensions: {
|
||||||
|
title: 'Rozszerzenia',
|
||||||
|
bepInExConsole: 'Konsola BepInExa',
|
||||||
|
audioMode: 'Tryb audio',
|
||||||
|
audioTooltip:
|
||||||
|
'Tryb ekskluzywny 2-kanałowy wymaga 7EVENDAYSHOLIDAYS-ExclusiveAudio',
|
||||||
|
audioShared: 'Współdzielony',
|
||||||
|
audio6Ch: 'Ekskluzywny 6-kanałowy',
|
||||||
|
audio2Ch: 'Ekskluzywny 2-kanałowy',
|
||||||
|
sampleRate: 'Częstotliwość',
|
||||||
|
blacklist: 'Czarna lista utworów',
|
||||||
|
blacklistTooltip:
|
||||||
|
'Utwory w tym zakresie ID nie będą zapisywane ani przesyłane',
|
||||||
|
bonusTracks: 'Odblokuj Bonusowe Utwory',
|
||||||
|
bonusTracksTooltip:
|
||||||
|
'Wyłączenie tej opcji może pomóc w uporządkowaniu listy utworów',
|
||||||
|
saekawa: 'Plik konfiguracyjny Saekawy',
|
||||||
|
inohara: 'Plik konfiguracyjny Inohary',
|
||||||
|
},
|
||||||
|
keyboard: {
|
||||||
|
title: 'Klawiatura',
|
||||||
|
tooltip:
|
||||||
|
'Dotyczy tylko wtedy, gdy moduł IO jest ustawiony na wbudowaną emulację lub zgodny moduł (np. mu3io.NET)',
|
||||||
|
leverMode: 'Tryb wajchy',
|
||||||
|
mouse: 'Mysz',
|
||||||
|
},
|
||||||
|
wine: {
|
||||||
|
prefix: 'Wine prefix',
|
||||||
|
runtime: 'Lokalizacja Wine',
|
||||||
|
},
|
||||||
|
startliner: {
|
||||||
|
offlineMode: 'Tryb offline',
|
||||||
|
offlineModeTooltip: 'Wyłącza pobierajkę pakietów.',
|
||||||
|
autoUpdate: 'Automatyczne aktualizacje',
|
||||||
|
verbose: 'Szczegółowe logi',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
onboarding: {
|
||||||
|
or: 'lub',
|
||||||
|
backButton: 'przycisku z tyłu',
|
||||||
|
standard: `
|
||||||
|
Możesz utknąć na następującym ekranie:
|
||||||
|
|
||||||
|
{bigblack}Aグループの基準機から設定を取得{endbig}
|
||||||
|
|
||||||
|
Wówczas musisz przejść do menu testowego i w ustawieniach gry {black}ゲーム設定{end} przełączyć z "podążaj za standardem" {black}基準機に従う{end} na "standard" {black}基準機{end}.
|
||||||
|
|
||||||
|
Do menu testowego możesz dostać się za pomocą %TESTMENU%.
|
||||||
|
`,
|
||||||
|
|
||||||
|
'ongeki-system-processing': `
|
||||||
|
Możesz utknąć na tym ekranie przez kilka(naście) minut. _To jest normalne_. Gra po prostu potrzebuje dużo czasu na załadowanie danych.
|
||||||
|
|
||||||
|
Jeśli zainstalujesz <code>7EVENDAYSHOLIDAYS/LoadBoost</code>, kolejne uruchomienia będą znacznie szybsze.
|
||||||
|
`,
|
||||||
|
|
||||||
|
'ongeki-lever': `
|
||||||
|
Musisz również skalibrować wajchę; w przeciwnym razie możesz otrzymać błąd 3301.
|
||||||
|
|
||||||
|
Przejdź do ustawień wajchy ({black}レバー設定{end}), przesuń wajchę do obu krawędzi, a następnie naciśnij "koniec" ({black}終了{end}) i "zapisz" ({black}保存する{end}).
|
||||||
|
`,
|
||||||
|
|
||||||
|
'chunithm-server': `
|
||||||
|
Jeśli utkniesz na tym ekranie, zrestartuj grę.
|
||||||
|
|
||||||
|
Jeśli problem będzie się powtarzał, {link}sprawdź swoją konfigurację sieciową{endlink}.
|
||||||
|
`,
|
||||||
|
|
||||||
|
finale: `
|
||||||
|
Możesz uzyskać dostęp do tej strony w każdej chwili, klikając prawym przyciskiem myszy przycisk START.
|
||||||
|
|
||||||
|
Dodatkowe zasoby:
|
||||||
|
|
||||||
|
- {segaguide}SEGAguide{endlink}
|
||||||
|
- {twotorial}two-torial{endlink}
|
||||||
|
|
||||||
|
## Miłej zabawy
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
};
|
@ -32,23 +32,24 @@ export const useGeneralStore = defineStore('general', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const configDir = computed(() => {
|
const loadDirs = async () => {
|
||||||
if (dirs.value === null) {
|
if (dirs.value === null) {
|
||||||
throw new Error('Invalid directory access');
|
const d = (await invoke('list_directories')) as Dirs;
|
||||||
|
dirs.value = d;
|
||||||
}
|
}
|
||||||
return dirs.value.config_dir;
|
};
|
||||||
|
|
||||||
|
const configDir = computed(async () => {
|
||||||
|
await loadDirs();
|
||||||
|
return dirs.value!.config_dir;
|
||||||
});
|
});
|
||||||
const dataDir = computed(() => {
|
const dataDir = computed(async () => {
|
||||||
if (dirs.value === null) {
|
await loadDirs();
|
||||||
throw new Error('Invalid directory access');
|
return dirs.value!.data_dir;
|
||||||
}
|
|
||||||
return dirs.value.data_dir;
|
|
||||||
});
|
});
|
||||||
const cacheDir = computed(() => {
|
const cacheDir = computed(async () => {
|
||||||
if (dirs.value === null) {
|
await loadDirs();
|
||||||
throw new Error('Invalid directory access');
|
return dirs.value!.cache_dir;
|
||||||
}
|
|
||||||
return dirs.value.cache_dir;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -321,8 +322,8 @@ export const usePrfStore = defineStore('prf', () => {
|
|||||||
const generalStore = useGeneralStore();
|
const generalStore = useGeneralStore();
|
||||||
|
|
||||||
const configDir = computed(async () => {
|
const configDir = computed(async () => {
|
||||||
return await path.join(
|
return path.join(
|
||||||
generalStore.configDir,
|
await generalStore.configDir,
|
||||||
`profile-${current.value?.meta.game}-${current.value?.meta.name}`
|
`profile-${current.value?.meta.game}-${current.value?.meta.name}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -373,6 +374,7 @@ export const useClientStore = defineStore('client', () => {
|
|||||||
const theme: Ref<'light' | 'dark' | 'system'> = ref('system');
|
const theme: Ref<'light' | 'dark' | 'system'> = ref('system');
|
||||||
const onboarded: Ref<Game[]> = ref([]);
|
const onboarded: Ref<Game[]> = ref([]);
|
||||||
const locale: Ref<Locale> = ref('en');
|
const locale: Ref<Locale> = ref('en');
|
||||||
|
const currentTab: Ref<string> = ref('users');
|
||||||
|
|
||||||
const _scaleValue = (value: ScaleType) =>
|
const _scaleValue = (value: ScaleType) =>
|
||||||
value === 's' ? 1 : value === 'm' ? 1.25 : value === 'l' ? 1.5 : 2;
|
value === 's' ? 1 : value === 'm' ? 1.25 : value === 'l' ? 1.5 : 2;
|
||||||
@ -412,7 +414,7 @@ export const useClientStore = defineStore('client', () => {
|
|||||||
const input = JSON.parse(
|
const input = JSON.parse(
|
||||||
await readTextFile(
|
await readTextFile(
|
||||||
await path.join(
|
await path.join(
|
||||||
generalStore.configDir,
|
await generalStore.configDir,
|
||||||
'client-options.json'
|
'client-options.json'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -439,6 +441,10 @@ export const useClientStore = defineStore('client', () => {
|
|||||||
if (input.locale) {
|
if (input.locale) {
|
||||||
locale.value = input.locale;
|
locale.value = input.locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (input.currentTab) {
|
||||||
|
currentTab.value = input.currentTab;
|
||||||
|
}
|
||||||
await setLocale(locale.value);
|
await setLocale(locale.value);
|
||||||
await setTheme(theme.value);
|
await setTheme(theme.value);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -464,7 +470,10 @@ export const useClientStore = defineStore('client', () => {
|
|||||||
const size = await w.innerSize();
|
const size = await w.innerSize();
|
||||||
|
|
||||||
await writeTextFile(
|
await writeTextFile(
|
||||||
await path.join(generalStore.configDir, 'client-options.json'),
|
await path.join(
|
||||||
|
await generalStore.configDir,
|
||||||
|
'client-options.json'
|
||||||
|
),
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
scaleFactor: scaleFactor.value,
|
scaleFactor: scaleFactor.value,
|
||||||
windowSize: {
|
windowSize: {
|
||||||
@ -474,6 +483,7 @@ export const useClientStore = defineStore('client', () => {
|
|||||||
theme: theme.value,
|
theme: theme.value,
|
||||||
onboarded: onboarded.value,
|
onboarded: onboarded.value,
|
||||||
locale: locale.value,
|
locale: locale.value,
|
||||||
|
currentTab: currentTab.value,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -549,6 +559,7 @@ export const useClientStore = defineStore('client', () => {
|
|||||||
locale,
|
locale,
|
||||||
timeout,
|
timeout,
|
||||||
scaleModel,
|
scaleModel,
|
||||||
|
currentTab,
|
||||||
_scaleValue,
|
_scaleValue,
|
||||||
scaleValue,
|
scaleValue,
|
||||||
load,
|
load,
|
||||||
|
@ -56,6 +56,7 @@ export interface ProfileData {
|
|||||||
display: DisplayConfig;
|
display: DisplayConfig;
|
||||||
network: NetworkConfig;
|
network: NetworkConfig;
|
||||||
bepinex: BepInExConfig;
|
bepinex: BepInExConfig;
|
||||||
|
wine: WineConfig;
|
||||||
mu3_ini: Mu3IniConfig | undefined;
|
mu3_ini: Mu3IniConfig | undefined;
|
||||||
keyboard: KeyboardConfig | undefined;
|
keyboard: KeyboardConfig | undefined;
|
||||||
patches: {
|
patches: {
|
||||||
@ -105,6 +106,11 @@ export interface BepInExConfig {
|
|||||||
console: boolean;
|
console: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface WineConfig {
|
||||||
|
runtime: string;
|
||||||
|
prefix: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Mu3IniConfig {
|
export interface Mu3IniConfig {
|
||||||
audio?: 'Shared' | 'Excl6Ch' | 'Excl2Ch';
|
audio?: 'Shared' | 'Excl6Ch' | 'Excl2Ch';
|
||||||
sample_rate: number;
|
sample_rate: number;
|
||||||
|
Reference in New Issue
Block a user