From 58745fec65a86b30883de6b4ae5ca0a3d9135875 Mon Sep 17 00:00:00 2001 From: xziino Date: Fri, 22 May 2026 16:33:39 +0200 Subject: [PATCH] CLAUDE.md: Planer-Dokumentation auf aktuellen Stand gebracht MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Datenmodell, Roadmap, Gantt-Entscheidungen, Äquivalente-Ort und Recast-Format aktualisiert; veraltete Punkte entfernt. Co-Authored-By: Claude Sonnet 4.6 --- CLAUDE.md | 108 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 32 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 1df4d29..74ac535 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -239,19 +239,22 @@ Raid-Cooldown-Planer: Welche Mitigation-Ability wird für welche Mechanik einges "name": "M8S – Prog Week 1", "createdAt": 1234567890, "updatedAt": 1234567890, - "source": { "reportCode": "abc123", "fightId": 6 }, + "source": { "reportCode": "abc123", "fightId": 6, "fightName": "Howling Blade", "fightStart": 0, "fightEnd": 420000, "language": "en" }, + "mitigationNames": { "Reprisal": "Vergeltung" }, + "folderId": null, "jobComposition": ["PLD", "WAR", "WHM", "SCH", "MNK", "DRG", "BRD", "SMN"], "mechanics": [ { "id": "uuid", "name": "Fourth-Wall Fusion", + "abilityId": 12345, "timestamp": 83000, "phase": "Phase 1", "unmitigatedDamage": 280000, "notes": "", "assignments": [ - { "ability": "Reprisal", "job": "PLD" }, - { "ability": "Shield Samba", "job": "BRD" } + { "ability": "Reprisal", "abilityName": "Vergeltung", "job": "PLD", "buffType": "debuff" }, + { "ability": "Shield Samba", "abilityName": "Schildsamba", "job": "BRD", "buffType": "buff" } ] } ] @@ -259,6 +262,8 @@ Raid-Cooldown-Planer: Welche Mitigation-Ability wird für welche Mechanik einges ``` Mehrere Pläne gespeichert in `localStorage` unter `ff14-planner-plans` als Array. +Ordner gespeichert unter `ff14-planner-folders`. Pläne referenzieren Ordner per `folderId`. +Aktiver Plan per `ff14-planner-active-plan` (ID) — wird beim Tab-Öffnen wiederhergestellt. ### Primärer Import-Flow: Export aus dem Analyse-Tab Der Haupteinstieg ist der Analyse-Tab — der Nutzer hat die Daten bereits geladen und sieht die Timeline. @@ -271,30 +276,61 @@ Der Haupteinstieg ist der Analyse-Tab — der Nutzer hat die Daten bereits gelad 4. AoE-Events werden zu Mechaniken; Phase-Information aus `phaseTransitions` wird mitübernommen 5. Weiterarbeiten im Planer-Tab -**Merge-Logik:** Mechaniken gelten als identisch wenn `abilityName` gleich und `|timestamp_a - timestamp_b| < 5000ms`. Nur neue Mechaniken werden hinzugefügt, bestehende Assignments bleiben erhalten. Neue Mechaniken werden timestamp-sortiert eingefügt. +**Merge-Logik:** Mechaniken gelten als identisch wenn `|timestamp_a - timestamp_b| < 1500ms`. Nur neue Mechaniken werden hinzugefügt, bestehende Assignments bleiben erhalten. Neue Mechaniken werden timestamp-sortiert eingefügt. **Warum Merge statt Überschreiben:** Progress-Szenario — erster Import enthält Phase 1, späterer Import fügt Phase 2 hinzu ohne Phase-1-Planung zu verlieren. +**Sprachlokalisierung:** `api/analysis.php` gibt `mitigation_names` (key → lokalisierter Name) zurück. Plan speichert diese in `mitigationNames`. `refreshPlanLanguage()` in `planner.js` aktualisiert Namen wenn Sprache wechselt (Event `ff14-language-change`). Anzeigename via `assignmentAbilityName(assignment, plan)`. + ### Implementierungs-Reihenfolge -| Schritt | Feature | Beschreibung | +| Schritt | Status | Feature | |---|---|---| -| 1 | **Datenfundament** | Plan-Datenmodell + localStorage CRUD (create, read, update, delete, copy) | -| 2 | **Tab-Grundgerüst** | Leere Tab-Hülle wie Analyse-Tab; Plan-Liste; Mechanik-Timeline (read-only) | -| 3 | **Import aus Analyse-Tab** | Export-Button + Dialog (s. oben); `window.plannerTab.importFromAnalysis()` | -| 4 | **Jobaufstellung** | 8 Slots mit Job-Dropdown; bestimmt verfügbare Abilities in Schritt 5 | -| 5 | **Ability-Zuweisung** | Pro Mechanik Abilities per Modal-Picker hinzufügen/entfernen | -| 6 | **Recast-Konflikt** | `data/recast-times.json`; rote Warnung wenn CD zwischen zwei Mechaniken noch läuft | -| 7 | **DR-Simulation** | `simuliert = unmitigated × ∏(1 − dr_i)`; grün/rot ob Spieler laut Simulation überlebt | -| 8 | **Job-Äquivalente** | `data/ability-equivalents.json`; auto-substituieren beim Job-Wechsel | -| 9 | **Analyse-Overlay** | Vergleich geplanter vs. tatsächlich genutzter CDs im Analyse-Tab | +| 1 | ✅ | **Datenfundament** — Plan-Datenmodell + localStorage CRUD | +| 2 | ✅ | **Tab-Grundgerüst** — Plan-Liste, Ordner, Mechanik-Timeline | +| 3 | ✅ | **Import aus Analyse-Tab** — Export-Button + Dialog + Merge | +| 4 | ✅ | **Jobaufstellung** — 8 Slots mit Job-Dropdown + Rollenfärbung | +| 5 | ✅ | **Ability-Zuweisung** — Modal-Picker + Rechtsklick-Remove + Äquivalenz-Hints | +| 6 | 🔜 | **Gantt-Chart** — Recast-Konflikte + DR%-Anzeige (s. unten) | +| 7 | 🔜 | **Analyse-Overlay** — geplante vs. tatsächlich genutzte CDs | -Schritte 1–3 = nutzbarer MVP. Schritte 4–6 = praktisch einsetzbar. 7–9 = Power-Features. +### Gantt-Chart — Design-Entscheidungen (Schritt 6) + +**Konzept:** Ergänzende Ansicht zur Mechaniken-Übersicht, nicht Ersatz. Umschaltbar per Toggle/Tab. + +**Layout:** +- X-Achse: Kampfzeit (0 bis Kampfende aus `source.fightEnd - source.fightStart`) +- Linke Spalte: Ability-Icons (eine Zeile pro eingesetzter Ability im Plan) — Zeilengranularität TBD +- Vertikale Linien: Mechaniken-Timestamps +- Farbige Balken: Ability aktiv (Dauer) + Cooldown-Bereich danach (gedimmt) +- Konflikte: wenn ein Balken eine Mechaniken-Linie überlappt = visuell hervorgehoben + +**Drag & Drop:** +- Ability-Icons aus Palette auf Timeline ziehen → Icon am Startpunkt, Balken zeigt Dauer +- Freies Ziehen ohne Snapping — Timestamp wird aus X-Position berechnet +- Bestehende Balken sind ebenfalls verschiebbar + +**Update-Button:** +- Gleicht Gantt-Positionen mit Mechaniken ab +- Matching-Logik: TBD (Overlap oder nächste Mechanik) — noch zu klären +- Aktualisiert Plan-Assignments entsprechend + +**DR-Simulation:** +- Pro Mechanik: `simulierter Schaden = unmitigiert × ∏(1 − dr_i)` für alle zugewiesenen Buffs/Debuffs +- Wird in der **Mechaniken-Übersicht** unter dem unmitigierten Schadenswert angezeigt +- Schilde werden **nicht** simuliert (Schildwerte nicht verlässlich aus Log ableitbar) +- Kein Pass/Fail-Urteil — nur der errechnete Zahlenwert, User entscheidet selbst + +**Recast-Daten:** `data/recast-times.json` — noch zu befüllen. Enthält Cooldown-Dauer (s) und Aktiv-Dauer (s) pro Ability: +```json +{ "Reprisal": { "recast": 60, "duration": 10 }, "Feint": { "recast": 90, "duration": 10 } } +``` ### UI-Paradigma - Visuell dem Analyse-Tab ähneln (Cards, gleiche CSS-Variablen, einheitliches Look & Feel) -- Mechaniken als vertikale Timeline-Cards +- Mechaniken als vertikale Timeline-Cards — primäre Bearbeitungsfläche bleibt erhalten - Ability-Picker als **Modal** (kein Inline-Dropdown) +- Gantt als zusätzliche Ansicht für den Planer (derjenige der die CDs koordiniert) - Nicht für mobile Geräte ausgelegt ### Spell-Verfügbarkeit nach Job @@ -324,31 +360,39 @@ Jobaufstellung → verfügbare Abilities (Subset von `MITIGATION_ABILITIES`): | RDM | Addle, Magick Barrier | | PCT | Addle, Tempera Coat, Tempera Grassa | -### Job-Äquivalente (`data/ability-equivalents.json`) -Abilities die funktional gleich sind aber unterschiedliche Namen haben — relevant beim Job-Wechsel im Slot: +### Job-Äquivalente (in `planner.js` als `ABILITY_EQUIVALENTS`) +Abilities die funktional gleich sind aber unterschiedliche Namen haben — zeigt Hinweis bei fehlendem Job. +Kein automatischer Austausch — nur Hinweis in rot/grün unter dem ausgegrauten Badge. | Gruppe | Abilities | |---|---| | 15% Party-Mitigation | Troubadour, Tactician, Shield Samba | | 10% Ground-Barrier | Sacred Soil, Kerachole | -Reprisal, Feint und Addle sind identische Ability-Namen über Jobs hinweg — kein Mapping nötig, die gleiche Ability bleibt einfach bestehen. +Reprisal, Feint und Addle sind identische Ability-Namen über Jobs hinweg — kein Mapping nötig. -**Verhalten beim Job-Wechsel:** Assignment wird auto-substituiert wenn Äquivalent für neuen Job existiert (mit Hinweis "automatisch gemappt"). Kein Äquivalent → Assignment ausgegraut (nicht gelöscht, Nutzer entscheidet). +### `extraAbilityGameID` in MITIGATION_ABILITIES (geplant) +Jeder Eintrag in `MITIGATION_ABILITIES` soll ein `actionId`-Feld bekommen — die echte Action-Row-ID aus FFLogs (`applybuff`-Event → `extraAbilityGameID`). Diese ID entspricht direkt der XIVAPI Action-Sheet-Row-ID und ermöglicht automatischen Icon-Lookup: +- 5-stellige IDs: führende 0 ergänzen falls XIVAPI 6 Stellen erwartet +- Lookup: `https://v2.xivapi.com/api/sheet/Action/{actionId}?fields=Name,Icon` +- Ermöglicht künftig automatisches Icon-Fetching statt manueller `MITIG_ICONS`-Pflege ### Recast-Zeiten (`data/recast-times.json`) -Wird für Konflikt-Erkennung benötigt (Schritt 6). Vollständige Liste wird beim Implementieren vervollständigt, Beispiele: -- Reprisal: 60s -- Feint / Addle: 90s -- Dark Missionary / Heart of Light: 90s -- Troubadour / Tactician / Shield Samba: 120s -- Temperance: 120s +Format: `{ "Ability": { "recast": 60, "duration": 10 } }` — noch zu befüllen. +Bekannte Werte (Beispiele): +- Reprisal: recast 60s, duration 10s +- Feint / Addle: recast 90s, duration 10s +- Dark Missionary / Heart of Light: recast 90s, duration 15s +- Troubadour / Tactician / Shield Samba: recast 120s, duration 15s +- Temperance: recast 120s, duration 20s +- Sacred Soil / Kerachole: recast 30s, duration 15s ### Technische Entscheidungen -- **Persistenz:** `localStorage` unter `ff14-planner-plans` — kein Backend nötig -- **IDs:** `crypto.randomUUID()` für Plan- und Mechanik-IDs +- **Persistenz:** `localStorage` — kein Backend nötig +- **IDs:** `crypto.randomUUID()` für Plan-, Mechanik- und Ordner-IDs +- **Eindeutige Namen:** `uniquePlanName()` verhindert Duplikate beim Erstellen und Importieren - **Keine Spielernamen:** Assignments sind Job-basiert (`{ ability, job }`), damit Pläne übertragbar sind -- **Kein Ability-Stacking:** FFXIV erlaubt keine doppelte Anwendung derselben Ability — jede Ability kommt pro Mechanik maximal einmal vor, doppelte Instanzen desselben Jobs im Static sind daher kein Sonderfall -- **Analyse-Overlay (Schritt 9):** Job aus tatsächlichem Pull → lookup welche Ability dieser Job im Plan hatte → Soll/Ist-Vergleich (kein Spielername-Matching nötig) -- **Shield-Attribution:** Aktuell nicht lösbar — `absorbed` im `damage`-Event ist ein Gesamtwert ohne Aufschlüsselung per Shield. Zu untersuchen: ob `calculatedheal`-Events die Shield-Kapazität beim Auftragen mitliefern. Vorerst zurückgestellt. -- **Plan kopieren:** Duplicate-Funktion für Plan-Varianten ("Week 3 v2") ohne Original zu verlieren +- **Kein Ability-Stacking:** FFXIV erlaubt keine doppelte Anwendung derselben Ability pro Mechanik +- **Shield-Attribution:** Nicht simulierbar — `absorbed` ist Gesamtwert ohne Aufschlüsselung. Bewusst weggelassen. +- **DR-Simulation:** Nur Buffs/Debuffs mit bekanntem `dr`-Wert aus `MITIGATION_ABILITIES`. Ergebnis als Zahlenwert, kein Pass/Fail. +- **fight.php:** Immer englischer Endpoint (`www.fflogs.com`) für stabile Fight-Namen unabhängig von Spracheinstellung