feat: select Anomaly Arbitration round

This commit is contained in:
CAtlas0784 committed 2026-10-25 00:45:23 +07:00
1 parent feb18074fe
commit 62a529ef3f
4 files changed
+159 -95

No files matched your search

+12 -13
View File
@@ -3661,16 +3661,17 @@ input:checked + .slider:before {
.monster-settings-stage-copy strong { color: var(--text-main); font-size: .92rem; line-height: 1.28; overflow-wrap: anywhere; }
.monster-settings-stage-card.is-boss .monster-settings-stage-meta:first-of-type { color: #fcd34d; }
.monster-settings-view[hidden] { display: none; }
.monster-aa-room-control { display: flex; align-items: center; justify-content: space-between; gap: 1.25rem; padding: 1rem 1.1rem; border: 1px solid rgba(56, 189, 248, .28); border-radius: 14px; background: linear-gradient(120deg, rgba(14, 165, 233, .1), rgba(15, 23, 42, .72)); }
.monster-aa-room-header { display: grid; gap: .6rem; min-width: 0; }
.monster-aa-room-copy h3 { margin: 0; color: var(--text-highlight); font-size: 1rem; }
.monster-aa-room-copy p { margin: .35rem 0 0; color: var(--text-muted); line-height: 1.5; }
.monster-aa-room-status { color: var(--text-muted); font-size: .88rem; line-height: 1.45; overflow-wrap: anywhere; }
.monster-aa-room-status.is-pending { color: #86efac; }
.monster-aa-room-status.is-error { color: #fda4af; }
.monster-aa-room-actions { display: flex; flex: 0 0 auto; align-items: center; gap: .6rem; }
.monster-aa-room-actions .btn { min-height: 42px; white-space: nowrap; }
.monster-aa-room-actions .btn:disabled { opacity: .55; cursor: not-allowed; }
.monster-aa-round-control { display: grid; grid-template-columns: minmax(0, 1fr) minmax(280px, .9fr); align-items: center; gap: 1.25rem; padding: 1rem 1.1rem; border: 1px solid rgba(56, 189, 248, .28); border-radius: 14px; background: linear-gradient(120deg, rgba(14, 165, 233, .1), rgba(15, 23, 42, .72)); }
.monster-aa-round-header { display: grid; gap: .6rem; min-width: 0; }
.monster-aa-round-copy h3 { margin: 0; color: var(--text-highlight); font-size: 1rem; }
.monster-aa-round-copy p { margin: .35rem 0 0; color: var(--text-muted); line-height: 1.5; }
.monster-aa-round-status { color: var(--text-muted); font-size: .88rem; line-height: 1.45; overflow-wrap: anywhere; }
.monster-aa-round-status.is-pending { color: #86efac; }
.monster-aa-round-status.is-error { color: #fda4af; }
.monster-aa-round-picker-wrap { display: grid; gap: .5rem; min-width: 0; }
.monster-aa-round-picker-label { color: var(--text-muted); font-size: .82rem; font-weight: 800; }
.monster-aa-round-picker { min-height: 46px; width: 100%; }
.monster-aa-round-picker:disabled { opacity: .55; cursor: not-allowed; }
.monster-settings-stage-heading { display: flex; align-items: center; gap: .65rem; flex-wrap: wrap; }
.monster-settings-stage-heading h3 { margin: 0; color: var(--text-highlight); font-size: 1.1rem; }
.monster-settings-badge { padding: .25rem .55rem; border: 1px solid rgba(192, 132, 252, .3); border-radius: 999px; color: #d8b4fe; background: rgba(168, 85, 247, .1); font-size: .75rem; font-weight: 700; }
@@ -3731,9 +3732,7 @@ input:checked + .slider:before {
.monster-settings-wave { flex-direction: column; }
.monster-settings-monsters { width: 100%; }
.monster-settings-stage-grid { grid-template-columns: 1fr; }
.monster-aa-room-control { align-items: stretch; flex-direction: column; }
.monster-aa-room-actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.monster-aa-room-actions .btn { width: 100%; }
.monster-aa-round-control { grid-template-columns: 1fr; align-items: stretch; }
.monster-custom-toolbar, .monster-custom-save-actions { align-items: stretch; flex-direction: column; }
.monster-custom-actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(145px, 1fr)); }
.monster-custom-save-actions .btn { width: 100%; }
+2 -2
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GaC-Srtool</title>
<link rel="stylesheet" href="css/styles.css?v=2.15">
<link rel="stylesheet" href="css/styles.css?v=2.16">
<link rel="stylesheet" href="css/item-catalog.css?v=2">
<link rel="icon" type="image/png" href="assets/logo.png">
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
@@ -1806,6 +1806,6 @@
<div class="toast-container" id="toast-container"></div>
<!-- Script Modules -->
<script type="module" src="js/app.js?v=3.2"></script>
<script type="module" src="js/app.js?v=3.3"></script>
</body>
</html>
+125 -80
View File
@@ -51,7 +51,7 @@ const state = {
inventorySaved: {},
inventoryDraft: {},
inventoryPage: 0,
monsterSettings: { activeMode: 'moc', catalog: null, groupId: '', stageId: '', waves: [], savedFingerprint: '', ready: false, canEdit: false, aaSelection: null, aaSelectionLoaded: false, aaSelectionBusy: false, aaSelectionError: '', aaSelectionErrorKey: '' },
monsterSettings: { activeMode: 'moc', catalog: null, groupId: '', stageId: '', waves: [], savedFingerprint: '', ready: false, canEdit: false, aaRoundSelection: null, aaRoundSelectionLoaded: false, aaRoundSelectionBusy: false, aaRoundSelectionError: '', aaRoundSelectionErrorKey: '' },
};
// UI Elements Map
@@ -6938,47 +6938,60 @@ function monsterStagePreviewNames(stage) {
return (stage?.monster_ids || []).map(monsterName).filter(Boolean);
}
function renderAARoomSelection(stage, groups) {
function renderAARoundSelection(groups) {
const editor = state.monsterSettings;
const section = monsterElement('section', 'monster-aa-room-control');
const header = monsterElement('div', 'monster-aa-room-header');
const copy = monsterElement('div', 'monster-aa-room-copy');
copy.append(monsterElement('h3', '', t('monsterAaRoomTitle')));
copy.append(monsterElement('p', '', t('monsterAaRoomDescription')));
const section = monsterElement('section', 'monster-aa-round-control');
const header = monsterElement('div', 'monster-aa-round-header');
const copy = monsterElement('div', 'monster-aa-round-copy');
copy.append(monsterElement('h3', '', t('monsterAaRoundTitle')));
copy.append(monsterElement('p', '', t('monsterAaRoundDescription')));
header.append(copy);
const queued = editor.aaSelection;
if (queued) {
const queuedStage = groups.flatMap(group => group.stages || []).find(item => Number(item.id) === Number(queued.peak_id));
const queuedName = monsterStagePreviewNames(queuedStage).slice(0, 2).join(' / ') || t('monsterSettingsStageTitle', { id: queued.peak_id });
const status = monsterElement('div', 'monster-aa-room-status is-pending', t('monsterAaRoomPending', { room: queuedName, id: queued.peak_id }));
const selection = editor.aaRoundSelection;
if (editor.aaRoundSelectionError) {
const status = monsterElement('div', 'monster-aa-round-status is-error', t(editor.aaRoundSelectionErrorKey || 'monsterAaRoundLoadError', { error: editor.aaRoundSelectionError }));
status.setAttribute('role', 'status');
header.append(status);
} else if (editor.aaSelectionError) {
const status = monsterElement('div', 'monster-aa-room-status is-error', t(editor.aaSelectionErrorKey || 'monsterAaRoomLoadError', { error: editor.aaSelectionError }));
} else if (editor.aaRoundSelectionBusy) {
const status = monsterElement('div', 'monster-aa-round-status', t('monsterAaRoundUpdating'));
status.setAttribute('role', 'status');
header.append(status);
} else if (!editor.aaSelectionLoaded && state.isConnected && state.serverMode === 'gac') {
header.append(monsterElement('div', 'monster-aa-room-status', t('monsterAaRoomLoading')));
} else if (!editor.aaRoundSelectionLoaded && state.isConnected && state.serverMode === 'gac') {
header.append(monsterElement('div', 'monster-aa-round-status', t('monsterAaRoundLoading')));
} else if (!state.isConnected || state.serverMode !== 'gac') {
header.append(monsterElement('div', 'monster-aa-room-status', t('monsterAaRoomConnect')));
header.append(monsterElement('div', 'monster-aa-round-status', t('monsterAaRoundConnect')));
} else if (selection) {
const selectedGroup = groups.find(group => Number(group.id) === Number(selection.peak_group_id));
const selectedName = monsterLocalizedText(selectedGroup?.names) || t('monsterSettingsGroupOption', { id: selection.peak_group_id, count: selectedGroup?.stages?.length || 0 });
const status = monsterElement('div', 'monster-aa-round-status is-pending', t('monsterAaRoundPending', { round: selectedName, id: selection.peak_group_id }));
status.setAttribute('role', 'status');
header.append(status);
} else {
header.append(monsterElement('div', 'monster-aa-round-status', t('monsterAaRoundDefault')));
}
const actions = monsterElement('div', 'monster-aa-room-actions');
const selectButton = monsterElement('button', 'btn btn-primary monster-aa-room-select', t('monsterAaRoomUse'));
selectButton.type = 'button';
selectButton.dataset.aaRoomAction = 'select';
selectButton.dataset.aaRoomId = String(stage.id);
selectButton.disabled = editor.aaSelectionBusy || !state.isConnected || state.serverMode !== 'gac' || !editor.catalog;
actions.append(selectButton);
if (queued) {
const clearButton = monsterElement('button', 'btn btn-secondary monster-aa-room-clear', t('monsterAaRoomClear'));
clearButton.type = 'button';
clearButton.dataset.aaRoomAction = 'clear';
clearButton.disabled = editor.aaSelectionBusy || !state.isConnected || state.serverMode !== 'gac';
actions.append(clearButton);
const picker = monsterElement('div', 'monster-aa-round-picker-wrap');
const label = monsterElement('label', 'monster-aa-round-picker-label', t('monsterAaRoundSelectLabel'));
label.htmlFor = 'monster-aa-round-picker';
const select = monsterElement('select', 'form-select monster-aa-round-picker');
select.id = 'monster-aa-round-picker';
select.dataset.aaRoundPicker = 'true';
select.setAttribute('aria-label', t('monsterAaRoundSelectLabel'));
select.disabled = editor.aaRoundSelectionBusy || !state.isConnected || state.serverMode !== 'gac' || !editor.catalog;
const defaultOption = document.createElement('option');
defaultOption.value = '';
defaultOption.textContent = t('monsterAaRoundDefaultOption');
select.append(defaultOption);
for (const group of groups) {
const option = document.createElement('option');
option.value = String(group.id);
const roundName = monsterLocalizedText(group.names) || t('monsterSettingsGroupOption', { id: group.id, count: group.stages.length });
option.textContent = `${roundName} · ${t('monsterAaRoundGroupId', { id: group.id })}`;
select.append(option);
}
section.append(header, actions);
select.value = selection ? String(selection.peak_group_id) : '';
picker.append(label, select);
section.append(header, picker);
return section;
}
@@ -6992,33 +7005,40 @@ function renderMonsterChallengeMode(mode) {
return;
}
const selectedGroup = groups.find(group => String(group.id) === String(state.monsterSettings.groupId)) || groups[0];
const preferredGroupId = mode === 'aa'
? (state.monsterSettings.aaRoundSelection?.peak_group_id ?? groups[0].id)
: state.monsterSettings.groupId;
const selectedGroup = groups.find(group => String(group.id) === String(preferredGroupId)) || groups[0];
state.monsterSettings.groupId = String(selectedGroup.id);
const selectedStage = selectedGroup.stages.find(stage => String(stage.id) === String(state.monsterSettings.stageId)) || selectedGroup.stages[0];
state.monsterSettings.stageId = String(selectedStage.id);
const groupPicker = monsterElement('section', 'monster-settings-picker-section');
groupPicker.append(monsterElement('h3', 'monster-settings-picker-title', t('monsterSettingsGroup')));
const groupGrid = monsterElement('div', 'monster-settings-group-grid');
for (const group of groups) {
const button = monsterElement('button', `monster-settings-group-card${group.id === selectedGroup.id ? ' active' : ''}`);
button.type = 'button';
button.dataset.monsterGroup = String(group.id);
button.setAttribute('aria-pressed', String(group.id === selectedGroup.id));
const copy = monsterElement('span', 'monster-settings-group-copy');
copy.append(monsterElement('strong', 'monster-settings-group-name', monsterLocalizedText(group.names) || t('monsterSettingsGroupOption', { id: group.id, count: group.stages.length })));
copy.append(monsterElement('span', 'monster-settings-group-meta', t('monsterSettingsGroupOption', { id: group.id, count: group.stages.length })));
button.append(copy);
const bossStage = group.stages.find(stage => stage.is_boss);
const bossId = bossStage?.monster_ids?.[0];
if (bossId) appendMonsterIdentity(button, bossId, 'group-feature');
groupGrid.append(button);
if (mode === 'aa') {
root.append(renderAARoundSelection(groups));
} else {
const groupPicker = monsterElement('section', 'monster-settings-picker-section');
groupPicker.append(monsterElement('h3', 'monster-settings-picker-title', t('monsterSettingsGroup')));
const groupGrid = monsterElement('div', 'monster-settings-group-grid');
for (const group of groups) {
const button = monsterElement('button', `monster-settings-group-card${group.id === selectedGroup.id ? ' active' : ''}`);
button.type = 'button';
button.dataset.monsterGroup = String(group.id);
button.setAttribute('aria-pressed', String(group.id === selectedGroup.id));
const copy = monsterElement('span', 'monster-settings-group-copy');
copy.append(monsterElement('strong', 'monster-settings-group-name', monsterLocalizedText(group.names) || t('monsterSettingsGroupOption', { id: group.id, count: group.stages.length })));
copy.append(monsterElement('span', 'monster-settings-group-meta', t('monsterSettingsGroupOption', { id: group.id, count: group.stages.length })));
button.append(copy);
const bossStage = group.stages.find(stage => stage.is_boss);
const bossId = bossStage?.monster_ids?.[0];
if (bossId) appendMonsterIdentity(button, bossId, 'group-feature');
groupGrid.append(button);
}
groupPicker.append(groupGrid);
root.append(groupPicker);
}
groupPicker.append(groupGrid);
root.append(groupPicker);
const stagePicker = monsterElement('section', 'monster-settings-picker-section');
stagePicker.append(monsterElement('h3', 'monster-settings-picker-title', t('monsterSettingsChallenge')));
stagePicker.append(monsterElement('h3', 'monster-settings-picker-title', t(mode === 'aa' ? 'monsterSettingsAARoomPreview' : 'monsterSettingsChallenge')));
const stageGrid = monsterElement('div', 'monster-settings-stage-grid');
for (const stage of selectedGroup.stages) {
const button = monsterElement('button', `monster-settings-stage-card${stage.id === selectedStage.id ? ' active' : ''}${stage.is_boss ? ' is-boss' : ''}`);
@@ -7039,8 +7059,6 @@ function renderMonsterChallengeMode(mode) {
stagePicker.append(stageGrid);
root.append(stagePicker);
if (mode === 'aa') root.append(renderAARoomSelection(selectedStage, groups));
const stageHeader = monsterElement('div', 'monster-settings-stage-heading');
const stageNames = monsterStagePreviewNames(selectedStage);
stageHeader.append(monsterElement('h3', '', stageNames.length ? stageNames.slice(0, 2).join(' / ') : t('monsterSettingsStageTitle', { id: selectedStage.id })));
@@ -7341,10 +7359,10 @@ async function loadMonsterSettings() {
editor.ready = false;
editor.canEdit = false;
editor.catalog = null;
editor.aaSelection = null;
editor.aaSelectionLoaded = false;
editor.aaSelectionError = '';
editor.aaSelectionErrorKey = '';
editor.aaRoundSelection = null;
editor.aaRoundSelectionLoaded = false;
editor.aaRoundSelectionError = '';
editor.aaRoundSelectionErrorKey = '';
setMonsterSettingsStatus('monsterSettingsLoading', 'loading');
let catalogError = null;
@@ -7353,12 +7371,25 @@ async function loadMonsterSettings() {
editor.catalog = await apiCall('/api/monster-settings/catalog');
} catch (error) { catalogError = error; }
try {
const result = await apiCall('/api/monster-settings/aa-room');
editor.aaSelection = result?.selection || null;
editor.aaSelectionLoaded = true;
const result = await apiCall('/api/monster-settings/aa-round');
editor.aaRoundSelection = result?.selection || null;
editor.aaRoundSelectionLoaded = true;
if (editor.aaRoundSelection) {
const selected = editor.catalog?.modes?.aa?.find(group => Number(group.id) === Number(editor.aaRoundSelection.peak_group_id));
if (selected) {
editor.groupId = String(selected.id);
if (!selected.stages.some(stage => String(stage.id) === String(editor.stageId))) editor.stageId = String(selected.stages[0]?.id || '');
}
} else {
const defaultGroup = editor.catalog?.modes?.aa?.[0];
if (defaultGroup) {
editor.groupId = String(defaultGroup.id);
if (!defaultGroup.stages.some(stage => String(stage.id) === String(editor.stageId))) editor.stageId = String(defaultGroup.stages[0]?.id || '');
}
}
} catch (error) {
editor.aaSelectionError = error.message;
editor.aaSelectionErrorKey = 'monsterAaRoomLoadError';
editor.aaRoundSelectionError = error.message;
editor.aaRoundSelectionErrorKey = 'monsterAaRoundLoadError';
}
}
@@ -7410,29 +7441,43 @@ function setupMonsterSettingsEvents() {
});
});
const root = document.getElementById('monster-settings-view');
root?.addEventListener('click', async event => {
const action = event.target.closest('[data-aa-room-action]');
if (!action || action.disabled) return;
root?.addEventListener('change', async event => {
const picker = event.target.closest('[data-aa-round-picker]');
if (!picker || picker.disabled) return;
const editor = state.monsterSettings;
if (editor.aaSelectionBusy) return;
editor.aaSelectionBusy = true;
editor.aaSelectionError = '';
editor.aaSelectionErrorKey = '';
if (editor.aaRoundSelectionBusy) return;
const peakGroupId = picker.value ? Number(picker.value) : 0;
if (peakGroupId) {
const selected = editor.catalog?.modes?.aa?.find(group => Number(group.id) === peakGroupId);
if (!selected) return;
editor.groupId = String(selected.id);
editor.stageId = String(selected.stages[0]?.id || '');
} else {
const defaultGroup = editor.catalog?.modes?.aa?.[0];
if (defaultGroup) {
editor.groupId = String(defaultGroup.id);
editor.stageId = String(defaultGroup.stages[0]?.id || '');
}
}
const previousSelection = editor.aaRoundSelection;
editor.aaRoundSelectionBusy = true;
editor.aaRoundSelectionError = '';
editor.aaRoundSelectionErrorKey = '';
editor.aaRoundSelection = peakGroupId ? { peak_group_id: peakGroupId } : null;
renderMonsterSettings();
try {
const payload = action.dataset.aaRoomAction === 'clear'
? { action: 'clear' }
: { peak_id: Number(action.dataset.aaRoomId) };
const result = await apiCall('/api/monster-settings/aa-room', 'POST', payload);
editor.aaSelection = result?.selection || null;
editor.aaSelectionLoaded = true;
showToast(t(editor.aaSelection ? 'monsterAaRoomSavedToast' : 'monsterAaRoomClearedToast'), 'success');
const payload = peakGroupId ? { peak_group_id: peakGroupId } : { action: 'clear' };
const result = await apiCall('/api/monster-settings/aa-round', 'POST', payload);
editor.aaRoundSelection = result?.selection || null;
editor.aaRoundSelectionLoaded = true;
showToast(t(editor.aaRoundSelection ? 'monsterAaRoundSavedToast' : 'monsterAaRoundClearedToast'), 'success');
} catch (error) {
editor.aaSelectionError = error.message;
editor.aaSelectionErrorKey = 'monsterAaRoomSaveError';
showToast(t('monsterAaRoomSaveError', { error: error.message }), 'error');
editor.aaRoundSelection = previousSelection;
editor.aaRoundSelectionError = error.message;
editor.aaRoundSelectionErrorKey = 'monsterAaRoundSaveError';
showToast(t('monsterAaRoundSaveError', { error: error.message }), 'error');
} finally {
editor.aaSelectionBusy = false;
editor.aaRoundSelectionBusy = false;
renderMonsterSettings();
}
});
+20
View File
@@ -6786,6 +6786,26 @@ for (const [language, additions] of Object.entries(AA_ROOM_SELECTION_TRANSLATION
Object.assign(TRANSLATIONS[language], additions);
}
const AA_ROUND_SELECTION_TRANSLATIONS = {
en: { monsterAaRoundTitle:'Choose the AA round', monsterAaRoundDescription:'Select the round the game should show when its AA data loads again. Choose a room in the game; entries below are only previews.', monsterAaRoundPending:'Selected round: {round} (Group {id}). Reopen Anomaly Arbitration in the game to show it.', monsterAaRoundSelectLabel:'Anomaly Arbitration round', monsterAaRoundDefaultOption:'Use the Client default round', monsterAaRoundDefault:'No round override. The Client default round will be shown.', monsterAaRoundUpdating:'Updating the AA round…', monsterAaRoundLoading:'Loading the saved AA round…', monsterAaRoundConnect:'Connect to GaC to choose the AA round shown in game.', monsterAaRoundLoadError:'Could not load the AA round: {error}', monsterAaRoundSavedToast:'AA round selected. Reopen Anomaly Arbitration in the game to show it.', monsterAaRoundClearedToast:'AA round override cleared. The Client default round will be shown.', monsterAaRoundSaveError:'Could not update the AA round: {error}', monsterAaRoundGroupId:'Round {id}', monsterSettingsAARoomPreview:'Rooms in this round · preview only' },
th: { monsterAaRoundTitle:'เลือกรอบ AA', monsterAaRoundDescription:'เลือกรอบที่จะแสดงในเกมเมื่อโหลดข้อมูล AA อีกครั้ง ส่วนห้องให้เลือกจากในเกม รายการด้านล่างมีไว้ดูตัวอย่างเท่านั้น', monsterAaRoundPending:'เลือกรอบ {round} (กลุ่ม {id}) แล้ว เปิด Anomaly Arbitration ในเกมอีกครั้งเพื่อให้แสดงรอบนี้', monsterAaRoundSelectLabel:'รอบ Anomaly Arbitration', monsterAaRoundDefaultOption:'ใช้รอบเริ่มต้นของ Client', monsterAaRoundDefault:'ไม่ได้แทนรอบ ระบบจะแสดงรอบเริ่มต้นของ Client', monsterAaRoundUpdating:'กำลังเปลี่ยนรอบ AA…', monsterAaRoundLoading:'กำลังโหลดรอบ AA ที่บันทึกไว้…', monsterAaRoundConnect:'เชื่อมต่อ GaC เพื่อเลือกรอบ AA ที่จะแสดงในเกม', monsterAaRoundLoadError:'โหลดรอบ AA ไม่สำเร็จ: {error}', monsterAaRoundSavedToast:'เลือกรอบ AA แล้ว เปิด Anomaly Arbitration ในเกมอีกครั้งเพื่อให้แสดงรอบนี้', monsterAaRoundClearedToast:'ล้างการแทนรอบ AA แล้ว ระบบจะแสดงรอบเริ่มต้นของ Client', monsterAaRoundSaveError:'เปลี่ยนรอบ AA ไม่สำเร็จ: {error}', monsterAaRoundGroupId:'รอบ {id}', monsterSettingsAARoomPreview:'ห้องในรอบนี้ · ตัวอย่างเท่านั้น' },
'zh-CN': { monsterAaRoundTitle:'选择 AA 轮次', monsterAaRoundDescription:'选择游戏重新加载 AA 数据时显示的轮次。具体房间仍在游戏内选择;下方条目仅供预览。', monsterAaRoundPending:'已选择轮次:{round}(组 {id})。请重新打开游戏内的异相仲裁以显示。', monsterAaRoundSelectLabel:'Anomaly Arbitration 轮次', monsterAaRoundDefaultOption:'使用 Client 默认轮次', monsterAaRoundDefault:'未覆盖轮次,将显示 Client 默认轮次。', monsterAaRoundUpdating:'正在更新 AA 轮次…', monsterAaRoundLoading:'正在加载已保存的 AA 轮次…', monsterAaRoundConnect:'连接 GaC 后才能选择游戏中显示的 AA 轮次。', monsterAaRoundLoadError:'无法加载 AA 轮次:{error}', monsterAaRoundSavedToast:'已选择 AA 轮次。请重新打开游戏内的异相仲裁以显示。', monsterAaRoundClearedToast:'已清除 AA 轮次覆盖,将显示 Client 默认轮次。', monsterAaRoundSaveError:'无法更新 AA 轮次:{error}', monsterAaRoundGroupId:'轮次 {id}', monsterSettingsAARoomPreview:'本轮房间 · 仅预览' },
'zh-TW': { monsterAaRoundTitle:'選擇 AA 輪次', monsterAaRoundDescription:'選擇遊戲重新載入 AA 資料時要顯示的輪次。房間仍在遊戲內選擇;下方項目僅供預覽。', monsterAaRoundPending:'已選擇輪次:{round}(組別 {id})。請重新開啟遊戲內的 Anomaly Arbitration 以顯示。', monsterAaRoundSelectLabel:'Anomaly Arbitration 輪次', monsterAaRoundDefaultOption:'使用 Client 預設輪次', monsterAaRoundDefault:'尚未覆寫輪次,將顯示 Client 預設輪次。', monsterAaRoundUpdating:'正在更新 AA 輪次…', monsterAaRoundLoading:'正在載入已儲存的 AA 輪次…', monsterAaRoundConnect:'連線 GaC 後才能選擇遊戲中顯示的 AA 輪次。', monsterAaRoundLoadError:'無法載入 AA 輪次:{error}', monsterAaRoundSavedToast:'已選擇 AA 輪次。請重新開啟遊戲內的 Anomaly Arbitration 以顯示。', monsterAaRoundClearedToast:'已清除 AA 輪次覆寫,將顯示 Client 預設輪次。', monsterAaRoundSaveError:'無法更新 AA 輪次:{error}', monsterAaRoundGroupId:'輪次 {id}', monsterSettingsAARoomPreview:'本輪房間 · 僅供預覽' },
ja: { monsterAaRoundTitle:'AAのラウンドを選択', monsterAaRoundDescription:'ゲームがAAデータを再読み込みしたときに表示するラウンドを選びます。部屋はゲーム内で選択してください。下の項目はプレビューのみです。', monsterAaRoundPending:'選択中のラウンド:{round}(グループ {id})。表示するにはゲーム内でAnomaly Arbitrationを開き直してください。', monsterAaRoundSelectLabel:'Anomaly Arbitrationのラウンド', monsterAaRoundDefaultOption:'Clientのデフォルトを使用', monsterAaRoundDefault:'ラウンドは上書きされていません。Clientのデフォルトを表示します。', monsterAaRoundUpdating:'AAラウンドを更新中…', monsterAaRoundLoading:'保存済みAAラウンドを読み込み中…', monsterAaRoundConnect:'ゲームに表示するAAラウンドを選ぶにはGaCに接続してください。', monsterAaRoundLoadError:'AAラウンドを読み込めませんでした:{error}', monsterAaRoundSavedToast:'AAラウンドを選択しました。表示するにはゲーム内のAnomaly Arbitrationを開き直してください。', monsterAaRoundClearedToast:'AAラウンド設定を解除しました。Clientのデフォルトを表示します。', monsterAaRoundSaveError:'AAラウンドを更新できませんでした:{error}', monsterAaRoundGroupId:'ラウンド {id}', monsterSettingsAARoomPreview:'このラウンドの部屋 · プレビューのみ' },
ko: { monsterAaRoundTitle:'AA 라운드 선택', monsterAaRoundDescription:'게임에서 AA 데이터를 다시 불러올 때 표시할 라운드를 선택하세요. 방은 게임 안에서 선택하며 아래 항목은 미리보기 전용입니다.', monsterAaRoundPending:'선택한 라운드: {round} (그룹 {id}). 게임에서 Anomaly Arbitration을 다시 열어 표시하세요.', monsterAaRoundSelectLabel:'Anomaly Arbitration 라운드', monsterAaRoundDefaultOption:'Client 기본 라운드 사용', monsterAaRoundDefault:'라운드 재정의가 없습니다. Client 기본 라운드를 표시합니다.', monsterAaRoundUpdating:'AA 라운드 업데이트 중…', monsterAaRoundLoading:'저장된 AA 라운드 불러오는 중…', monsterAaRoundConnect:'게임에 표시할 AA 라운드를 선택하려면 GaC에 연결하세요.', monsterAaRoundLoadError:'AA 라운드를 불러오지 못했습니다: {error}', monsterAaRoundSavedToast:'AA 라운드를 선택했습니다. 게임에서 Anomaly Arbitration을 다시 열어 표시하세요.', monsterAaRoundClearedToast:'AA 라운드 재정의를 지웠습니다. Client 기본 라운드를 표시합니다.', monsterAaRoundSaveError:'AA 라운드를 업데이트하지 못했습니다: {error}', monsterAaRoundGroupId:'라운드 {id}', monsterSettingsAARoomPreview:'이 라운드의 방 · 미리보기만' },
vi: { monsterAaRoundTitle:'Chọn vòng AA', monsterAaRoundDescription:'Chọn vòng sẽ hiển thị khi game tải lại dữ liệu AA. Hãy chọn phòng trong game; các mục bên dưới chỉ để xem trước.', monsterAaRoundPending:'Đã chọn vòng: {round} (Nhóm {id}). Mở lại Anomaly Arbitration trong game để hiển thị.', monsterAaRoundSelectLabel:'Vòng Anomaly Arbitration', monsterAaRoundDefaultOption:'Dùng vòng mặc định của Client', monsterAaRoundDefault:'Không ghi đè vòng. Sẽ hiển thị vòng mặc định của Client.', monsterAaRoundUpdating:'Đang cập nhật vòng AA…', monsterAaRoundLoading:'Đang tải vòng AA đã lưu…', monsterAaRoundConnect:'Kết nối GaC để chọn vòng AA hiển thị trong game.', monsterAaRoundLoadError:'Không thể tải vòng AA: {error}', monsterAaRoundSavedToast:'Đã chọn vòng AA. Mở lại Anomaly Arbitration trong game để hiển thị.', monsterAaRoundClearedToast:'Đã xóa ghi đè vòng AA. Sẽ hiển thị vòng mặc định của Client.', monsterAaRoundSaveError:'Không thể cập nhật vòng AA: {error}', monsterAaRoundGroupId:'Vòng {id}', monsterSettingsAARoomPreview:'Phòng trong vòng này · chỉ xem trước' },
id: { monsterAaRoundTitle:'Pilih ronde AA', monsterAaRoundDescription:'Pilih ronde yang ditampilkan saat game memuat ulang data AA. Pilih ruang dari dalam game; entri di bawah hanya pratinjau.', monsterAaRoundPending:'Ronde terpilih: {round} (Grup {id}). Buka kembali Anomaly Arbitration di game untuk menampilkannya.', monsterAaRoundSelectLabel:'Ronde Anomaly Arbitration', monsterAaRoundDefaultOption:'Gunakan ronde default Client', monsterAaRoundDefault:'Tidak ada ronde yang ditimpa. Ronde default Client akan ditampilkan.', monsterAaRoundUpdating:'Memperbarui ronde AA…', monsterAaRoundLoading:'Memuat ronde AA tersimpan…', monsterAaRoundConnect:'Hubungkan ke GaC untuk memilih ronde AA yang ditampilkan di game.', monsterAaRoundLoadError:'Tidak dapat memuat ronde AA: {error}', monsterAaRoundSavedToast:'Ronde AA dipilih. Buka kembali Anomaly Arbitration di game untuk menampilkannya.', monsterAaRoundClearedToast:'Penggantian ronde AA dihapus. Ronde default Client akan ditampilkan.', monsterAaRoundSaveError:'Tidak dapat memperbarui ronde AA: {error}', monsterAaRoundGroupId:'Ronde {id}', monsterSettingsAARoomPreview:'Ruang di ronde ini · pratinjau saja' },
es: { monsterAaRoundTitle:'Elegir ronda de AA', monsterAaRoundDescription:'Elige la ronda que mostrará el juego al volver a cargar los datos de AA. Elige la sala dentro del juego; las entradas de abajo son solo una vista previa.', monsterAaRoundPending:'Ronda elegida: {round} (grupo {id}). Vuelve a abrir Anomaly Arbitration en el juego para mostrarla.', monsterAaRoundSelectLabel:'Ronda de Anomaly Arbitration', monsterAaRoundDefaultOption:'Usar la ronda predeterminada del cliente', monsterAaRoundDefault:'No hay una ronda sobrescrita. Se mostrará la predeterminada del cliente.', monsterAaRoundUpdating:'Actualizando ronda de AA…', monsterAaRoundLoading:'Cargando ronda de AA guardada…', monsterAaRoundConnect:'Conéctate a GaC para elegir la ronda de AA que se muestra en el juego.', monsterAaRoundLoadError:'No se pudo cargar la ronda de AA: {error}', monsterAaRoundSavedToast:'Ronda de AA elegida. Vuelve a abrir Anomaly Arbitration en el juego para mostrarla.', monsterAaRoundClearedToast:'Se borró la sobrescritura de AA. Se mostrará la ronda predeterminada del cliente.', monsterAaRoundSaveError:'No se pudo actualizar la ronda de AA: {error}', monsterAaRoundGroupId:'Ronda {id}', monsterSettingsAARoomPreview:'Salas de esta ronda · solo vista previa' },
fr: { monsterAaRoundTitle:'Choisir le tour AA', monsterAaRoundDescription:'Choisissez le tour que le jeu affichera au prochain chargement des données AA. Choisissez la salle dans le jeu ; les entrées ci-dessous sont des aperçus.', monsterAaRoundPending:'Tour sélectionné : {round} (groupe {id}). Rouvrez Anomaly Arbitration dans le jeu pour l’afficher.', monsterAaRoundSelectLabel:'Tour Anomaly Arbitration', monsterAaRoundDefaultOption:'Utiliser le tour par défaut du client', monsterAaRoundDefault:'Aucun tour forcé. Le tour par défaut du client sera affiché.', monsterAaRoundUpdating:'Mise à jour du tour AA…', monsterAaRoundLoading:'Chargement du tour AA enregistré…', monsterAaRoundConnect:'Connectez-vous à GaC pour choisir le tour AA affiché dans le jeu.', monsterAaRoundLoadError:'Impossible de charger le tour AA : {error}', monsterAaRoundSavedToast:'Tour AA sélectionné. Rouvrez Anomaly Arbitration dans le jeu pour l’afficher.', monsterAaRoundClearedToast:'Remplacement du tour AA effacé. Le tour par défaut du client sera affiché.', monsterAaRoundSaveError:'Impossible de modifier le tour AA : {error}', monsterAaRoundGroupId:'Tour {id}', monsterSettingsAARoomPreview:'Salles de ce tour · aperçu uniquement' },
de: { monsterAaRoundTitle:'AA-Runde auswählen', monsterAaRoundDescription:'Wähle die Runde, die das Spiel beim erneuten Laden der AA-Daten anzeigen soll. Den Raum wählst du im Spiel; die Einträge unten sind nur Vorschauen.', monsterAaRoundPending:'Ausgewählte Runde: {round} (Gruppe {id}). Öffne Anomaly Arbitration im Spiel erneut, damit sie angezeigt wird.', monsterAaRoundSelectLabel:'Anomaly-Arbitration-Runde', monsterAaRoundDefaultOption:'Client-Standardrunde verwenden', monsterAaRoundDefault:'Keine Runde überschrieben. Die Client-Standardrunde wird angezeigt.', monsterAaRoundUpdating:'AA-Runde wird aktualisiert…', monsterAaRoundLoading:'Gespeicherte AA-Runde wird geladen…', monsterAaRoundConnect:'Mit GaC verbinden, um die im Spiel angezeigte AA-Runde auszuwählen.', monsterAaRoundLoadError:'AA-Runde konnte nicht geladen werden: {error}', monsterAaRoundSavedToast:'AA-Runde ausgewählt. Öffne Anomaly Arbitration im Spiel erneut.', monsterAaRoundClearedToast:'AA-Rundenüberschreibung entfernt. Die Client-Standardrunde wird angezeigt.', monsterAaRoundSaveError:'AA-Runde konnte nicht aktualisiert werden: {error}', monsterAaRoundGroupId:'Runde {id}', monsterSettingsAARoomPreview:'Räume dieser Runde · nur Vorschau' },
ru: { monsterAaRoundTitle:'Выбрать раунд AA', monsterAaRoundDescription:'Выберите раунд, который игра покажет при повторной загрузке данных AA. Комнату выбирайте в игре; записи ниже — только предварительный просмотр.', monsterAaRoundPending:'Выбран раунд: {round} (группа {id}). Откройте Anomaly Arbitration в игре повторно, чтобы увидеть его.', monsterAaRoundSelectLabel:'Раунд Anomaly Arbitration', monsterAaRoundDefaultOption:'Использовать раунд клиента по умолчанию', monsterAaRoundDefault:'Раунд не переопределён. Будет показан раунд клиента по умолчанию.', monsterAaRoundUpdating:'Обновление раунда AA…', monsterAaRoundLoading:'Загрузка сохранённого раунда AA…', monsterAaRoundConnect:'Подключитесь к GaC, чтобы выбрать отображаемый в игре раунд AA.', monsterAaRoundLoadError:'Не удалось загрузить раунд AA: {error}', monsterAaRoundSavedToast:'Раунд AA выбран. Повторно откройте Anomaly Arbitration в игре.', monsterAaRoundClearedToast:'Переопределение раунда AA очищено. Будет показан раунд клиента по умолчанию.', monsterAaRoundSaveError:'Не удалось изменить раунд AA: {error}', monsterAaRoundGroupId:'Раунд {id}', monsterSettingsAARoomPreview:'Комнаты этого раунда · только просмотр' },
pt: { monsterAaRoundTitle:'Escolher rodada de AA', monsterAaRoundDescription:'Escolha a rodada que o jogo exibirá ao carregar os dados de AA novamente. Escolha a sala no jogo; as entradas abaixo são apenas prévias.', monsterAaRoundPending:'Rodada selecionada: {round} (grupo {id}). Reabra Anomaly Arbitration no jogo para exibi-la.', monsterAaRoundSelectLabel:'Rodada de Anomaly Arbitration', monsterAaRoundDefaultOption:'Usar rodada padrão do Client', monsterAaRoundDefault:'Nenhuma rodada substituída. A rodada padrão do Client será exibida.', monsterAaRoundUpdating:'Atualizando rodada de AA…', monsterAaRoundLoading:'Carregando rodada de AA salva…', monsterAaRoundConnect:'Conecte-se ao GaC para escolher a rodada de AA exibida no jogo.', monsterAaRoundLoadError:'Não foi possível carregar a rodada de AA: {error}', monsterAaRoundSavedToast:'Rodada de AA selecionada. Reabra Anomaly Arbitration no jogo para exibi-la.', monsterAaRoundClearedToast:'Substituição da rodada de AA removida. A rodada padrão do Client será exibida.', monsterAaRoundSaveError:'Não foi possível atualizar a rodada de AA: {error}', monsterAaRoundGroupId:'Rodada {id}', monsterSettingsAARoomPreview:'Salas desta rodada · apenas prévia' }
};
for (const [language, additions] of Object.entries(AA_ROUND_SELECTION_TRANSLATIONS)) {
Object.assign(TRANSLATIONS[language], additions);
}
const MONSTER_PICKER_TRANSLATIONS = {
en: 'Search monsters by name or ID',
th: 'ค้นหามอนสเตอร์ด้วยชื่อหรือ ID',