Merge remote-tracking branch 'origin/Main' into test-gay
This commit is contained in:
commit
a3b722e132
13 files changed
+1464
-57
No files matched your search
@@ -1,8 +1,10 @@
|
||||
import { COMMANDS, usage, inspectCommand, completeCommand } from './command-assistant.mjs';
|
||||
import { AVATAR_METADATA, getAvatarInfo } from './avatars-data.js';
|
||||
import { LIGHTCONE_METADATA, RELIC_SET_METADATA, getLightconeInfo, getRelicSetInfo } from './equipment-data.js';
|
||||
import { initializeItemCatalog } from './item-catalog.js?v=2';
|
||||
import { initializeUnstuck } from './unstuck.js?v=1';
|
||||
import { PRYDWEN_BUILD_GUIDES } from './build-guides-data.js';
|
||||
import { SUPPORTED_LANGUAGES, TRANSLATIONS, getCurrentLanguage, setLanguage, t, translateElement, translatePath } from './i18n.js?v=2.12';
|
||||
import { SUPPORTED_LANGUAGES, TRANSLATIONS, getCurrentLanguage, setLanguage, t, translateElement, translatePath } from './i18n.js?v=2.13';
|
||||
import {
|
||||
getAvatarIconUrl,
|
||||
getLightconeArtUrl,
|
||||
@@ -963,6 +965,12 @@ function applyTranslations() {
|
||||
if (val) elem.alt = val;
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-i18n-aria-label]').forEach(elem => {
|
||||
const key = elem.getAttribute('data-i18n-aria-label');
|
||||
const val = t(key);
|
||||
if (val) elem.setAttribute('aria-label', val);
|
||||
});
|
||||
|
||||
// Update dynamic filter dropdown options
|
||||
updateFilterDropdownTranslations();
|
||||
|
||||
@@ -1535,6 +1543,17 @@ function hasAvatarBattleStatsData(avatars) {
|
||||
});
|
||||
}
|
||||
|
||||
function hasAvatarDamageBreakdownData(avatar) {
|
||||
const damageTypes = avatar?.attack_type_damage;
|
||||
return Number(avatar?.total_break_damage) > 0
|
||||
|| (damageTypes && Object.keys(damageTypes).length > 0);
|
||||
}
|
||||
|
||||
function hasAvatarMaxHitData(avatar) {
|
||||
const maxDamage = avatar?.attack_type_max_damage;
|
||||
return Boolean(maxDamage && Object.values(maxDamage).some(value => Number(value) > 0));
|
||||
}
|
||||
|
||||
function getAvatarDamagePercent(avatar, teamDamage, available) {
|
||||
if (!available) return null;
|
||||
const reportedPercent = Number(avatar?.damage_percent);
|
||||
@@ -6988,7 +7007,10 @@ 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);
|
||||
@@ -9230,30 +9252,30 @@ function renderEmptyDamageAnalyst() {
|
||||
|
||||
function orderBattleReportAvatars(avatars) {
|
||||
if (!Array.isArray(avatars) || avatars.length < 2) return avatars || [];
|
||||
if (analystState.currentReport?.is_currency_wars || avatars.length > 4) return avatars;
|
||||
if ((typeof analystState !== 'undefined' && analystState.currentReport?.is_currency_wars) || avatars.length > 4) return avatars;
|
||||
|
||||
const lineup = state.statusData?.lineups;
|
||||
if (!lineup) return avatars;
|
||||
|
||||
const lineupSlots = Array.isArray(lineup)
|
||||
? lineup.map((avatarId, slot) => [slot, avatarId])
|
||||
: Object.entries(lineup).sort(([left], [right]) => Number(left) - Number(right));
|
||||
const lineupIds = lineupSlots
|
||||
.map(([, avatarId]) => Number(avatarId))
|
||||
.filter(avatarId => Number.isSafeInteger(avatarId) && avatarId > 0);
|
||||
const reportById = new Map();
|
||||
|
||||
for (const avatar of avatars) {
|
||||
const avatarId = Number(avatar?.avatar_id);
|
||||
if (!Number.isSafeInteger(avatarId) || avatarId <= 0 || reportById.has(avatarId)) {
|
||||
return avatars;
|
||||
}
|
||||
reportById.set(avatarId, avatar);
|
||||
// Battle slots remain stable when the overworld team changes or the native
|
||||
// statistics dictionary enumerates characters in a different order.
|
||||
const slots = avatars.map(avatar => avatar?.slot);
|
||||
if (slots.every(slot => Number.isSafeInteger(slot) && slot >= 0)
|
||||
&& new Set(slots).size === avatars.length) {
|
||||
return [...avatars].sort((left, right) => left.slot - right.slot);
|
||||
}
|
||||
|
||||
const orderedIds = [...new Set(lineupIds)].filter(avatarId => reportById.has(avatarId));
|
||||
if (orderedIds.length !== avatars.length) return avatars;
|
||||
return orderedIds.map(avatarId => reportById.get(avatarId));
|
||||
// A historical report without battle slots must keep its recorded order.
|
||||
return avatars;
|
||||
}
|
||||
|
||||
function damageBreakdownForAvatar(avatar) {
|
||||
const damage = avatar.attack_type_damage || {};
|
||||
const normal = Number(damage.Normal) || 0;
|
||||
const skill = Number(damage.BPSkill ?? damage.Skill) || 0;
|
||||
const ultimate = Number(damage.Ultra ?? damage.Ultimate) || 0;
|
||||
const breakDamage = Number(avatar.total_break_damage || damage.BreakDamage) || 0;
|
||||
// Aggregate totals can include damage without an attack-type entry. Keep it
|
||||
// visible without counting named subcategories a second time.
|
||||
const other = Math.max(0, (Number(avatar.total_damage) || 0) - normal - skill - ultimate - breakDamage);
|
||||
return { normal, skill, ultimate, breakDamage, other };
|
||||
}
|
||||
|
||||
function renderDamageAnalyst() {
|
||||
@@ -9364,6 +9386,8 @@ function renderDamageAnalyst() {
|
||||
const color = colors[idx % colors.length];
|
||||
const info = getAvatarInfo(a.avatar_id);
|
||||
const pct = getAvatarDamagePercent(a, teamDmg, hasAvatarDamage);
|
||||
const hasDamageBreakdown = hasAvatarDamageBreakdownData(a);
|
||||
const hasMaxHit = hasAvatarMaxHitData(a);
|
||||
|
||||
let maxHit = 0;
|
||||
if (a.attack_type_max_damage) {
|
||||
@@ -9372,10 +9396,7 @@ function renderDamageAnalyst() {
|
||||
}
|
||||
}
|
||||
|
||||
const dNormal = a.attack_type_damage?.Normal || 0;
|
||||
const dSkill = a.attack_type_damage?.BPSkill || a.attack_type_damage?.Skill || 0;
|
||||
const dUlt = a.attack_type_damage?.Ultra || a.attack_type_damage?.Ultimate || 0;
|
||||
const dBreak = a.total_break_damage || a.attack_type_damage?.BreakDamage || 0;
|
||||
const { normal: dNormal, skill: dSkill, ultimate: dUlt, breakDamage: dBreak, other: dOther } = damageBreakdownForAvatar(a);
|
||||
const dFollowup = (a.attack_type_damage?.Insert || 0) + (a.attack_type_damage?.Pursued || 0);
|
||||
const dDot = a.attack_type_damage?.DOT || 0;
|
||||
|
||||
@@ -9416,10 +9437,11 @@ function renderDamageAnalyst() {
|
||||
<div>
|
||||
<div style="font-size: 0.725rem; font-weight: 700; color: var(--text-muted); text-transform: uppercase;">${t('analystTotalDamage')}</div>
|
||||
<div style="font-size: 1.5rem; font-weight: 900; color: #fff;">${hasAvatarDamage ? formatNumber(a.total_damage) : '—'}</div>
|
||||
${Number(a.memosprite_damage) > 0 ? `<div style="font-size: 0.7rem; color: var(--text-muted);">Memosprite: ${formatNumber(a.memosprite_damage)} (included)</div>` : ''}
|
||||
</div>
|
||||
<div style="text-align: right;">
|
||||
<div style="font-size: 0.725rem; color: var(--text-muted);">${t('analystMaxHit')}</div>
|
||||
<div style="font-size: 0.95rem; font-weight: 800; color: #f87171;">${hasAvatarDamage ? formatNumber(maxHit) : '—'}</div>
|
||||
<div style="font-size: 0.95rem; font-weight: 800; color: #f87171;">${hasMaxHit ? formatNumber(maxHit) : '—'}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9433,19 +9455,23 @@ function renderDamageAnalyst() {
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 0.4rem; margin-bottom: 1rem;">
|
||||
<div style="padding: 0.4rem 0.6rem; border-radius: 6px; background: rgba(255,255,255,0.02); border: 1px solid rgba(255,255,255,0.04); display: flex; justify-content: space-between; font-size: 0.775rem;">
|
||||
<span style="color: var(--text-muted);">${t('analystDmgNormal')}</span>
|
||||
<span style="font-weight: 700; color: var(--text-main);">${hasAvatarDamage ? formatNumber(dNormal) : '—'}</span>
|
||||
<span style="font-weight: 700; color: var(--text-main);">${hasDamageBreakdown ? formatNumber(dNormal) : '—'}</span>
|
||||
</div>
|
||||
<div style="padding: 0.4rem 0.6rem; border-radius: 6px; background: rgba(255,255,255,0.02); border: 1px solid rgba(255,255,255,0.04); display: flex; justify-content: space-between; font-size: 0.775rem;">
|
||||
<span style="color: var(--text-muted);">${t('analystDmgSkill')}</span>
|
||||
<span style="font-weight: 700; color: #38bdf8;">${hasAvatarDamage ? formatNumber(dSkill) : '—'}</span>
|
||||
<span style="font-weight: 700; color: #38bdf8;">${hasDamageBreakdown ? formatNumber(dSkill) : '—'}</span>
|
||||
</div>
|
||||
<div style="padding: 0.4rem 0.6rem; border-radius: 6px; background: rgba(255,255,255,0.02); border: 1px solid rgba(255,255,255,0.04); display: flex; justify-content: space-between; font-size: 0.775rem;">
|
||||
<span style="color: var(--text-muted);">${t('analystDmgUlt')}</span>
|
||||
<span style="font-weight: 700; color: #c084fc;">${hasAvatarDamage ? formatNumber(dUlt) : '—'}</span>
|
||||
<span style="font-weight: 700; color: #c084fc;">${hasDamageBreakdown ? formatNumber(dUlt) : '—'}</span>
|
||||
</div>
|
||||
<div style="padding: 0.4rem 0.6rem; border-radius: 6px; background: rgba(255,255,255,0.02); border: 1px solid rgba(255,255,255,0.04); display: flex; justify-content: space-between; font-size: 0.775rem;">
|
||||
<span style="color: var(--text-muted);">${t('analystDmgBreak')}</span>
|
||||
<span style="font-weight: 700; color: #fbbf24;">${hasAvatarDamage ? formatNumber(dBreak) : '—'}</span>
|
||||
<span style="font-weight: 700; color: #fbbf24;">${hasDamageBreakdown ? formatNumber(dBreak) : '—'}</span>
|
||||
</div>
|
||||
<div style="padding: 0.4rem 0.6rem; border-radius: 6px; background: rgba(255,255,255,0.02); border: 1px solid rgba(255,255,255,0.04); display: flex; justify-content: space-between; font-size: 0.775rem;">
|
||||
<span style="color: var(--text-muted);">Other</span>
|
||||
<span style="font-weight: 700; color: #f472b6;">${hasAvatarDamage ? formatNumber(dOther) : '—'}</span>
|
||||
</div>
|
||||
${dFollowup > 0 ? `
|
||||
<div style="padding: 0.4rem 0.6rem; border-radius: 6px; background: rgba(255,255,255,0.02); border: 1px solid rgba(255,255,255,0.04); display: flex; justify-content: space-between; font-size: 0.775rem;">
|
||||
@@ -9459,6 +9485,14 @@ function renderDamageAnalyst() {
|
||||
<span style="font-weight: 700; color: #a78bfa;">${formatNumber(dDot)}</span>
|
||||
</div>
|
||||
` : ''}
|
||||
${Object.entries(a.attack_type_damage || {})
|
||||
.filter(([type, damage]) => Number(damage) > 0 && !['Normal', 'BPSkill', 'Skill', 'Ultra', 'Ultimate', 'BreakDamage', 'Insert', 'Pursued', 'DOT'].includes(type))
|
||||
.map(([type, damage]) => `
|
||||
<div style="padding: 0.4rem 0.6rem; border-radius: 6px; background: rgba(255,255,255,0.02); border: 1px solid rgba(255,255,255,0.04); display: flex; justify-content: space-between; gap: 0.4rem; font-size: 0.775rem;">
|
||||
<span style="color: var(--text-muted);">${escapeHtml(type.replace(/([a-z])([A-Z])/g, '$1 $2'))}</span>
|
||||
<span style="font-weight: 700; color: #f472b6;">${formatNumber(Number(damage))}</span>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 0.75rem; flex-wrap: wrap; padding-top: 0.65rem; border-top: 1px solid rgba(255,255,255,0.06); font-size: 0.75rem; color: var(--text-muted);">
|
||||
@@ -9752,6 +9786,8 @@ async function init() {
|
||||
await loadCachedStorageData();
|
||||
setupServerModes();
|
||||
setupLanguageSelector();
|
||||
initializeItemCatalog();
|
||||
initializeUnstuck({ apiCall, isConnected: () => state.isConnected, showToast });
|
||||
setupTabs();
|
||||
setupModalSubtabs();
|
||||
setupEvents();
|
||||
|
||||
Reference in new issue
Block a user