From a9b3cc86663a28aadbd899ea7f76136c7d2578d6 Mon Sep 17 00:00:00 2001 From: xziino Date: Sun, 24 May 2026 15:04:21 +0200 Subject: [PATCH] Planer: Clarity of Corundum + separate Tankbuster-Fixes - Clarity of Corundum (GNB Proc, 15% DR, statusId 1002684) neu in MITIGATION_ABILITIES, ABILITY_DR, JOB_ABILITIES, TIMELINE_PERSONAL_ABILITIES - statusId fuer Heart of Corundum (1002683) und Great Nebula (1003838) nachgetragen (stabilere Erkennung via buffs-Feld) - Icons heruntergeladen: heart-of-corundum.png, heart-of-stone.png, clarity-of-corundum.png (teilt HoC-Action-Icon vorlaeufig) - Cache-Version v3 -> v4 (erzwingt Neu-Fetch nach Erkennungs-Aenderungen) Separate Tankbuster: - tankMaxHpFromEvent(): maxHP direkt aus dem aoe_event des getroffenen Tanks statt Roster-Durchschnitt (ein Tank getroffen = sein MaxHP) - renderMechanicListHtml: m.tankMaxHp hat Vorrang vor avgTankMaxHp(plan) - plannedAssignmentsForMechanic: persoenliche Mitigation erscheint nur auf der direkt zugewiesenen Mechanik (DRK-CDs nicht mehr auf GNB-TB) - DR-Label: 'mitigiert' -> 'nach DR' (verbleibender Schaden, nicht reduzierter Betrag) Co-Authored-By: Claude Sonnet 4.6 --- api/analysis.php | 5 +- api/cache.php | 2 +- .../icons/mitigation/clarity-of-corundum.png | Bin 0 -> 5409 bytes assets/icons/mitigation/heart-of-corundum.png | Bin 0 -> 5409 bytes assets/icons/mitigation/heart-of-stone.png | Bin 0 -> 4781 bytes js/ffxiv-data.js | 7 ++- js/planner.js | 53 ++++++++++++++++-- 7 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 assets/icons/mitigation/clarity-of-corundum.png create mode 100644 assets/icons/mitigation/heart-of-corundum.png create mode 100644 assets/icons/mitigation/heart-of-stone.png diff --git a/api/analysis.php b/api/analysis.php index 5fd55f6..805415f 100644 --- a/api/analysis.php +++ b/api/analysis.php @@ -122,10 +122,11 @@ const MITIGATION_ABILITIES = [ // GNB 'Superbolide' => ['dr' => 100, 'buffType' => 'buff', 'extraAbilityGameID' => 16152], 'Nebula' => ['dr' => 30, 'buffType' => 'buff', 'extraAbilityGameID' => 16148], - 'Great Nebula' => ['dr' => 40, 'buffType' => 'buff', 'extraAbilityGameID' => 36935], + 'Great Nebula' => ['dr' => 40, 'buffType' => 'buff', 'statusId' => 1003838, 'extraAbilityGameID' => 36935], 'Camouflage' => ['dr' => 10, 'buffType' => 'buff', 'extraAbilityGameID' => 16140], 'Heart of Stone' => ['dr' => 15, 'buffType' => 'buff', 'extraAbilityGameID' => 16161], - 'Heart of Corundum' => ['dr' => 15, 'buffType' => 'buff', 'extraAbilityGameID' => 25758], + 'Heart of Corundum' => ['dr' => 15, 'buffType' => 'buff', 'statusId' => 1002683, 'extraAbilityGameID' => 25758], + 'Clarity of Corundum' => ['dr' => 15, 'buffType' => 'buff', 'statusId' => 1002684, 'extraAbilityGameID' => 25758], // Proc von Heart of Corundum, kann beliebiges Partymitglied treffen // DPS 'Riddle of Earth' => ['dr' => 20, 'buffType' => 'buff', 'extraAbilityGameID' => 7394], 'Shade Shift' => ['dr' => 0, 'buffType' => 'shield', 'extraAbilityGameID' => 2241], diff --git a/api/cache.php b/api/cache.php index e77fa93..1ad39d3 100644 --- a/api/cache.php +++ b/api/cache.php @@ -2,7 +2,7 @@ declare(strict_types=1); const CACHED_LOG_DIR = __DIR__ . '/../cached_logs'; -const CACHED_LOG_VERSION = 'v3'; +const CACHED_LOG_VERSION = 'v4'; function cache_language(string $language): string { $language = strtolower(trim($language)); diff --git a/assets/icons/mitigation/clarity-of-corundum.png b/assets/icons/mitigation/clarity-of-corundum.png new file mode 100644 index 0000000000000000000000000000000000000000..326d844c5905ce7785beef0e150047a6cd4e5466 GIT binary patch literal 5409 zcmXX~eNY-{n#VXUYwkws%JXJ#2j%MOYTO-a{D@`*6{+3ZEq6DQxVy85CPXnwsiSUG z(g#G*?j&r+irImG*2ND3Q)L-v2N5%#V-&SzjKiHGRAP{rh^U-&6vIbaLxW9ouc@mN zv9O!>>G%CTzmMn6Z_ky!d-BI8X*Alqzy8%Peh=P%a{T(?55Vs~QxC7wX#e=~*T4AL zAFe07noIoh-_HN_`%qlw|Kh)`L)Xq+8M*r6+yDQm|Fib5zcFf0<^8KaBAsYxyWd&V z=rEq*r|2t{eB$xvTq|Z(*?aS_Z@8nk(%9a)_7aR>D)X=@52R%2Ad-+UQ9q}J>19`# z{k-s~+-_Kh>{;P`|2HPnW!d-=&%_o?|4koIpKfp zoYnM|}C9e(1=h=lPm&V{^ItOcy3WMQl5Y`23~M%$dC^ZUZorp)_T1=kBq;n54P zPOzorIdre}W}4oWHhQ^4H}AbEk_5n!LFi?QZpj;l`??Zc(2PltGXjP_n#f zrdwFf-iUnR?mPZFKy3xQj~Q@|vr?wWp?K6*V^R48@7$^)`E!MJ2Knp`kNS`}nq6*TO(!e-d(2a&%*+3kkpV;?Xra{?SO$ z%tE>;)ktkKuva279~@g`cjyn-L*?H4J|z_Vi;!E9PD@2eAG)lH6Lx52*LR(`%h$-@ zc-VWt9G1++RI=9KStx^wW-q(r5jVbR_^7EcMK6~|cHQtvlnRG)jNP5APDPu>c4yTb+79h`wnA%`Dai z!xN_rwuBb{sxWeBq-xLcuip*B0VlR)nYjL)0pn1c@6~Wu0e{cEZ8pZD(}WK#F=3n9Op=$Az}CKALapXNyu=va zGul%9y$=rqnN?AZ6H`}7FsSsxT7m^RnE{|}KP zp=`2V|ILN7O#bYG0h2x+V8uSO-;6XY7}yW%#xL8toNz!@E0bu1abl?T;0&4{AeVL4 zEYq+6k_LK@H_0FI@V%XULa{c3CC@P{5`s?xq`5e1aQD&q#9(Vsv8DA`ddHRw`bueY z6s6Vs*#gG~+Lwh~&N^4Qq^i; zZjX_)S%$x*^(WG=tCVtqR{LpV^)JgnI39NBa+xA-6b+*OM{dT1P zE1{4%{Na$XXqmk4v9j7z@lw9#l!5r8Aa(eL;~il^E+0;(hu42obJ_RUXblx0HGBWb zkTjli-BQRuT=8>z%AQ{M8}2#oOY5%h9KPv9u1IykckZWYOrGRVtbdz(^k_BYnZ{*E z-qSmL&`Dk`*vSmi+id5dq-DQkD;d1(Ycn3feITyd%;MV$6ge^FpDL9nG5OSIJ@XCY zOQ8a|uEMo=jA&pHxYVM`JLQDyA7U8~F%Djep27>@nyLt)kpo_z?Bp`w9bbjvhTO|U zf?{cN?8ye>neM{N)t$I?Y_bcYByjzgB}e`dVV@_$^|iSy8F@UB#N1{`k4jbl#0GRmzQpQI(4G@@Gq5nKik>LhEua+8?3+A-|-9?J=&q-+a9Ouk$+N{ z@X-G_dwD<dU0uwvM<}#l_2}LW> zh<=QvdIeLf2 zh0b=$;izgWR!z`17PqHJ`W}*_FYKG(j2BSn=uOqt{i1{^5! zYK6@;l+$euMZ~j_ejRO2!HPYZej`VK6DsJ8Fujc0)4Dt)IM6GSrR!alQjFnMqmll| zE-2X_c7TU%eI@Zg@gF2`Pmz*M$LoZ0Oz};&8Sm$-*K(%ZNPz_m|pR4?^7OLpJVo$6f%>;$8+=Jq}03 z#EiSAG*D$>^V@9AiOf#VoDeyX<9~8fS3&riKR$)6WHk1o{ZNkP;f}6MG9-e0Jk#4q zBBlxSm7vDp88jC-RJ*#q19UiWg_(b6BZ>Cwxi!UWHwDV<1uoUvK;-?uPi{t@4 z#JO`IJ9+ioVuGWud^RHi$qf)!aML&90gci#LH%#oJILzL$hE;G5UnnTUlw?ioo0y% zdUjhbm7PBp4mDiA$3}wh<4&*#tLm!I6KADGj^f~C${y0CflIJU(Q8)$vdCg~R&Ig_ zOc5ru_gLTF8b#a(!e9=-XaeLNz3||9WkPVXRAd*^OCRgY63<5q*LR8G_F6=+vRW3*yyYmT8|lP3E-N&$t&A9>dsZp-rGgUnGC+uH@sS*pDY(p!SpfWyWrh35&Ls`XxDJ(+}9e)N8!I`n8#!t&9N^Z(wVq$H^Ur1e-sUsm_E9Qi+ZX6A=tfKf~R@t+A0EtXN zI0#(38;N)?xdKsfZ-eFqBgIi$0vDh42r7?AhP{o5KzyG9vZKwM<#OGu$ zXCsFNW2PcZ>kupLqQ2wd!!dr@^98F|2#Zru}OS6}(HI-xD;|*!*On z63w4J7yvLRi|2stJ>EAjbbYrR24>;yP{w*(0aRhAmN0;#NPvs0maf&9a|VG(vg~n{(HT~O(Q}~L_8o6?$MEO0YFI%BzUSCWG@r& ziUOb-b$-yApVRGIh00^n;4=9sICm7tO2{+pzv($1VbHAQY=J)Q?PRAHkR%(_Gk(kE z=&F=*Vde%gDC!3RisL4iMemwMPxvPf^^=E2S?hNV3nAagz%)rmf^|k^8B{AQ%a<>goLw*E1K9=YD~f-NJHY&)Ikc$;)=LLMj6b!9#kUD=w;HUyU+ELi z@d*dFV@01Qo@?miaOfsk@$E`V3z?92fv=nTNNOyyEupXbAy*@sTSgqAUS%d(Qs7ve z&cMtC=|fM;;kX?pcDc@(gGamdcjek^Y&~Qe?Sn>5OaA;ic>3B3`9T%w5cSI`LfzYZ zcKslzu6^Eda{Rm1&_~}Y%e~`2zxQQEj?u!UHl4L8IcHmbdp-m@Ur|54I0O;{ z13nNp_1Py=I6Q>Y!k}YRpTPq)+`S=|Kw`$DSzM#Q5Z)8tKm* zZaQp`EerrPR+X~>9R{`tKgfeXbV1-rx#9C#z&MQ+56U5O%5yyPv#MB~5wU;eZ5=;MxV4_|MJ`~Mt)v>>;C{Iz>D+% literal 0 HcmV?d00001 diff --git a/assets/icons/mitigation/heart-of-corundum.png b/assets/icons/mitigation/heart-of-corundum.png new file mode 100644 index 0000000000000000000000000000000000000000..326d844c5905ce7785beef0e150047a6cd4e5466 GIT binary patch literal 5409 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 literal 0 HcmV?d00001 diff --git a/assets/icons/mitigation/heart-of-stone.png b/assets/icons/mitigation/heart-of-stone.png new file mode 100644 index 0000000000000000000000000000000000000000..8466d30b7a4f7aac597df76441228484bc0b1699 GIT binary patch literal 4781 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 PY45*x?p@WtuzLOvkJOac literal 0 HcmV?d00001 diff --git a/js/ffxiv-data.js b/js/ffxiv-data.js index 4305def..43b71c3 100644 --- a/js/ffxiv-data.js +++ b/js/ffxiv-data.js @@ -69,6 +69,7 @@ { name: 'Camouflage', buffType: 'buff', extraAbilityGameID: 16140, duration: 20 }, { name: 'Heart of Stone', buffType: 'buff', extraAbilityGameID: 16161, duration: 7 }, { name: 'Heart of Corundum', buffType: 'buff', extraAbilityGameID: 25758, duration: 8 }, + { name: 'Clarity of Corundum', buffType: 'buff', extraAbilityGameID: 25758, duration: 4 }, // Proc von HoC, geht auf beliebiges Partymitglied { name: 'Reprisal', buffType: 'debuff' }, ], 'WHM': [ @@ -156,7 +157,7 @@ 'Oblation': 'DRK', 'Heart of Light': 'GNB', 'Superbolide': 'GNB', 'Nebula': 'GNB', 'Great Nebula': 'GNB', 'Camouflage': 'GNB', 'Heart of Stone': 'GNB', - 'Heart of Corundum': 'GNB', + 'Heart of Corundum': 'GNB', 'Clarity of Corundum': 'GNB', 'Temperance': 'WHM', 'Divine Benison': 'WHM', 'Divine Caress': 'WHM', 'Sacred Soil': 'SCH', 'Expedient': 'SCH', 'Fey Illumination': 'SCH', 'Galvanize': 'SCH', 'Seraphic Veil': 'SCH', 'Catalyze': 'SCH', @@ -219,6 +220,9 @@ 'Tempera Coat': 'assets/icons/mitigation/tempera-coat.png', 'Tempera Grassa': 'assets/icons/mitigation/tempera-grassa.png', 'Improvised Finish': 'assets/icons/mitigation/improvised-finish.png', + 'Heart of Corundum': 'assets/icons/mitigation/heart-of-corundum.png', + 'Clarity of Corundum': 'assets/icons/mitigation/clarity-of-corundum.png', + 'Heart of Stone': 'assets/icons/mitigation/heart-of-stone.png', }; const ABILITY_DR = { @@ -259,6 +263,7 @@ 'Camouflage': 0.10, 'Heart of Stone': 0.15, 'Heart of Corundum': 0.15, + 'Clarity of Corundum': 0.15, 'Riddle of Earth': 0.20, 'Third Eye': 0.10, }; diff --git a/js/planner.js b/js/planner.js index 320366a..2d8e58b 100644 --- a/js/planner.js +++ b/js/planner.js @@ -493,10 +493,40 @@ function avgNonTankMaxHp(plan) { return Math.round(hps.reduce((s, v) => s + v, 0) / hps.length); } +function avgTankMaxHp(plan) { + const roster = plan.playerRoster ?? []; + const jobComp = plan.jobComposition ?? []; + const hps = jobComp + .map((job, i) => ({ job, maxHp: roster[i]?.maxHp ?? 0 })) + .filter(p => p.job && JOB_ROLE[p.job] === 'tank' && p.maxHp > 0) + .map(p => p.maxHp); + if (!hps.length) return 0; + // Tankbuster trifft einen Tank → Durchschnitt über alle gefundenen Tanks + // (1 Tank → sein MaxHP direkt; 2 Tanks → (hp1 + hp2) / 2) + return Math.round(hps.reduce((s, v) => s + v, 0) / hps.length); +} + +// Ermittelt den maxHP-Wert direkt aus dem aoe_event (für präzise Tankbuster-Anzeige) +function tankMaxHpFromEvent(ev) { + if (!ev?.isHeavyTankbuster) return 0; + const tankTargets = (ev.targets ?? []).filter(t => t.role === 'tank' && (t.maxHp ?? 0) > 0); + if (tankTargets.length === 1) return tankTargets[0].maxHp; + if (tankTargets.length > 1) { + // Mehrere Tanks gleichzeitig → Durchschnitt + return Math.round(tankTargets.reduce((s, t) => s + t.maxHp, 0) / tankTargets.length); + } + // Fallback: erstes Target mit maxHp (z.B. wenn Role nicht gesetzt) + const any = (ev.targets ?? []).find(t => (t.maxHp ?? 0) > 0); + return any?.maxHp ?? 0; +} + function simulateDrMultiplier(mechanic, assignments = mechanic.assignments ?? []) { + const isTankbuster = !!mechanic.isHeavyTankbuster; let mult = 1; for (const a of assignments) { if (a.buffType === 'shield') continue; + // Persönliche Mitigation nur bei Tankbustern einrechnen + if (!isTankbuster && TIMELINE_PERSONAL_ABILITIES.has(a.ability)) continue; mult *= (1 - (ABILITY_DR[a.ability] ?? 0)); } return mult; @@ -510,6 +540,13 @@ function plannedAssignmentsForMechanic(plan, targetMechanic) { for (const entry of canonicalAssignmentActivations(plan, { dedupeKey: canonicalMechanicKey })) { if (targetTime < entry.start - tolerance || targetTime > entry.end + tolerance) continue; + // Persönliche Mitigation zeigt nur auf der Mechanik, der sie direkt zugewiesen ist + // (verhindert dass DRK-Cooldowns auf GNB-Tankbuster erscheinen und umgekehrt) + if (TIMELINE_PERSONAL_ABILITIES.has(entry.assignment.ability) + && entry.mechanic.id !== targetMechanic.id) { + continue; + } + result.push({ ...entry.assignment, sourceMechanicId: entry.mechanic.id, @@ -535,9 +572,14 @@ function renderMechanicListHtml(plan) { } const activeJobSet = new Set(plan.jobComposition.filter(j => j)); - const avgHp = avgNonTankMaxHp(plan); + const nonTankAvgHp = avgNonTankMaxHp(plan); + const tankAvgHp = avgTankMaxHp(plan); return mechanics.map(m => { + // Tankbuster: gespeicherter maxHP des getroffenen Tanks hat Vorrang (präziser als Roster-Durchschnitt) + const avgHp = m.isHeavyTankbuster + ? ((m.tankMaxHp ?? 0) > 0 ? m.tankMaxHp : tankAvgHp) + : nonTankAvgHp; const planned = plannedAssignmentsForMechanic(plan, m); const sorted = sortedAssignments(planned); const assignHtml = sorted.length === 0 @@ -588,7 +630,7 @@ function renderMechanicListHtml(plan) { : '' } ${hasDrAssign || hasShield ? `
- ${hasDrAssign ? `→ ${fmtNumber(drOnly)} mitigiert` : ''} + ${hasDrAssign ? `→ ${fmtNumber(drOnly)} nach DR` : ''} ${hasShield ? `Mitigation mit Schild ${fmtNumber(mitigFull)}` : ''}
` : ''}
${assignHtml}
@@ -711,6 +753,7 @@ const TIMELINE_PERSONAL_ABILITIES = new Set([ 'Camouflage', 'Heart of Stone', 'Heart of Corundum', + 'Clarity of Corundum', 'Divine Benison', 'Intersection', 'the Spire', @@ -2267,6 +2310,7 @@ function aoeEventsToMechanics(aoeEvents, fightStart, phases, players, withMitiga phase: phase?.name ?? '', unmitigatedDamage: avgUnmit, isHeavyTankbuster: !!ev.isHeavyTankbuster, + tankMaxHp: tankMaxHpFromEvent(ev), notes: '', assignments, }; @@ -2387,9 +2431,10 @@ async function refreshPlanLanguage(planId) { })); return { ...mechanic, - name: match.abilityName ?? mechanic.name, - abilityId: match.abilityId ?? mechanic.abilityId, + name: match.abilityName ?? mechanic.name, + abilityId: match.abilityId ?? mechanic.abilityId, isHeavyTankbuster: mechanic.mechanicTypeManual ? !!mechanic.isHeavyTankbuster : !!match.isHeavyTankbuster, + tankMaxHp: mechanic.mechanicTypeManual ? (mechanic.tankMaxHp ?? 0) : tankMaxHpFromEvent(match), assignments, }; });