4 Commits
Author SHA1 Message Date
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 710 additions and 76 deletions
+51
View File
@@ -1,5 +1,56 @@
# Changelog # Changelog
## 1.4.5 (2026-09-09)
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. 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. 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) ## 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. 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.
+535 -57
View File
@@ -34,6 +34,9 @@
-- Smart Healing rangt HoTs aller Klassen nicht mehr ab. -- Smart Healing rangt HoTs aller Klassen nicht mehr ab.
-- Smart Healing rangt in Heilketten auch ueber Zaubergrenzen -- Smart Healing rangt in Heilketten auch ueber Zaubergrenzen
-- ab (Grosse Heilung -> Geringes Heilen), abschaltbar mit /fbp smartcross. -- ab (Grosse Heilung -> Geringes Heilen), abschaltbar mit /fbp smartcross.
-- * v1.4.5: Blizzards Gruppenfenster ausblendbar (schliesst sich mit dem
-- Anheftmodus gegenseitig aus), Wut, Energie und Fokus im Balken,
-- +Heilung der Ausruestung ueber ClassicAPI in der Vorhersage.
-- --
-- Ehre wem Ehre gebuehrt: Aufbau, Namensplaketten und Grundidee stammen -- Ehre wem Ehre gebuehrt: Aufbau, Namensplaketten und Grundidee stammen
-- aus dem Original. -- aus dem Original.
@@ -120,6 +123,9 @@ HealBox = {
ButtonSpacing = 2, -- px zwischen den Buttons (1..20) ButtonSpacing = 2, -- px zwischen den Buttons (1..20)
RowSpacing = 4, -- px zwischen den Plaketten (1..20) RowSpacing = 4, -- px zwischen den Plaketten (1..20)
ManaBar = 1, -- Manabalken im Lebensbalken anzeigen ManaBar = 1, -- Manabalken im Lebensbalken anzeigen
PowerBar = 0, -- auch Wut, Energie und Fokus im Balken zeigen
HideBlizzParty = 0, -- Blizzards Gruppenfenster verstecken
HealBonus = 1, -- +Heilung der Ausruestung in die Vorhersage rechnen
ShowPets = 1, -- Begleiter als eigene Plaketten anzeigen ShowPets = 1, -- Begleiter als eigene Plaketten anzeigen
ClassColors = 1, -- Namen in Klassenfarbe ClassColors = 1, -- Namen in Klassenfarbe
RangeFade = 1, -- Plakette ausgrauen, wenn ausser Reichweite RangeFade = 1, -- Plakette ausgrauen, wenn ausser Reichweite
@@ -145,7 +151,7 @@ HealBox = {
-- feuert ADDON_LOADED fuer uns. -- feuert ADDON_LOADED fuer uns.
FBADDON_NAME = "Heal Box Vanilla"; FBADDON_NAME = "Heal Box Vanilla";
FBADDON_FOLDER = "FBHealBox"; FBADDON_FOLDER = "FBHealBox";
HealBoxVersion = "|cFFFFFF00v1.4.4.3|r"; HealBoxVersion = "|cFFFFFF00v1.4.5|r";
-- ========================================================================== -- ==========================================================================
-- [ Lokalisierung / Localization ] -- [ Lokalisierung / Localization ]
@@ -279,7 +285,7 @@ FBLocale["enUS"] = {
FBP_INCOMING = "Incoming", FBP_INCOMING = "Incoming",
FBP_DEBUG = "Debug:", FBP_DEBUG = "Debug:",
FBP_RESET = "Learned values discarded.", FBP_RESET = "Learned values discarded.",
FBP_COMMANDS = "Commands: /fbp config (options window), /fbp test (test mode), /fbp buffs (buff diagnostics), /fbp forceload (show for warrior/rogue/hunter), /fbp smartcross (downranking across spells), /fbp debug, /fbp reset", FBP_COMMANDS = "Commands: /fbp config (options window), /fbp test (test mode), /fbp buffs (buff diagnostics), /fbp forceload (show for warrior/rogue/hunter), /fbp smartcross (downranking across spells), /fbp healbonus (equipment bonus), /fbp debug, /fbp reset",
FBP_SMART = "Smart Healing: %s (safety margin %d %%)", FBP_SMART = "Smart Healing: %s (safety margin %d %%)",
DBG_HOT = "HoT %s on %s: %d per tick, %ds", DBG_HOT = "HoT %s on %s: %d per tick, %ds",
@@ -293,6 +299,14 @@ FBLocale["enUS"] = {
SMART_CROSS_ON = "Smart Healing may now switch spell within a heal chain (e.g. Greater Heal to Lesser Heal). |cFF00FF00On|r.", SMART_CROSS_ON = "Smart Healing may now switch spell within a heal chain (e.g. Greater Heal to Lesser Heal). |cFF00FF00On|r.",
SMART_CROSS_OFF = "Smart Healing now stays within the assigned spell and only lowers its rank. |cFFFF0000Cross-spell off|r.", SMART_CROSS_OFF = "Smart Healing now stays within the assigned spell and only lowers its rank. |cFFFF0000Cross-spell off|r.",
SMART_CROSS_NEEDS = "Note: Smart Healing itself is off, so this has no effect yet. Turn it on in the options or with the Smart Healing switch on the Buttons tab.", SMART_CROSS_NEEDS = "Note: Smart Healing itself is off, so this has no effect yet. Turn it on in the options or with the Smart Healing switch on the Buttons tab.",
HIDEPARTY = "Hide Blizzard party frames",
HIDEPARTY_TIP = "Hides Blizzard's party frames while you are in a group, so only the Heal Box plates remain. Cannot be combined with 'Attach to party frames', because that mode docks the plates onto exactly those frames; whichever one is on greys the other out. Switching it off brings the frames back at once, and so does a class the addon does not load for.",
POWERBAR = "Show rage, energy, focus",
POWERBAR_TIP = "The thin bar under the health bar normally shows mana and stays hidden for everyone else. With this on, warriors, rogues and pets get their own resource in its usual colour: rage red, energy yellow, focus orange. Needs the mana bar to be on.",
HEALBONUS_ON = "Equipment bonus of +%d healing is now included in the prediction. |cFF00FF00On|r.",
HEALBONUS_OFF = "Equipment bonus is no longer included, spell tooltips count as they are. |cFFFF0000Off|r.",
HEALBONUS_NA = "No API delivers a healing bonus. ClassicAPI (or anything else with GetSpellBonusHealing) enables this; without it the learned values from the combat log carry the gear anyway.",
FBP_HEALBONUS = "Equipment: +%d healing, applied to unlearned ranks: %s",
CLASS_BLOCKED = "not shown for %s: this addon is made for healing classes. Warriors, rogues and hunters have no heals, no heal prediction and nothing to gain from the mana ticker.", CLASS_BLOCKED = "not shown for %s: this addon is made for healing classes. Warriors, rogues and hunters have no heals, no heal prediction and nothing to gain from the mana ticker.",
CLASS_BLOCKED_HINT = "Type /fbp forceload to show it anyway. The setting is kept for this character.", CLASS_BLOCKED_HINT = "Type /fbp forceload to show it anyway. The setting is kept for this character.",
@@ -419,7 +433,7 @@ FBLocale["deDE"] = {
FBP_INCOMING = "Fremdheilung", FBP_INCOMING = "Fremdheilung",
FBP_DEBUG = "Debug:", FBP_DEBUG = "Debug:",
FBP_RESET = "Gelernte Werte verworfen.", FBP_RESET = "Gelernte Werte verworfen.",
FBP_COMMANDS = "Befehle: /fbp config (Optionsfenster), /fbp test (Testmodus), /fbp buffs (Buff-Diagnose), /fbp forceload (Anzeige fuer Krieger/Schurke/Jaeger), /fbp smartcross (Abrangen ueber Zaubergrenzen), /fbp debug, /fbp reset", FBP_COMMANDS = "Befehle: /fbp config (Optionsfenster), /fbp test (Testmodus), /fbp buffs (Buff-Diagnose), /fbp forceload (Anzeige fuer Krieger/Schurke/Jaeger), /fbp smartcross (Abrangen ueber Zaubergrenzen), /fbp healbonus (Ausruestungsbonus), /fbp debug, /fbp reset",
FBP_SMART = "Smart Healing: %s (Sicherheitsaufschlag %d %%)", FBP_SMART = "Smart Healing: %s (Sicherheitsaufschlag %d %%)",
DBG_HOT = "HoT %s auf %s: %d pro Tick, %ds", DBG_HOT = "HoT %s auf %s: %d pro Tick, %ds",
@@ -433,6 +447,14 @@ FBLocale["deDE"] = {
SMART_CROSS_ON = "Smart Healing darf den Zauber innerhalb einer Heilkette wechseln (z. B. Grosse Heilung zu Geringem Heilen). |cFF00FF00An|r.", SMART_CROSS_ON = "Smart Healing darf den Zauber innerhalb einer Heilkette wechseln (z. B. Grosse Heilung zu Geringem Heilen). |cFF00FF00An|r.",
SMART_CROSS_OFF = "Smart Healing bleibt beim belegten Zauber und senkt nur dessen Rang. |cFFFF0000Kettenwechsel aus|r.", SMART_CROSS_OFF = "Smart Healing bleibt beim belegten Zauber und senkt nur dessen Rang. |cFFFF0000Kettenwechsel aus|r.",
SMART_CROSS_NEEDS = "Hinweis: Smart Healing selbst ist aus, das wirkt also noch nicht. Einschalten im Optionsfenster ueber den Schalter Smart Healing im Reiter Buttons.", SMART_CROSS_NEEDS = "Hinweis: Smart Healing selbst ist aus, das wirkt also noch nicht. Einschalten im Optionsfenster ueber den Schalter Smart Healing im Reiter Buttons.",
HIDEPARTY = "Blizzard-Gruppenfenster aus",
HIDEPARTY_TIP = "Versteckt Blizzards Gruppenfenster, solange du in einer Gruppe bist, sodass nur die Plaketten der Heal Box uebrig bleiben. Nicht zusammen mit 'An Gruppenfenster anheften' nutzbar, weil dieser Modus die Plaketten genau an diese Frames haengt; was gerade an ist, graut das andere aus. Ausschalten holt die Frames sofort zurueck, ebenso eine Klasse, fuer die das Addon nicht laedt.",
POWERBAR = "Wut, Energie, Fokus zeigen",
POWERBAR_TIP = "Der schmale Streifen unter dem Lebensbalken zeigt normalerweise Mana und bleibt bei allen anderen leer. Eingeschaltet bekommen Krieger, Schurken und Begleiter ihre eigene Ressource in der gewohnten Farbe: Wut rot, Energie gelb, Fokus orange. Setzt den Manabalken voraus.",
HEALBONUS_ON = "Ausruestungsbonus von +%d Heilung wird jetzt eingerechnet. |cFF00FF00An|r.",
HEALBONUS_OFF = "Ausruestungsbonus wird nicht mehr eingerechnet, es zaehlt der nackte Tooltip. |cFFFF0000Aus|r.",
HEALBONUS_NA = "Keine API liefert einen Heilbonus. Mit ClassicAPI (oder etwas anderem mit GetSpellBonusHealing) geht das; ohne sie tragen die gelernten Werte aus dem Combatlog die Ausruestung ohnehin mit.",
FBP_HEALBONUS = "Ausruestung: +%d Heilung, auf ungelernte Raenge angewandt: %s",
CLASS_BLOCKED = "wird fuer %s nicht angezeigt: Das Addon ist fuer Heilerklassen gemacht. Krieger, Schurken und Jaeger haben keine Heilzauber, keine Heilvorhersage und keinen Nutzen vom Mana-Ticker.", CLASS_BLOCKED = "wird fuer %s nicht angezeigt: Das Addon ist fuer Heilerklassen gemacht. Krieger, Schurken und Jaeger haben keine Heilzauber, keine Heilvorhersage und keinen Nutzen vom Mana-Ticker.",
CLASS_BLOCKED_HINT = "Mit /fbp forceload trotzdem anzeigen. Die Einstellung bleibt fuer diesen Charakter gespeichert.", CLASS_BLOCKED_HINT = "Mit /fbp forceload trotzdem anzeigen. Die Einstellung bleibt fuer diesen Charakter gespeichert.",
@@ -579,7 +601,7 @@ FBLocale["esES"] = {
FBP_INCOMING = "Entrante", FBP_INCOMING = "Entrante",
FBP_DEBUG = "Depuración:", FBP_DEBUG = "Depuración:",
FBP_RESET = "Valores aprendidos descartados.", FBP_RESET = "Valores aprendidos descartados.",
FBP_COMMANDS = "Comandos: /fbp config (ventana de opciones), /fbp test (modo de prueba), /fbp buffs (diagnóstico de beneficios), /fbp forceload (mostrar para guerrero/pícaro/cazador), /fbp smartcross (reducción entre hechizos), /fbp debug, /fbp reset", FBP_COMMANDS = "Comandos: /fbp config (ventana de opciones), /fbp test (modo de prueba), /fbp buffs (diagnóstico de beneficios), /fbp forceload (mostrar para guerrero/pícaro/cazador), /fbp smartcross (reducción entre hechizos), /fbp healbonus (bono de equipo), /fbp debug, /fbp reset",
FBP_SMART = "Smart Healing: %s (margen de seguridad %d %%)", FBP_SMART = "Smart Healing: %s (margen de seguridad %d %%)",
DBG_HOT = "HoT %s sobre %s: %d por pulso, %ds", DBG_HOT = "HoT %s sobre %s: %d por pulso, %ds",
DBG_SHIELD = "Escudo %s sobre %s: %d absorción, %ds", DBG_SHIELD = "Escudo %s sobre %s: %d absorción, %ds",
@@ -592,6 +614,14 @@ FBLocale["esES"] = {
SMART_CROSS_ON = "Smart Healing puede cambiar de hechizo dentro de una cadena de curación (p. ej. Curar más y Curar menos). |cFF00FF00Activado|r.", SMART_CROSS_ON = "Smart Healing puede cambiar de hechizo dentro de una cadena de curación (p. ej. Curar más y Curar menos). |cFF00FF00Activado|r.",
SMART_CROSS_OFF = "Smart Healing se queda en el hechizo asignado y solo baja su rango. |cFFFF0000Cambio de hechizo desactivado|r.", SMART_CROSS_OFF = "Smart Healing se queda en el hechizo asignado y solo baja su rango. |cFFFF0000Cambio de hechizo desactivado|r.",
SMART_CROSS_NEEDS = "Nota: Smart Healing está desactivado, así que esto aún no tiene efecto. Actívalo en la pestaña Botones.", SMART_CROSS_NEEDS = "Nota: Smart Healing está desactivado, así que esto aún no tiene efecto. Actívalo en la pestaña Botones.",
HIDEPARTY = "Ocultar marcos de grupo",
HIDEPARTY_TIP = "Oculta los marcos de grupo de Blizzard mientras estás en un grupo, dejando solo las placas de Heal Box. No se puede combinar con 'Anclar a los marcos de grupo', porque ese modo ancla las placas justo en esos marcos; el que esté activo desactiva el otro.",
POWERBAR = "Mostrar ira, energía, enfoque",
POWERBAR_TIP = "La barra fina bajo la salud muestra normalmente maná y queda vacía para los demás. Activada, guerreros, pícaros y mascotas muestran su recurso en su color habitual: ira roja, energía amarilla, enfoque naranja. Requiere la barra de maná.",
HEALBONUS_ON = "El bono de equipo de +%d de sanación ya se incluye en la predicción. |cFF00FF00Activado|r.",
HEALBONUS_OFF = "El bono de equipo ya no se incluye, cuenta el tooltip puro. |cFFFF0000Desactivado|r.",
HEALBONUS_NA = "Ninguna API ofrece un bono de sanación. ClassicAPI (u otra con GetSpellBonusHealing) lo habilita; sin ella, los valores aprendidos del registro de combate ya incluyen el equipo.",
FBP_HEALBONUS = "Equipo: +%d de sanación, aplicado a rangos no aprendidos: %s",
CLASS_BLOCKED = "no se muestra para %s: este addon está hecho para clases sanadoras. Guerreros, pícaros y cazadores no tienen curaciones, ni predicción de curación, ni provecho del marcador de maná.", CLASS_BLOCKED = "no se muestra para %s: este addon está hecho para clases sanadoras. Guerreros, pícaros y cazadores no tienen curaciones, ni predicción de curación, ni provecho del marcador de maná.",
CLASS_BLOCKED_HINT = "Escribe /fbp forceload para mostrarlo igualmente. El ajuste se guarda para este personaje.", CLASS_BLOCKED_HINT = "Escribe /fbp forceload para mostrarlo igualmente. El ajuste se guarda para este personaje.",
@@ -710,7 +740,7 @@ FBLocale["frFR"] = {
FBP_INCOMING = "Entrant", FBP_INCOMING = "Entrant",
FBP_DEBUG = "Débogage :", FBP_DEBUG = "Débogage :",
FBP_RESET = "Valeurs apprises effacées.", FBP_RESET = "Valeurs apprises effacées.",
FBP_COMMANDS = "Commandes : /fbp config (fenêtre des options), /fbp test (mode test), /fbp buffs (diagnostic des buffs), /fbp forceload (afficher pour guerrier/voleur/chasseur), /fbp smartcross (rang abaissé entre sorts), /fbp debug, /fbp reset", FBP_COMMANDS = "Commandes : /fbp config (fenêtre des options), /fbp test (mode test), /fbp buffs (diagnostic des buffs), /fbp forceload (afficher pour guerrier/voleur/chasseur), /fbp smartcross (rang abaissé entre sorts), /fbp healbonus (bonus d'équipement), /fbp debug, /fbp reset",
FBP_SMART = "Smart Healing : %s (marge de sécurité %d %%)", FBP_SMART = "Smart Healing : %s (marge de sécurité %d %%)",
DBG_HOT = "HoT %s sur %s : %d par tick, %ds", DBG_HOT = "HoT %s sur %s : %d par tick, %ds",
DBG_SHIELD = "Bouclier %s sur %s : %d absorption, %ds", DBG_SHIELD = "Bouclier %s sur %s : %d absorption, %ds",
@@ -723,6 +753,14 @@ FBLocale["frFR"] = {
SMART_CROSS_ON = "Smart Healing peut changer de sort dans une chaîne de soins (p. ex. Soins supérieurs vers Soins inférieurs). |cFF00FF00Activé|r.", SMART_CROSS_ON = "Smart Healing peut changer de sort dans une chaîne de soins (p. ex. Soins supérieurs vers Soins inférieurs). |cFF00FF00Activé|r.",
SMART_CROSS_OFF = "Smart Healing reste sur le sort assigné et n'abaisse que son rang. |cFFFF0000Changement de sort désactivé|r.", SMART_CROSS_OFF = "Smart Healing reste sur le sort assigné et n'abaisse que son rang. |cFFFF0000Changement de sort désactivé|r.",
SMART_CROSS_NEEDS = "Note : Smart Healing lui-même est désactivé, ceci n'a donc pas encore d'effet. Activez-le dans l'onglet Boutons.", SMART_CROSS_NEEDS = "Note : Smart Healing lui-même est désactivé, ceci n'a donc pas encore d'effet. Activez-le dans l'onglet Boutons.",
HIDEPARTY = "Masquer les cadres de groupe",
HIDEPARTY_TIP = "Masque les cadres de groupe de Blizzard tant que vous êtes en groupe, il ne reste que les plaques de Heal Box. Incompatible avec 'Ancrer aux cadres de groupe', car ce mode ancre les plaques précisément sur ces cadres ; celui qui est actif grise l'autre.",
POWERBAR = "Afficher rage, énergie, focus",
POWERBAR_TIP = "La fine barre sous la santé montre normalement le mana et reste vide pour les autres. Activée, les guerriers, voleurs et familiers affichent leur ressource dans sa couleur habituelle : rage rouge, énergie jaune, focus orange. Nécessite la barre de mana.",
HEALBONUS_ON = "Le bonus d'équipement de +%d soins est désormais pris en compte. |cFF00FF00Activé|r.",
HEALBONUS_OFF = "Le bonus d'équipement n'est plus pris en compte, seul l'infobulle compte. |cFFFF0000Désactivé|r.",
HEALBONUS_NA = "Aucune API ne fournit de bonus aux soins. ClassicAPI (ou autre avec GetSpellBonusHealing) l'active ; sans elle, les valeurs apprises du journal de combat portent déjà l'équipement.",
FBP_HEALBONUS = "Équipement : +%d soins, appliqué aux rangs non appris : %s",
CLASS_BLOCKED = "non affiché pour %s : cet addon est fait pour les classes soigneuses. Les guerriers, voleurs et chasseurs n'ont pas de soins, pas de prévision de soins et aucun usage du compteur de mana.", CLASS_BLOCKED = "non affiché pour %s : cet addon est fait pour les classes soigneuses. Les guerriers, voleurs et chasseurs n'ont pas de soins, pas de prévision de soins et aucun usage du compteur de mana.",
CLASS_BLOCKED_HINT = "Tapez /fbp forceload pour l'afficher quand même. Le réglage est conservé pour ce personnage.", CLASS_BLOCKED_HINT = "Tapez /fbp forceload pour l'afficher quand même. Le réglage est conservé pour ce personnage.",
@@ -841,7 +879,7 @@ FBLocale["itIT"] = {
FBP_INCOMING = "In arrivo", FBP_INCOMING = "In arrivo",
FBP_DEBUG = "Debug:", FBP_DEBUG = "Debug:",
FBP_RESET = "Valori appresi scartati.", FBP_RESET = "Valori appresi scartati.",
FBP_COMMANDS = "Comandi: /fbp config (finestra opzioni), /fbp test (modalità test), /fbp buffs (diagnostica benefici), /fbp forceload (mostra per guerriero/ladro/cacciatore), /fbp smartcross (riduzione tra incantesimi), /fbp debug, /fbp reset", FBP_COMMANDS = "Comandi: /fbp config (finestra opzioni), /fbp test (modalità test), /fbp buffs (diagnostica benefici), /fbp forceload (mostra per guerriero/ladro/cacciatore), /fbp smartcross (riduzione tra incantesimi), /fbp healbonus (bonus equipaggiamento), /fbp debug, /fbp reset",
FBP_SMART = "Smart Healing: %s (margine di sicurezza %d %%)", FBP_SMART = "Smart Healing: %s (margine di sicurezza %d %%)",
DBG_HOT = "HoT %s su %s: %d per tick, %ds", DBG_HOT = "HoT %s su %s: %d per tick, %ds",
DBG_SHIELD = "Scudo %s su %s: %d assorbimento, %ds", DBG_SHIELD = "Scudo %s su %s: %d assorbimento, %ds",
@@ -854,6 +892,14 @@ FBLocale["itIT"] = {
SMART_CROSS_ON = "Smart Healing può cambiare incantesimo all'interno di una catena di cure (p. es. da Cura Superiore a Cura Inferiore). |cFF00FF00Attivo|r.", SMART_CROSS_ON = "Smart Healing può cambiare incantesimo all'interno di una catena di cure (p. es. da Cura Superiore a Cura Inferiore). |cFF00FF00Attivo|r.",
SMART_CROSS_OFF = "Smart Healing resta sull'incantesimo assegnato e ne abbassa solo il rango. |cFFFF0000Cambio incantesimo disattivato|r.", SMART_CROSS_OFF = "Smart Healing resta sull'incantesimo assegnato e ne abbassa solo il rango. |cFFFF0000Cambio incantesimo disattivato|r.",
SMART_CROSS_NEEDS = "Nota: Smart Healing stesso è disattivato, quindi questo non ha ancora effetto. Attivalo nella scheda Pulsanti.", SMART_CROSS_NEEDS = "Nota: Smart Healing stesso è disattivato, quindi questo non ha ancora effetto. Attivalo nella scheda Pulsanti.",
HIDEPARTY = "Nascondi i riquadri gruppo",
HIDEPARTY_TIP = "Nasconde i riquadri del gruppo di Blizzard finché sei in gruppo, restano solo le targhette di Heal Box. Non combinabile con 'Aggancia ai riquadri gruppo', perché quella modalità aggancia le targhette proprio a quei riquadri; quella attiva disattiva l'altra.",
POWERBAR = "Mostra ira, energia, focus",
POWERBAR_TIP = "La barra sottile sotto la salute mostra di norma il mana e resta vuota per gli altri. Attiva, guerrieri, ladri e famigli mostrano la loro risorsa nel colore consueto: ira rossa, energia gialla, focus arancione. Richiede la barra del mana.",
HEALBONUS_ON = "Il bonus dell'equipaggiamento di +%d cura viene ora incluso. |cFF00FF00Attivo|r.",
HEALBONUS_OFF = "Il bonus dell'equipaggiamento non viene più incluso, conta il tooltip nudo. |cFFFF0000Disattivo|r.",
HEALBONUS_NA = "Nessuna API fornisce un bonus alle cure. ClassicAPI (o altro con GetSpellBonusHealing) lo abilita; senza, i valori appresi dal registro di combattimento includono già l'equipaggiamento.",
FBP_HEALBONUS = "Equipaggiamento: +%d cura, applicato ai ranghi non appresi: %s",
CLASS_BLOCKED = "non mostrato per %s: questo addon è pensato per le classi curatrici. Guerrieri, ladri e cacciatori non hanno cure, né previsione delle cure, né vantaggi dal contatore del mana.", CLASS_BLOCKED = "non mostrato per %s: questo addon è pensato per le classi curatrici. Guerrieri, ladri e cacciatori non hanno cure, né previsione delle cure, né vantaggi dal contatore del mana.",
CLASS_BLOCKED_HINT = "Scrivi /fbp forceload per mostrarlo comunque. L'impostazione resta salvata per questo personaggio.", CLASS_BLOCKED_HINT = "Scrivi /fbp forceload per mostrarlo comunque. L'impostazione resta salvata per questo personaggio.",
@@ -902,6 +948,14 @@ NamePlateHeight = 28;
-- Manabalken: "Balken im Balken" am unteren Rand des Lebensbalkens -- Manabalken: "Balken im Balken" am unteren Rand des Lebensbalkens
FBMANA_BAR_HEIGHT = 5; -- px FBMANA_BAR_HEIGHT = 5; -- px
FBMANA_BAR_COLOR = { 0.15, 0.40, 1.00, 1 }; -- blau FBMANA_BAR_COLOR = { 0.15, 0.40, 1.00, 1 }; -- blau
-- Farben je Energieart, wie sie UnitPowerType liefert. Nur Mana faerbt den
-- Balken standardmaessig; die uebrigen erscheinen erst mit HealBox.PowerBar.
FBPOWER_COLORS = {
[0] = { 0.15, 0.40, 1.00, 1 }, -- Mana, blau
[1] = { 0.85, 0.20, 0.20, 1 }, -- Wut, rot
[2] = { 1.00, 0.55, 0.20, 1 }, -- Fokus, orange
[3] = { 1.00, 0.85, 0.10, 1 }, -- Energie, gelb
};
FBMANA_BG_ALPHA = 0.35; -- dunkler Streifen hinter dem Mana (0 = aus) FBMANA_BG_ALPHA = 0.35; -- dunkler Streifen hinter dem Mana (0 = aus)
-- Begleiter-Plaketten: Namensfarbe, Einrueckung unter dem Besitzer (die -- Begleiter-Plaketten: Namensfarbe, Einrueckung unter dem Besitzer (die
@@ -1054,7 +1108,7 @@ FBTestMode = false;
-- los = true zeigt das Sichtlinien-Abzeichen, aggro = true den roten Rahmen, -- los = true zeigt das Sichtlinien-Abzeichen, aggro = true den roten Rahmen,
-- hotLeft/shieldLeft Restsekunden auf Button 1 bzw. 2. -- hotLeft/shieldLeft Restsekunden auf Button 1 bzw. 2.
FBTestGhosts = { FBTestGhosts = {
["party1"] = { name = "Brynn", class = "WARRIOR", hpMax = 3400, hp = 0.90, swing = 0.08, hasMana = false, buffMissing = true, state = "dead" }, ["party1"] = { name = "Brynn", class = "WARRIOR", hpMax = 3400, hp = 0.90, swing = 0.08, hasMana = false, power = 1, mpMax = 100, mp = 0.45, buffMissing = true, state = "dead" },
["party2"] = { name = "Cerys", class = "WARLOCK", hpMax = 2300, hp = 0.55, swing = 0.10, hasMana = true, mpMax = 3100, mp = 0.65, shield = 450, los = true }, ["party2"] = { name = "Cerys", class = "WARLOCK", hpMax = 2300, hp = 0.55, swing = 0.10, hasMana = true, mpMax = 3100, mp = 0.65, shield = 450, los = true },
["party3"] = { name = "Dorn", class = "HUNTER", hpMax = 2900, hp = 0.30, swing = 0.15, hasMana = true, mpMax = 2400, mp = 0.35, inc = 700, aggro = true, hotLeft = 9, shieldLeft = 21, ["party3"] = { name = "Dorn", class = "HUNTER", hpMax = 2900, hp = 0.30, swing = 0.15, hasMana = true, mpMax = 2400, mp = 0.35, inc = 700, aggro = true, hotLeft = 9, shieldLeft = 21,
-- sechs Buffs: Seelenstaerke, Willen, Schattenschutz, Furchtzauberschutz, Mal der Wildnis (fremd, ohne Uhr), Koenige -- sechs Buffs: Seelenstaerke, Willen, Schattenschutz, Furchtzauberschutz, Mal der Wildnis (fremd, ohne Uhr), Koenige
@@ -1065,9 +1119,9 @@ FBTestGhosts = {
{ tex = "Interface\\Icons\\Spell_Nature_Regeneration", dur = 1800 }, { tex = "Interface\\Icons\\Spell_Nature_Regeneration", dur = 1800 },
{ tex = "Interface\\Icons\\Spell_Magic_MageArmor", left = 1750, dur = 1800 } } }, { tex = "Interface\\Icons\\Spell_Magic_MageArmor", left = 1750, dur = 1800 } } },
["party4"] = { name = "Elowen", class = "DRUID", hpMax = 2700, hp = 0.95, swing = 0.04, hasMana = true, mpMax = 3600, mp = 0.90, debuff = true, debuffTex = "Interface\\Icons\\Spell_Shadow_ShadowWordPain", debuffCount = 3, outOfRange = true }, ["party4"] = { name = "Elowen", class = "DRUID", hpMax = 2700, hp = 0.95, swing = 0.04, hasMana = true, mpMax = 3600, mp = 0.90, debuff = true, debuffTex = "Interface\\Icons\\Spell_Shadow_ShadowWordPain", debuffCount = 3, outOfRange = true },
["pet"] = { name = "Fang", hpMax = 1900, hp = 0.75, swing = 0.12, hasMana = false }, ["pet"] = { name = "Fang", hpMax = 1900, hp = 0.75, swing = 0.12, hasMana = false, power = 3, mpMax = 100, mp = 0.80 },
["partypet2"] = { name = "Zorbek", hpMax = 1200, hp = 0.60, swing = 0.10, hasMana = true, mpMax = 900, mp = 0.50 }, ["partypet2"] = { name = "Zorbek", hpMax = 1200, hp = 0.60, swing = 0.10, hasMana = true, mpMax = 900, mp = 0.50 },
["partypet3"] = { name = "Bramble", hpMax = 2100, hp = 0.40, swing = 0.14, hasMana = false, inc = 300, ["partypet3"] = { name = "Bramble", hpMax = 2100, hp = 0.40, swing = 0.14, hasMana = false, power = 2, mpMax = 100, mp = 0.60, inc = 300,
debuffType = "Disease", debuffTex = "Interface\\Icons\\Spell_Nature_NullifyDisease", debuffCount = 1 }, debuffType = "Disease", debuffTex = "Interface\\Icons\\Spell_Nature_NullifyDisease", debuffCount = 1 },
}; };
@@ -1127,18 +1181,26 @@ end
-- liefert mp, mpMax, hasMana. hasMana ist nur wahr, wenn die Einheit -- liefert mp, mpMax, hasMana. hasMana ist nur wahr, wenn die Einheit
-- tatsaechlich Mana nutzt (Powertyp 0). Krieger, Schurken, Druiden in -- tatsaechlich Mana nutzt (Powertyp 0). Krieger, Schurken, Druiden in
-- Gestalt und Jaegerbegleiter bekommen keinen Manabalken. -- Gestalt und Jaegerbegleiter bekommen keinen Manabalken.
-- Energie einer Einheit: Wert, Maximum, anzeigen?, Energieart (0 = Mana).
-- Ohne HealBox.PowerBar bleibt es beim Mana, Wut, Energie und Fokus liefern
-- dann wie frueher "nichts anzuzeigen" und der Lebensbalken bleibt voll hoch.
function FBUnitMana(unit) function FBUnitMana(unit)
local g = FBTest_Ghost(unit); local g = FBTest_Ghost(unit);
if (g) then if (g) then
if (not g.hasMana) then return 0, 0, false; end if (not g.hasMana) then
return math.floor(g.mpMax * g.mp), g.mpMax, true; 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 end
local ptype = 0; local ptype = 0;
if (UnitPowerType) then ptype = UnitPowerType(unit); end if (UnitPowerType) then ptype = UnitPowerType(unit); end
if (ptype ~= 0) then return 0, 0, false; end if (ptype ~= 0) and (HealBox.PowerBar ~= 1) then return 0, 0, false, nil; end
local mp, mpMax = UnitMana(unit), UnitManaMax(unit); local mp, mpMax = UnitMana(unit), UnitManaMax(unit);
if (not mpMax) or (mpMax <= 0) then return 0, 0, false; end if (not mpMax) or (mpMax <= 0) then return 0, 0, false, nil; end
return (mp or 0), mpMax, true; return (mp or 0), mpMax, true, ptype;
end end
-- nil (lebt), "dead", "ghost" oder "offline" -- nil (lebt), "dead", "ghost" oder "offline"
@@ -1329,6 +1391,7 @@ function FBHealBox_HideAll()
end end
if (panel) then panel:Hide(); end if (panel) then panel:Hide(); end
if (MMButton) then MMButton:Hide(); end if (MMButton) then MMButton:Hide(); end
FBHealBox_ApplyBlizzParty(); -- Blizzards Gruppenfenster zurueckgeben
FBHealBox_RunHook("Suppress"); FBHealBox_RunHook("Suppress");
end end
@@ -1367,6 +1430,7 @@ function FBHealBox_StartUp()
FBHealBox_SyncOptions(); FBHealBox_SyncOptions();
HealBoxAttachMode(HealBox.AttachMode); HealBoxAttachMode(HealBox.AttachMode);
FBHealBox_ApplyButtonSpacing(); FBHealBox_ApplyButtonSpacing();
FBHealBox_ApplyBlizzParty();
if (MMButton) then MMButton:Show(); end if (MMButton) then MMButton:Show(); end
FBUpdateNames(); FBUpdateNames();
end end
@@ -1389,6 +1453,7 @@ function FBHealBox_OnLoad()
this:RegisterEvent("UNIT_MANA"); this:RegisterEvent("UNIT_MANA");
this:RegisterEvent("UNIT_MAXMANA"); this:RegisterEvent("UNIT_MAXMANA");
this:RegisterEvent("UNIT_DISPLAYPOWER"); this:RegisterEvent("UNIT_DISPLAYPOWER");
this:RegisterEvent("UNIT_INVENTORY_CHANGED");
end end
-- Fehlende Schluessel in den geladenen SavedVariables nachziehen -- Fehlende Schluessel in den geladenen SavedVariables nachziehen
@@ -1404,6 +1469,9 @@ function FBHealBox_ApplyDefaults()
if (HealBox.ButtonSpacing == nil) then HealBox.ButtonSpacing = 2; end if (HealBox.ButtonSpacing == nil) then HealBox.ButtonSpacing = 2; end
if (HealBox.RowSpacing == nil) then HealBox.RowSpacing = 4; end if (HealBox.RowSpacing == nil) then HealBox.RowSpacing = 4; end
if (HealBox.ManaBar == nil) then HealBox.ManaBar = 1; end if (HealBox.ManaBar == nil) then HealBox.ManaBar = 1; end
if (HealBox.PowerBar == nil) then HealBox.PowerBar = 0; end
if (HealBox.HideBlizzParty == nil) then HealBox.HideBlizzParty = 0; end
if (HealBox.HealBonus == nil) then HealBox.HealBonus = 1; end
if (HealBox.ShowPets == nil) then HealBox.ShowPets = 1; end if (HealBox.ShowPets == nil) then HealBox.ShowPets = 1; end
if (HealBox.ClassColors == nil) then HealBox.ClassColors = 1; end if (HealBox.ClassColors == nil) then HealBox.ClassColors = 1; end
if (HealBox.RangeFade == nil) then HealBox.RangeFade = 1; end if (HealBox.RangeFade == nil) then HealBox.RangeFade = 1; end
@@ -1434,6 +1502,8 @@ function FBHealBox_SyncOptions()
if (AttachModeCheck) then AttachModeCheck:SetChecked(HealBox.AttachMode == 1); end if (AttachModeCheck) then AttachModeCheck:SetChecked(HealBox.AttachMode == 1); end
if (HealCommCheck) then HealCommCheck:SetChecked(HealBox.HealComm == 1); end if (HealCommCheck) then HealCommCheck:SetChecked(HealBox.HealComm == 1); end
if (ManaBarCheck) then ManaBarCheck:SetChecked(HealBox.ManaBar == 1); end if (ManaBarCheck) then ManaBarCheck:SetChecked(HealBox.ManaBar == 1); end
if (PowerBarCheck) then PowerBarCheck:SetChecked(HealBox.PowerBar == 1); end
if (HidePartyCheck) then HidePartyCheck:SetChecked(HealBox.HideBlizzParty == 1); end
if (ShowPetsCheck) then ShowPetsCheck:SetChecked(HealBox.ShowPets == 1); end if (ShowPetsCheck) then ShowPetsCheck:SetChecked(HealBox.ShowPets == 1); end
if (TestModeCheck) then TestModeCheck:SetChecked(FBTestMode); end if (TestModeCheck) then TestModeCheck:SetChecked(FBTestMode); end
if (ClassColorsCheck) then ClassColorsCheck:SetChecked(HealBox.ClassColors == 1); end if (ClassColorsCheck) then ClassColorsCheck:SetChecked(HealBox.ClassColors == 1); end
@@ -1453,6 +1523,7 @@ function FBHealBox_SyncOptions()
FBHealBox_UpdatePlateActionLabels(); FBHealBox_UpdatePlateActionLabels();
FBHealBox_ApplyRightClickLayout(); FBHealBox_ApplyRightClickLayout();
FBHealBox_UpdateSmartCrossState(); FBHealBox_UpdateSmartCrossState();
FBHealBox_UpdatePartyExclusion();
FBHealBox_RunHook("SyncOptions"); FBHealBox_RunHook("SyncOptions");
end end
@@ -1472,6 +1543,26 @@ function FBHealBox_UpdateSmartCrossState()
end end
end end
-- Anheftmodus und das Verstecken der Blizzard-Frames schliessen sich aus:
-- was gerade nicht geht, wird gesperrt und ausgegraut.
function FBHealBox_UpdatePartyExclusion()
local pairsList = {
{ box = AttachModeCheck, blocked = (HealBox.HideBlizzParty == 1) },
{ box = HidePartyCheck, blocked = (HealBox.AttachMode == 1) },
};
for _, e in ipairs(pairsList) do
if (e.box) then
if (e.blocked) then
e.box:Disable();
if (e.box.Text) then e.box.Text:SetTextColor(0.5, 0.5, 0.5, 1); end
else
e.box:Enable();
if (e.box.Text) then e.box.Text:SetTextColor(1, 0.82, 0, 1); end
end
end
end
end
function FBUnitGUID(unit) function FBUnitGUID(unit)
if (FBHasSuperWoW and UnitExists(unit)) then if (FBHasSuperWoW and UnitExists(unit)) then
local exists, guid = UnitExists(unit); local exists, guid = UnitExists(unit);
@@ -1528,6 +1619,8 @@ function FBLoadSpellData()
-- Tooltips auswerten: welche dieser Zauber sind HoTs bzw. Absorb-Schilde? -- Tooltips auswerten: welche dieser Zauber sind HoTs bzw. Absorb-Schilde?
FBPredict_BuildWatch(); FBPredict_BuildWatch();
FBSpellNameCache = {}; FBSpellNameCache = {};
FBSpellCastCache = {};
FBHealBox_InvalidateRangeSpell();
FBHealBox_ProbeAPIs(); FBHealBox_ProbeAPIs();
-- Doppelt gezaehlte Absorb-Lernwerte (Versionen vor 1.4.2) verwerfen -- Doppelt gezaehlte Absorb-Lernwerte (Versionen vor 1.4.2) verwerfen
FBPredict_SanitizeMemory(); FBPredict_SanitizeMemory();
@@ -1551,6 +1644,7 @@ end
-- side = "L" (Standard) oder "R" (Rechtsklick) -- side = "L" (Standard) oder "R" (Rechtsklick)
function FBApplySpellChoice(i, castString, side) function FBApplySpellChoice(i, castString, side)
if type(castString) == "number" then return; end if type(castString) == "number" then return; end
FBHealBox_InvalidateRangeSpell(); -- Belegung geaendert
local names, icons, ids, fields = FBChoiceTables(side); local names, icons, ids, fields = FBChoiceTables(side);
names[i] = castString; names[i] = castString;
@@ -2075,6 +2169,12 @@ function FBHealBox_OnEvent(event, arg1)
-- im naechsten Frame zusammengefasst. -- im naechsten Frame zusammengefasst.
if (event == "PARTY_MEMBERS_CHANGED" or event == "UNIT_PET") then if (event == "PARTY_MEMBERS_CHANGED" or event == "UNIT_PET") then
FBNamesDirty = true; FBNamesDirty = true;
FBBlizzPartyDirty = true; -- neue Mitglieder gleich mit verstecken
end
-- Ausruestung gewechselt: gemerkten +Heilung-Wert verwerfen
if (event == "UNIT_INVENTORY_CHANGED") and (arg1 == "player") then
FBHealBox_InvalidateHealBonus();
end end
if (event == "UNIT_NAME_UPDATE") then if (event == "UNIT_NAME_UPDATE") then
@@ -2543,7 +2643,7 @@ function FBHealBox_DirectAmount(spellName, sd)
if (not sd) then return nil; end if (not sd) then return nil; end
local info = FBPredict_GetSpellInfo(sd.id, spellName); local info = FBPredict_GetSpellInfo(sd.id, spellName);
if (not info) or (not info.direct) or info.shield or info.hot or (not info.isHeal) then return nil; end if (not info) or (not info.direct) or info.shield or info.hot or (not info.isHeal) then return nil; end
return FBPredict_Remembered("direct", spellName, sd.rank) or info.direct; return FBPredict_ExpectedDirect(spellName, sd.rank, info, sd.id);
end end
-- Alle Zauber, die als kleinere Ausgabe von base gelten (base immer dabei) -- Alle Zauber, die als kleinere Ausgabe von base gelten (base immer dabei)
@@ -2915,6 +3015,18 @@ end
-- Buff-Texturen einer Einheit, je Frame nur einmal gelesen: Vorhersage-Scan -- Buff-Texturen einer Einheit, je Frame nur einmal gelesen: Vorhersage-Scan
-- und Buff-Wache brauchen dieselbe Liste im selben Event. -- und Buff-Wache brauchen dieselbe Liste im selben Event.
-- Grossschreibung von Texturpfaden einmal merken. Die Pfade wiederholen sich
-- staendig, strupper legt sonst bei jedem Aufruf einen neuen String an, der
-- gleich wieder Muell ist. Die Tabelle bleibt klein: es gibt nur so viele
-- Eintraege wie unterschiedliche Buff-Texturen.
FBTexUpperMemo = {};
function FBHealBox_UpperTex(tex)
if (not tex) then return nil; end
local u = FBTexUpperMemo[tex];
if (not u) then u = strupper(tex); FBTexUpperMemo[tex] = u; end
return u;
end
FBBuffScanMemo = {}; -- [unit] = { t, tex = {}, list = {}, n } FBBuffScanMemo = {}; -- [unit] = { t, tex = {}, list = {}, n }
function FBHealBox_UnitBuffs(unit) function FBHealBox_UnitBuffs(unit)
local now = GetTime(); local now = GetTime();
@@ -2926,7 +3038,7 @@ function FBHealBox_UnitBuffs(unit)
while (i <= 32) do while (i <= 32) do
local tex = UnitBuff(unit, i); local tex = UnitBuff(unit, i);
if (not tex) then break; end if (not tex) then break; end
tex = strupper(tex); tex = FBHealBox_UpperTex(tex);
m.tex[tex] = true; m.tex[tex] = true;
m.list[i] = tex; m.list[i] = tex;
i = i + 1; i = i + 1;
@@ -3211,10 +3323,24 @@ function FBLOS_HasUnitXP()
end end
-- UnitXP sicher abfragen: true / false, nil wenn nicht verfuegbar -- UnitXP sicher abfragen: true / false, nil wenn nicht verfuegbar
-- Ein Durchlauf hat geworfen, obwohl die Form sich vorher bewaehrt hatte.
-- Dann gehen alle drei Abfragen wieder in den geschuetzten Einzelaufruf: der
-- faengt den Fehler ab, liefert nil und der Rueckfallweg greift wie frueher.
-- Das Addon heilt sich also selbst, statt dauerhaft Fehler zu werfen.
function FBHealBox_ApiFailed()
FBAPI_RangeDirect = false;
FBAPI_DistDirect = false;
FBAPI_SightDirect = false;
end
-- Wie bei der Reichweite: der erste Aufruf geschuetzt, danach direkt.
FBAPI_SightDirect = false;
function FBLOS_QueryUnitXP(unit) function FBLOS_QueryUnitXP(unit)
if (not UnitXP) then return nil; end if (not UnitXP) then return nil; end
if (FBAPI_SightDirect) then return UnitXP("inSight", "player", unit); end
local ok, res = pcall(UnitXP, "inSight", "player", unit); local ok, res = pcall(UnitXP, "inSight", "player", unit);
if (not ok) then return nil; end if (not ok) then return nil; end
FBAPI_SightDirect = true;
return res; return res;
end end
@@ -3254,6 +3380,10 @@ function FBLOS_Clear(name)
end end
function FBHealBox_CheckLOSAll() function FBHealBox_CheckLOSAll()
if (not pcall(FBHealBox_CheckLOSSweep)) then FBHealBox_ApiFailed(); end
end
function FBHealBox_CheckLOSSweep()
for p = 1, FBSlotCount do for p = 1, FBSlotCount do
local f = FBPartyFrame[p]; local f = FBPartyFrame[p];
if (f and f.LOSIcon) then if (f and f.LOSIcon) then
@@ -3309,6 +3439,9 @@ function FBHealBox_ProbeAPIs()
FBAPI_Probed = true; FBAPI_Probed = true;
FBAPI_SpellRange = false; FBAPI_RangeForm = nil; FBAPI_SpellRange = false; FBAPI_RangeForm = nil;
FBAPI_UsableSpell = false; FBAPI_UsableForm = nil; FBAPI_UsableSpell = false; FBAPI_UsableForm = nil;
-- Direktaufruf erst wieder erlauben, wenn eine Form sich bewaehrt hat
FBAPI_RangeDirect = false; FBAPI_DistDirect = false; FBAPI_SightDirect = false;
FBHealBox_ProbeHealBonus();
if (type(IsSpellInRange) == "function") then if (type(IsSpellInRange) == "function") then
local ok = pcall(IsSpellInRange, 1, BOOKTYPE_SPELL, "player"); local ok = pcall(IsSpellInRange, 1, BOOKTYPE_SPELL, "player");
if (ok) then if (ok) then
@@ -3329,6 +3462,120 @@ function FBHealBox_ProbeAPIs()
end end
end end
-- ==========================================================================
-- [ +Heilung aus der Ausruestung ]
--
-- Vanilla-Tooltips zeigen den Heilbonus der Ausruestung nicht, der Tooltip
-- eines Zaubers nennt also immer den nackten Grundwert. Gelernte Werte aus
-- dem Combatlog enthalten den Bonus dagegen von selbst, deshalb greift die
-- Rechnung hier nur bei Raengen, die noch nie gewirkt wurden.
--
-- Den Bonus liefert eine Zusatz-API, wenn eine da ist (ClassicAPI bringt
-- GetSpellBonusHealing mit). Gewichtet wird er wie in Vanilla ueblich mit
-- Zauberzeit geteilt durch 3,5, gedeckelt bei 3,5 Sekunden; Instants rechnen
-- mit 1,5 Sekunden. Ohne API bleibt der Bonus 0 und alles laeuft wie bisher.
-- ==========================================================================
FBAPI_HealBonusFn = nil; -- gefundene Funktion oder nil
FBSpellCastCache = {}; -- [bookID] = Zauberzeit in Sekunden oder false
function FBHealBox_ProbeHealBonus()
FBAPI_HealBonusFn = nil;
FBHealBonusValue = nil;
local names = { "GetSpellBonusHealing", "GetSpellBonusHeal", "GetHealingBonus" };
for _, n in ipairs(names) do
local fn = getglobal(n);
if (type(fn) == "function") then
local ok, v = pcall(fn);
if (ok) and (type(v) == "number") then FBAPI_HealBonusFn = fn; return; end
end
end
-- ClassicAPI legt seine Nachbauten je nach Fassung in eine eigene Tabelle
if (type(ClassicAPI) == "table") then
local t = ClassicAPI.API or ClassicAPI;
for _, n in ipairs(names) do
local fn = t[n];
if (type(fn) == "function") then
local ok, v = pcall(fn);
if (ok) and (type(v) == "number") then FBAPI_HealBonusFn = fn; return; end
end
end
end
end
-- Aktueller +Heilung-Wert oder 0.
--
-- Der Wert aendert sich nur beim Ausruestungswechsel, wird aber bei einem
-- Smart-Healing-Klick fuer jeden Kandidaten gebraucht (mit Heilketten bis zu
-- fuenfzehn). Deshalb einmal lesen und merken; UNIT_INVENTORY_CHANGED und
-- der Zauberbuch-Neuaufbau werfen den Wert weg.
FBHealBonusValue = nil;
function FBHealBox_InvalidateHealBonus()
FBHealBonusValue = nil;
end
function FBHealBox_HealingBonus()
if (not FBAPI_Probed) then FBHealBox_ProbeAPIs(); end
if (HealBox.HealBonus ~= 1) or (not FBAPI_HealBonusFn) then return 0; end
if (FBHealBonusValue ~= nil) then return FBHealBonusValue; end
local v;
local ok, res = pcall(FBAPI_HealBonusFn);
if (ok) and (type(res) == "number") and (res > 0) then v = res; else v = 0; end
FBHealBonusValue = v;
return v;
end
-- Zauberzeit aus dem Tooltip. Sie steht rechts in der zweiten Zeile
-- ("2.5 sec cast"), Instants stehen dort als "Instant cast". 0 = Instant.
function FBHealBox_SpellCastSeconds(id)
if (not id) then return nil; end
local c = FBSpellCastCache[id];
if (c ~= nil) then return c or nil; end
-- Regelfall ist der Treffer oben: FBPredict_TooltipText fuellt den
-- Zwischenspeicher beim Auslesen der Zauberdaten mit. Hierher kommt nur,
-- wer noch nie durch die Tooltip-Auswertung gelaufen ist.
FBPredictTip:SetOwner(UIParent, "ANCHOR_NONE");
FBPredictTip:ClearLines();
FBPredictTip:SetSpell(id, BOOKTYPE_SPELL);
local secs = nil;
for i = 1, 6 do
for _, side in ipairs({ "Left", "Right" }) do
local fs = getglobal("FBHealBoxScanTipText"..side..i);
if (fs and fs:IsShown()) then
local t = fs:GetText();
if (t) then
local _, _, v = string.find(t, "([%d%.]+)%s+[Ss]ec%s+cast");
if (v) then secs = tonumber(v); end
if (not secs) and string.find(t, "[Ii]nstant") then secs = 0; end
end
end
end
end
FBSpellCastCache[id] = secs or false;
return secs;
end
-- Anteil des +Heilung-Werts, der auf diesen Zauber entfaellt
function FBHealBox_HealBonusFor(bookID)
local bonus = FBHealBox_HealingBonus();
if (bonus <= 0) then return 0; end
local secs = FBHealBox_SpellCastSeconds(bookID);
if (not secs) then secs = 2.5; end -- Zauberzeit unlesbar: mittlerer Wert
if (secs <= 0) then secs = 1.5; end -- Instants rechnen mit 1,5 Sekunden
if (secs > 3.5) then secs = 3.5; end
return bonus * (secs / 3.5);
end
-- Erwartete Sofortheilung eines Rangs: gelernter Wert, sonst Tooltip plus
-- anteiliger Ausruestungsbonus
function FBPredict_ExpectedDirect(spellName, rank, info, bookID)
local learned = FBPredict_Remembered("direct", spellName, rank);
if (learned) then return learned; end
if (not info) or (not info.direct) then return nil; end
return info.direct + FBHealBox_HealBonusFor(bookID);
end
-- Reichweite eines Zaubers aus dem Tooltip (Meter) oder nil -- Reichweite eines Zaubers aus dem Tooltip (Meter) oder nil
function FBHealBox_SpellRangeYards(id) function FBHealBox_SpellRangeYards(id)
local c = FBSpellRangeCache[id]; local c = FBSpellRangeCache[id];
@@ -3358,12 +3605,23 @@ function FBHealBox_SpellInRange(id, unit)
if (not FBAPI_Probed) then FBHealBox_ProbeAPIs(); end if (not FBAPI_Probed) then FBHealBox_ProbeAPIs(); end
if (FBAPI_SpellRange) then if (FBAPI_SpellRange) then
local ok, r; local ok, r;
if (FBAPI_RangeForm == 3) then -- Der erste Aufruf je Form laeuft geschuetzt. Danach ist bewiesen,
-- dass der Client sie versteht, und pcall faellt weg: im Vierzigerraid
-- waren das 80 geschuetzte Aufrufe je Sekunde nur fuer die Reichweite.
if (FBAPI_RangeDirect) then
ok = true;
if (FBAPI_RangeForm == 3) then
r = IsSpellInRange(id, BOOKTYPE_SPELL, unit);
else
r = IsSpellInRange(FBHealBox_SpellNameOf(id), unit);
end
elseif (FBAPI_RangeForm == 3) then
ok, r = pcall(IsSpellInRange, id, BOOKTYPE_SPELL, unit); ok, r = pcall(IsSpellInRange, id, BOOKTYPE_SPELL, unit);
else else
ok, r = pcall(IsSpellInRange, FBHealBox_SpellNameOf(id), unit); ok, r = pcall(IsSpellInRange, FBHealBox_SpellNameOf(id), unit);
end end
if (ok) then if (ok) then
FBAPI_RangeDirect = true;
if (r == 1 or r == true) then return 1; end if (r == 1 or r == true) then return 1; end
if (r == 0 or r == false) then return 0; end if (r == 0 or r == false) then return 0; end
return nil; return nil;
@@ -3373,8 +3631,14 @@ function FBHealBox_SpellInRange(id, unit)
end end
local range = FBHealBox_SpellRangeYards(id); local range = FBHealBox_SpellRangeYards(id);
if (UnitXP and range) then if (UnitXP and range) then
local ok, d = pcall(UnitXP, "distanceBetween", "player", unit); local ok, d;
if (FBAPI_DistDirect) then
ok = true; d = UnitXP("distanceBetween", "player", unit);
else
ok, d = pcall(UnitXP, "distanceBetween", "player", unit);
end
if (ok and type(d) == "number") then if (ok and type(d) == "number") then
FBAPI_DistDirect = true;
if (d <= range) then return 1; else return 0; end if (d <= range) then return 1; else return 0; end
end end
end end
@@ -3419,11 +3683,23 @@ end
FBRangeAccum = 0; FBRangeAccum = 0;
-- Erster belegter Button: Zauber fuer die Reichweitenpruefung. Wird je
-- Einheit und Durchlauf gebraucht, im Vierzigerraid also hundertfach je
-- Sekunde, aendert sich aber nur beim Umbelegen. Also merken.
FBRangeSpellCached = nil; -- false = keiner belegt, nil = neu suchen
function FBHealBox_InvalidateRangeSpell()
FBRangeSpellCached = nil;
end
function FBHealBox_RangeSpellID() function FBHealBox_RangeSpellID()
if (FBRangeSpellCached ~= nil) then return FBRangeSpellCached or nil; end
local found = false;
for i = 1, MaxButtonCount do for i = 1, MaxButtonCount do
if (FBActiveSpellIDs[i]) then return FBActiveSpellIDs[i]; end if (FBActiveSpellIDs[i]) then found = FBActiveSpellIDs[i]; break; end
end end
return nil; FBRangeSpellCached = found;
return found or nil;
end end
function FBHealBox_UnitInRange(unit) function FBHealBox_UnitInRange(unit)
@@ -3443,7 +3719,14 @@ function FBHealBox_UnitInRange(unit)
return true; return true;
end end
function FBHealBox_CheckRangeAll() -- Der Durchlauf selbst laeuft geschuetzt: ein pcall je Durchlauf statt eines
-- je Einheit. Das kostet praktisch nichts und haelt einen spaeten Fehler aus
-- den Reichweiten-Abfragen trotzdem vom Frame fern.
function FBHealBox_CheckRangeAll()
if (not pcall(FBHealBox_CheckRangeSweep)) then FBHealBox_ApiFailed(); end
end
function FBHealBox_CheckRangeSweep()
for p = 1, FBSlotCount do for p = 1, FBSlotCount do
local f = FBPartyFrame[p]; local f = FBPartyFrame[p];
if (f) then if (f) then
@@ -3550,6 +3833,15 @@ function FBHealBox_ApplyLocale()
SmartCrossCheck.Text:SetText(FBT("SMARTCROSS")); SmartCrossCheck.Text:SetText(FBT("SMARTCROSS"));
SmartCrossCheck.tooltipText = FBT("SMARTCROSS_TIP"); SmartCrossCheck.tooltipText = FBT("SMARTCROSS_TIP");
end end
if (HidePartyCheck) then
HidePartyCheck.Text:SetText(FBT("HIDEPARTY"));
HidePartyCheck.tooltipText = FBT("HIDEPARTY_TIP");
end
if (PowerBarCheck) then
PowerBarCheck.Text:SetText(FBT("POWERBAR"));
PowerBarCheck.tooltipText = FBT("POWERBAR_TIP");
end
FBHealBox_UpdatePartyExclusion();
FBUpdateSmartMarginText(); FBUpdateSmartMarginText();
FBHealBox_UpdateSmartCrossState(); FBHealBox_UpdateSmartCrossState();
if (CooldownsCheck) then if (CooldownsCheck) then
@@ -3954,6 +4246,10 @@ function FBHealBoxCreateAddonOptionFrame()
local cy = gy - 95; local cy = gy - 95;
AttachModeCheck = FBHealBox_CreateCheck("$parentCheckButton", tabGeneral, 40, cy, "ATTACH", "ATTACH_TIP", function() AttachModeCheck = FBHealBox_CreateCheck("$parentCheckButton", tabGeneral, 40, cy, "ATTACH", "ATTACH_TIP", function()
HealBox.AttachMode = AttachModeCheck:GetChecked() and 1 or 0; HealBox.AttachMode = AttachModeCheck:GetChecked() and 1 or 0;
-- Anheften und Verstecken schliessen sich aus
if (HealBox.AttachMode == 1) then HealBox.HideBlizzParty = 0; end
if (HidePartyCheck) then HidePartyCheck:SetChecked(HealBox.HideBlizzParty == 1); end
FBHealBox_UpdatePartyExclusion();
HealBoxAttachMode(HealBox.AttachMode); HealBoxAttachMode(HealBox.AttachMode);
FBUpdateNames(); FBUpdateNames();
end); end);
@@ -4039,8 +4335,29 @@ function FBHealBoxCreateAddonOptionFrame()
end); end);
BuffIconsCheck:SetChecked(1); BuffIconsCheck:SetChecked(1);
HidePartyCheck = FBHealBox_CreateCheck("FBHealBoxHidePartyCheck", tabGeneral, 40, cy - 210, "HIDEPARTY", "HIDEPARTY_TIP", function()
HealBox.HideBlizzParty = HidePartyCheck:GetChecked() and 1 or 0;
if (HealBox.HideBlizzParty == 1) then
HealBox.AttachMode = 0;
if (AttachModeCheck) then AttachModeCheck:SetChecked(nil); end
HealBoxAttachMode(0);
FBUpdateNames();
end
FBHealBox_UpdatePartyExclusion();
FBHealBox_ApplyBlizzParty();
end);
HidePartyCheck:SetChecked(nil);
PowerBarCheck = FBHealBox_CreateCheck("FBHealBoxPowerBarCheck", tabGeneral, 250, cy - 210, "POWERBAR", "POWERBAR_TIP", function()
HealBox.PowerBar = PowerBarCheck:GetChecked() and 1 or 0;
FBHealBox_InvalidateUnitCaches();
FBHealBox_RefreshAllBars();
FBHealBox_RunHook("SyncOptions");
end);
PowerBarCheck:SetChecked(nil);
-- [ Sprache und Buff-Wache ] ------------------------------------------- -- [ Sprache und Buff-Wache ] -------------------------------------------
local py = cy - 215; local py = cy - 245;
FBLangBtn = FBHealBox_CreatePickButton("FBHealBoxLangBtn", tabGeneral, 35, py, 180, 26, 18); FBLangBtn = FBHealBox_CreatePickButton("FBHealBoxLangBtn", tabGeneral, 35, py, 180, 26, 18);
FBLangBtn.icon:SetTexture("Interface\\Icons\\INV_Misc_Note_01"); FBLangBtn.icon:SetTexture("Interface\\Icons\\INV_Misc_Note_01");
FBLangBtn:SetScript("OnEnter", function() FBLangBtn:SetScript("OnEnter", function()
@@ -4185,6 +4502,7 @@ function FBHealBoxButtons()
end end
function FBHealBoxButtonsChanged() function FBHealBoxButtonsChanged()
FBHealBox_InvalidateRangeSpell();
local rightOn = (HealBox.RightClick == 1); local rightOn = (HealBox.RightClick == 1);
for p = 1, FBSlotCount do for p = 1, FBSlotCount do
local unit = FBPartyUnit[p]; local unit = FBPartyUnit[p];
@@ -4462,6 +4780,46 @@ function FBHealBox_BlizzAnchor(p)
return nil; return nil;
end end
-- ==========================================================================
-- [ Blizzards Gruppenfenster ]
--
-- Der Anheftmodus haengt die Plaketten genau an PartyMemberFrame1 bis 4.
-- Beides gleichzeitig ergibt keinen Sinn, deshalb sperren sich die zwei
-- Optionen im Optionsfenster gegenseitig, und diese Pruefung hier ist der
-- Sicherheitsgurt fuer alte gespeicherte Werte. Im Ruhezustand der
-- Klassensperre gibt das Addon die Frames ebenfalls wieder frei.
-- ==========================================================================
function FBHealBox_HideBlizzPartyActive()
if (FBAddonSuppressed) then return false; end
if (HealBox.AttachMode == 1) then return false; end
return (HealBox.HideBlizzParty == 1);
end
function FBHealBox_ApplyBlizzParty()
local hide = FBHealBox_HideBlizzPartyActive();
for i = 1, 4 do
local f = getglobal("PartyMemberFrame"..i);
if (f) then
-- Blizzard zeigt die Frames bei jeder Gruppenaenderung neu an,
-- deshalb einmalig OnShow abfangen statt nur einmal zu verstecken
if (not f.fbShowHooked) then
f.fbShowHooked = true;
f.fbOldOnShow = f:GetScript("OnShow");
f:SetScript("OnShow", function()
if (this.fbOldOnShow) then this.fbOldOnShow(); end
if (FBHealBox_HideBlizzPartyActive()) then this:Hide(); end
end);
end
if (hide) then
f:Hide();
elseif (UnitExists("party"..i)) then
f:Show();
end
end
end
end
function HealBoxAttachMode(mode) function HealBoxAttachMode(mode)
if (not FBHealBox1) then return; end if (not FBHealBox1) then return; end
@@ -4509,6 +4867,7 @@ function HealBoxAttachMode(mode)
end end
FBHealBox_Layout(); FBHealBox_Layout();
end end
FBHealBox_ApplyBlizzParty();
end end
-- ========================================================================== -- ==========================================================================
@@ -4588,14 +4947,34 @@ function FBPredict_TooltipText(bookID)
FBPredictTip:SetSpell(bookID, BOOKTYPE_SPELL); FBPredictTip:SetSpell(bookID, BOOKTYPE_SPELL);
local txt = ""; local txt = "";
local secs = nil;
local i = 1; local i = 1;
while (i <= 30) do while (i <= 30) do
local fs = getglobal("FBHealBoxScanTipTextLeft"..i); local fs = getglobal("FBHealBoxScanTipTextLeft"..i);
if (not fs or not fs:IsShown()) then break; end if (not fs or not fs:IsShown()) then break; end
local line = fs:GetText(); local line = fs:GetText();
if (line) then txt = txt.." "..line; end if (line) then txt = txt.." "..line; end
-- Die Zauberzeit steht rechts ("2.5 sec cast", "Instant cast"). Sie
-- kommt bewusst nicht in txt: eine Zahl wie 2.5 wuerde die Muster
-- fuer Schilddauer und Heilbetrag durcheinanderbringen. Hier wird sie
-- nur nebenbei gelesen, solange der Tooltip ohnehin steht, und
-- gemerkt. Der Ausruestungsbonus braucht dann keinen eigenen Scan.
if (secs == nil) then
local rs = getglobal("FBHealBoxScanTipTextRight"..i);
if (rs and rs:IsShown()) then
local rline = rs:GetText();
if (rline) then
local _, _, v = string.find(rline, "([%d%.]+)%s+[Ss]ec%s+cast");
if (v) then secs = tonumber(v); end
if (secs == nil) and string.find(rline, "[Ii]nstant") then secs = 0; end
end
end
end
i = i + 1; i = i + 1;
end end
if (FBSpellCastCache[bookID] == nil) then
FBSpellCastCache[bookID] = secs or false;
end
return txt; return txt;
end end
@@ -4823,22 +5202,47 @@ function FBPredict_StartBuff(unitName, spellName, secs)
FBBuffIconsDirty = true; FBBuffIconsDirty = true;
end end
-- Restlaufzeit eines eigenen Buffs (Textur) ueber die Spielerbuff-API -- Restlaufzeiten aller eigenen Buffs, [TEXTUR] = Sekunden.
function FBPredict_PlayerBuffTimeLeft(tex) --
if (not GetPlayerBuff) or (not GetPlayerBuffTexture) or (not GetPlayerBuffTimeLeft) then return nil; end -- Frueher lief je gesuchtem Buff eine eigene Schleife ueber die gesamte
-- Buffliste. Bei sechs Wachen und dreissig Buffs waren das rund 200 Aufrufe
-- je Sekunde. Jetzt wird die Liste einmal je Frame gelesen und alle Wachen
-- bedienen sich daraus; der Zeitstempel arbeitet wie bei FBHealBox_UnitBuffs.
FBPlayerBuffLeft = {};
FBPlayerBuffStamp = nil;
function FBPredict_ScanPlayerBuffTimes()
local now = GetTime();
if (FBPlayerBuffStamp == now) then return FBPlayerBuffLeft; end
FBPlayerBuffStamp = now;
for k in pairs(FBPlayerBuffLeft) do FBPlayerBuffLeft[k] = nil; end
if (not GetPlayerBuff) or (not GetPlayerBuffTexture) or (not GetPlayerBuffTimeLeft) then
return FBPlayerBuffLeft;
end
local i = 0; local i = 0;
while true do while true do
local id = GetPlayerBuff(i, "HELPFUL"); local id = GetPlayerBuff(i, "HELPFUL");
if (not id) or (id < 0) then break; end if (not id) or (id < 0) then break; end
local t = GetPlayerBuffTexture(id); local t = GetPlayerBuffTexture(id);
if (t and strupper(t) == tex) then if (t) then
local left = GetPlayerBuffTimeLeft(id); local left = GetPlayerBuffTimeLeft(id);
if (left and left > 0) then return left; end if (left and left > 0) then
return nil; local up = FBHealBox_UpperTex(t);
-- gleiche Textur mehrfach (etwa gestapelte Buffs): laengste Zeit
if (not FBPlayerBuffLeft[up]) or (left > FBPlayerBuffLeft[up]) then
FBPlayerBuffLeft[up] = left;
end
end
end end
i = i + 1; i = i + 1;
end end
return nil; return FBPlayerBuffLeft;
end
-- Restlaufzeit eines eigenen Buffs (Textur, gross geschrieben) oder nil
function FBPredict_PlayerBuffTimeLeft(tex)
if (not tex) then return nil; end
return FBPredict_ScanPlayerBuffTimes()[tex];
end end
-- [ Lernspeicher (wandert in die SavedVariables) ] -------------------------- -- [ Lernspeicher (wandert in die SavedVariables) ] --------------------------
@@ -5056,7 +5460,7 @@ function FBPredict_CastStart(spellName, castMs)
local info = FBPredict_GetSpellInfo(bookID, spellName); local info = FBPredict_GetSpellInfo(bookID, spellName);
if (not info) or (not info.direct) then return; end if (not info) or (not info.direct) then return; end
local amount = FBPredict_Remembered("direct", spellName, rank) or info.direct; local amount = FBPredict_ExpectedDirect(spellName, rank, info, bookID) or info.direct;
FBLOS_Clear(FBPredict_ResolveTarget()); -- Cast laeuft an: Sichtlinie ist da FBLOS_Clear(FBPredict_ResolveTarget()); -- Cast laeuft an: Sichtlinie ist da
FBPredictDirect = { FBPredictDirect = {
@@ -5196,6 +5600,22 @@ function FBPredict_ToPattern(gs, anchor)
return p; return p;
end end
-- Feststehendes Wortstueck aus einer Client-Vorlage schneiden: alles vor dem
-- ersten Platzhalter faellt weg, alles ab dem naechsten ebenfalls, uebrig
-- bleibt ein Stueck reiner Text fuer den billigen Vortest. Bei "Your %s heals
-- %s for %d." ist das " heals ". Klappt das nicht, greift der Rueckfall.
function FBPredict_PlainPart(template, fallback)
if (not template) or (type(template) ~= "string") then return fallback; end
local s1, e1 = string.find(template, "%%%a");
if (not s1) then return fallback; end
local rest = string.sub(template, e1 + 1);
local s2 = string.find(rest, "%%%a");
if (s2) then rest = string.sub(rest, 1, s2 - 1); end
-- Satzzeichen am Ende stoeren nicht, zu kurze Stuecke taugen aber nichts
if (string.len(rest) < 4) then return fallback; end
return rest;
end
function FBPredict_InitPatterns() function FBPredict_InitPatterns()
-- "%s gains %d health from your %s." -- "%s gains %d health from your %s."
FBPredictPatHoTOther = FBPredict_ToPattern(PERIODICAURAHEALOTHERSELF, true) FBPredictPatHoTOther = FBPredict_ToPattern(PERIODICAURAHEALOTHERSELF, true)
@@ -5213,6 +5633,13 @@ function FBPredict_InitPatterns()
-- " (%d absorbed)" -- " (%d absorbed)"
FBPredictPatAbsorb = FBPredict_ToPattern(ABSORB_TRAILER, false) FBPredictPatAbsorb = FBPredict_ToPattern(ABSORB_TRAILER, false)
or "%((%d+) absorbed%)"; or "%((%d+) absorbed%)";
-- Vortests: " heals " und " health from your ".
-- Beim Tick wird bewusst die Selbst-Vorlage genommen: "You gain ..." und
-- "%s gains ..." unterscheiden sich im Verb, das Stueck dahinter ist in
-- beiden gleich. Ein aus der Fremd-Vorlage geschnittenes " gains " wuerde
-- die eigenen Ticks aussperren.
FBPRED_WORD_HEAL = FBPredict_PlainPart(HEALEDSELFOTHER, " heals ");
FBPRED_WORD_TICK = FBPredict_PlainPart(PERIODICAURAHEALSELFSELF, " health from your ");
end end
-- Events, bei denen das Opfer immer der Spieler selbst ist -- Events, bei denen das Opfer immer der Spieler selbst ist
@@ -5343,32 +5770,40 @@ function FBPredict_ParseCombat(event, msg)
return; return;
end end
-- Direktheilung auf jemand anderen: "Your Flash Heal heals Bob for 1240." -- Vor den verankerten Mustern ein billiger Textvergleich (viertes
local _, _, spell, who, amt = string.find(msg, FBPredictPatHealOther); -- Argument true = einfache Suche ohne Musterlogik). Fremde Heilungen und
if (spell and who and amt) then -- fremde Ticks fallen so nach einem Vergleich raus statt nach vier
FBPredict_OnDirectHeal(spell, who, tonumber(amt)); -- Musterlaeufen; im Raid sind das die meisten Meldungen.
return; if (string.find(msg, FBPRED_WORD_HEAL, 1, true)) then
-- Direktheilung auf jemand anderen: "Your Flash Heal heals Bob for 1240."
local _, _, spell, who, amt = string.find(msg, FBPredictPatHealOther);
if (spell and who and amt) then
FBPredict_OnDirectHeal(spell, who, tonumber(amt));
return;
end
-- Direktheilung auf mich: "Your Flash Heal heals you for 1240."
local _, _, spell2, amt2 = string.find(msg, FBPredictPatHealSelf);
if (spell2 and amt2) then
FBPredict_OnDirectHeal(spell2, UnitName("player"), tonumber(amt2));
return;
end
end end
-- Direktheilung auf mich: "Your Flash Heal heals you for 1240." if (string.find(msg, FBPRED_WORD_TICK, 1, true)) then
local _, _, spell2, amt2 = string.find(msg, FBPredictPatHealSelf); -- HoT-Tick auf jemand anderen: "Bob gains 194 health from your Renew."
if (spell2 and amt2) then local _, _, who3, amt3, spell3 = string.find(msg, FBPredictPatHoTOther);
FBPredict_OnDirectHeal(spell2, UnitName("player"), tonumber(amt2)); if (who3 and amt3 and spell3) then
return; FBPredict_OnTick(who3, tonumber(amt3), spell3);
end return;
end
-- HoT-Tick auf jemand anderen: "Bob gains 194 health from your Renew." -- HoT-Tick auf mich: "You gain 194 health from your Renew."
local _, _, who3, amt3, spell3 = string.find(msg, FBPredictPatHoTOther); local _, _, amt4, spell4 = string.find(msg, FBPredictPatHoTSelf);
if (who3 and amt3 and spell3) then if (amt4 and spell4) then
FBPredict_OnTick(who3, tonumber(amt3), spell3); FBPredict_OnTick(UnitName("player"), tonumber(amt4), spell4);
return; return;
end end
-- HoT-Tick auf mich: "You gain 194 health from your Renew."
local _, _, amt4, spell4 = string.find(msg, FBPredictPatHoTSelf);
if (amt4 and spell4) then
FBPredict_OnTick(UnitName("player"), tonumber(amt4), spell4);
return;
end end
end end
@@ -5456,6 +5891,7 @@ FBPredictFrame:SetScript("OnUpdate", function()
end); end);
FBNamesDirty = false; FBNamesDirty = false;
FBBlizzPartyDirty = false;
FBBtnStatesDirty = nil; FBBtnStatesDirty = nil;
FBBuffIconsDirty = true; FBBuffIconsDirty = true;
FBBuffIconsAccum = 0; FBBuffIconsAccum = 0;
@@ -5466,6 +5902,12 @@ function FBPredict_OnUpdate(elapsed)
FBNamesDirty = false; FBNamesDirty = false;
FBUpdateNames(); FBUpdateNames();
end end
-- Blizzards Gruppenfenster im selben Sammelpunkt, statt bei jedem
-- einzelnen Ereignis einer Salve
if (FBBlizzPartyDirty) then
FBBlizzPartyDirty = false;
FBHealBox_ApplyBlizzParty();
end
-- Aufgeschobene Button-Zustaende (USABLE schlaegt COOLDOWN, da es beides tut) -- Aufgeschobene Button-Zustaende (USABLE schlaegt COOLDOWN, da es beides tut)
if (FBBtnStatesDirty) then if (FBBtnStatesDirty) then
local ev = FBBtnStatesDirty; local ev = FBBtnStatesDirty;
@@ -5806,6 +6248,21 @@ SlashCmdList["FBHEALPREDICT"] = function(msg)
return; return;
end end
-- Ausruestungsbonus in der Vorhersage an/aus
if (msg == "healbonus" or msg == "bonus") then
if (not FBAPI_Probed) then FBHealBox_ProbeAPIs(); end
if (not FBAPI_HealBonusFn) then
DEFAULT_CHAT_FRAME:AddMessage("|cFFFFFF00"..FBADDON_NAME..":|r "..FBT("HEALBONUS_NA"));
return;
end
if (HealBox.HealBonus == 1) then HealBox.HealBonus = 0; else HealBox.HealBonus = 1; end
local key = "HEALBONUS_OFF";
if (HealBox.HealBonus == 1) then key = "HEALBONUS_ON"; end
DEFAULT_CHAT_FRAME:AddMessage("|cFFFFFF00"..FBADDON_NAME..":|r "
..format(FBT(key), math.floor(FBHealBox_HealingBonus() + 0.5)));
return;
end
-- Abrangen ueber Zaubergrenzen (Heilketten) an/aus -- Abrangen ueber Zaubergrenzen (Heilketten) an/aus
if (msg == "smartcross" or msg == "cross") then if (msg == "smartcross" or msg == "cross") then
if (HealBox.SmartCross == 1) then HealBox.SmartCross = 0; else HealBox.SmartCross = 1; end if (HealBox.SmartCross == 1) then HealBox.SmartCross = 0; else HealBox.SmartCross = 1; end
@@ -5858,6 +6315,14 @@ SlashCmdList["FBHEALPREDICT"] = function(msg)
return; return;
end end
if (not FBAPI_Probed) then FBHealBox_ProbeAPIs(); end
if (FBAPI_HealBonusFn) then
local state = FBT("FBP_STATE_OFF");
if (HealBox.HealBonus == 1) then state = FBT("FBP_STATE_ON"); end
DEFAULT_CHAT_FRAME:AddMessage("|cFF00FFFF[FBP]|r "..format(FBT("FBP_HEALBONUS"),
math.floor(FBHealBox_HealingBonus() + 0.5), state));
end
DEFAULT_CHAT_FRAME:AddMessage("|cFF00FFFF[FBP]|r "..FBT("FBP_WATCHED")); DEFAULT_CHAT_FRAME:AddMessage("|cFF00FFFF[FBP]|r "..FBT("FBP_WATCHED"));
for spellName, w in pairs(FBPredictWatch) do for spellName, w in pairs(FBPredictWatch) do
local info = FBPredict_GetSpellInfo(w.bookID, spellName); local info = FBPredict_GetSpellInfo(w.bookID, spellName);
@@ -6136,7 +6601,8 @@ end
function FBHealBox_BuffIconList(unitName, g, out) function FBHealBox_BuffIconList(unitName, g, out)
local n = 0; local n = 0;
if (g) then if (g) then
for _, b in ipairs(g.buffs or {}) do if (not g.buffs) then return 0; end
for _, b in ipairs(g.buffs) do
n = n + 1; n = n + 1;
local e = out[n] or {}; out[n] = e; local e = out[n] or {}; out[n] = e;
e.tex = b.tex; e.expires = b.left and (GetTime() + b.left); e.duration = b.dur; e.name = "Test"; e.tex = b.tex; e.expires = b.left and (GetTime() + b.left); e.duration = b.dur; e.name = "Test";
@@ -6254,19 +6720,31 @@ function FBHealBox_UpdateAllBuffIcons()
FBHealBox_RunHook("BuffIcons"); FBHealBox_RunHook("BuffIcons");
end end
-- Balkenfarbe der Energieart anpassen. Der Zwischenspeicher am Rahmen
-- verhindert, dass die Farbe bei jedem Durchlauf neu gesetzt wird.
function FBHealBox_SetPowerColor(bar, cache, ptype)
if (not bar) then return; end
local t = ptype or 0;
if (cache) and (cache.powerType == t) then return; end
if (cache) then cache.powerType = t; end
local c = FBPOWER_COLORS[t] or FBMANA_BAR_COLOR;
bar:SetStatusBarColor(c[1], c[2], c[3], c[4]);
end
-- Manabalken: nur wenn eingeschaltet, die Plakette sichtbar ist und die -- Manabalken: nur wenn eingeschaltet, die Plakette sichtbar ist und die
-- Einheit tatsaechlich Mana nutzt. Sonst weg, dann ist der Lebensbalken -- Einheit tatsaechlich Mana nutzt. Sonst weg, dann ist der Lebensbalken
-- wieder auf voller Hoehe zu sehen. -- wieder auf voller Hoehe zu sehen.
function FBHealBox_UpdateMana(unit, frame) function FBHealBox_UpdateMana(unit, frame)
if (not frame.ManaBar) then return; end if (not frame.ManaBar) then return; end
local mp, mpMax, hasMana = 0, 0, false; local mp, mpMax, hasMana, ptype = 0, 0, false, nil;
if (HealBox.ManaBar == 1) and (not frame.plateHidden) then if (HealBox.ManaBar == 1) and (not frame.plateHidden) then
mp, mpMax, hasMana = FBUnitMana(unit); mp, mpMax, hasMana, ptype = FBUnitMana(unit);
end end
if (not hasMana) then if (not hasMana) then
if (frame.manaShown ~= false) then frame.manaShown = false; frame.ManaBar:Hide(); end if (frame.manaShown ~= false) then frame.manaShown = false; frame.ManaBar:Hide(); end
return; return;
end end
FBHealBox_SetPowerColor(frame.ManaBar, frame, ptype);
if (frame.lastMpMax ~= mpMax) then if (frame.lastMpMax ~= mpMax) then
frame.lastMpMax = mpMax; frame.lastMpMax = mpMax;
frame.ManaBar:SetMinMaxValues(0, mpMax); frame.ManaBar:SetMinMaxValues(0, mpMax);
@@ -6279,7 +6757,7 @@ end
function FBHealBox_InvalidateUnitCaches() function FBHealBox_InvalidateUnitCaches()
for p = 1, FBSlotCount do for p = 1, FBSlotCount do
local f = FBPartyFrame[p]; local f = FBPartyFrame[p];
if (f) then f.dispelKnown = nil; f.lastText = nil; f.lastMax = nil; f.colorKey = nil; f.manaShown = nil; f.lastMpMax = nil; f.vHp = nil; f.vShield = nil; f.vInc = nil; f.vMp = nil; end if (f) then f.dispelKnown = nil; f.lastText = nil; f.lastMax = nil; f.colorKey = nil; f.manaShown = nil; f.lastMpMax = nil; f.powerType = nil; f.vHp = nil; f.vShield = nil; f.vInc = nil; f.vMp = nil; end
end end
end end
+2 -2
View File
@@ -1,9 +1,9 @@
## Interface: 11200 ## Interface: 11200
## Title: Heal Box Vanilla |cFFFFFF00v1.4.4.3|r ## Title: Heal Box Vanilla |cFFFFFF00v1.4.5|r
## Notes: Heal/raid frame addon like Healium, with quick-cast buttons, heal prediction, mana ticker and more. ## 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. ## 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 ## Author: Dourd (Argent Dawn EU) | Vanilla-Port & Erweiterung 09/2026: Mquadrat
## Version: 1.4.4.3 ## Version: 1.4.5
## SavedVariablesPerCharacter: HealBox ## SavedVariablesPerCharacter: HealBox
## OptionalDeps: SuperWoW ## OptionalDeps: SuperWoW
+48 -10
View File
@@ -28,7 +28,8 @@ FBRAID_MAX = 40;
FBRAID_GROUPS = 8; FBRAID_GROUPS = 8;
FBRAID_PER_GROUP = 5; FBRAID_PER_GROUP = 5;
FBRAID_MAX_BUTTONS = 4; 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_MANA_H = 3; -- px Manastreifen in der Zelle
FBRAID_LOS_SIZE = 10; -- px Sichtlinien-Auge in der Zelle FBRAID_LOS_SIZE = 10; -- px Sichtlinien-Auge in der Zelle
FBRAID_HEADER_H = 12; -- px Gruppenkopf FBRAID_HEADER_H = 12; -- px Gruppenkopf
@@ -437,8 +438,14 @@ end
function FBRaid_Mana(cell) function FBRaid_Mana(cell)
local g = cell.ghost; local g = cell.ghost;
if (g) then if (g) then
if (not g.hasMana) then return 0, 0, false; end if (not g.hasMana) then
return math.floor(g.mpMax * g.mp), g.mpMax, true; -- 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 end
return FBUnitMana(cell.unit); return FBUnitMana(cell.unit);
end end
@@ -738,7 +745,7 @@ function FBRaid_UpdateRoster()
if (FBRaidCells[g] and FBRaidCells[g][pos]) then if (FBRaidCells[g] and FBRaidCells[g][pos]) then
local c = FBRaidCells[g][pos]; local c = FBRaidCells[g][pos];
c.unit = nil; c.name = nil; c.ghost = nil; c.index = nil; 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.vHp = nil; c.vShield = nil; c.vInc = nil; c.vMp = nil;
c:Hide(); c:Hide();
end end
@@ -940,6 +947,7 @@ function FBRaid_UpdateCell(c, auraChanged)
if (state == "ghost") then key = "STATE_GHOST"; end if (state == "ghost") then key = "STATE_GHOST"; end
if (state == "offline") then key = "STATE_OFFLINE"; end if (state == "offline") then key = "STATE_OFFLINE"; end
FBRaid_SetText(c, FBT(key)); FBRaid_SetText(c, FBT(key));
c.lastPct = nil; c.lastDef = nil; -- Zahlenspeicher gilt nicht mehr
FBRaid_SetMax(c, hpMax); FBRaid_SetMax(c, hpMax);
FBRaid_SetValues(c, 0, 0, 0); FBRaid_SetValues(c, 0, 0, 0);
FBRaid_SetColor(c, "state", 0.5, 0.5, 0.5, 1); FBRaid_SetColor(c, "state", 0.5, 0.5, 0.5, 1);
@@ -956,19 +964,29 @@ function FBRaid_UpdateCell(c, auraChanged)
if (incTop > hpMax) then incTop = hpMax; end if (incTop > hpMax) then incTop = hpMax; end
FBRaid_SetValues(c, hp, shieldTop, incTop); 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 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 elseif (cfg.HPText == "deficit") then
local def = hpMax - hp; 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 else
c.lastPct = nil; c.lastDef = nil;
FBRaid_SetText(c, false); FBRaid_SetText(c, false);
end end
-- Mana -- 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 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.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.vMp ~= mp) then c.vMp = mp; c.ManaBar:SetValue(mp); end
if (c.manaShown ~= true) then c.manaShown = true; c.ManaBar:Show(); end if (c.manaShown ~= true) then c.manaShown = true; c.ManaBar:Show(); end
@@ -1199,10 +1217,30 @@ function FBRaid_SyncButtons()
end end
-- Reichweite, Sichtlinie und Geister-Atmung im Takt -- 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) function FBRaid_Tick(force)
if (not FBRaid_IsActive()) then return; end 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 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 for pos = 1, FBRAID_PER_GROUP do
local c = FBRaidCells[g][pos]; local c = FBRaidCells[g][pos];
if (c and c.unit and c:IsShown()) then if (c and c.unit and c:IsShown()) then
@@ -1264,7 +1302,7 @@ FBRaidEventFrame:SetScript("OnUpdate", function()
FBRaid_RefreshBuffBorders(); FBRaid_RefreshBuffBorders();
end end
FBRaidTickAccum = FBRaidTickAccum + (arg1 or 0); FBRaidTickAccum = FBRaidTickAccum + (arg1 or 0);
if (FBRaidTickAccum < FBRAID_TICK) then return; end if (FBRaidTickAccum < (FBRAID_TICK / FBRAID_TICK_SLICES)) then return; end
FBRaidTickAccum = 0; FBRaidTickAccum = 0;
FBRaid_Tick(false); FBRaid_Tick(false);
end); end);
+12 -1
View File
@@ -422,8 +422,19 @@ FBTickerFrame:SetScript("OnEvent", function()
end end
FBTicker_UpdateGate(); FBTicker_UpdateGate();
end); end);
-- Der Funke wandert in fuenf Sekunden ueber den Balken, ein Neuzeichnen in
-- jedem Frame bringt dabei kein sichtbar weicheres Bild. Ein fester Takt von
-- 0,03 Sekunden (rund 33 Bilder je Sekunde) spart auf schnellen Rechnern die
-- Haelfte der Durchlaeufe samt der Breiten- und Hoehenabfragen je Balken.
FBTickerDrawAccum = 0;
FBTICK_DRAW_STEP = 0.03;
FBTickerFrame:SetScript("OnUpdate", function() FBTickerFrame:SetScript("OnUpdate", function()
if (FBAddonSuppressed) then return; end if (FBAddonSuppressed) then return; end
if (not FBTicker.gate) then return; end
FBTickerDrawAccum = FBTickerDrawAccum + (arg1 or 0);
if (FBTickerDrawAccum < FBTICK_DRAW_STEP) then return; end
FBTickerDrawAccum = 0;
FBTicker_Draw(); FBTicker_Draw();
end); end);
@@ -529,7 +540,7 @@ FBHealBox_RegisterHook("Loaded", function()
end); end);
-- Klassensperre des Kerns: Funken ausknipsen -- Klassensperre des Kerns: Funken ausknipsen
FBHealBox_RegisterHook("Suppress", function() 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 if (e.spark) then e.spark:Hide(); end
end end
return true; return true;
+62 -6
View File
@@ -1,16 +1,16 @@
# Heal Box Vanilla # Heal Box Vanilla
ADDON DOCUMENTATION · VERSION 1.4.4.3 · World of Warcraft CLIENT 1.12.1 ADDON DOCUMENTATION · VERSION 1.4.5 · 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. 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. **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="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="842" height="1103" alt="Screenshot 2026-09-09 080054" src="https://github.com/user-attachments/assets/61ef0883-fee6-4cab-98bb-240bb1a03e71" />
\--- \---
@@ -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. 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 ### Dispel colouring
If someone carries a debuff **your** class can remove, their health bar takes the debuff colour instead of the HP colour: If someone carries a debuff **your** class can remove, their health bar takes the debuff colour instead of the HP colour:
@@ -283,6 +285,10 @@ The window has two tabs.
**Mana bar**: shows or hides the mana strip inside the health bar. On by default. **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. **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. **Debuff icon**: shows or hides the debuff icon with stack count next to the name. On by default.
@@ -367,6 +373,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). 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 ### 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. 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 +440,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 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 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 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 raid`|Toggles raid mode|
|`/fbp raidtest 20` · `40` · `off`|Raid test with 20 or 40 ghosts, or off| |`/fbp raidtest 20` · `40` · `off`|Raid test with 20 or 40 ghosts, or off|
|`/fbp ticker`|Toggles the mana ticker| |`/fbp ticker`|Toggles the mana ticker|
@@ -462,6 +475,9 @@ Everything lives in the `HealBox` table, saved **per character**:
|`PlateLeft` · `PlateRight`|Click action on a plate: `target`, `menu`, `move` or `none`| |`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| |`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`| |`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| |`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| |`ClassColors`|1 = names in class colour, 0 = white|
|`RangeFade`|1 = fade plates out of range, 0 = off| |`RangeFade`|1 = fade plates out of range, 0 = off|
@@ -515,10 +531,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)| |`FBMENU_GRACE_TIME`|3.0|Menu auto-close (999 = off)|
|`FBPREDICT_TICK_DEFAULT`|3|Default tick interval for HoTs| |`FBPREDICT_TICK_DEFAULT`|3|Default tick interval for HoTs|
|`FBPREDICT_THROTTLE`|0.2|Update rate of the prediction| |`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_DRAW_STEP`|0.03|Redraw step of the mana ticker spark|
|`FBPREDICT_CONFIRM_TIME`|3.0|Time to wait for the aura confirmation| |`FBPREDICT_CONFIRM_TIME`|3.0|Time to wait for the aura confirmation|
|`FBPREDICT_TARGET_TIME`|2.0|Lifetime of the remembered cast target| |`FBPREDICT_TARGET_TIME`|2.0|Lifetime of the remembered cast target|
|`FBPredictTickInterval`|`{Lifebloom = 1}`|Deviating tick intervals| |`FBPredictTickInterval`|`{Lifebloom = 1}`|Deviating tick intervals|
|`FBCommGroupHeal`|`{Prayer of Healing}`|What is broadcast as `GrpHeal`| |`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| |`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| |`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`| |`FBBlockedClasses`|`WARRIOR`, `ROGUE`, `HUNTER`|Classes the addon does not load for without `/fbp forceload`|
@@ -550,6 +569,14 @@ 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_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_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| |`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|
|`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_CheckAggroAll()` · `FBHealBox_ApplyBorder(f)`|Red border for the attacked member; border precedence|
|`FBHealBox_UpdateSpellTimers()` · `FBHealBox_SpellTimerFor(...)`|HoT/shield timers on buttons| |`FBHealBox_UpdateSpellTimers()` · `FBHealBox_SpellTimerFor(...)`|HoT/shield timers on buttons|
|`FBHealBox_UpdateButtonCooldown(b)` · `FBHealBox_UpdateAllCooldowns()`|Cooldown sweep| |`FBHealBox_UpdateButtonCooldown(b)` · `FBHealBox_UpdateAllCooldowns()`|Cooldown sweep|
@@ -707,6 +734,7 @@ 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 * 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 * HealComm sync with Puppeteer, pfUI, Luna and others, without any Ace libraries
* English, German, Spanish, French and Italian localization, switchable in game * English, German, Spanish, French and Italian localization, switchable in game
* 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.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.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 * 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 +745,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.5 · original by Dourd, UI Overhauled · ported to Vanilla and extended 09/2026 by Mquadrat
_______________________________________________________________________ _______________________________________________________________________
GERMAN GERMAN
# Heal Box Vanilla # Heal Box Vanilla
ADDON DOKUMENTATION · VERSION 1.4.4.3 · World of Warcraft CLIENT 1.12.1 ADDON DOKUMENTATION · VERSION 1.4.5 · 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. 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 +833,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. 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 ### 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: Hat jemand einen Debuff, den **deine** Klasse entfernen kann, färbt sich sein Lebensbalken in der Debuff-Farbe statt nach HP-Stand:
@@ -999,6 +1029,10 @@ Das Fenster hat zwei Reiter.
**Manabalken**: Manastreifen im Lebensbalken an/aus. Standardmäßig an. **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. **Begleiter anzeigen**: alle Pet-Plaketten an/aus. Standardmäßig an.
**Debuff-Icon**: Debuff-Icon mit Stackzahl neben dem Namen an/aus. Standardmäßig an. **Debuff-Icon**: Debuff-Icon mit Stackzahl neben dem Namen an/aus. Standardmäßig an.
@@ -1081,6 +1115,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). 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 ### 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. 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 +1182,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 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 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 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 raid`|Raidmodus an/aus|
|`/fbp raidtest 20` · `40` · `off`|Raid-Test mit 20 oder 40 Geistern, oder aus| |`/fbp raidtest 20` · `40` · `off`|Raid-Test mit 20 oder 40 Geistern, oder aus|
|`/fbp ticker`|Mana-Ticker an/aus| |`/fbp ticker`|Mana-Ticker an/aus|
@@ -1176,6 +1217,9 @@ Alles liegt in der Tabelle `HealBox`, gespeichert **pro Charakter**:
|`PlateLeft` · `PlateRight`|Klickaktion auf einer Plakette: `target`, `menu`, `move` oder `none`| |`PlateLeft` · `PlateRight`|Klickaktion auf einer Plakette: `target`, `menu`, `move` oder `none`|
|`SmartRank` · `SmartMargin`|Smart Healing an/aus (Standard aus) und Sicherheitsaufschlag in Prozent| |`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| |`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| |`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ß| |`ClassColors`|1 = Namen in Klassenfarbe, 0 = weiß|
|`RangeFade`|1 = Plaketten außer Reichweite abblenden, 0 = aus| |`RangeFade`|1 = Plaketten außer Reichweite abblenden, 0 = aus|
@@ -1227,10 +1271,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)| |`FBMENU_GRACE_TIME`|3.0|Auto-Close des Menüs (999 = aus)|
|`FBPREDICT_TICK_DEFAULT`|3|Standard-Tickintervall für HoTs| |`FBPREDICT_TICK_DEFAULT`|3|Standard-Tickintervall für HoTs|
|`FBPREDICT_THROTTLE`|0.2|Update-Rate der Vorhersage| |`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_DRAW_STEP`|0.03|Zeichentakt des Ticker-Funkens|
|`FBPREDICT_CONFIRM_TIME`|3.0|Wartezeit auf die Aura-Bestätigung| |`FBPREDICT_CONFIRM_TIME`|3.0|Wartezeit auf die Aura-Bestätigung|
|`FBPREDICT_TARGET_TIME`|2.0|Gültigkeit des gemerkten Cast-Ziels| |`FBPREDICT_TARGET_TIME`|2.0|Gültigkeit des gemerkten Cast-Ziels|
|`FBPredictTickInterval`|`{Lifebloom = 1}`|Abweichende Tickintervalle| |`FBPredictTickInterval`|`{Lifebloom = 1}`|Abweichende Tickintervalle|
|`FBCommGroupHeal`|`{Prayer of Healing}`|Was als `GrpHeal` gefunkt wird| |`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| |`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| |`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| |`FBBlockedClasses`|`WARRIOR`, `ROGUE`, `HUNTER`|Klassen, für die das Addon ohne `/fbp forceload` nicht lädt|
@@ -1261,6 +1308,14 @@ Alle Stellschrauben stehen als Globals oben in ihrem jeweiligen Abschnitt und la
|`FBHealBox_SmartRank(castString, unit)`|Wählt den zu wirkenden Rang| |`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_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| |`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|
|`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_CheckAggroAll()` · `FBHealBox_ApplyBorder(f)`|Roter Rahmen für den Angegriffenen; Rahmen-Vorrang|
|`FBHealBox_UpdateSpellTimers()` · `FBHealBox_SpellTimerFor(...)`|HoT/Schild-Timer auf Buttons| |`FBHealBox_UpdateSpellTimers()` · `FBHealBox_SpellTimerFor(...)`|HoT/Schild-Timer auf Buttons|
|`FBHealBox_UpdateButtonCooldown(b)` · `FBHealBox_UpdateAllCooldowns()`|Cooldown-Uhr| |`FBHealBox_UpdateButtonCooldown(b)` · `FBHealBox_UpdateAllCooldowns()`|Cooldown-Uhr|
@@ -1407,6 +1462,7 @@ 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 * Heilvorhersage für Direktheilung, HoT-Restticks und Absorb-Schilde, selbstkorrigierend über den Combatlog
* HealComm-Sync mit Puppeteer, pfUI, Luna und Co., ohne Ace-Bibliotheken * HealComm-Sync mit Puppeteer, pfUI, Luna und Co., ohne Ace-Bibliotheken
* Lokalisierung Deutsch, Englisch, Spanisch, Französisch und Italienisch, im laufenden Spiel umschaltbar * Lokalisierung Deutsch, Englisch, Spanisch, Französisch und Italienisch, im laufenden Spiel umschaltbar
* 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.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.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 * 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 +1473,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.5 · Original von Dourd, UI Overhauled · Vanilla-Portierung und Erweiterung 09/2026 von Mquadrat
--- ---