From d42bde81f6d4aff43a3a55304e6dc4a8b9f7eb5a Mon Sep 17 00:00:00 2001 From: Akurosia Kamo Date: Tue, 9 Jun 2026 23:04:30 +0200 Subject: [PATCH] small role fix --- js/planner.js | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/js/planner.js b/js/planner.js index 64640e7..63bb773 100644 --- a/js/planner.js +++ b/js/planner.js @@ -150,6 +150,14 @@ function abilityIcon(ability) { return MITIG_ICONS[ability] ?? actionMetaByName[ability]?.icon ?? ''; } +function actualAbilityIcon(actual) { + const actionId = String(actual?.actionId ?? actual?.extraAbilityGameID ?? ''); + return abilityIcon(actual?.ability) + || (actionId && actionMetaById[actionId]?.icon) + || actionMetaByName[actual?.name]?.icon + || ''; +} + function abilityShieldText(ability) { return actionMetaByName[ability]?.shield ?? ''; } @@ -3322,6 +3330,8 @@ function collectActualMitigations(event) { ability, name: mitigation.name ?? ability, sourceJob, + actionId: mitigation.extraAbilityGameID ?? null, + extraAbilityGameID: mitigation.extraAbilityGameID ?? null, appliedAt: Number.isFinite(Number(mitigation.appliedAt)) ? Number(mitigation.appliedAt) : null, buffType: mitigation.buffType ?? abilityDefinition(ability)?.buffType ?? 'buff', }); @@ -3336,6 +3346,8 @@ function collectActualCasts(casts, actualFightStart) { name: cast.name ?? cast.key, sourceJob: JOB_FROM_TYPE[cast.sourcePlayerType] ?? '', sourceName: cast.sourceName ?? '', + actionId: cast.extraAbilityGameID ?? null, + extraAbilityGameID: cast.extraAbilityGameID ?? null, timestamp: Number(cast.timestamp) || 0, rel: (Number(cast.timestamp) || 0) - actualFightStart, buffType: cast.buffType ?? abilityDefinition(cast.key ?? cast.name)?.buffType ?? 'buff', @@ -3345,22 +3357,20 @@ function collectActualCasts(casts, actualFightStart) { function actualMatchesAssignment(actual, assignment) { if ((actual.ability ?? actual.name) !== assignment.ability) return false; if (!assignment.job || !actual.sourceJob) return true; - return actual.sourceJob === assignment.job; + if (actual.sourceJob === assignment.job) return true; + return jobCanUseAbility(actual.sourceJob, assignment.ability); } -function findCastForAssignment(actualCasts, consumedCasts, assignment, plannedStart, mechanicTime) { +function findCastForAssignment(actualCasts, assignment, plannedStart, mechanicTime) { const durationMs = assignmentDurationSeconds(assignment) * 1000; const earlyWindow = Math.max(15000, durationMs + 5000); const lateWindow = Math.max(10000, mechanicTime - plannedStart + 5000); const candidates = actualCasts .map((actual, idx) => ({ actual, idx, delta: actual.rel - plannedStart })) - .filter(item => !consumedCasts.has(item.idx)) .filter(item => actualMatchesAssignment(item.actual, assignment)) .filter(item => item.delta >= -earlyWindow && item.delta <= lateWindow) .sort((a, b) => Math.abs(a.delta) - Math.abs(b.delta)); - const match = candidates[0] ?? null; - if (match) consumedCasts.add(match.idx); - return match; + return candidates[0] ?? null; } function findActualMechanic(planMechanic, actualEvents, used, actualFightStart) { @@ -3392,7 +3402,6 @@ function findActualMechanic(planMechanic, actualEvents, used, actualFightStart) function comparePlanToAnalysis(plan, actualEvents, actualFightStart, actualCastEvents = []) { const usedMechanics = new Set(); const actualCasts = collectActualCasts(actualCastEvents, actualFightStart); - const consumedCasts = new Set(); const rows = []; const summary = { ok: 0, early: 0, late: 0, missing: 0, extra: 0, unmatched: 0, unknown: 0 }; @@ -3409,7 +3418,7 @@ function comparePlanToAnalysis(plan, actualEvents, actualFightStart, actualCastE const consumedActual = new Set(); const items = planned.map(assignment => { const plannedStart = Number(assignment.sourceStart ?? assignmentStartMs(mechanic, assignment)) || 0; - const castMatch = findCastForAssignment(actualCasts, consumedCasts, assignment, plannedStart, mechanic.timestamp); + const castMatch = findCastForAssignment(actualCasts, assignment, plannedStart, mechanic.timestamp); if (!castMatch) { summary.missing += 1; return { status: 'missing', assignment }; @@ -3497,7 +3506,7 @@ function compareAssignmentChip(assignment, plan) { } function compareActualChip(actual, plan, status = 'extra', delta = null, note = '') { - const icon = abilityIcon(actual.ability); + const icon = actualAbilityIcon(actual); const name = localizedAbilityName(actual.ability, plan); const deltaHtml = delta == null || status === 'ok' ? '' : `${escHtml(compareDeltaText(delta))}`; const noteHtml = note ? `${escHtml(note)}` : ''; @@ -3753,6 +3762,7 @@ function initCompareModal() { const json = await res.json(); if (json.reauth) { window.location.href = window.App?.authStartUrl?.() ?? 'auth/start.php'; return; } if (json.error) throw new Error(json.error); + await ensureActionMetaLoaded(); compareLastPlan = plan; compareLastResult = comparePlanToAnalysis(plan, json.aoe_events ?? [], Number(fight.startTime) || 0, json.mitigation_casts ?? []); renderLastCompare();