Analyse+Planer: Phys/Mag-DR fix (Feint/Addle) + Plenary Indulgence (WHM)

- ffxiv-data.js: abilityDr() für typabhängige DR — Feint 10% phys/5% mag, Addle 10% mag/5% phys
- analysis.js + planner.js: abilityDr() in simulateDrMultiplier() und Debuff-Tooltip
- analysis.php: Plenary Indulgence (statusId 1001219 "Confession", 10% DR, WHM)
- ffxiv-data.js: Plenary Indulgence in JOB_ABILITIES/ABILITY_DR/MITIG_ICONS
- Action.json: Eintrag 7433 (recast 600 = 60s) für Gantt-Diagramm
- Icon: plenary-indulgence.png von XIVAPI
- cache.php: v11

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
xziino 2026-05-28 12:53:58 +02:00
parent 3726a35a72
commit 4003060699
7 changed files with 31 additions and 5 deletions

View File

@ -88,6 +88,7 @@ const MITIGATION_ABILITIES = [
'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],
'Plenary Indulgence' => ['dr' => 10, 'buffType' => 'buff', 'statusId' => 1001219, 'extraAbilityGameID' => 7433], // FFLogs: "Confession"
'Aquaveil' => ['dr' => 15, 'buffType' => 'buff', 'statusId' => 1002708, 'extraAbilityGameID' => 25861], // Personal, WHM auf Ziel
'Sacred Soil' => ['dr' => 10, 'buffType' => 'buff', 'statusId' => 1001944, 'extraAbilityGameID' => 188],
'Expedient' => ['dr' => 10, 'buffType' => 'buff', 'statusId' => 1002711, 'extraAbilityGameID' => 25868], // FFLogs: "Desperate Measures"

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
const CACHED_LOG_DIR = __DIR__ . '/../cached_logs';
const CACHED_LOG_VERSION = 'v9';
const CACHED_LOG_VERSION = 'v11';
function cache_language(string $language): string {
$language = strtolower(trim($language));

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -419,6 +419,18 @@
"icon": "https://xivapi.com/i/003000/003087_hr1.png",
"shield": null
},
"7433": {
"cast": 0,
"recast": 600,
"names": {
"en": "Plenary Indulgence",
"de": "Vollkommener Ablass",
"fr": "Indulgence plénière",
"jp": "インドゥルゲンティア"
},
"icon": null,
"shield": null
},
"16536": {
"cast": 0,
"recast": 1200,

View File

@ -1,5 +1,5 @@
(function () {
const { MITIG_ICONS, JOB_ABBR, ABILITY_JOBS, JOB_ROLE, abilityTypeIsPhysical, abilityTypeIsMagical } = window.FF14_DATA;
const { MITIG_ICONS, JOB_ABBR, ABILITY_JOBS, JOB_ROLE, abilityTypeIsPhysical, abilityTypeIsMagical, abilityDr } = window.FF14_DATA;
function dmgTypeBadge(abilityType) {
if (abilityType == null) return '';
@ -612,7 +612,8 @@
].map(m => {
const iconSrc = mitigationIcon(m);
if (!iconSrc) return '';
const dr = m.dr > 0 ? ` ${m.dr}%` : '';
const drPct = Math.round(abilityDr(m.name, ev.abilityType) * 100) || m.dr || 0;
const dr = drPct > 0 ? ` ${drPct}%` : '';
const jobAbbr = m.sourcePlayerType ? (JOB_ABBR[m.sourcePlayerType] ?? '') : '';
const label = jobAbbr ? `${jobAbbr} · ${m.name}` : m.name;
return m.missing

View File

@ -10,6 +10,13 @@
function abilityTypeIsPhysical(type) { return (parseInt(type) & ABILITY_TYPE_PHYSICAL) !== 0; }
function abilityTypeIsMagical(type) { return (parseInt(type) & ABILITY_TYPE_MAGICAL) !== 0; }
// Type-aware DR: Feint 10% phys / 5% mag, Addle 10% mag / 5% phys
function abilityDr(abilityName, abilityType) {
if (abilityName === 'Feint') return abilityTypeIsPhysical(abilityType) ? 0.10 : 0.05;
if (abilityName === 'Addle') return abilityTypeIsMagical(abilityType) ? 0.10 : 0.05;
return ABILITY_DR[abilityName] ?? 0;
}
const JOB_FROM_TYPE = {
'Paladin': 'PLD', 'Warrior': 'WAR', 'DarkKnight': 'DRK', 'Gunbreaker': 'GNB',
'WhiteMage': 'WHM', 'Scholar': 'SCH', 'Astrologian': 'AST', 'Sage': 'SGE',
@ -89,6 +96,7 @@
],
'WHM': [
{ name: 'Temperance', buffType: 'buff' },
{ name: 'Plenary Indulgence', buffType: 'buff', extraAbilityGameID: 7433, duration: 10 },
{ name: 'Aquaveil', buffType: 'buff', extraAbilityGameID: 25861, duration: 8 }, // Personal, WHM auf Ziel
{ name: 'Divine Benison', buffType: 'shield', extraAbilityGameID: 7432, duration: 15 },
{ name: 'Divine Caress', buffType: 'shield' },
@ -177,7 +185,7 @@
'Heart of Light': 'GNB', 'Superbolide': 'GNB', 'Nebula': 'GNB',
'Great Nebula': 'GNB', 'Camouflage': 'GNB', 'Heart of Stone': 'GNB',
'Heart of Corundum': 'GNB', 'Clarity of Corundum': 'GNB',
'Temperance': 'WHM', 'Aquaveil': 'WHM', 'Divine Benison': 'WHM', 'Divine Caress': 'WHM',
'Temperance': 'WHM', 'Plenary Indulgence': 'WHM', 'Aquaveil': 'WHM', 'Divine Benison': 'WHM', 'Divine Caress': 'WHM',
'Sacred Soil': 'SCH', 'Expedient': 'SCH', 'Fey Illumination': 'SCH',
'Galvanize': 'SCH', 'Seraphic Veil': 'SCH', 'Catalyze': 'SCH',
'Collective Unconscious': 'AST', 'Exaltation': 'AST', 'Neutral Sect': 'AST',
@ -204,6 +212,7 @@
'Dark Missionary': 'assets/icons/mitigation/dark-missionary.png',
'Heart of Light': 'assets/icons/mitigation/heart-of-light.png',
'Temperance': 'assets/icons/mitigation/temperance.png',
'Plenary Indulgence': 'assets/icons/mitigation/plenary-indulgence.png',
'Sacred Soil': 'assets/icons/mitigation/sacred-soil.png',
'Expedient': 'assets/icons/mitigation/expedient.png',
'Fey Illumination': 'assets/icons/mitigation/fey-illumination.png',
@ -258,6 +267,7 @@
'Dark Missionary': 0.10,
'Heart of Light': 0.10,
'Temperance': 0.10,
'Plenary Indulgence': 0.10,
'Sacred Soil': 0.10,
'Expedient': 0.10,
'Collective Unconscious': 0.10,
@ -323,5 +333,6 @@
ABILITY_TYPE_MAGICAL,
abilityTypeIsPhysical,
abilityTypeIsMagical,
abilityDr,
};
})();

View File

@ -651,7 +651,7 @@ function simulateDrMultiplier(mechanic, assignments = mechanic.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));
mult *= (1 - abilityDr(a.ability, mechanic.abilityType));
}
return mult;
}
@ -2340,6 +2340,7 @@ const {
TANK_JOBS,
abilityTypeIsPhysical,
abilityTypeIsMagical,
abilityDr,
} = window.FF14_DATA;
function dmgTypeBadge(abilityType) {