Compare commits
2 Commits
58745fec65
...
349645f4cb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
349645f4cb | ||
|
|
b6d44d8ae0 |
@ -76,57 +76,57 @@ function fflogs_gql(string $query): array {
|
||||
// buffType 'debuff' = boss debuff, shown in event header
|
||||
const MITIGATION_ABILITIES = [
|
||||
// ── Damage reduction buffs ──────────────────────────────────────────────
|
||||
'Passage of Arms' => ['dr' => 15, 'buffType' => 'buff', 'statusId' => 1001175],
|
||||
'Dark Missionary' => ['dr' => 10, 'buffType' => 'buff', 'statusId' => 1001894],
|
||||
'Heart of Light' => ['dr' => 10, 'buffType' => 'buff', 'statusId' => 1001839],
|
||||
'Temperance' => ['dr' => 10, 'buffType' => 'buff', 'statusId' => 1001873],
|
||||
'Sacred Soil' => ['dr' => 10, 'buffType' => 'buff', 'statusId' => 1001944],
|
||||
'Expedient' => ['dr' => 10, 'buffType' => 'buff', 'statusId' => 1002711], // FFLogs: "Desperate Measures"
|
||||
'Fey Illumination' => ['dr' => 5, 'buffType' => 'buff', 'statusId' => 1000317],
|
||||
'Collective Unconscious' => ['dr' => 10, 'buffType' => 'buff', 'statusId' => 1000849],
|
||||
'Holos' => ['dr' => 10, 'buffType' => 'buff', 'statusId' => 1003003],
|
||||
'Kerachole' => ['dr' => 10, 'buffType' => 'buff', 'statusId' => 1002618],
|
||||
'Troubadour' => ['dr' => 15, 'buffType' => 'buff', 'statusId' => 1001934],
|
||||
'Tactician' => ['dr' => 15, 'buffType' => 'buff', 'statusId' => 1001951],
|
||||
'Shield Samba' => ['dr' => 15, 'buffType' => 'buff', 'statusId' => 1001826],
|
||||
'Magick Barrier' => ['dr' => 10, 'buffType' => 'buff', 'statusId' => 1002707],
|
||||
'Passage of Arms' => ['dr' => 15, 'buffType' => 'buff', 'statusId' => 1001175, 'extraAbilityGameID' => 7385],
|
||||
'Dark Missionary' => ['dr' => 10, 'buffType' => 'buff', 'statusId' => 1001894, 'extraAbilityGameID' => 16471],
|
||||
'Heart of Light' => ['dr' => 10, 'buffType' => 'buff', 'statusId' => 1001839, 'extraAbilityGameID' => 16160],
|
||||
'Temperance' => ['dr' => 10, 'buffType' => 'buff', 'statusId' => 1001873, 'extraAbilityGameID' => 16536],
|
||||
'Sacred Soil' => ['dr' => 10, 'buffType' => 'buff', 'statusId' => 1001944, 'extraAbilityGameID' => 188],
|
||||
'Expedient' => ['dr' => 10, 'buffType' => 'buff', 'statusId' => 1002711, 'extraAbilityGameID' => 25868], // FFLogs: "Desperate Measures"
|
||||
'Fey Illumination' => ['dr' => 5, 'buffType' => 'buff', 'statusId' => 1000317, 'extraAbilityGameID' => 16538],
|
||||
'Collective Unconscious' => ['dr' => 10, 'buffType' => 'buff', 'statusId' => 1000849, 'extraAbilityGameID' => 3613],
|
||||
'Holos' => ['dr' => 10, 'buffType' => 'buff', 'statusId' => 1003003, 'extraAbilityGameID' => 24310],
|
||||
'Kerachole' => ['dr' => 10, 'buffType' => 'buff', 'statusId' => 1002618, 'extraAbilityGameID' => 24298],
|
||||
'Troubadour' => ['dr' => 15, 'buffType' => 'buff', 'statusId' => 1001934, 'extraAbilityGameID' => 7405],
|
||||
'Tactician' => ['dr' => 15, 'buffType' => 'buff', 'statusId' => 1001951, 'extraAbilityGameID' => 16889],
|
||||
'Shield Samba' => ['dr' => 15, 'buffType' => 'buff', 'statusId' => 1001826, 'extraAbilityGameID' => 16012],
|
||||
'Magick Barrier' => ['dr' => 10, 'buffType' => 'buff', 'statusId' => 1002707, 'extraAbilityGameID' => 25857],
|
||||
// ── Shields ─────────────────────────────────────────────────────────────
|
||||
// PLD
|
||||
'Divine Veil' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1001362],
|
||||
'Guardian' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1003830], // FFLogs: "Guardian's Will"
|
||||
'Divine Veil' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1001362, 'extraAbilityGameID' => 3540],
|
||||
'Guardian' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1003830, 'extraAbilityGameID' => 36920], // FFLogs: "Guardian's Will"
|
||||
// WAR
|
||||
'Shake It Off' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1001457],
|
||||
'Bloodwhetting' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1002678],
|
||||
'Shake It Off' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1001457, 'extraAbilityGameID' => 7388],
|
||||
'Bloodwhetting' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1002678, 'extraAbilityGameID' => 25751],
|
||||
// WHM
|
||||
'Divine Benison' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1001218],
|
||||
'Divine Caress' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1003903],
|
||||
'Divine Benison' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1001218, 'extraAbilityGameID' => 7432],
|
||||
'Divine Caress' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1003903, 'extraAbilityGameID' => 37011],
|
||||
// AST
|
||||
'Intersection' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1001889],
|
||||
'Neutral Sect' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1001921],
|
||||
'the Spire' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1003892], // FFLogs: "The Spire"
|
||||
'Intersection' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1001889, 'extraAbilityGameID' => 16556],
|
||||
'Neutral Sect' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1001921, 'extraAbilityGameID' => 16559],
|
||||
'the Spire' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1003892, 'extraAbilityGameID' => 37025], // FFLogs: "The Spire"
|
||||
// SGE
|
||||
'Panhaima' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1002613],
|
||||
'Holosakos' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1003365],
|
||||
'Eukrasian Prognosis' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1002609],
|
||||
'Eukrasian Prognosis II' => ['dr' => 0, 'buffType' => 'shield'], // TODO
|
||||
'Eukrasian Diagnosis' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1002607],
|
||||
'Differential Diagnosis' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1002608],
|
||||
'Haima' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1002612],
|
||||
'Panhaima' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1002613, 'extraAbilityGameID' => 24311],
|
||||
'Holosakos' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1003365, 'extraAbilityGameID' => 24310],
|
||||
'Eukrasian Prognosis' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1002609, 'extraAbilityGameID' => 24292],
|
||||
'Eukrasian Prognosis II' => ['dr' => 0, 'buffType' => 'shield', 'extraAbilityGameID' => 37034],
|
||||
'Eukrasian Diagnosis' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1002607, 'extraAbilityGameID' => 24291],
|
||||
'Differential Diagnosis' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1002608, 'extraAbilityGameID' => 24291],
|
||||
'Haima' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1002612, 'extraAbilityGameID' => 24305],
|
||||
// SCH
|
||||
'Galvanize' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1000297],
|
||||
'Seraphic Veil' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1001917],
|
||||
'Catalyze' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1001918],
|
||||
'Galvanize' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1000297, 'extraAbilityGameID' => 185],
|
||||
'Seraphic Veil' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1001917, 'extraAbilityGameID' => 16548],
|
||||
'Catalyze' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1001918, 'extraAbilityGameID' => 185],
|
||||
// SMN
|
||||
'Radiant Aegis' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1002702],
|
||||
'Radiant Aegis' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1002702, 'extraAbilityGameID' => 25799],
|
||||
// PCT
|
||||
'Tempera Coat' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1003686],
|
||||
'Tempera Grassa' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1003687],
|
||||
'Tempera Coat' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1003686, 'extraAbilityGameID' => 34685],
|
||||
'Tempera Grassa' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1003687, 'extraAbilityGameID' => 34686],
|
||||
// DNC
|
||||
'Improvised Finish' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1002697],
|
||||
'Improvised Finish' => ['dr' => 0, 'buffType' => 'shield', 'statusId' => 1002697, 'extraAbilityGameID' => 25789],
|
||||
// ── Boss debuffs ────────────────────────────────────────────────────────
|
||||
'Reprisal' => ['dr' => 10, 'buffType' => 'debuff', 'statusId' => 1001193],
|
||||
'Feint' => ['dr' => 10, 'buffType' => 'debuff', 'statusId' => 1001195],
|
||||
'Addle' => ['dr' => 10, 'buffType' => 'debuff', 'statusId' => 1001203],
|
||||
'Reprisal' => ['dr' => 10, 'buffType' => 'debuff', 'statusId' => 1001193, 'extraAbilityGameID' => 7535],
|
||||
'Feint' => ['dr' => 10, 'buffType' => 'debuff', 'statusId' => 1001195, 'extraAbilityGameID' => 7549],
|
||||
'Addle' => ['dr' => 10, 'buffType' => 'debuff', 'statusId' => 1001203, 'extraAbilityGameID' => 7560],
|
||||
];
|
||||
|
||||
function resolveMitigations(string $buffStr, array $mitigIdMap): array {
|
||||
@ -144,6 +144,7 @@ function resolveMitigations(string $buffStr, array $mitigIdMap): array {
|
||||
'name' => $name,
|
||||
'dr' => $mitigIdMap[$id]['dr'],
|
||||
'buffType' => $mitigIdMap[$id]['buffType'],
|
||||
'extraAbilityGameID' => $mitigIdMap[$id]['extraAbilityGameID'] ?? null,
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -161,7 +162,13 @@ function shieldsActiveAt(array $shieldTimeline, int $targetId, float $ts, array
|
||||
if ($iv['apply'] <= $ts && ($iv['remove'] === null || $iv['remove'] >= $ts - 200)) {
|
||||
if (isset($mitigIdMap[$statusId])) {
|
||||
$m = $mitigIdMap[$statusId];
|
||||
$result[] = ['key' => $m['key'] ?? $m['name'], 'name' => $m['name'], 'dr' => $m['dr'], 'buffType' => $m['buffType']];
|
||||
$result[] = [
|
||||
'key' => $m['key'] ?? $m['name'],
|
||||
'name' => $m['name'],
|
||||
'dr' => $m['dr'],
|
||||
'buffType' => $m['buffType'],
|
||||
'extraAbilityGameID' => $m['extraAbilityGameID'] ?? null,
|
||||
];
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -278,6 +285,7 @@ for ($page = 0; $page < 10; $page++) {
|
||||
// that were consumed by a hit (absent from the damage event's buffs snapshot).
|
||||
$shieldTimeline = []; // targetId → statusId → [[apply, remove|null], ...]
|
||||
$statusNames = []; // statusId → localized display name from Buffs events
|
||||
$statusActionIds = []; // statusId → applybuff extraAbilityGameID from FFLogs
|
||||
|
||||
if (!empty($trackedStatusIds)) {
|
||||
$nextPage = $startTime;
|
||||
@ -312,6 +320,10 @@ if (!empty($trackedStatusIds)) {
|
||||
if (is_string($evName) && $evName !== '') {
|
||||
$statusNames[$abId] = $evName;
|
||||
}
|
||||
$extraAbilityGameID = (int)($ev['extraAbilityGameID'] ?? 0);
|
||||
if ($extraAbilityGameID > 0) {
|
||||
$statusActionIds[$abId] = $extraAbilityGameID;
|
||||
}
|
||||
|
||||
$tgtId = (int)($ev['targetID'] ?? 0);
|
||||
$ts = (float)($ev['timestamp'] ?? 0);
|
||||
@ -344,6 +356,11 @@ foreach ($statusNames as $statusId => $displayName) {
|
||||
$mitigIdMap[$statusId]['name'] = $displayName;
|
||||
}
|
||||
}
|
||||
foreach ($statusActionIds as $statusId => $extraAbilityGameID) {
|
||||
if (isset($mitigIdMap[$statusId])) {
|
||||
$mitigIdMap[$statusId]['extraAbilityGameID'] = $extraAbilityGameID;
|
||||
}
|
||||
}
|
||||
|
||||
$mitigationNames = [];
|
||||
foreach ($mitigIdMap as $meta) {
|
||||
|
||||
@ -80,6 +80,30 @@ select option { background: var(--bg2); }
|
||||
|
||||
.btn-sm { padding: 5px 13px; font-size: 13px; }
|
||||
|
||||
/* ── Export choice dropdown ─────────────────────────────────────────────────── */
|
||||
.export-choice-menu {
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
background: var(--bg2);
|
||||
border: 1px solid var(--bg3);
|
||||
border-radius: var(--r);
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 16px rgba(0,0,0,0.5);
|
||||
}
|
||||
.export-choice-item {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 9px 18px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: var(--t1);
|
||||
font-size: 13px;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.export-choice-item:hover { background: var(--bg3); color: var(--gold); }
|
||||
|
||||
/* ── Stats row ──────────────────────────────────────────────────────────────── */
|
||||
.stats-row {
|
||||
display: flex;
|
||||
|
||||
@ -724,6 +724,42 @@
|
||||
mitigationNames,
|
||||
};
|
||||
},
|
||||
exportRefForPlanner() {
|
||||
const sameReportId = parseInt(refFightSelect.value, 10);
|
||||
const extId = parseInt(refExtFightSelect.value, 10);
|
||||
let fight = null, reportCode = '', fightId = 0;
|
||||
if (sameReportId) {
|
||||
fight = allSameReportFights.find(f => f.id === sameReportId);
|
||||
reportCode = window.App?.reportCode ?? '';
|
||||
fightId = sameReportId;
|
||||
} else if (extId) {
|
||||
fight = extFights.find(f => f.id === extId);
|
||||
reportCode = extReportCode;
|
||||
fightId = extId;
|
||||
}
|
||||
const transitions = fight?.phaseTransitions ?? [];
|
||||
const phases = transitions.length === 0 ? [] : [
|
||||
{ id: 0, name: 'Ganzer Fight', startTime: fight.startTime, endTime: fight.endTime },
|
||||
...transitions.map((t, i) => ({
|
||||
id: t.id,
|
||||
name: `Phase ${t.id}`,
|
||||
startTime: t.startTime,
|
||||
endTime: transitions[i + 1]?.startTime ?? fight.endTime,
|
||||
})),
|
||||
];
|
||||
return {
|
||||
aoeEvents: refEvents,
|
||||
fightStart: refFightStart,
|
||||
phases,
|
||||
players: refPlayers,
|
||||
fightName: fight?.name ?? 'Referenz-Fight',
|
||||
reportCode,
|
||||
fightId,
|
||||
fightEnd: fight?.endTime ?? 0,
|
||||
mitigationNames,
|
||||
};
|
||||
},
|
||||
hasRefExport() { return refEvents.length > 0; },
|
||||
reset() {
|
||||
lastFightId = null;
|
||||
refEvents = [];
|
||||
@ -745,7 +781,45 @@
|
||||
},
|
||||
};
|
||||
|
||||
document.getElementById('export-to-planner-btn')?.addEventListener('click', () => {
|
||||
document.getElementById('export-to-planner-btn')?.addEventListener('click', (e) => {
|
||||
if (!refEvents.length) {
|
||||
window.plannerTab?.showImportModal(window.analysisTab.exportForPlanner());
|
||||
return;
|
||||
}
|
||||
showExportChoiceMenu(e.currentTarget);
|
||||
});
|
||||
|
||||
function showExportChoiceMenu(anchor) {
|
||||
document.getElementById('export-choice-menu')?.remove();
|
||||
const menu = document.createElement('div');
|
||||
menu.id = 'export-choice-menu';
|
||||
menu.className = 'export-choice-menu';
|
||||
|
||||
[
|
||||
{ label: 'Aktueller Fight', fn: () => window.analysisTab.exportForPlanner() },
|
||||
{ label: 'Referenz-Fight', fn: () => window.analysisTab.exportRefForPlanner() },
|
||||
].forEach(({ label, fn }) => {
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'export-choice-item';
|
||||
btn.textContent = label;
|
||||
btn.addEventListener('click', () => {
|
||||
menu.remove();
|
||||
window.plannerTab?.showImportModal(fn());
|
||||
});
|
||||
menu.appendChild(btn);
|
||||
});
|
||||
|
||||
document.body.appendChild(menu);
|
||||
const rect = anchor.getBoundingClientRect();
|
||||
menu.style.top = (rect.bottom + 4) + 'px';
|
||||
menu.style.right = (window.innerWidth - rect.right) + 'px';
|
||||
|
||||
const close = (ev) => {
|
||||
if (!menu.contains(ev.target) && ev.target !== anchor) {
|
||||
menu.remove();
|
||||
document.removeEventListener('click', close, true);
|
||||
}
|
||||
};
|
||||
setTimeout(() => document.addEventListener('click', close, true), 0);
|
||||
}
|
||||
})();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user