forked from xziino/ff14-mitigator
Analyse+Planer: Phys/Mag-Badge für Schadenstyp (abilityType)
- analysis.php: masterData.abilities.type im GQL-Query + abilityType in AoE-Events - analysis.js + planner.js: dmgTypeBadge() zeigt [Phys]/[Mag] neben Ability-Namen - cache.php: Version v8 → v9 (Cache-Invalidierung) - components.css + planner.css: .dmg-type-badge Styles (orange=phys, blau=mag) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
1e881be482
commit
3726a35a72
@ -251,6 +251,7 @@ $pdResult = fflogs_gql(<<<GQL
|
|||||||
abilities {
|
abilities {
|
||||||
gameID
|
gameID
|
||||||
name
|
name
|
||||||
|
type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -261,10 +262,12 @@ GQL);
|
|||||||
if (isset($pdResult['_reauth'])) { echo json_encode(['reauth' => true]); exit; }
|
if (isset($pdResult['_reauth'])) { echo json_encode(['reauth' => true]); exit; }
|
||||||
if (isset($pdResult['_curl_error'])) { http_response_code(502); echo json_encode(['error' => $pdResult['_curl_error']]); exit; }
|
if (isset($pdResult['_curl_error'])) { http_response_code(502); echo json_encode(['error' => $pdResult['_curl_error']]); exit; }
|
||||||
|
|
||||||
// abilityGameID/statusID → display name
|
// abilityGameID/statusID → display name + damage type
|
||||||
$abilityNames = [];
|
$abilityNames = [];
|
||||||
|
$abilityTypes = [];
|
||||||
foreach ($pdResult['data']['reportData']['report']['masterData']['abilities'] ?? [] as $ab) {
|
foreach ($pdResult['data']['reportData']['report']['masterData']['abilities'] ?? [] as $ab) {
|
||||||
$abilityNames[(int)$ab['gameID']] = $ab['name'];
|
$abilityNames[(int)$ab['gameID']] = $ab['name'];
|
||||||
|
if (isset($ab['type'])) $abilityTypes[(int)$ab['gameID']] = (int)$ab['type'];
|
||||||
}
|
}
|
||||||
|
|
||||||
// gameID → mitigation meta: primary from masterData, statusId fallback for
|
// gameID → mitigation meta: primary from masterData, statusId fallback for
|
||||||
@ -524,6 +527,7 @@ foreach ($allEvents as $ev) {
|
|||||||
'maxHp' => (int)($ev['targetResources']['maxHitPoints'] ?? 0),
|
'maxHp' => (int)($ev['targetResources']['maxHitPoints'] ?? 0),
|
||||||
'buffs' => $ev['buffs'] ?? '',
|
'buffs' => $ev['buffs'] ?? '',
|
||||||
'name' => $abilityNames[$abId] ?? $ev['ability']['name'] ?? ('Ability #' . $abId),
|
'name' => $abilityNames[$abId] ?? $ev['ability']['name'] ?? ('Ability #' . $abId),
|
||||||
|
'abilityType' => isset($ev['ability']['type']) ? (int)$ev['ability']['type'] : ($abilityTypes[$abId] ?? null),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -543,6 +547,7 @@ foreach ($byAbility as $abId => $events) {
|
|||||||
'timestamp' => (int)$ev['ts'],
|
'timestamp' => (int)$ev['ts'],
|
||||||
'abilityId' => $abId,
|
'abilityId' => $abId,
|
||||||
'abilityName' => $ev['name'],
|
'abilityName' => $ev['name'],
|
||||||
|
'abilityType' => $ev['abilityType'] ?? null,
|
||||||
'targets' => [],
|
'targets' => [],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -633,6 +638,7 @@ foreach ($clusters as $group) {
|
|||||||
'timestamp' => $group['timestamp'],
|
'timestamp' => $group['timestamp'],
|
||||||
'abilityId' => $group['abilityId'],
|
'abilityId' => $group['abilityId'],
|
||||||
'abilityName' => $group['abilityName'],
|
'abilityName' => $group['abilityName'],
|
||||||
|
'abilityType' => $group['abilityType'] ?? null,
|
||||||
'targets' => $targets,
|
'targets' => $targets,
|
||||||
'totalDamage' => array_sum(array_column($targets, 'amount')),
|
'totalDamage' => array_sum(array_column($targets, 'amount')),
|
||||||
'isHeavyTankbuster' => $isHeavyTankbuster,
|
'isHeavyTankbuster' => $isHeavyTankbuster,
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
const CACHED_LOG_DIR = __DIR__ . '/../cached_logs';
|
const CACHED_LOG_DIR = __DIR__ . '/../cached_logs';
|
||||||
const CACHED_LOG_VERSION = 'v8';
|
const CACHED_LOG_VERSION = 'v9';
|
||||||
|
|
||||||
function cache_language(string $language): string {
|
function cache_language(string $language): string {
|
||||||
$language = strtolower(trim($language));
|
$language = strtolower(trim($language));
|
||||||
|
|||||||
@ -143,6 +143,10 @@ select option { background: var(--bg2); }
|
|||||||
.badge-gold { background: var(--goldbg); border-color: rgba(200,168,75,.4); color: var(--gold); }
|
.badge-gold { background: var(--goldbg); border-color: rgba(200,168,75,.4); color: var(--gold); }
|
||||||
.badge-planned { opacity: 0.55; border-style: dashed; }
|
.badge-planned { opacity: 0.55; border-style: dashed; }
|
||||||
|
|
||||||
|
.dmg-type-badge { font-size: 11px; font-weight: 600; padding: 1px 5px; border-radius: 3px; letter-spacing: .03em; }
|
||||||
|
.dmg-type--phys { background: rgba(230,140,60,.15); color: var(--orange); border: 1px solid rgba(230,140,60,.35); }
|
||||||
|
.dmg-type--mag { background: rgba(74,158,255,.12); color: var(--blue); border: 1px solid rgba(74,158,255,.3); }
|
||||||
|
|
||||||
/* ── DR Bar ─────────────────────────────────────────────────────────────────── */
|
/* ── DR Bar ─────────────────────────────────────────────────────────────────── */
|
||||||
.dr-bar-wrap {
|
.dr-bar-wrap {
|
||||||
background: var(--bg2);
|
background: var(--bg2);
|
||||||
|
|||||||
@ -276,6 +276,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mechanic-name {
|
.mechanic-name {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
color: var(--t1);
|
color: var(--t1);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|||||||
@ -1,5 +1,12 @@
|
|||||||
(function () {
|
(function () {
|
||||||
const { MITIG_ICONS, JOB_ABBR, ABILITY_JOBS, JOB_ROLE } = window.FF14_DATA;
|
const { MITIG_ICONS, JOB_ABBR, ABILITY_JOBS, JOB_ROLE, abilityTypeIsPhysical, abilityTypeIsMagical } = window.FF14_DATA;
|
||||||
|
|
||||||
|
function dmgTypeBadge(abilityType) {
|
||||||
|
if (abilityType == null) return '';
|
||||||
|
if (abilityTypeIsPhysical(abilityType)) return '<span class="dmg-type-badge dmg-type--phys">Phys</span>';
|
||||||
|
if (abilityTypeIsMagical(abilityType)) return '<span class="dmg-type-badge dmg-type--mag">Mag</span>';
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
// Deduplicated list of all mitigations across all targets of a ref event
|
// Deduplicated list of all mitigations across all targets of a ref event
|
||||||
function collectRefMitigs(refEvent) {
|
function collectRefMitigs(refEvent) {
|
||||||
@ -758,6 +765,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="aoe-ability">
|
<div class="aoe-ability">
|
||||||
${ev.abilityName}
|
${ev.abilityName}
|
||||||
|
${dmgTypeBadge(ev.abilityType)}
|
||||||
<span class="aoe-total">— ${fmtDmg(ev.totalDamage)} total</span>
|
<span class="aoe-total">— ${fmtDmg(ev.totalDamage)} total</span>
|
||||||
${debuffIconsHtml}
|
${debuffIconsHtml}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -749,7 +749,7 @@ function renderMechanicListHtml(plan) {
|
|||||||
<div class="mechanic-time">${escHtml(fmtTimestamp(m.timestamp))}</div>
|
<div class="mechanic-time">${escHtml(fmtTimestamp(m.timestamp))}</div>
|
||||||
<div class="mechanic-body">
|
<div class="mechanic-body">
|
||||||
${m.phase ? `<div class="mechanic-phase">${escHtml(m.phase)}</div>` : ''}
|
${m.phase ? `<div class="mechanic-phase">${escHtml(m.phase)}</div>` : ''}
|
||||||
<div class="mechanic-name">${escHtml(m.name)}</div>
|
<div class="mechanic-name">${escHtml(m.name)}${dmgTypeBadge(m.abilityType)}</div>
|
||||||
${m.unmitigatedDamage
|
${m.unmitigatedDamage
|
||||||
? `<div class="mechanic-dmg">${fmtNumber(m.unmitigatedDamage)} unmitigiert${avgHp ? ` <span class="mechanic-avg-hp">∅ ${fmtNumber(avgHp)} HP</span>` : ''}</div>`
|
? `<div class="mechanic-dmg">${fmtNumber(m.unmitigatedDamage)} unmitigiert${avgHp ? ` <span class="mechanic-avg-hp">∅ ${fmtNumber(avgHp)} HP</span>` : ''}</div>`
|
||||||
: ''
|
: ''
|
||||||
@ -2338,7 +2338,16 @@ const {
|
|||||||
MELEE_JOBS,
|
MELEE_JOBS,
|
||||||
MITIG_ICONS,
|
MITIG_ICONS,
|
||||||
TANK_JOBS,
|
TANK_JOBS,
|
||||||
|
abilityTypeIsPhysical,
|
||||||
|
abilityTypeIsMagical,
|
||||||
} = window.FF14_DATA;
|
} = window.FF14_DATA;
|
||||||
|
|
||||||
|
function dmgTypeBadge(abilityType) {
|
||||||
|
if (abilityType == null) return '';
|
||||||
|
if (abilityTypeIsPhysical(abilityType)) return '<span class="dmg-type-badge dmg-type--phys">Phys</span>';
|
||||||
|
if (abilityTypeIsMagical(abilityType)) return '<span class="dmg-type-badge dmg-type--mag">Mag</span>';
|
||||||
|
return '';
|
||||||
|
}
|
||||||
// Groups of abilities that are functionally equivalent across different jobs.
|
// Groups of abilities that are functionally equivalent across different jobs.
|
||||||
// Used to suggest replacements when a job is missing from the composition.
|
// Used to suggest replacements when a job is missing from the composition.
|
||||||
const ABILITY_EQUIVALENTS = [
|
const ABILITY_EQUIVALENTS = [
|
||||||
@ -2442,6 +2451,7 @@ function aoeEventsToMechanics(aoeEvents, fightStart, phases, players, withMitiga
|
|||||||
id: crypto.randomUUID(),
|
id: crypto.randomUUID(),
|
||||||
name: ev.abilityName,
|
name: ev.abilityName,
|
||||||
abilityId: ev.abilityId,
|
abilityId: ev.abilityId,
|
||||||
|
abilityType: ev.abilityType ?? null,
|
||||||
timestamp: relTs,
|
timestamp: relTs,
|
||||||
phase: phase?.name ?? '',
|
phase: phase?.name ?? '',
|
||||||
unmitigatedDamage: avgUnmit,
|
unmitigatedDamage: avgUnmit,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user