20 Commits
Author SHA1 Message Date
Mquadrat fac63b2d19 Add files via upload 2026-10-07 22:48:10 +02:00
Mquadrat b6db62d7dc Update README.md 2026-10-06 10:09:24 +02:00
Mquadrat 934e0047b0 Add files via upload 2026-10-06 10:08:02 +02:00
Mquadrat d0a3bbfa9b Update README.md 2026-10-05 18:52:09 +02:00
Mquadrat 86cfea6b76 Add files via upload 2026-10-05 18:50:57 +02:00
Mquadrat 38c3accf14 Update README.md 2026-09-12 09:24:18 +02:00
Mquadrat e6f98eb65a Update README.md 2026-09-12 09:23:48 +02:00
Mquadrat 12e0f0dfe0 Update README.md 2026-09-12 09:23:14 +02:00
Mquadrat 08a4abbfe5 Add files via upload 2026-09-12 09:22:48 +02:00
Mquadrat 87075c8c54 Update README.md 2026-09-11 19:38:22 +02:00
Mquadrat f0704bbd5c Update README.md 2026-09-11 19:33:07 +02:00
Mquadrat 4d961b4c4a Add files via upload 2026-09-11 19:32:29 +02:00
Mquadrat 46bfcd966b Update README.md 2026-09-11 19:18:59 +02:00
Mquadrat 28564b230f Update CHANGELOG.md 2026-09-11 19:17:26 +02:00
Mquadrat 2b57864a47 Add files via upload 2026-09-11 19:16:52 +02:00
Mquadrat 728a3ab5c6 Update README.md 2026-09-09 08:14:06 +02:00
Mquadrat f527200b77 Update CHANGELOG.md 2026-09-09 08:07:19 +02:00
Mquadrat be2844dc87 Update README.md 2026-09-09 08:04:16 +02:00
Mquadrat 4a40166251 Update README.md 2026-09-09 08:03:29 +02:00
Mquadrat f3de187efc Add files via upload 2026-09-09 08:02:31 +02:00
6 changed files with 1453 additions and 177 deletions
+157
View File
@@ -1,5 +1,162 @@
# Changelog
## 1.4.6 (2026-10-06)
Performance pass over the display loop, with no change in behaviour: only the units that actually changed are redrawn, and two loops that ran empty five times a second now stop early.
### English
**Performance**
- **Only the units that changed are redrawn.** The 0.2 second pass used to set a single dirty flag: if any heal over time ticked anywhere, everything was redrawn, which in a full raid meant forty cells plus ten plates although exactly one unit had changed. The pass now collects the affected unit names in a reused table and hands them to `FBHealBox_RefreshUnitsByName`, and the raid module picks up the same list through the new `RefreshNames` hook. With several HoTs running this turns three to five full sweeps a second into at most one plus a handful of single-unit updates.
- **A full sweep stays as a safety net.** At most once a second, and only while something is actually changing, the old full refresh still runs, so a name that does not match a plate for any reason can never leave a stale bar behind for longer than that.
- **Empty leftovers are cleared.** When the last heal over time or the last foreign heal on a unit expires, the now-empty sub-table is removed instead of being left behind. Several places read `FBHoTs[name]` as "is anything running on this unit", and an empty table answered yes.
- **Raid spell timers skip cells with nothing to show.** The intent to skip was already in the code but the result was thrown away two lines later, so the button loop ran anyway: in a full raid that was 160 do-nothing calls five times a second. The cell is now skipped outright, exactly as the plates already did.
- **Spell timers get an early out.** When no heal over time and no shield of yours is running anywhere, the plate loop no longer asks every slot for its unit and name five times a second; it only looks where a timer still has to be cleared. Classes without HoTs and the time between fights benefit.
**Checked and left alone**
- The three `OnUpdate` loops do no unnecessary work. The prediction checks three dirty flags and two counters per frame, the mana ticker leaves at its gate (a full mana bar means no pass at all), and the raid ghost ticker is hidden outside test mode. Event handling filters unit events through a lookup table rather than walking every frame.
- The global cooldown has been drawn as a sweep since 1.4.5.1, which means every visible button gets a fresh sweep after every cast. That is the intended behaviour and the animation runs in the client, not in Lua, so it stays. Should it ever feel heavy in a dense raid, `FBCD_SHOW_MIN` set to 2 limits the sweep to real cooldowns again.
### Deutsch
**Leistung**
- **Nur noch die Einheiten neu zeichnen, bei denen sich etwas geaendert hat.** Der 0,2-Sekunden-Takt setzte bisher ein einziges Dirty-Flag: Lief irgendwo ein HoT-Tick ab, wurde alles neu gezeichnet, im Vierzigerraid also vierzig Zellen und zehn Plaketten, obwohl sich bei genau einer Einheit etwas geaendert hatte. Der Takt sammelt die betroffenen Namen jetzt in einer wiederverwendeten Tabelle und reicht sie an `FBHealBox_RefreshUnitsByName`; das Raidmodul bekommt dieselbe Liste ueber den neuen Hook `RefreshNames`. Mit mehreren laufenden HoTs werden aus drei bis fuenf vollen Durchlaeufen je Sekunde hoechstens einer plus eine Handvoll Einzel-Updates.
- **Der volle Durchlauf bleibt als Sicherheitsnetz.** Hoechstens einmal je Sekunde, und nur solange sich ueberhaupt etwas aendert, laeuft er weiterhin. Ein Name, der aus irgendeinem Grund zu keiner Plakette passt, kann so nie laenger als eine Sekunde einen alten Balken stehen lassen.
- **Leere Reste werden weggeraeumt.** Laeuft der letzte HoT oder die letzte fremde Heilung auf einer Einheit ab, verschwindet die nun leere Untertabelle, statt liegen zu bleiben. Mehrere Stellen lesen `FBHoTs[name]` als "laeuft da ueberhaupt etwas", und eine leere Tabelle hat darauf mit ja geantwortet.
- **Raid-Zaubertimer ueberspringen Zellen ohne Anzeige.** Die Absicht zu ueberspringen stand schon im Code, das Ergebnis wurde aber zwei Zeilen spaeter wieder verworfen, sodass die Buttonschleife trotzdem lief: im Vierzigerraid 160 Leeraufrufe fuenfmal je Sekunde. Die Zelle wird jetzt wirklich uebersprungen, genau wie es die Plaketten laengst machen.
- **Zaubertimer steigen frueher aus.** Laeuft nirgends ein eigener HoT und kein eigener Schild, fragt die Plakettenschleife nicht mehr fuenfmal je Sekunde jeden Slot nach Einheit und Namen, sondern schaut nur noch dort hinein, wo ein Timer wegzuraeumen ist. Davon profitieren Klassen ohne HoTs und die Zeit zwischen den Kaempfen.
**Geprueft und so gelassen**
- Die drei `OnUpdate`-Schleifen arbeiten nicht unnoetig. Die Vorhersage prueft je Frame drei Dirty-Flags und zwei Zaehler, der Mana-Ticker steigt am Torwaechter aus (voller Manabalken heisst gar kein Durchlauf), und der Geister-Ticker im Raid ist ausserhalb des Testmodus versteckt. Die Ereignisverarbeitung filtert Unit-Events ueber eine Nachschlagetabelle, statt je Frame zu suchen.
- Der globale Cooldown laeuft seit 1.4.5.1 als Uhr mit, das heisst nach jedem Zauber bekommt jeder sichtbare Button eine neue Uhr gesetzt. Das ist das gewollte Verhalten, und die Animation laeuft im Client, nicht in Lua, deshalb bleibt es so. Sollte es im dichten Raid doch schwer wirken, beschraenkt `FBCD_SHOW_MIN` auf 2 die Uhr wieder auf echte Abklingzeiten.
## 1.4.5.3 (2026-10-05)
A readability option suggested by a user: the area behind the bars can be given a solid background, so the game world no longer shows through where health is missing.
### English
**New**
- **Bar background.** New slider *Bar background* on the *General* tab, 0 to 100 per cent in steps of 5. At 0, which is the default, nothing changes: the plate stays see-through and grass, sky or stone show through the empty part of the health bar. Turned up, a quiet dark grey surface sits behind the bars, so the green of the health bar stands on a fixed background. At 100 the plate is opaque. The shade is `FBBAR_BG_COLOR` (0.15 grey) and the setting is kept per character in `HealBox.BarBG`.
- **Where it sits.** The texture hangs on the lowest of the four stacked bars, the incoming-heal bar, on the `BACKGROUND` layer. That puts it under the prediction, the shield, the health and the mana bar, and it is shown and hidden together with them, so nothing is left behind on a plate that is currently empty or hidden by the attach mode. At 0 per cent no texture is set at all, rather than a fully transparent one.
- **Raid cells need nothing.** They already have their own backdrop at 80 per cent black, so there is no world shining through there; the slider deliberately only touches the plates.
**Thanks**
- The idea and a working patch came from a user who finds the translucent bar hard to read. The patch used `WHITE8X8` plus `SetVertexColor`; the version shipped here uses `SetTexture(r, g, b, a)`, which creates a solid colour directly in 1.12 and is what the mana strip already does. Same result, no texture file involved.
### Deutsch
**Neu**
- **Balkenhintergrund.** Neuer Regler *Balkenhintergrund* im Reiter *Allgemein*, 0 bis 100 Prozent in Fuenferschritten. Bei 0, dem Standard, aendert sich nichts: Die Plakette bleibt durchscheinend, durch den leeren Teil des Lebensbalkens sieht man Gras, Himmel oder Stein. Hochgedreht liegt eine ruhige dunkelgraue Flaeche hinter den Balken, das Gruen des Lebensbalkens steht dann auf festem Grund. Bei 100 ist die Plakette undurchsichtig. Der Grundton ist `FBBAR_BG_COLOR` (0,15 Grau), die Einstellung bleibt je Charakter in `HealBox.BarBG` gespeichert.
- **Wo die Flaeche haengt.** Die Textur sitzt auf der untersten der vier gestapelten Balken, der Heilvorhersage, auf der Ebene `BACKGROUND`. Damit liegt sie unter Vorhersage, Schild, Leben und Mana, und sie wird zusammen mit ihnen ein- und ausgeblendet; auf einer leeren oder im Anheftmodus versteckten Plakette bleibt also nichts stehen. Bei 0 Prozent wird gar keine Textur gesetzt statt einer voellig durchsichtigen.
- **Raidzellen brauchen nichts.** Sie haben bereits ihren eigenen Hintergrund mit 80 Prozent Schwarz, dort scheint keine Welt durch; der Regler fasst bewusst nur die Plaketten an.
**Dank**
- Idee und ein lauffaehiger Patch kamen von einem Nutzer, dem der durchscheinende Balken schlecht lesbar ist. Der Patch benutzte `WHITE8X8` mit `SetVertexColor`; hier ausgeliefert wird `SetTexture(r, g, b, a)`, das in 1.12 direkt eine Vollfarbe erzeugt und genau das ist, was der Manastreifen ohnehin schon macht. Gleiches Ergebnis, ohne Texturdatei.
## 1.4.5.2 (2026-09-12)
One fix: a running HoT no longer pulls Smart Healing down a rank.
### English
**Fixed**
- **A HoT on the target no longer talks Smart Healing into a lower rank.** The full healing still owed by a running HoT was subtracted from the deficit as if it had already landed, so a ticking Renew could turn a Heal rank 4 into a Lesser Heal. Only healing that arrives right away is deducted now, meaning direct heals and spells reported over HealComm, roughly one to three seconds out; HoTs stay out of the calculation because they spread their healing over up to fifteen seconds. They are of course still shown on the bar, and the rule that HoTs are never downranked themselves is untouched.
### Deutsch
**Behoben**
- **Ein HoT auf dem Ziel redet Smart Healing keinen kleineren Rang mehr ein.** Die noch offene Heilung eines laufenden HoT wurde vom Fehlbetrag abgezogen, als waere sie schon angekommen; ein tickendes Erneuerung konnte so aus einem Heilen Rang 4 ein Geringes Heilen machen. Abgezogen wird jetzt nur noch Heilung, die gleich ankommt, also Direktheilungen und ueber HealComm gemeldete Zauber, grob ein bis drei Sekunden; HoTs bleiben aus der Rechnung heraus, weil sie ihre Heilung ueber bis zu fuenfzehn Sekunden verteilen. Angezeigt werden sie auf dem Balken selbstverstaendlich weiterhin, und die Regel, dass HoTs selbst nie abgerangt werden, bleibt unberuehrt.
## 1.4.5.1 (2026-09-11)
Button and ticker fixes: the mana ticker spark moves smoothly again, and the global cooldown no longer greys out every button but runs as a sweep instead.
### English
**Fixed**
- **The mana ticker spark moves smoothly again.** The spark was only redrawn once it had travelled half a pixel. That sounds frugal, but it crosses the bar in five seconds, roughly 20 pixels per second, so at 60 frames it advanced on every second frame at best and, depending on rounding, sometimes after one frame and sometimes after two. That uneven step was the stutter, and the fixed 0.03 second redraw step introduced in 1.4.5 made it worse. The threshold is now effectively gone (0.05 px) and the spark is drawn every frame again, which doubles its motion from 30 to 60 steps per second with an even gap.
- **Drawing every frame still costs nothing.** Each spark remembers the width and height of its bar and re-reads them four times a second (`FBTICK_GEOM_STEP`) instead of asking the frame on every pass, and the gate check sits in front of it all: with a full mana bar there is no pass at all.
- **The global cooldown no longer darkens every button.** After casting anything, the client reports every spell as unusable for the length of the global cooldown. Taken literally, that turned all icons dark grey for a second and a half after every cast, as if nothing were available at all. A running cooldown no longer than the global one (`FBCD_MIN_DURATION`) is no longer treated as a reason to darken a button. Blue for missing mana, red for out of range and grey for a spell that really cannot be cast, for instance in the wrong shapeshift form, all work as before. This affects the plates and the raid cells alike, both go through `FBHealBox_ButtonUsable`.
- **It runs as a sweep instead.** Not showing it at all was the other half of the inconsistency: an instant like Renew or Abolish Disease left every button untouched, while Power Word: Shield, which has a real cooldown in 1.12, showed one. The sweep is the calm way to show a short wait, so after every cast you watch it run out on all buttons, the way the action bars do it.
- **Two thresholds instead of one.** The display threshold moved into its own constant `FBCD_SHOW_MIN` (0, show every running cooldown) and is no longer tied to `FBCD_MIN_DURATION` (2), which now only answers whether a cooldown is a reason to darken a button. The two were the same value before, which is why showing the global cooldown and not darkening for it could not be had at the same time. Setting `FBCD_SHOW_MIN` to 2 restores the quiet display. A cooldown is also only shown when one is really running (`cd[1] > 0`), and the sweep starts in the very next frame because the button pass is not throttled.
### Deutsch
**Behoben**
- **Der Funke im Manabalken laeuft wieder rund.** Neu gezeichnet wurde er erst, wenn er einen halben Pixel weitergewandert war. Das klingt sparsam, er braucht fuer den Balken aber fuenf Sekunden, also rund 20 Pixel je Sekunde: Bei 60 Bildern kam er damit bestenfalls in jedem zweiten Frame voran und je nach Rundung mal nach einem, mal nach zwei Frames. Genau dieser ungleiche Schritt war das Ruckeln, und der feste Zeichentakt von 0,03 Sekunden aus 1.4.5 hat es verstaerkt. Die Schwelle ist jetzt praktisch weg (0,05 px) und gezeichnet wird wieder in jedem Frame, das verdoppelt die Bewegung von 30 auf 60 gleichmaessige Schritte je Sekunde.
- **Das Zeichnen je Frame kostet trotzdem nichts.** Jeder Funke merkt sich Breite und Hoehe seines Balkens und liest sie viermal je Sekunde nach (`FBTICK_GEOM_STEP`), statt sie bei jedem Durchlauf zu erfragen, und der Torwaechter sitzt weiterhin davor: Bei vollem Manabalken laeuft gar kein Durchlauf.
- **Der globale Cooldown dunkelt nicht mehr alle Buttons ab.** Nach jedem gewirkten Zauber meldet der Client fuer die Dauer des globalen Cooldowns saemtliche Zauber als nicht nutzbar. Woertlich genommen wurden dadurch nach jedem Zauber anderthalb Sekunden lang alle Symbole dunkelgrau, als waere gar nichts mehr verfuegbar. Eine laufende Abklingzeit, die nicht laenger ist als der globale Cooldown (`FBCD_MIN_DURATION`), gilt jetzt nicht mehr als Grund zum Abdunkeln. Blau fuer fehlendes Mana, Rot fuer ausser Reichweite und Grau fuer einen Zauber, der wirklich nicht geht, etwa in der falschen Gestalt, arbeiten unveraendert weiter. Das gilt fuer Plaketten und Raidzellen gleichermassen, beide laufen ueber `FBHealBox_ButtonUsable`.
- **Stattdessen laeuft er als Uhr mit.** Ihn gar nicht zu zeigen war die andere Haelfte der Ungereimtheit: Ein Instant wie Erneuerung oder Krankheit aufheben liess alle Buttons unberuehrt, waehrend Machtwort: Schild, das in 1.12 eine echte Abklingzeit hat, eine Uhr zeigte. Die Uhr ist die ruhige Art, eine kurze Wartezeit anzuzeigen: Nach jedem Zauber laeuft sie auf allen Buttons ab, so wie es die Aktionsleisten machen.
- **Zwei Schwellen statt einer.** Die Anzeigeschwelle sitzt jetzt in einer eigenen Konstante `FBCD_SHOW_MIN` (0, also jede laufende Abklingzeit zeigen) und haengt nicht mehr an `FBCD_MIN_DURATION` (2), die nur noch beantwortet, ob eine Abklingzeit ein Grund zum Abdunkeln ist. Vorher war beides derselbe Wert, deshalb liess sich "globalen Cooldown zeigen" und "wegen ihm nicht abdunkeln" nicht gleichzeitig haben. Wer `FBCD_SHOW_MIN` auf 2 setzt, hat die ruhige Anzeige zurueck. Gezeigt wird ausserdem nur, wenn wirklich eine Abklingzeit laeuft (`cd[1] > 0`), und die Uhr startet im naechsten Frame, weil der Button-Durchgang nicht gedrosselt ist.
## 1.4.5 (2026-09-08)
Three additions around the frames and the prediction: Blizzard's party frames can go away, the resource bar is no longer reserved for mana, and gear healing is counted where an API can supply it. Plus a performance pass with no change in behaviour.
### English
**New & Changed**
- **Hide Blizzard party frames.** New switch on the *General* tab that hides `PartyMemberFrame1` to `4` while you are grouped, leaving only the Heal Box plates. Off by default. Blizzard shows those frames again on every roster change, so the addon hooks their `OnShow` once instead of hiding them a single time; a frame that reappears is hidden again in the same moment.
- **Mutually exclusive with the attach mode.** *Default party frames* docks the plates onto exactly those frames, so the two options can never both be on. Whichever one is ticked disables and greys out the other (`FBHealBox_UpdatePartyExclusion`), and `FBHealBox_HideBlizzPartyActive()` re-checks the same rule in code for saved settings that were edited by hand. Switching the option off brings the frames back immediately, and so does the class gate: an addon that stays asleep for warriors, rogues and hunters returns the frames as well.
- **Rage, energy and focus in the resource bar.** The thin strip under the health bar used to be reserved for mana and stayed empty for everyone else. New switch *Show rage, energy, focus* on the *General* tab gives every unit its own resource in its usual colour, from the new table `FBPOWER_COLORS`: mana blue, rage red, focus orange, energy yellow. `FBUnitMana()` now returns the power type as a fourth value, and both the plates and the raid cells colour their bar from it. Off by default, and it still needs the mana bar to be on.
- **Equipment healing bonus in the prediction.** Vanilla spell tooltips show the naked base value; the bonus from your gear is missing. Learned values from the combat log carry it automatically, so the gap only affected ranks you had never cast. `FBHealBox_ProbeHealBonus()` now looks for `GetSpellBonusHealing`, `GetSpellBonusHeal` and `GetHealingBonus`, first as globals and then inside a `ClassicAPI` table, and `FBPredict_ExpectedDirect()` adds the share that belongs to the spell.
- **Weighted the vanilla way.** The bonus counts as cast time divided by 3.5, capped at 3.5 seconds, with instants counting as 1.5 and an unreadable cast time as 2.5. Cast time is read once per spellbook slot from the tooltip (`FBHealBox_SpellCastSeconds`, right-hand side of line 2), so a 3 second Greater Heal takes 600 of a +700 bonus and a 1.5 second Flash Heal takes 300. Without a suitable API the bonus stays 0 and nothing about the old behaviour changes.
- **New command `/fbp healbonus`.** Turns the equipment bonus off and on, saved per character in `HealBox.HealBonus` (on by default). `/fbp` reports the value found and whether it is being applied; the command says so when no API supplies a bonus at all.
**Performance (no change in behaviour)**
- **Own buff timers read once per frame.** `FBPredict_PlayerBuffTimeLeft` used to walk the whole player buff list once per watched buff, calling `strupper` on every texture along the way: with six watches and thirty buffs that was around 200 API calls and 200 throwaway strings a second. The list is now read once per frame into a texture-to-seconds map (`FBPredict_ScanPlayerBuffTimes`), the way `FBHealBox_UnitBuffs` already worked, and every watch is served from it. Texture paths are upper-cased once and remembered (`FBHealBox_UpperTex`), which also removes the same allocation from the unit buff scan.
- **Range and line of sight in raid mode are spread over several ticks.** `FBRaid_Tick` used to check up to 40 cells in one frame every half second. It now walks a quarter of the groups per tick at a quarter of the interval (`FBRAID_TICK_SLICES`), so a full sweep still takes the same half second while the peak load per frame drops to a quarter.
- **`pcall` per sweep instead of per unit.** Range, distance and line of sight went through a protected call for every single unit, up to 160 a second in a full raid. The first successful call now marks the form as safe and the individual calls go straight through, while the sweep as a whole stays protected: one `pcall` per pass in `FBHealBox_CheckRangeAll`, `FBHealBox_CheckLOSAll` and `FBRaid_Tick`. A client that throws on the very first call keeps the old per-call protection and its fallback path.
- **Self-healing if an API throws late.** Should a sweep throw after the form had already proven itself, `FBHealBox_ApiFailed()` puts all three queries back to the protected single call, where the error is caught and the fallback takes over as before. The frame is never torn open, and at worst one pass is skipped.
- **Raid health text no longer builds strings it throws away.** The percentage and deficit texts were formatted before the change check, so every `UNIT_HEALTH` in a 40 man raid produced a string that was usually discarded immediately. The cell now compares the number and only formats on a real change, the way the plates always did.
- **Cheap pre-test before the combat log patterns.** Up to four anchored patterns ran on every message from twenty registered events. A plain substring test now filters first, with the words cut out of the client's own message templates so it works in every language. The tick test deliberately comes from the self template, because "You gain" and "%s gains" differ in the verb but share what follows.
- **Equipment bonus read once instead of per candidate.** With heal chains a single Smart Healing click asked the API for the bonus up to fifteen times. The value is now remembered and dropped again on `UNIT_INVENTORY_CHANGED` or a spellbook rebuild.
- **Cast time comes free with the spell scan.** `FBHealBox_SpellCastSeconds` used to build its own tooltip on a cache miss, which could mean a dozen tooltip builds in the middle of combat on the first click. `FBPredict_TooltipText` now picks the cast time off the right-hand side while the tooltip is standing anyway and fills the cache; the standalone scan remains only as a fallback. The cast time is deliberately kept out of the parsed text, because a number like 2.5 would confuse the shield duration and heal amount patterns.
- **Smaller things.** The range spell of the first assigned button is remembered instead of being searched over ten slots on every range check (invalidated on rebinding and on a spellbook rebuild). The ticker redraws on a fixed 0.03 second step instead of every frame (taken back in 1.4.5.1, it made the spark stutter). Blizzard's party frames are re-evaluated in the same collection point as the name updates instead of on every event of a burst. Two `or {}` fallbacks in loops no longer allocate a throwaway table.
### Deutsch
**Neu & Geaendert**
- **Blizzards Gruppenfenster ausblenden.** Neuer Schalter im Reiter *Allgemein*, der `PartyMemberFrame1` bis `4` versteckt, solange du in einer Gruppe bist, sodass nur die Plaketten der Heal Box uebrig bleiben. Standardmaessig aus. Blizzard zeigt diese Frames bei jeder Gruppenaenderung neu an, deshalb haengt sich das Addon einmalig in deren `OnShow` statt sie nur einmal zu verstecken; ein Frame, der wieder auftaucht, verschwindet im selben Moment erneut.
- **Schliesst sich mit dem Anheftmodus aus.** *Standard-Gruppenfenster* haengt die Plaketten genau an diese Frames, beide Optionen koennen also nie zusammen an sein. Was angehakt ist, sperrt und graut das andere aus (`FBHealBox_UpdatePartyExclusion`), und `FBHealBox_HideBlizzPartyActive()` prueft dieselbe Regel im Code noch einmal nach, fuer von Hand bearbeitete gespeicherte Werte. Ausschalten holt die Frames sofort zurueck, ebenso die Klassensperre: Ein Addon, das fuer Krieger, Schurken und Jaeger schlaeft, gibt die Frames mit zurueck.
- **Wut, Energie und Fokus im Ressourcenbalken.** Der schmale Streifen unter dem Lebensbalken war dem Mana vorbehalten und blieb bei allen anderen leer. Der neue Schalter *Wut, Energie, Fokus zeigen* im Reiter *Allgemein* gibt jeder Einheit ihre eigene Ressource in der gewohnten Farbe, aus der neuen Tabelle `FBPOWER_COLORS`: Mana blau, Wut rot, Fokus orange, Energie gelb. `FBUnitMana()` liefert die Energieart jetzt als vierten Rueckgabewert, Plaketten und Raidzellen faerben ihren Balken danach. Standardmaessig aus, und der Manabalken muss weiterhin an sein.
- **Heilbonus der Ausruestung in der Vorhersage.** Vanilla-Tooltips zeigen den nackten Grundwert, der Bonus der Ausruestung fehlt darin. Gelernte Werte aus dem Combatlog tragen ihn von selbst, die Luecke betraf also nur Raenge, die nie gewirkt wurden. `FBHealBox_ProbeHealBonus()` sucht jetzt nach `GetSpellBonusHealing`, `GetSpellBonusHeal` und `GetHealingBonus`, erst als globale Funktion, dann in einer `ClassicAPI`-Tabelle, und `FBPredict_ExpectedDirect()` schlaegt den Anteil auf, der auf den Zauber entfaellt.
- **Gewichtet wie in Vanilla ueblich.** Der Bonus zaehlt mit Zauberzeit geteilt durch 3,5, gedeckelt bei 3,5 Sekunden, Instants rechnen mit 1,5 und eine unlesbare Zauberzeit mit 2,5. Die Zauberzeit wird einmal je Zauberbuchplatz aus dem Tooltip gelesen (`FBHealBox_SpellCastSeconds`, rechte Seite der zweiten Zeile). Eine Grosse Heilung mit 3 Sekunden nimmt von +700 Heilung also 600 mit, eine Blitzheilung mit 1,5 Sekunden 300. Ohne passende API bleibt der Bonus 0 und am bisherigen Verhalten aendert sich nichts.
- **Neuer Befehl `/fbp healbonus`.** Schaltet den Ausruestungsbonus aus und wieder ein, gespeichert je Charakter in `HealBox.HealBonus` (Standard an). `/fbp` nennt den gefundenen Wert und ob er angewandt wird; der Befehl sagt es, wenn ueberhaupt keine API einen Bonus liefert.
**Leistung (ohne Funktionsaenderung)**
- **Eigene Bufflaufzeiten einmal je Frame.** `FBPredict_PlayerBuffTimeLeft` lief bisher je ueberwachtem Buff einmal durch die gesamte Buffliste und rief dabei fuer jede Textur `strupper` auf: bei sechs Wachen und dreissig Buffs rund 200 API-Aufrufe und 200 Wegwerf-Strings je Sekunde. Die Liste wird jetzt einmal je Frame in eine Tabelle Textur nach Sekunden gelesen (`FBPredict_ScanPlayerBuffTimes`), genau wie es `FBHealBox_UnitBuffs` schon vormacht, und alle Wachen bedienen sich daraus. Texturpfade werden einmal gross geschrieben und gemerkt (`FBHealBox_UpperTex`), was dieselbe Zuteilung auch aus dem Buffscan der Einheiten nimmt.
- **Reichweite und Sichtlinie im Raid auf mehrere Ticks verteilt.** `FBRaid_Tick` pruefte alle halbe Sekunde bis zu 40 Zellen in einem einzigen Frame. Jetzt kommt je Tick ein Viertel der Gruppen dran, dafuer viermal so oft (`FBRAID_TICK_SLICES`): Der volle Durchlauf dauert weiterhin eine halbe Sekunde, die Spitzenlast je Frame sinkt auf ein Viertel.
- **`pcall` je Durchlauf statt je Einheit.** Reichweite, Abstand und Sichtlinie liefen fuer jede einzelne Einheit durch einen geschuetzten Aufruf, im Vierzigerraid bis zu 160 je Sekunde. Der erste erfolgreiche Aufruf erklaert die Form jetzt fuer sicher und die Einzelaufrufe gehen direkt hinein, der Durchlauf als Ganzes bleibt aber geschuetzt: ein `pcall` je Durchgang in `FBHealBox_CheckRangeAll`, `FBHealBox_CheckLOSAll` und `FBRaid_Tick`. Ein Client, der schon beim ersten Aufruf wirft, behaelt den geschuetzten Einzelaufruf samt Rueckfallweg.
- **Selbstheilung, wenn eine API doch spaet wirft.** Wirft ein Durchlauf, obwohl die Form sich vorher bewaehrt hatte, stellt `FBHealBox_ApiFailed()` alle drei Abfragen auf den geschuetzten Einzelaufruf zurueck, wo der Fehler abgefangen wird und der Rueckfall wie frueher greift. Der Frame wird nie aufgerissen, schlimmstenfalls faellt ein Durchgang aus.
- **Kein HP-Text im Raid, der gleich wieder weggeworfen wird.** Prozent- und Deficit-Text wurden vor dem Vergleich gebaut, jedes `UNIT_HEALTH` im Vierzigerraid erzeugte also einen String, der meist sofort verfiel. Die Zelle vergleicht jetzt die Zahl und formatiert nur bei echter Aenderung, so wie es die Plaketten immer schon tun.
- **Billiger Vortest vor den Combatlog-Mustern.** Bei jeder Meldung aus zwanzig registrierten Ereignissen liefen bis zu vier verankerte Muster. Ein einfacher Textvergleich filtert jetzt vorweg, mit Wortstuecken, die aus den Meldungsvorlagen des Clients geschnitten werden und damit in jeder Sprache passen. Der Tick-Vortest kommt bewusst aus der Selbst-Vorlage, weil sich "You gain" und "%s gains" im Verb unterscheiden, im Rest aber gleich sind.
- **Ausruestungsbonus einmal statt je Kandidat.** Mit Heilketten fragte ein einziger Smart-Healing-Klick die API bis zu fuenfzehnmal nach dem Bonus. Der Wert wird jetzt gemerkt und bei `UNIT_INVENTORY_CHANGED` oder einem Neuaufbau des Zauberbuchs wieder verworfen.
- **Zauberzeit faellt beim Auslesen der Zauber mit ab.** `FBHealBox_SpellCastSeconds` baute bei einem Fehlgriff einen eigenen Tooltip, was beim ersten Klick mitten im Kampf ein Dutzend Tooltip-Aufbauten bedeuten konnte. `FBPredict_TooltipText` liest die Zauberzeit jetzt nebenbei von der rechten Seite ab, solange der Tooltip ohnehin steht, und fuellt den Zwischenspeicher; der eigene Scan bleibt nur als Rueckfall. Der Wert kommt bewusst nicht in den ausgewerteten Text, weil eine Zahl wie 2.5 die Muster fuer Schilddauer und Heilbetrag durcheinanderbraechte.
- **Kleinigkeiten.** Der Reichweiten-Zauber des ersten belegten Buttons wird gemerkt, statt bei jeder Pruefung ueber zehn Plaetze zu suchen (verworfen beim Umbelegen und beim Neuaufbau des Zauberbuchs). Der Ticker zeichnet in einem festen Takt von 0,03 Sekunden statt in jedem Frame (in 1.4.5.1 zurueckgenommen, der Funke ruckelte dadurch). Blizzards Gruppenfenster werden im selben Sammelpunkt wie die Namen neu bewertet statt bei jedem Ereignis einer Salve. Zwei `or {}`-Rueckfaelle in Schleifen legen keine Wegwerf-Tabelle mehr an.
## 1.4.4.3 (2026-09-08)
Class gate, heal chains and a Smart Healing fix. The addon no longer loads its display for warriors, rogues and hunters, Smart Healing keeps its hands off heal over time spells, and downranking may now switch spell inside a heal chain.
+1068 -132
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -1,9 +1,9 @@
## Interface: 11200
## Title: Heal Box Vanilla |cFFFFFF00v1.4.4.3|r
## Title: Heal Box Vanilla |cFFFFFF00v1.4.6.1|r
## Notes: Heal/raid frame addon like Healium, with quick-cast buttons, heal prediction, mana ticker and more.
## Notes-deDE: Heal/Raidframe Addon aehnlich Healium, mit Schnellzugriff Buttons, Heal Prediction und Mana Ticker und mehr.
## Author: Dourd (Argent Dawn EU) | Vanilla-Port & Erweiterung 09/2026: Mquadrat
## Version: 1.4.4.3
## Version: 1.4.6.1
## SavedVariablesPerCharacter: HealBox
## OptionalDeps: SuperWoW
+99 -26
View File
@@ -28,7 +28,8 @@ FBRAID_MAX = 40;
FBRAID_GROUPS = 8;
FBRAID_PER_GROUP = 5;
FBRAID_MAX_BUTTONS = 4;
FBRAID_TICK = 0.5; -- Sek.: Reichweite und Sichtlinie
FBRAID_TICK = 0.5; -- Sek.: voller Durchlauf Reichweite und Sichtlinie
FBRAID_TICK_SLICES = 4; -- in so viele Haeppchen zerlegt (je 2 Gruppen)
FBRAID_MANA_H = 3; -- px Manastreifen in der Zelle
FBRAID_LOS_SIZE = 10; -- px Sichtlinien-Auge in der Zelle
FBRAID_HEADER_H = 12; -- px Gruppenkopf
@@ -289,6 +290,7 @@ FBRaidTestMode = 0; -- 0 | 20 | 40
FBRaidTestGhosts = {}; -- [i] = Geist-Datensatz (Testmodus)
FBRaidTickAccum = 0;
FBRaidDragging = false;
FBRaidAppliedScale = nil; -- zuletzt gesetzte Skalierung (FBRaid_LayoutAll)
function FBRaid_Cfg()
if (not HealBox.Raid) then FBRaid_ApplyDefaults(); end
@@ -437,8 +439,14 @@ end
function FBRaid_Mana(cell)
local g = cell.ghost;
if (g) then
if (not g.hasMana) then return 0, 0, false; end
return math.floor(g.mpMax * g.mp), g.mpMax, true;
if (not g.hasMana) then
-- Wut, Energie und Fokus nur, wenn der Kern sie zeigen soll
if (HealBox.PowerBar == 1) and (g.power) and (g.mpMax) then
return math.floor(g.mpMax * (g.mp or 0)), g.mpMax, true, g.power;
end
return 0, 0, false, nil;
end
return math.floor(g.mpMax * g.mp), g.mpMax, true, 0;
end
return FBUnitMana(cell.unit);
end
@@ -657,7 +665,12 @@ function FBRaid_CreateCell(g, pos)
if (FBDragSpell) then
local side = "L";
if (arg1 == "RightButton" or IsShiftKeyDown()) then side = "R"; end
if (FBHealBox_DropSpell(i, side)) then return; end
-- Nicht die Schleifenvariable i verwenden: Lua 5.0 (Client
-- 1.12) teilt sie zwischen allen hier erzeugten Closures, alle
-- vier Buttons saehen ihren Endwert und legten den Zauber
-- auf Button 4. b ist dagegen je Durchlauf eine neue lokale
-- Variable.
if (FBHealBox_DropSpell(b.btnIndex, side)) then return; end
end
if (FBRaidTestMode > 0) then
DEFAULT_CHAT_FRAME:AddMessage("|cFFFFFF00"..FBADDON_NAME..":|r "..FBT("RAID_TEST_CLICK"));
@@ -738,7 +751,7 @@ function FBRaid_UpdateRoster()
if (FBRaidCells[g] and FBRaidCells[g][pos]) then
local c = FBRaidCells[g][pos];
c.unit = nil; c.name = nil; c.ghost = nil; c.index = nil;
c.dispelKnown = nil; c.lastText = nil; c.lastMax = nil; c.colorKey = nil; c.manaShown = nil; c.lastMpMax = nil;
c.dispelKnown = nil; c.lastText = nil; c.lastPct = nil; c.lastDef = nil; c.lastMax = nil; c.colorKey = nil; c.manaShown = nil; c.lastMpMax = nil; c.powerType = nil;
c.vHp = nil; c.vShield = nil; c.vInc = nil; c.vMp = nil;
c:Hide();
end
@@ -820,7 +833,16 @@ function FBRaid_LayoutAll()
local titleH = 0;
if (cfg.ShowTitle == 1) then titleH = FBRAID_TITLE_H + 2; FBRaidFrame.Title:Show(); else FBRaidFrame.Title:Hide(); end
FBRaidFrame:SetScale(cfg.Scale or 1);
-- SetScale wertet die Ankerversaetze im neuen Massstab aus. Ohne erneutes
-- Verankern wanderte das Raster beim Ziehen am Regler und sprang erst
-- beim naechsten Rosterwechsel zurueck. Nur bei echter Aenderung, und
-- nie waehrend das Raster gerade gezogen wird.
local scale = cfg.Scale or 1;
if (FBRaidAppliedScale ~= scale) then
FBRaidAppliedScale = scale;
FBRaidFrame:SetScale(scale);
if (not FBRaidDragging) then FBRaid_RestorePosition(); end
end
local perRow = cfg.GroupsPerRow;
if (perRow < 1) then perRow = 1; end
@@ -940,6 +962,7 @@ function FBRaid_UpdateCell(c, auraChanged)
if (state == "ghost") then key = "STATE_GHOST"; end
if (state == "offline") then key = "STATE_OFFLINE"; end
FBRaid_SetText(c, FBT(key));
c.lastPct = nil; c.lastDef = nil; -- Zahlenspeicher gilt nicht mehr
FBRaid_SetMax(c, hpMax);
FBRaid_SetValues(c, 0, 0, 0);
FBRaid_SetColor(c, "state", 0.5, 0.5, 0.5, 1);
@@ -956,19 +979,29 @@ function FBRaid_UpdateCell(c, auraChanged)
if (incTop > hpMax) then incTop = hpMax; end
FBRaid_SetValues(c, hp, shieldTop, incTop);
-- HP-Text
-- HP-Text. Verglichen wird die Zahl, nicht der fertige Text: sonst baut
-- jedes UNIT_HEALTH einen String, der meist sofort wieder verworfen wird.
if (cfg.HPText == "percent") then
FBRaid_SetText(c, math.floor(hp / hpMax * 100).."%");
local pct = math.floor(hp / hpMax * 100);
if (c.lastPct ~= pct) then
c.lastPct = pct; c.lastDef = nil;
FBRaid_SetText(c, pct.."%");
end
elseif (cfg.HPText == "deficit") then
local def = hpMax - hp;
if (def > 0) then FBRaid_SetText(c, "-"..def); else FBRaid_SetText(c, ""); end
if (c.lastDef ~= def) then
c.lastDef = def; c.lastPct = nil;
if (def > 0) then FBRaid_SetText(c, "-"..def); else FBRaid_SetText(c, ""); end
end
else
c.lastPct = nil; c.lastDef = nil;
FBRaid_SetText(c, false);
end
-- Mana
local mp, mpMax, hasMana = FBRaid_Mana(c);
local mp, mpMax, hasMana, ptype = FBRaid_Mana(c);
if (cfg.ManaBar == 1 and hasMana and mpMax > 0) then
FBHealBox_SetPowerColor(c.ManaBar, c, ptype);
if (c.lastMpMax ~= mpMax) then c.lastMpMax = mpMax; c.ManaBar:SetMinMaxValues(0, mpMax); end
if (c.vMp ~= mp) then c.vMp = mp; c.ManaBar:SetValue(mp); end
if (c.manaShown ~= true) then c.manaShown = true; c.ManaBar:Show(); end
@@ -1075,21 +1108,25 @@ function FBRaid_UpdateSpellTimers(now)
for pos = 1, FBRAID_PER_GROUP do
local c = FBRaidCells[g][pos];
if (c) then
-- ohne verfolgten HoT/Schild auf der Einheit nur einmal ausblenden
local shown = on and c.unit and c:IsShown() and (c.ghost or FBHoTs[c.name] or FBShields[c.name]);
if (not shown and not c.timersShown) then shown = nil; end
c.timersShown = shown and true or false;
if (shown == nil) then shown = false; end
for i = 1, FBRAID_MAX_BUTTONS do
local b = c.buttons[i];
if (shown and b:IsShown()) then
local text, color = FBHealBox_SpellTimerFor(b.spellBase, c.name, now, c.ghost, i);
if (not text and b.spellBaseR) then
text, color = FBHealBox_SpellTimerFor(b.spellBaseR, c.name, now, nil, i);
local shown = on and c.unit and c:IsShown() and (c.ghost or FBHoTs[c.name] or FBShields[c.name]
or (FBWeakenedSoul and FBWeakenedSoul[c.name]));
-- Nichts anzuzeigen und nichts mehr wegzuraeumen: Zelle
-- ueberspringen. Vorher lief die Buttonschleife auch dann
-- durch, im Vierzigerraid 160 Leeraufrufe fuenfmal je
-- Sekunde. Der Kern macht es bei den Plaketten genauso.
if (shown or c.timersShown) then
c.timersShown = (shown and true) or false;
for i = 1, FBRAID_MAX_BUTTONS do
local b = c.buttons[i];
if (shown and b:IsShown()) then
local text, color = FBHealBox_SpellTimerFor(b.spellBase, c.name, now, c.ghost, i);
if (not text and b.spellBaseR) then
text, color = FBHealBox_SpellTimerFor(b.spellBaseR, c.name, now, nil, i);
end
FBHealBox_SetButtonTimer(b, text, color);
else
FBHealBox_SetButtonTimer(b, nil);
end
FBHealBox_SetButtonTimer(b, text, color);
else
FBHealBox_SetButtonTimer(b, nil);
end
end
end
@@ -1199,10 +1236,30 @@ function FBRaid_SyncButtons()
end
-- Reichweite, Sichtlinie und Geister-Atmung im Takt
-- Reichweite und Sichtlinie kosten je Zelle einen Aufruf ins Spiel hinein.
-- Bei acht Gruppen waeren das in einem Rutsch bis zu 80 Abfragen in einem
-- einzigen Frame. Deshalb wandert der Durchlauf in Haeppchen: je Tick nur
-- ein Teil der Gruppen, nach FBRAID_TICK_SLICES Ticks sind alle einmal dran.
-- Die Taktdauer ist entsprechend kuerzer, der volle Durchlauf dauert also
-- weiterhin FBRAID_TICK Sekunden. force = true macht alles auf einmal.
FBRaidTickSlice = 0;
-- Der Durchlauf laeuft geschuetzt, aber nur einmal je Tick statt einmal je
-- Zelle: im Vierzigerraid ein pcall alle 0,125 Sekunden statt achtzig je
-- Sekunde. Wirft eine Abfrage doch, gehen die Direktaufrufe zurueck in den
-- geschuetzten Einzelaufruf und der Rueckfallweg greift wieder.
function FBRaid_Tick(force)
if (not FBRaid_IsActive()) then return; end
local slice = FBRaidTickSlice;
FBRaidTickSlice = math.mod(FBRaidTickSlice + 1, FBRAID_TICK_SLICES);
if (not pcall(FBRaid_TickSweep, slice, force)) then
if (FBHealBox_ApiFailed) then FBHealBox_ApiFailed(); end
end
end
function FBRaid_TickSweep(slice, force)
for g = 1, FBRAID_GROUPS do
if (FBRaidCells[g]) then
if (FBRaidCells[g]) and (force or (math.mod(g - 1, FBRAID_TICK_SLICES) == slice)) then
for pos = 1, FBRAID_PER_GROUP do
local c = FBRaidCells[g][pos];
if (c and c.unit and c:IsShown()) then
@@ -1264,7 +1321,7 @@ FBRaidEventFrame:SetScript("OnUpdate", function()
FBRaid_RefreshBuffBorders();
end
FBRaidTickAccum = FBRaidTickAccum + (arg1 or 0);
if (FBRaidTickAccum < FBRAID_TICK) then return; end
if (FBRaidTickAccum < (FBRAID_TICK / FBRAID_TICK_SLICES)) then return; end
FBRaidTickAccum = 0;
FBRaid_Tick(false);
end);
@@ -1545,6 +1602,22 @@ FBHealBox_RegisterHook("ActiveToggle", function()
FBRaid_UpdateVisibility();
return true;
end);
-- Nur die Zellen anfassen, deren Einheit sich geaendert hat. Der Kern
-- schickt die Namensliste mit; eine Zelle, die nicht drinsteht, kostet
-- einen Tabellenzugriff statt einer vollen Aktualisierung.
FBHealBox_RegisterHook("RefreshNames", function(names)
if (not FBRaid_IsActive()) or (not names) then return true; end
for g = 1, FBRAID_GROUPS do
if (FBRaidCells[g]) then
for pos = 1, FBRAID_PER_GROUP do
local c = FBRaidCells[g][pos];
if (c and c.unit and c.name and names[c.name]) then FBRaid_UpdateCell(c); end
end
end
end
return true;
end);
FBHealBox_RegisterHook("RefreshAllBars", function()
FBRaid_RefreshAll();
return true;
+31 -7
View File
@@ -351,7 +351,8 @@ end
function FBTicker_Draw()
if (not FBTicker.gate) then return; end
local frac, mode = FBTicker_Progress(GetTime());
local now = GetTime();
local frac, mode = FBTicker_Progress(now);
if (not frac) then
FBTicker_HideAll();
return;
@@ -364,8 +365,17 @@ function FBTicker_Draw()
local bar, s = e.bar, e.spark;
if (s and bar) then
if (bar:IsShown()) then
local bw = bar:GetWidth() or 0;
local bh = bar:GetHeight() or 0;
-- Breite und Hoehe aendern sich nur beim Umbauen der Anzeige.
-- Sie werden deshalb viermal je Sekunde nachgelesen und
-- dazwischen gemerkt; so kostet das Zeichnen je Frame fast
-- nichts mehr und darf wieder in jedem Frame laufen.
if (not e.geomT) or ((now - e.geomT) >= FBTICK_GEOM_STEP) then
e.geomT = now;
e.bw = bar:GetWidth() or 0;
e.bh = bar:GetHeight() or 0;
end
local bw = e.bw or 0;
local bh = e.bh or 0;
if (bw > w and bh > 0) then
if (e.w ~= w or e.h ~= bh) then
e.w = w; e.h = bh;
@@ -376,10 +386,16 @@ function FBTicker_Draw()
e.mode = mode;
s:SetTexture(col[1], col[2], col[3], col[4]);
end
-- Anker nur setzen, wenn der Funke mindestens einen halben
-- Pixel weitergewandert ist
-- Anker setzen, sobald sich die Position ueberhaupt
-- geaendert hat. Eine Schwelle von einem halben Pixel
-- klingt sparsam, der Funke wandert aber nur rund 20 px
-- je Sekunde: bei 60 Bildern kam er damit nur in jedem
-- zweiten Frame voran, und je nach Rundung mal nach einem,
-- mal nach zwei Frames. Genau das sah ruckelig aus. Die
-- Feinrundung auf ganze Bildpunkte macht ohnehin die
-- Oberflaeche selbst.
local x = frac * (bw - w);
if (not e.x) or (math.abs(x - e.x) >= 0.5) then
if (not e.x) or (math.abs(x - e.x) >= 0.05) then
e.x = x;
s:ClearAllPoints();
s:SetPoint("LEFT", bar, "LEFT", x, 0);
@@ -422,8 +438,16 @@ FBTickerFrame:SetScript("OnEvent", function()
end
FBTicker_UpdateGate();
end);
-- Gezeichnet wird in jedem Frame. Ein fester Takt spart zwar Durchlaeufe,
-- macht die Bewegung aber sichtbar stufig: der Funke braucht fuer den Balken
-- fuenf Sekunden, jede ausgelassene Position sieht man sofort. Teuer ist das
-- Zeichnen nicht mehr, weil die Balkenmasse gemerkt werden und der Ausstieg
-- ueber das Gate davor sitzt (voller Manabalken = gar kein Durchlauf).
FBTICK_GEOM_STEP = 0.25; -- Sek.: so oft werden Breite und Hoehe nachgelesen
FBTickerFrame:SetScript("OnUpdate", function()
if (FBAddonSuppressed) then return; end
if (not FBTicker.gate) then return; end
FBTicker_Draw();
end);
@@ -529,7 +553,7 @@ FBHealBox_RegisterHook("Loaded", function()
end);
-- Klassensperre des Kerns: Funken ausknipsen
FBHealBox_RegisterHook("Suppress", function()
for _, e in ipairs(FBTicker.sparks or {}) do
for _, e in ipairs(FBTicker.sparks) do
if (e.spark) then e.spark:Hide(); end
end
return true;
+96 -10
View File
@@ -1,16 +1,16 @@
# Heal Box Vanilla
ADDON DOCUMENTATION · VERSION 1.4.4.3 · World of Warcraft CLIENT 1.12.1
ADDON DOCUMENTATION · VERSION 1.4.6 · World of Warcraft CLIENT 1.12.1
Party, pet and self heal display with quick-cast buttons for healers. One name plate with a health bar per group slot, plus one for every pet in the group directly below its owner, and next to it up to ten freely assignable spell buttons. A thin mana bar sits inside the health bar for everyone who actually uses mana. On top of that a complete heal prediction (direct heals, remaining HoT ticks and absorb shields) that corrects itself from the combat log and shares its numbers with other healers in the HealComm format. The interface is available in **English and German**, switchable in the options window.
**The short version:** click the minimap button (or type `/fbp config`) → options window → pick a spell for each button → done. Everything else happens on its own. `/fbp` tells you at any time what the prediction currently believes. **New in 1.4.1:** tick *Test mode* to fill the display with ghost players and arrange everything without a group.
<img width="769" height="475" alt="grafik" src="https://github.com/user-attachments/assets/de8d0f4b-7862-4d9a-8956-76da46dd1e71" />
<img width="784" height="483" alt="Screenshot 2026-09-09 080144" src="https://github.com/user-attachments/assets/e2bcef5e-b193-4ef9-88fc-1f828167fcfb" />
<img width="956" height="847" alt="Screenshot 2026-09-05 210241" src="https://github.com/user-attachments/assets/d7508232-eb56-47ef-8f7e-c39ab0c2b434" />
<img width="837" height="1097" alt="Screenshot 2026-09-08 205118" src="https://github.com/user-attachments/assets/1c5cd627-15dc-48a2-b4ec-46e7afaae172" />
<img width="845" height="1105" alt="grafik" src="https://github.com/user-attachments/assets/fef5d825-0c5c-4710-8994-b51e4712ceb2" />
\---
@@ -89,6 +89,8 @@ Everything is clipped at the end of the bar: a shield exceeding maximum HP stays
The mana bar is `FBMANA_BAR_HEIGHT` (5) pixels high and lies on the bottom edge of the health bar. Where mana is missing a darker translucent strip shows through (`FBMANA_BG_ALPHA`, 0.35, set to 0 for none). It only appears when the unit's **power type is mana** (`UnitPowerType() == 0`): warriors, rogues, hunter pets and druids in cat or bear form get no strip, and the health bar is visible at full height. The bar follows `UNIT_MANA`, `UNIT_MAXMANA` and `UNIT_DISPLAYPOWER`. The *Mana bar* option switches it off entirely.
With *Show rage, energy, focus* ticked the strip is no longer reserved for mana: every unit gets its own resource in its usual colour, taken from `FBPOWER_COLORS` (mana blue, rage red, focus orange, energy yellow). Druids switching form change colour with `UNIT_DISPLAYPOWER` like any other power change. Off by default, because for a healer an empty strip on a warrior is information too: there is nothing there you could refill.
### Dispel colouring
If someone carries a debuff **your** class can remove, their health bar takes the debuff colour instead of the HP colour:
@@ -114,6 +116,8 @@ Up to ten buttons sit next to each plate, each showing its spell's icon. A **lef
**Smart Healing (off by default).** With *Smart Healing* on, a click casts the lowest rank of the assigned spell whose expected heal covers the target's missing health, minus healing already on the way, plus the *Safety margin* (default 20 %). Expected heals come from the learned values of the prediction where available, otherwise from the tooltip average. It never goes above the rank you assigned, applies to direct heals only, and below 30 % health it always casts the assigned rank. **Heal over time spells are never downranked**, whatever the class: Renew, Rejuvenation, Regrowth, Tranquility, Lifebloom, Wild Growth, Riptide and Earth Shield always go out at the rank you assigned. A HoT spreads its healing over many seconds, so the health missing at the moment of the click says nothing about which rank fits, and a downranked HoT keeps ticking too weakly for its whole duration. Mixed spells such as Regrowth count as HoTs as well. Shields and buffs such as Fortitude are likewise cast as assigned, and a spell only qualifies at all if its tooltip describes a heal.
**A running HoT does not count as incoming healing.** Only what lands right away is subtracted: direct heals and spells reported over HealComm, so one to three seconds out. The healing still owed by a ticking Renew stays out of it. Counting it in full would make the deficit look tiny and turn a Heal rank 4 into a Lesser Heal, although the target needs health now and not in a quarter of a minute. The HoT is still shown on the bar, it just does not take part in the rank decision.
**Heal chains (new in 1.4.4.3).** Downranking is not limited to the assigned spell. Within a *heal chain* the spell itself may change, so a click on Greater Heal can go out as Lesser Heal rank 3 when that covers the deficit. The chains hold the single-target direct heals of one class:
|Class|Chain|
@@ -127,7 +131,9 @@ Everything in the chain is a candidate, and the one with the smallest expected h
The *Smartcross* switch on the *Buttons* tab turns chain switching off and on, `/fbp smartcross` does the same from chat. With it off, Smart Healing stays on the assigned spell and only lowers its rank, the way it worked before 1.4.4.3. The chains live in `FBHealChains` near the Smart Healing code and can be edited freely; spells you do not want swapped simply come out of the list. Downsides: the estimate ignores crits, and with burst damage or when you want to overheal on purpose (a tank before a big hit) the lower rank can fall short. Leave it off whenever overhealing is what you want. `/fbp debug` prints every decision, `/fbp` shows the state.
**Cooldowns.** Every button shows the usual cooldown sweep for its spell. The global cooldown is not shown (`FBCD_MIN_DURATION`). Option *Cooldowns on buttons*.
**Cooldowns.** Every button shows the usual cooldown sweep for its spell, the global cooldown included: after every cast you watch the short wait run out on all buttons, the way the action bars do it.
What the global cooldown must never do is darken the icons. While it runs, the client reports every spell as unusable, so taken literally all buttons would go grey for a second and a half and then snap back to bright after every single cast. That is why the two are handled by separate thresholds: `FBCD_SHOW_MIN` (0) decides from which length the sweep runs, `FBCD_MIN_DURATION` (2) the length up to which a cooldown is not treated as a reason to darken a button. Setting `FBCD_SHOW_MIN` to 2 leaves the global cooldown out of the display again. Option *Cooldowns on buttons*.
**HoT and shield timers.** The button of a spell shows, for its unit, the remaining seconds of your own HoT (green) or shield (blue) of that spell. When Power Word: Shield is used up, the same button shows Weakened Soul in red until the target can be shielded again. The left-click spell is checked first, then the right-click spell. Only your own effects are tracked. Option *HoT and shield timers*.
@@ -281,8 +287,14 @@ The window has two tabs.
**Default party frames**: instead of the addon's own plates, the buttons attach to Blizzard's default party frames (`PartyMemberFrameN`); pet buttons attach to `PetFrame` and `PartyMemberFrameNPetFrame`. The addon's name plates and bars are hidden; the heal prediction keeps working invisibly.
**Bar background**: how solid the area behind the bars is, 0 to 100 per cent in steps of 5. Default 0, which is the old look: where health is missing, the game world shows through the plate. Turn it up and a quiet dark grey surface (`FBBAR_BG_COLOR`) sits behind the bars, so the green of the health bar stands on a fixed background instead of on grass, sky or stone. At 100 the plate is opaque. Suggested by a user who found the see-through bar hard to read, and it is worth a try for anyone playing on a bright screen or in a cluttered zone.
**Mana bar**: shows or hides the mana strip inside the health bar. On by default.
**Hide Blizzard party frames**: hides `PartyMemberFrame1` to `4` while you are in a group, so only the Heal Box plates remain. Off by default. This and *Default party frames* can never both be on, because the attach mode docks the plates onto exactly those frames; whichever one is ticked greys the other out. Switching it off brings the frames back immediately, and a class the addon does not load for gets them back too.
**Show rage, energy, focus**: the mana strip normally stays empty for anyone without mana. With this on, warriors, rogues and pets show their own resource in the usual colour (rage red, energy yellow, focus orange, table `FBPOWER_COLORS`). Needs the mana bar to be on. Off by default.
**Show pets**: shows or hides all pet plates. On by default.
**Debuff icon**: shows or hides the debuff icon with stack count next to the name. On by default.
@@ -367,6 +379,12 @@ HoTs cast from the action bar are recognised as well, then with the highest know
The tick interval cannot be read from the tooltip in Vanilla and therefore lives in `FBPredictTickInterval` (3 seconds by default, Lifebloom 1).
### Equipment bonus
Vanilla spell tooltips show the naked base value, the healing bonus from your gear is not in there. Learned values from the combat log carry it automatically, so the gap only exists for ranks you have never cast. If an API supplies the bonus, the addon closes that gap: the value is weighted the vanilla way, cast time divided by 3.5 and capped at 3.5 seconds, instants counting as 1.5. A 3 second Greater Heal with +700 healing therefore starts out 600 higher than its tooltip, a 1.5 second Flash Heal 300.
`GetSpellBonusHealing` is what the addon looks for, plus `GetSpellBonusHeal` and `GetHealingBonus`, first as a global and then inside a `ClassicAPI` table. **ClassicAPI** provides it; without any such API the bonus stays 0 and nothing changes. `/fbp` reports the value found and whether it is being applied, `/fbp healbonus` turns it off. The first learned value for a rank always wins over the estimate.
### Absorb shields
Maximum absorb from the spellbook tooltip, consumption from the combat log (`(123 absorbed)`). For `\*_VS_SELF_*` events the victim is the player, otherwise the message is searched for one of the currently shielded names.
@@ -428,6 +446,7 @@ On receive, your own messages are filtered by sender name, and since HealComm st
|`/fbp buffs`|Lists the tracked buff spells, their presence and remaining time on you, and your raw buff textures|
|`/fbp forceload`|Warrior, rogue and hunter only: shows the addon anyway, or hides it again. Saved per character|
|`/fbp smartcross`|Smart Healing: downranking across spells within a heal chain on/off (on by default)|
|`/fbp healbonus`|Counts the equipment healing bonus into the prediction, on/off. Only works when an API supplies the bonus|
|`/fbp raid`|Toggles raid mode|
|`/fbp raidtest 20` · `40` · `off`|Raid test with 20 or 40 ghosts, or off|
|`/fbp ticker`|Toggles the mana ticker|
@@ -454,6 +473,7 @@ Everything lives in the `HealBox` table, saved **per character**:
|`ButtonSpacing`|Gap between the buttons in px (0 to 20)|
|`RowSpacing`|Gap between the plates in px (0 to 20)|
|`ManaBar`|1 = mana strip on, 0 = off|
|`BarBG`|Opacity of the bar background in per cent, 0 to 100. 0 (default) keeps the see-through look|
|`ShowPets`|1 = pet plates on, 0 = off|
|`SpellChoiceR[1..10]`|Cast string per button for right click|
|`RightClick`|1 = right-click spell on, 0 = off (default)|
@@ -462,6 +482,9 @@ Everything lives in the `HealBox` table, saved **per character**:
|`PlateLeft` · `PlateRight`|Click action on a plate: `target`, `menu`, `move` or `none`|
|`SmartRank` · `SmartMargin`|Smart Healing on/off (default off) and safety margin in percent|
|`SmartCross`|1 = downranking may switch spell within a heal chain (default), 0 = stay on the assigned spell. Set in the options or with `/fbp smartcross`|
|`PowerBar`|1 = the bar also shows rage, energy and focus, 0 = mana only (default)|
|`HideBlizzParty`|1 = Blizzard's party frames stay hidden, 0 = untouched (default). Never active together with `AttachMode`|
|`HealBonus`|1 = equipment healing bonus counts towards unlearned ranks (default), 0 = plain tooltip values. `/fbp healbonus`|
|`Cooldowns` · `AggroMark` · `SpellTimers` · `BuffIcons`|Cooldown sweep, red border for the attacked member, HoT/shield timers, buff icons left of the bar|
|`ClassColors`|1 = names in class colour, 0 = white|
|`RangeFade`|1 = fade plates out of range, 0 = off|
@@ -488,6 +511,7 @@ Every knob is a global at the top of its own section and can be changed without
|`FBMANA_BAR_HEIGHT`|5|Height of the mana strip in px|
|`FBMANA_BAR_COLOR`|`{0.15, 0.4, 1, 1}`|Colour of the mana strip|
|`FBMANA_BG_ALPHA`|0.35|Dark strip behind missing mana (0 = off)|
|`FBBAR_BG_COLOR`|0.15 · 0.15 · 0.15|Shade of the bar background; how solid it sits is the `BarBG` option|
|`FBPET_NAME_COLOR`|`{0.75, 0.85, 1, 1}`|Name colour on pet plates|
|`FBPET_INDENT`|12|Indent (and width reduction) of pet plates|
|`FBPET_ICON` · `FBPET_ICON_SIZE`|footprint · 12|Paw icon in front of pet names|
@@ -499,7 +523,8 @@ Every knob is a global at the top of its own section and can be changed without
|`FBRANGE_ALPHA` · `FBRANGE_INTERVAL`|0.5 · 0.5|Faded opacity and check interval of the range fading|
|`FBBUFF_MISSING_COLOR`|`{1, 0.5, 0, 1}`|Border colour when the watched buff is missing|
|`FBAGGRO_COLOR`|`{1, 0.15, 0.15, 1}`|Border colour for the attacked member|
|`FBCD_MIN_DURATION`|2|Cooldowns shorter than this (the global cooldown) are not shown|
|`FBCD_MIN_DURATION`|2|Length of the global cooldown: a cooldown up to this length does not darken a button|
|`FBCD_SHOW_MIN`|0|From which length the cooldown sweep runs. 0 shows every cooldown including the global one, 2 leaves it out|
|`FBTIMER_COLOR_HOT` · `_SHIELD` · `_WS`|green · blue · red|Timer colours on the buttons|
|`FBBUFFICON_SIZE` · `FBBUFFICON_GAP` · `FBBUFFICON_MAX` · `FBBUFFICON_XOFF`|8 · 1 · 6 · -2|Buff icons left of the plate|
|`FBBUFFICON_STEPS` · `FBBUFFICON_GREY`|32 · 0.30|Duration progress steps (32) and grey tint when client cannot desaturate|
@@ -515,10 +540,13 @@ Every knob is a global at the top of its own section and can be changed without
|`FBMENU_GRACE_TIME`|3.0|Menu auto-close (999 = off)|
|`FBPREDICT_TICK_DEFAULT`|3|Default tick interval for HoTs|
|`FBPREDICT_THROTTLE`|0.2|Update rate of the prediction|
|`FBRAID_TICK` · `FBRAID_TICK_SLICES`|0.5 · 4|Full sweep for raid range and line of sight, and how many ticks it is spread over|
|`FBTICK_GEOM_STEP`|0.25|How often the ticker re-reads the bar size (the spark itself is drawn every frame)|
|`FBPREDICT_CONFIRM_TIME`|3.0|Time to wait for the aura confirmation|
|`FBPREDICT_TARGET_TIME`|2.0|Lifetime of the remembered cast target|
|`FBPredictTickInterval`|`{Lifebloom = 1}`|Deviating tick intervals|
|`FBCommGroupHeal`|`{Prayer of Healing}`|What is broadcast as `GrpHeal`|
|`FBPOWER_COLORS`|blue · red · orange · yellow|Bar colour per resource (mana, rage, focus, energy)|
|`FBHealChains`|(table)|Which spells count as the same heal, only smaller. Smart Healing may switch spell inside a chain|
|`FBHoTSpells`|(table)|Heal over time spells that Smart Healing never downranks|
|`FBBlockedClasses`|`WARRIOR`, `ROGUE`, `HUNTER`|Classes the addon does not load for without `/fbp forceload`|
@@ -550,6 +578,16 @@ Every knob is a global at the top of its own section and can be changed without
|`FBHealBox_SmartRank(castString, unit)`|Picks the rank to cast|
|`FBHealBox_IsHoT(base, ranks)`|Heal over time? List of names plus tooltip, spell watch and running HoTs. Smart Healing skips these|
|`FBHealBox_HealFamily(base)` · `FBHealBox_DirectAmount(spell, sd)`|The heal chain a spell belongs to; the expected heal of one rank, or nil if the spell is not eligible|
|`FBPredict_ExpectedDirect(spell, rank, info, id)`|Expected direct heal: learned value, otherwise tooltip plus the share of the equipment bonus|
|`FBHealBox_ProbeHealBonus()` · `FBHealBox_HealingBonus()` · `FBHealBox_HealBonusFor(id)`|Finds an API for the healing bonus, reads it, and weights it by cast time|
|`FBHealBox_SpellCastSeconds(id)`|Cast time from the tooltip (0 = instant), cached per spellbook slot|
|`FBHealBox_ApplyBlizzParty()` · `FBHealBox_HideBlizzPartyActive()`|Hides or restores Blizzard's party frames, including the lock against the attach mode|
|`FBHealBox_SetPowerColor(bar, cache, ptype)`|Colours a resource bar for mana, rage, focus or energy|
|`FBHealBox_ApplyBarBG(f)` · `FBHealBox_ApplyBarBGAll()`|Sets the background behind a plate's bars from the `BarBG` option|
|`FBHealBox_RefreshUnitsByName(names)`|Redraws only the plates whose unit is in the name set; the raid module gets the same set through the `RefreshNames` hook|
|`FBPredict_ScanPlayerBuffTimes()`|Reads all of your own buff timers once per frame into a texture-to-seconds map|
|`FBHealBox_ApiFailed()`|Puts range, distance and line of sight back to the protected single call after a sweep threw|
|`FBHealBox_UpperTex(tex)`|Upper-cased texture path, remembered, so `strupper` does not allocate per call|
|`FBHealBox_CheckAggroAll()` · `FBHealBox_ApplyBorder(f)`|Red border for the attacked member; border precedence|
|`FBHealBox_UpdateSpellTimers()` · `FBHealBox_SpellTimerFor(...)`|HoT/shield timers on buttons|
|`FBHealBox_UpdateButtonCooldown(b)` · `FBHealBox_UpdateAllCooldowns()`|Cooldown sweep|
@@ -707,6 +745,11 @@ Entries that do not exist do no harm: if the spellbook scan does not find them,
* heal prediction for direct heals, remaining HoT ticks and absorb shields, self-correcting from the combat log
* HealComm sync with Puppeteer, pfUI, Luna and others, without any Ace libraries
* English, German, Spanish, French and Italian localization, switchable in game
* 1.4.6: performance pass without functional change (only changed units are redrawn via the `RefreshNames` hook, raid spell timers skip idle cells, spell timers leave early when nothing is running); see CHANGELOG
* 1.4.5.3: adjustable background behind the plate bars, so the game world no longer shows through where health is missing; see CHANGELOG
* 1.4.5.2: a running HoT no longer counts as incoming healing when Smart Healing picks a rank; see CHANGELOG
* 1.4.5.1: mana ticker spark no longer stutters (movement threshold and redraw step), and the global cooldown no longer darkens every button but is shown as a sweep instead (own threshold `FBCD_SHOW_MIN`); see CHANGELOG
* 1.4.5: Blizzard's party frames can be hidden (mutually exclusive with the attach mode), rage, energy and focus in the resource bar, and the equipment healing bonus via ClassicAPI in the prediction, plus a performance pass without functional change (player buffs read once per frame, staggered raid range and line-of-sight sweeps, fewer protected calls, no throwaway strings in the raid health text); see CHANGELOG
* 1.4.4.3: class gate for warriors, rogues and hunters (display stays off, chat hint, `/fbp forceload` to override) and Smart Healing no longer downranks heal over time spells of any class. Smart Healing downranks across spells inside a heal chain (Greater Heal to Lesser Heal, Holy Light to Flash of Light), `/fbp smartcross` turns it off; see CHANGELOG
* 1.4.4.2: 32-step buff icon duration display (replacing the 4-quadrant clock with a 32-stage vertical wipe) and syntax/diagnostic bugfixes; see CHANGELOG
* 1.4.4.1: buff tracking & tooltip scanning fix (Divine Spirit clock icon), expanded class spell lists with blessings, buffs, utility and rez spells, group buff alternate tracking; see CHANGELOG
@@ -717,14 +760,14 @@ Entries that do not exist do no harm: if the spellbook scan does not find them,
---
Heal Box Vanilla v1.4.4.3 · original by Dourd, UI Overhauled · ported to Vanilla and extended 09/2026 by Mquadrat
Heal Box Vanilla v1.4.6 · original by Dourd, UI Overhauled · ported to Vanilla and extended 09/2026 by Mquadrat
_______________________________________________________________________
GERMAN
# Heal Box Vanilla
ADDON DOKUMENTATION · VERSION 1.4.4.3 · World of Warcraft CLIENT 1.12.1
ADDON DOKUMENTATION · VERSION 1.4.6 · World of Warcraft CLIENT 1.12.1
Party-, Begleiter- und Selbst-Heilanzeige mit Schnellzugriff-Buttons für Heiler. Für jeden Gruppenplatz eine Namensplakette mit Lebensbalken, dazu eine für jeden Begleiter in der Gruppe direkt unter seinem Besitzer, daneben bis zu zehn frei belegbare Zauber-Buttons. Ein schmaler Manabalken liegt im Lebensbalken, bei allen, die tatsächlich Mana nutzen. Dazu eine vollständige Heilvorhersage (Direktheilung, HoT-Restticks und Absorb-Schilde), die sich über den Combatlog selbst korrigiert und ihre Werte im HealComm-Format mit anderen Heilern teilt. Die Oberfläche gibt es auf **Deutsch und Englisch**, umschaltbar im Optionsfenster.
@@ -805,6 +848,8 @@ Alles wird am Balkenende abgeschnitten: Ein Schild über der Maximal-HP bleibt u
Der Manabalken ist `FBMANA_BAR_HEIGHT` (5) Pixel hoch und liegt auf der Unterkante des Lebensbalkens. Wo Mana fehlt, scheint ein dunkler, halbtransparenter Streifen durch (`FBMANA_BG_ALPHA`, 0.35, auf 0 setzen, wenn unerwünscht). Er erscheint nur, wenn der **Powertyp der Einheit Mana** ist (`UnitPowerType() == 0`): Krieger, Schurken, Jägerbegleiter und Druiden in Katzen- oder Bärengestalt bekommen keinen Streifen, der Lebensbalken ist dann auf voller Höhe zu sehen. Der Balken folgt `UNIT_MANA`, `UNIT_MAXMANA` und `UNIT_DISPLAYPOWER`. Die Option *Manabalken* schaltet ihn ganz ab.
Mit *Wut, Energie, Fokus zeigen* ist der Streifen nicht mehr dem Mana vorbehalten: Jede Einheit bekommt ihre eigene Ressource in der gewohnten Farbe aus `FBPOWER_COLORS` (Mana blau, Wut rot, Fokus orange, Energie gelb). Druiden, die die Gestalt wechseln, wechseln über `UNIT_DISPLAYPOWER` die Farbe mit, wie bei jeder anderen Änderung des Powertyps. Standardmäßig aus, denn für einen Heiler ist ein leerer Streifen beim Krieger auch eine Information: Da ist nichts, was du auffüllen könntest.
### Dispel-Färbung
Hat jemand einen Debuff, den **deine** Klasse entfernen kann, färbt sich sein Lebensbalken in der Debuff-Farbe statt nach HP-Stand:
@@ -830,6 +875,8 @@ Rechts neben jeder Plakette liegen bis zu zehn Buttons, jeder mit dem Icon seine
**Smart Healing (standardmäßig aus).** Mit *Smart Healing* wirkt ein Klick den niedrigsten Rang des belegten Zaubers, dessen erwartete Heilung das fehlende Leben des Ziels abzüglich schon eingehender Heilung plus *Sicherheitsaufschlag* (Standard 20 %) deckt. Die erwartete Heilung stammt aus den gelernten Werten der Vorhersage, wo vorhanden, sonst aus dem Tooltip-Mittelwert. Nie über dem belegten Rang, nur für Direktheilungen, und unter 30 % Leben immer der belegte Rang. **Zauber mit Heilung über Zeit werden nie abgerangt**, egal welcher Klasse: Erneuerung, Verjüngung, Nachwachsen, Gelassenheit, Lebensblüte, Wildwuchs, Springflut und Erdschild gehen immer im belegten Rang raus. Ein HoT verteilt seine Heilung über viele Sekunden, das im Moment des Klicks fehlende Leben sagt also nichts darüber aus, welcher Rang passt, und ein abgerangter HoT tickt die volle Laufzeit zu schwach. Gemischte Zauber wie Nachwachsen zählen ebenfalls als HoT. Schilde und Buffs wie Seelenstärke gehen genauso wie belegt raus, und ein Zauber kommt überhaupt nur in Frage, wenn sein Tooltip eine Heilung beschreibt.
**Ein laufender HoT zählt nicht als eingehende Heilung.** Abgezogen wird nur, was gleich ankommt: Direktheilungen und über HealComm gemeldete Zauber, also ein bis drei Sekunden. Die offene Restheilung eines tickenden Erneuerung bleibt außen vor. Sie voll anzurechnen ließe den Fehlbetrag winzig aussehen und machte aus einem Heilen Rang 4 ein Geringes Heilen, obwohl das Ziel jetzt Leben braucht und nicht in einer Viertelminute. Auf dem Balken wird der HoT weiterhin angezeigt, er geht nur nicht in die Rangwahl ein.
**Heilketten (neu in 1.4.4.3).** Abgerangt wird nicht nur innerhalb des belegten Zaubers. Innerhalb einer *Heilkette* darf auch der Zauber selbst wechseln, ein Klick auf Große Heilung kann also als Geringes Heilen Rang 3 rausgehen, wenn das den Fehlbetrag deckt. Die Ketten enthalten die Einzelziel-Direktheilungen einer Klasse:
|Klasse|Kette|
@@ -843,7 +890,9 @@ Alles in der Kette ist Kandidat, gewonnen hat der mit der kleinsten erwarteten H
Der Schalter *Smartcross* im Reiter *Buttons* schaltet den Kettenwechsel aus und wieder ein, `/fbp smartcross` tut dasselbe aus dem Chat. Aus bleibt Smart Healing beim belegten Zauber und senkt nur dessen Rang, so wie es vor 1.4.4.3 war. Die Ketten stehen in `FBHealChains` direkt beim Smart-Healing-Code und lassen sich frei bearbeiten; Zauber, die nicht getauscht werden sollen, fliegen einfach aus der Liste. Nachteile: Die Schätzung kennt keine Crits, und bei Schadensspitzen oder gewolltem Überheilen (Tank vor einem großen Treffer) kann der kleinere Rang zu wenig sein. Aus lassen, wann immer Overheal gewollt ist. `/fbp debug` zeigt jede Entscheidung, `/fbp` den Zustand.
**Cooldowns.** Jeder Button zeigt die gewohnte Cooldown-Uhr seines Zaubers. Der globale Cooldown wird nicht gezeigt (`FBCD_MIN_DURATION`). Option *Cooldowns auf den Buttons*.
**Cooldowns.** Jeder Button zeigt die gewohnte Cooldown-Uhr seines Zaubers, den globalen Cooldown eingeschlossen: Nach jedem Zauber läuft die kurze Wartezeit auf allen Buttons ab, so wie es die Aktionsleisten machen.
Was der globale Cooldown auf keinen Fall tun darf, ist die Symbole abdunkeln. Solange er läuft, meldet der Client jeden Zauber als nicht nutzbar, wörtlich genommen würden also nach jedem einzelnen Zauber alle Buttons anderthalb Sekunden grau und dann schlagartig wieder hell. Deshalb sind es zwei getrennte Schwellen: `FBCD_SHOW_MIN` (0) entscheidet, ab welcher Länge die Uhr läuft, `FBCD_MIN_DURATION` (2) die Länge, bis zu der eine Abklingzeit nicht als Grund zum Abdunkeln gilt. Wer `FBCD_SHOW_MIN` auf 2 setzt, hat den globalen Cooldown wieder aus der Anzeige. Option *Cooldowns auf den Buttons*.
**HoT- und Schild-Timer.** Der Button eines Zaubers zeigt für seine Einheit die Restsekunden deines eigenen HoTs (grün) oder Schilds (blau) dieses Zaubers. Ist Machtwort: Schild verbraucht, zeigt derselbe Button rot die Geschwächte Seele, bis das Ziel wieder schildbar ist. Geprüft wird zuerst der Linksklick-Zauber, dann der Rechtsklick-Zauber. Nur eigene Effekte werden verfolgt. Option *HoT- und Schild-Timer*.
@@ -997,8 +1046,14 @@ Das Fenster hat zwei Reiter.
**Standard-Gruppenfenster**: statt eigener Plaketten hängen die Buttons an Blizzards Standard-Gruppenfenstern (`PartyMemberFrameN`); die Pet-Buttons an `PetFrame` bzw. `PartyMemberFrameNPetFrame`. Die eigenen Namensplaketten und Balken werden dabei ausgeblendet; die Heilvorhersage arbeitet unsichtbar weiter.
**Balkenhintergrund**: wie deckend die Fläche hinter den Balken liegt, 0 bis 100 Prozent in Fünferschritten. Standard 0, also das bisherige Bild: Wo Leben fehlt, scheint die Spielwelt durch die Plakette. Hochgedreht liegt eine ruhige dunkelgraue Fläche hinter den Balken (`FBBAR_BG_COLOR`), das Grün des Lebensbalkens steht dann auf festem Grund statt auf Gras, Himmel oder Stein. Bei 100 ist die Plakette undurchsichtig. Angeregt von einem Nutzer, dem der durchscheinende Balken schlecht lesbar war, und einen Versuch wert für alle mit hellem Bildschirm oder unruhiger Umgebung.
**Manabalken**: Manastreifen im Lebensbalken an/aus. Standardmäßig an.
**Blizzard-Gruppenfenster aus**: versteckt `PartyMemberFrame1` bis `4`, solange du in einer Gruppe bist, sodass nur die Plaketten der Heal Box übrig bleiben. Standardmäßig aus. Diese Option und *Standard-Gruppenfenster* können nie beide an sein, weil der Anheftmodus die Plaketten genau an diese Frames hängt; was angehakt ist, graut das andere aus. Ausschalten holt die Frames sofort zurück, und eine Klasse, für die das Addon nicht lädt, bekommt sie ebenfalls zurück.
**Wut, Energie, Fokus zeigen**: der Manastreifen bleibt normalerweise leer bei allen ohne Mana. Eingeschaltet zeigen Krieger, Schurken und Begleiter ihre eigene Ressource in der gewohnten Farbe (Wut rot, Energie gelb, Fokus orange, Tabelle `FBPOWER_COLORS`). Setzt den Manabalken voraus. Standardmäßig aus.
**Begleiter anzeigen**: alle Pet-Plaketten an/aus. Standardmäßig an.
**Debuff-Icon**: Debuff-Icon mit Stackzahl neben dem Namen an/aus. Standardmäßig an.
@@ -1081,6 +1136,12 @@ HoTs von der Aktionsleiste werden ebenfalls erkannt, dann mit dem höchsten beka
Das Tickintervall ist in Vanilla nicht aus dem Tooltip lesbar und steht deshalb in `FBPredictTickInterval` (Standard 3 Sekunden, Lifebloom 1).
### Ausrüstungsbonus
Vanilla-Tooltips zeigen den nackten Grundwert, der Heilbonus deiner Ausrüstung steht nicht darin. Gelernte Werte aus dem Combatlog tragen ihn von selbst, die Lücke gibt es also nur bei Rängen, die du nie gewirkt hast. Liefert eine API den Bonus, schließt das Addon diese Lücke: Der Wert wird wie in Vanilla üblich mit Zauberzeit geteilt durch 3,5 gewichtet und bei 3,5 Sekunden gedeckelt, Instants zählen als 1,5. Eine Große Heilung mit 3 Sekunden Zauberzeit startet bei +700 Heilung also 600 über ihrem Tooltip, eine Blitzheilung mit 1,5 Sekunden 300.
Gesucht wird `GetSpellBonusHealing`, dazu `GetSpellBonusHeal` und `GetHealingBonus`, erst als globale Funktion, dann in einer `ClassicAPI`-Tabelle. **ClassicAPI** bringt das mit; ohne eine solche API bleibt der Bonus 0 und es ändert sich nichts. `/fbp` nennt den gefundenen Wert und ob er angewandt wird, `/fbp healbonus` schaltet ihn ab. Der erste gelernte Wert eines Rangs schlägt die Schätzung immer.
### Absorb-Schilde
Maximaler Absorb aus dem Zauberbuch-Tooltip, Verbrauch aus dem Combatlog (`(123 absorbed)`). Bei `\*_VS_SELF_*`-Events ist das Opfer der Spieler, sonst wird unter den aktuell beschildeten Namen gesucht.
@@ -1142,6 +1203,7 @@ Beim Empfang werden eigene Nachrichten über den Absendernamen gefiltert, und da
|`/fbp buffs`|Listet die verfolgten Buff-Zauber, ihre Präsenz und Restzeit auf dir sowie deine rohen Buff-Texturen|
|`/fbp forceload`|Nur für Krieger, Schurke und Jäger: zeigt das Addon trotzdem an oder blendet es wieder aus. Pro Charakter gespeichert|
|`/fbp smartcross`|Smart Healing: Abrangen über Zaubergrenzen innerhalb einer Heilkette an/aus (Standard an)|
|`/fbp healbonus`|Rechnet den Heilbonus der Ausrüstung in die Vorhersage, an/aus. Wirkt nur, wenn eine API den Bonus liefert|
|`/fbp raid`|Raidmodus an/aus|
|`/fbp raidtest 20` · `40` · `off`|Raid-Test mit 20 oder 40 Geistern, oder aus|
|`/fbp ticker`|Mana-Ticker an/aus|
@@ -1168,6 +1230,7 @@ Alles liegt in der Tabelle `HealBox`, gespeichert **pro Charakter**:
|`ButtonSpacing`|Abstand der Buttons in px (0 bis 20)|
|`RowSpacing`|Abstand der Plaketten in px (0 bis 20)|
|`ManaBar`|1 = Manastreifen an, 0 = aus|
|`BarBG`|Deckkraft des Balkenhintergrunds in Prozent, 0 bis 100. 0 (Standard) behält das durchscheinende Bild|
|`ShowPets`|1 = Pet-Plaketten an, 0 = aus|
|`SpellChoiceR[1..10]`|Cast-String je Button für Rechtsklick|
|`RightClick`|1 = Rechtsklick-Zauber an, 0 = aus (Standard)|
@@ -1176,6 +1239,9 @@ Alles liegt in der Tabelle `HealBox`, gespeichert **pro Charakter**:
|`PlateLeft` · `PlateRight`|Klickaktion auf einer Plakette: `target`, `menu`, `move` oder `none`|
|`SmartRank` · `SmartMargin`|Smart Healing an/aus (Standard aus) und Sicherheitsaufschlag in Prozent|
|`SmartCross`|1 = Abrangen darf den Zauber innerhalb einer Heilkette wechseln (Standard), 0 = beim belegten Zauber bleiben. In den Optionen oder mit `/fbp smartcross` schaltbar|
|`PowerBar`|1 = der Balken zeigt auch Wut, Energie und Fokus, 0 = nur Mana (Standard)|
|`HideBlizzParty`|1 = Blizzards Gruppenfenster bleiben versteckt, 0 = unangetastet (Standard). Nie zusammen mit `AttachMode` aktiv|
|`HealBonus`|1 = Heilbonus der Ausrüstung zählt bei ungelernten Rängen (Standard), 0 = nackte Tooltipwerte. `/fbp healbonus`|
|`Cooldowns` · `AggroMark` · `SpellTimers` · `BuffIcons`|Cooldown-Uhr, roter Rahmen für den Angegriffenen, HoT/Schild-Timer, Buff-Icons links am Balken|
|`ClassColors`|1 = Namen in Klassenfarbe, 0 = weiß|
|`RangeFade`|1 = Plaketten außer Reichweite abblenden, 0 = aus|
@@ -1200,6 +1266,7 @@ Alle Stellschrauben stehen als Globals oben in ihrem jeweiligen Abschnitt und la
|`FBMANA_BAR_HEIGHT`|5|Höhe des Manastreifens in px|
|`FBMANA_BAR_COLOR`|`{0.15, 0.4, 1, 1}`|Farbe des Manastreifens|
|`FBMANA_BG_ALPHA`|0.35|Dunkler Streifen hinter fehlendem Mana (0 = aus)|
|`FBBAR_BG_COLOR`|0.15 · 0.15 · 0.15|Grundton des Balkenhintergrunds; wie deckend er liegt, regelt die Option `BarBG`|
|`FBPET_NAME_COLOR`|`{0.75, 0.85, 1, 1}`|Namensfarbe auf Pet-Plaketten|
|`FBPET_INDENT`|12|Einrückung (und Verschmälerung) der Pet-Plaketten|
|`FBPET_ICON` · `FBPET_ICON_SIZE`|Fußabdruck · 12|Pfoten-Icon vor Pet-Namen|
@@ -1211,7 +1278,8 @@ Alle Stellschrauben stehen als Globals oben in ihrem jeweiligen Abschnitt und la
|`FBRANGE_ALPHA` · `FBRANGE_INTERVAL`|0.5 · 0.5|Deckkraft und Prüfintervall des Reichweiten-Fadings|
|`FBBUFF_MISSING_COLOR`|`{1, 0.5, 0, 1}`|Rahmenfarbe bei fehlendem Wache-Buff|
|`FBAGGRO_COLOR`|`{1, 0.15, 0.15, 1}`|Rahmenfarbe für den Angegriffenen|
|`FBCD_MIN_DURATION`|2|Kürzere Cooldowns (globaler Cooldown) werden nicht gezeigt|
|`FBCD_MIN_DURATION`|2|Länge des globalen Cooldowns: Eine Abklingzeit bis zu dieser Länge dunkelt keinen Button ab|
|`FBCD_SHOW_MIN`|0|Ab welcher Länge die Cooldown-Uhr läuft. 0 zeigt jede Abklingzeit samt globalem Cooldown, 2 lässt ihn weg|
|`FBTIMER_COLOR_HOT` · `_SHIELD` · `_WS`|grün · blau · rot|Timerfarben auf den Buttons|
|`FBBUFFICON_SIZE` · `FBBUFFICON_GAP` · `FBBUFFICON_MAX` · `FBBUFFICON_XOFF`|8 · 1 · 6 · -2|Buff-Icons links neben der Plakette|
|`FBBUFFICON_STEPS` · `FBBUFFICON_GREY`|32 · 0.30|Anzahl Ablaufstufen (32) und Grauton, falls Client nicht entsättigen kann|
@@ -1227,10 +1295,13 @@ Alle Stellschrauben stehen als Globals oben in ihrem jeweiligen Abschnitt und la
|`FBMENU_GRACE_TIME`|3.0|Auto-Close des Menüs (999 = aus)|
|`FBPREDICT_TICK_DEFAULT`|3|Standard-Tickintervall für HoTs|
|`FBPREDICT_THROTTLE`|0.2|Update-Rate der Vorhersage|
|`FBRAID_TICK` · `FBRAID_TICK_SLICES`|0.5 · 4|Voller Durchlauf für Reichweite und Sichtlinie im Raid, und auf wie viele Ticks er verteilt wird|
|`FBTICK_GEOM_STEP`|0.25|Wie oft der Ticker die Balkenmaße nachliest (der Funke selbst wird in jedem Frame gezeichnet)|
|`FBPREDICT_CONFIRM_TIME`|3.0|Wartezeit auf die Aura-Bestätigung|
|`FBPREDICT_TARGET_TIME`|2.0|Gültigkeit des gemerkten Cast-Ziels|
|`FBPredictTickInterval`|`{Lifebloom = 1}`|Abweichende Tickintervalle|
|`FBCommGroupHeal`|`{Prayer of Healing}`|Was als `GrpHeal` gefunkt wird|
|`FBPOWER_COLORS`|blau · rot · orange · gelb|Balkenfarbe je Ressource (Mana, Wut, Fokus, Energie)|
|`FBHealChains`|(Tabelle)|Welche Zauber als derselbe Heilzauber in klein gelten. Innerhalb einer Kette darf Smart Healing den Zauber wechseln|
|`FBHoTSpells`|(Tabelle)|Zauber mit Heilung über Zeit, die Smart Healing nie abrangt|
|`FBBlockedClasses`|`WARRIOR`, `ROGUE`, `HUNTER`|Klassen, für die das Addon ohne `/fbp forceload` nicht lädt|
@@ -1261,6 +1332,16 @@ Alle Stellschrauben stehen als Globals oben in ihrem jeweiligen Abschnitt und la
|`FBHealBox_SmartRank(castString, unit)`|Wählt den zu wirkenden Rang|
|`FBHealBox_IsHoT(base, ranks)`|Heilung über Zeit? Namensliste plus Tooltip, Zauberwache und laufende HoTs. Smart Healing lässt diese aus|
|`FBHealBox_HealFamily(base)` · `FBHealBox_DirectAmount(spell, sd)`|Die Heilkette eines Zaubers; die erwartete Heilung eines Rangs, oder nil, wenn der Zauber nicht in Frage kommt|
|`FBPredict_ExpectedDirect(spell, rank, info, id)`|Erwartete Sofortheilung: gelernter Wert, sonst Tooltip plus Anteil am Ausrüstungsbonus|
|`FBHealBox_ProbeHealBonus()` · `FBHealBox_HealingBonus()` · `FBHealBox_HealBonusFor(id)`|Sucht eine API für den Heilbonus, liest sie aus und gewichtet nach Zauberzeit|
|`FBHealBox_SpellCastSeconds(id)`|Zauberzeit aus dem Tooltip (0 = Instant), je Zauberbuchplatz gemerkt|
|`FBHealBox_ApplyBlizzParty()` · `FBHealBox_HideBlizzPartyActive()`|Versteckt Blizzards Gruppenfenster oder gibt sie zurück, samt Sperre gegen den Anheftmodus|
|`FBHealBox_SetPowerColor(bar, cache, ptype)`|Färbt einen Ressourcenbalken für Mana, Wut, Fokus oder Energie|
|`FBHealBox_ApplyBarBG(f)` · `FBHealBox_ApplyBarBGAll()`|Setzt den Hintergrund hinter den Balken einer Plakette nach der Option `BarBG`|
|`FBHealBox_RefreshUnitsByName(names)`|Zeichnet nur die Plaketten neu, deren Einheit in der Namensliste steht; das Raidmodul bekommt dieselbe Liste über den Hook `RefreshNames`|
|`FBPredict_ScanPlayerBuffTimes()`|Liest alle eigenen Bufflaufzeiten einmal je Frame in eine Tabelle Textur nach Sekunden|
|`FBHealBox_ApiFailed()`|Stellt Reichweite, Abstand und Sichtlinie auf den geschützten Einzelaufruf zurück, wenn ein Durchlauf geworfen hat|
|`FBHealBox_UpperTex(tex)`|Groß geschriebener Texturpfad, gemerkt, damit `strupper` nicht je Aufruf zuteilt|
|`FBHealBox_CheckAggroAll()` · `FBHealBox_ApplyBorder(f)`|Roter Rahmen für den Angegriffenen; Rahmen-Vorrang|
|`FBHealBox_UpdateSpellTimers()` · `FBHealBox_SpellTimerFor(...)`|HoT/Schild-Timer auf Buttons|
|`FBHealBox_UpdateButtonCooldown(b)` · `FBHealBox_UpdateAllCooldowns()`|Cooldown-Uhr|
@@ -1407,6 +1488,11 @@ Nicht vorhandene Einträge stören nicht: Findet der Zauberbuch-Scan sie nicht,
* Heilvorhersage für Direktheilung, HoT-Restticks und Absorb-Schilde, selbstkorrigierend über den Combatlog
* HealComm-Sync mit Puppeteer, pfUI, Luna und Co., ohne Ace-Bibliotheken
* Lokalisierung Deutsch, Englisch, Spanisch, Französisch und Italienisch, im laufenden Spiel umschaltbar
* 1.4.6: Leistungsdurchgang ohne Funktionsänderung (nur geänderte Einheiten werden neu gezeichnet, über den Hook `RefreshNames`, Raid-Zaubertimer überspringen stille Zellen, Zaubertimer steigen früher aus); siehe CHANGELOG
* 1.4.5.3: Einstellbarer Hintergrund hinter den Balken der Plaketten, damit die Spielwelt nicht mehr durch fehlendes Leben scheint; siehe CHANGELOG
* 1.4.5.2: Ein laufender HoT zählt bei der Rangwahl von Smart Healing nicht mehr als anfliegende Heilung; siehe CHANGELOG
* 1.4.5.1: Ruckeln des Manafunkens behoben (Bewegungsschwelle und Zeichentakt), der globale Cooldown dunkelt nicht mehr alle Buttons ab und läuft stattdessen als Uhr mit (eigene Schwelle `FBCD_SHOW_MIN`); siehe CHANGELOG
* 1.4.5: Blizzards Gruppenfenster ausblendbar (schließt sich mit dem Anheftmodus gegenseitig aus), Wut, Energie und Fokus im Ressourcenbalken, Heilbonus der Ausrüstung über ClassicAPI in der Vorhersage, dazu ein Leistungsdurchgang ohne Funktionsänderung (Spielerbuffs einmal je Frame, gestaffelte Reichweiten- und Sichtlinienprüfung im Raid, weniger geschützte Aufrufe, keine Wegwerf-Strings im Raid-HP-Text); siehe CHANGELOG
* 1.4.4.3: Klassensperre für Krieger, Schurke und Jäger (Anzeige bleibt aus, Hinweis im Chat, Freischaltung mit `/fbp forceload`) und Smart Healing rangt HoTs aller Klassen nicht mehr ab. Smart Healing rangt innerhalb einer Heilkette auch über Zaubergrenzen ab (Große Heilung zu Geringem Heilen, Heiliges Licht zu Blitz des Lichts), `/fbp smartcross` schaltet es aus; siehe CHANGELOG
* 1.4.4.2: 32-Stufen-Ablaufanzeige für Buff-Icons (ersetzt die 4-Quadranten-Uhr durch 32 vertikale Stufen) sowie Syntax- und Diagnose-Korrekturen; siehe CHANGELOG
* 1.4.4.1: Buff-Erkennung & Tooltip-Scan behoben (Göttlicher Willen Uhr-Icon), vollständige Klassen-Zauberlisten mit Segen, Buffs, Hilfszaubern und Wiederbelebung, Gruppen-Buff-Erkennung; siehe CHANGELOG
@@ -1417,7 +1503,7 @@ Nicht vorhandene Einträge stören nicht: Findet der Zauberbuch-Scan sie nicht,
---
Heal Box Vanilla v1.4.4.3 · Original von Dourd, UI Overhauled · Vanilla-Portierung und Erweiterung 09/2026 von Mquadrat
Heal Box Vanilla v1.4.6 · Original von Dourd, UI Overhauled · Vanilla-Portierung und Erweiterung 09/2026 von Mquadrat
---