mirror of
https://github.com/QbiXibQ/FBHealBox.git
synced 2026-10-08 15:10:01 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3a9d50181 | ||
|
|
90de27471c | ||
|
|
e86cf8c474 | ||
|
|
fac63b2d19 | ||
|
|
b6db62d7dc | ||
|
|
934e0047b0 | ||
|
|
d0a3bbfa9b | ||
|
|
86cfea6b76 | ||
|
|
38c3accf14 | ||
|
|
e6f98eb65a | ||
|
|
12e0f0dfe0 | ||
|
|
08a4abbfe5 | ||
|
|
87075c8c54 | ||
|
|
f0704bbd5c | ||
|
|
4d961b4c4a | ||
|
|
46bfcd966b | ||
|
|
28564b230f | ||
|
|
2b57864a47 | ||
|
|
728a3ab5c6 |
+242
-3
@@ -1,6 +1,245 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## 1.4.5 (2026-09-09)
|
## 1.4.7 (2026-10-08)
|
||||||
|
|
||||||
|
The complete code review in one version. Fixes first: Weakened Soul finally shows, other healers' HoTs and shields no longer pass as yours, a click only counts for the cast it started, direct heals are learned, the tooltip scanner reads cast time and range where they actually are, Smart Healing leaves group heals and cooldown spells alone, Smart Damage's minimum damage is safe again, plus line of sight, localized clients, the scale slider and drag and drop in the raid grid. Then performance, robustness and clean-up: redraws collected once per frame, mana events only touch the mana strip, no generic globals any more, modules independent of each other, errors reported instead of swallowed.
|
||||||
|
|
||||||
|
### English
|
||||||
|
|
||||||
|
**Fixed**
|
||||||
|
|
||||||
|
- **Weakened Soul shows up.** The red Weakened Soul timer on the shield button was worked out from the shield entry, and that entry is deleted the moment the shield breaks, which is exactly when Weakened Soul starts to matter. So it hardly ever appeared. It now runs in a table of its own (`FBWeakenedSoul`) for 15 seconds after your own Power Word: Shield, on plates and raid cells alike.
|
||||||
|
- **Other healers' HoTs no longer count as yours.** Every HoT seen only as a buff was entered as your own, with your highest rank and its full duration. It filled the prediction bar and the button timer even when it was another druid's Rejuvenation. Such a HoT is now provisional and counts nowhere until your own first tick (`… from your Rejuvenation.`) confirms it. If none of yours arrives within one tick interval plus `FBPREDICT_HOT_CONFIRM_GRACE` (1.5) seconds, it is dropped and remembered as someone else's for as long as the buff stays. A tick of yours for a HoT that is not tracked at all adds it on the spot. `/fbp` marks provisional HoTs with `(?)`.
|
||||||
|
- **Other priests' shields no longer count as yours.** A shield seen only as a buff used your learned absorb value and showed your timer. It now gets the tooltip value, and only shields cast through the Heal Box buttons get the button timer and start Weakened Soul.
|
||||||
|
- **Smart Healing leaves group heals and cooldown spells alone.** An assigned Prayer of Healing or Chain Heal was downranked by the health missing on the one unit you clicked; over a player at full health that meant rank 1, however the rest of the group looked. Spells with a cooldown such as Holy Shock were downranked as well and then burned the whole cooldown on a small rank. Both are now cast as assigned: the known cases are listed in `FBSmartSkip`, and any spell whose tooltip names a cooldown longer than the global one is left alone too. Within a heal chain they are never picked either. Tooltip help and debug output in all five languages say so.
|
||||||
|
- **Smart Healing rates low ranks correctly.** In vanilla, ranks learned below level 20 only get a reduced share of +healing, 3.75 per cent less for every level below 20. The estimate added the full share, so with a lot of +healing a Lesser Heal rank 3 looked far stronger than it is and Smart Healing picked ranks that fell short. The learning levels of the ranks concerned are in `FBRankLearnLevel` and the bonus is cut accordingly.
|
||||||
|
- **The tooltip scanner reads cast time and range at the right place.** In 1.12 the cast time sits on the left of line 3 and the range on the right of line 2. The scanner looked for the cast time on the right and for the range on the left, exactly the wrong way round. The range was never found, so the exact distance check through UnitXP (used when the client has no `IsSpellInRange`) never ran. The cast time was only found for the highest ranks through a fallback scan, and every other rank weighted the gear bonus with a fallback of 2.5 seconds. Cast time, range and now also the cooldown are read together from both columns of the first five tooltip lines and kept per spellbook slot. The range and mana caches are now also cleared when you learn a new rank, because that moves the slots behind it. `/fbp` lists the three values for every watched spell.
|
||||||
|
- **Line of sight errors only mark the unit you clicked.** Without UnitXP the error went to the last button target of the past two seconds, otherwise to your friendly target, otherwise to yourself. A Smite into a pillar right after a heal greyed out the player you had just healed, and without a heal click your own plate got the eye. Now only the target of the click that caused the error is marked: up to `FBLOS_ERROR_WINDOW` (1) second after the click, and for spells with a cast time until one second after the cast ends, because the server checks line of sight again at the end of a cast. A cast that goes through, an interruption, another error message or another spell starting ends the wait, and your own plate is never marked.
|
||||||
|
- **Class tables work on every client language.** `UnitClass` returns the localized class name first, and that is what the addon kept. All tables keyed by class (spell lists, buff watch, dispel colours, class icon, Smart Damage) use the English name, so on a German, French or Spanish client they stayed empty and dispel colouring did not work at all. The class now comes from the English token; chat lines and the options window still show the localized name (`FBClassLocal`). Spell lists and tooltip patterns remain English, see the README.
|
||||||
|
- **The scale slider no longer moves the display.** `SetScale` reads the anchor offsets in the new scale, so dragging the slider made the plates and the raid grid wander off, and they only jumped back after the next reload or roster change. Both are anchored again right after scaling; the raid grid only when the scale really changed and never while you are dragging it.
|
||||||
|
- **Drag and drop on raid mini buttons.** The click handler of the four mini buttons used the variable of the loop that created them. Lua 5.0, the version inside client 1.12, shares that variable between all functions created in the loop, so every mini button saw its final value and a spell dropped on any of them landed on button 4. The handler now uses the button's own index.
|
||||||
|
- **A click only counts for the cast it started.** Target and rank of a click on a Heal Box button stayed valid for two and three seconds for every following cast, even after a failed click and for casts from the action bar. A Flash Heal from the bar right after a click was booked for the clicked player with the clicked rank and announced that way over HealComm, and after a failed shield click another priest's shield on the same player passed as yours as soon as any aura there changed. A click now belongs only to the spell that starts or goes through right after it (`FBPREDICT_CLICK_TIME`, 2 seconds); a failure, an error message or another spell drops it. A click made while another spell is still being cast waits for the next start, so spam clicking and the spell queue of client mods keep the running cast intact. Error messages and failed casts always answer the latest attempt; to know which one that is, Heal Box now counts every attempt through hooks on `UseAction`, `CastSpellByName` and `CastSpell`, which only count and pass everything on. HoTs, shields and buffs are confirmed only once the cast has gone through.
|
||||||
|
- **Direct heals are learned.** The server usually reports the end of a cast before the heal shows up in the combat log, and by then the cast was already forgotten. The self correction of direct heals therefore hardly ever learned anything. A finished cast now waits up to two seconds for its line.
|
||||||
|
- **Smart Damage's minimum damage is safe again.** The smallest hit seen so far counted as a rank's minimum damage. After a single high roll that was above the real minimum (Smite rank 1 does 13 to 17), and the chosen rank did not kill. The smallest normal hit is still what gets learned, but it now only proves a bonus: hit minus the tooltip's maximum, and only that is added to the tooltip's minimum. It stays the smallest hit, because boosts such as Curse of Shadow or Power Infusion only raise some hits. Saved values keep working unchanged.
|
||||||
|
- **Smart Damage's own health estimate stays out of raids.** There the combat log does not show all damage of the other groups, so every measurement came out too low, and for mob types you only meet in raids the estimate was far too small. In a raid the module now neither measures nor uses its estimate; real values, MobHealth3 and MobInfo-2 still count. Outside raids, damage of friendly players outside your group and other players' damage over time count as well.
|
||||||
|
- **Raid grid.** A cell taken over by a new player kept the red aggro border of the previous one until the next hostile target; the cells now drop that state on every roster change. The *Class colours* and *Buff icons* switches on the *General* tab reach the grid at once instead of with the next roster change. And `/fbp raid` during a raid test no longer leaves the test ghosts breathing in the background, which redrew the grid five times a second until the next reload.
|
||||||
|
- **Blizzard's party frames stay hidden when another addon hid them.** With *Hide Blizzard party frames* off (the default), every group change showed the frames again. Heal Box now only brings back what it hid itself. Saved settings with both this option and the attach mode on locked both switches in the options; the attach mode now wins at login.
|
||||||
|
- **Scale slider in attach mode.** There the buttons hang on Blizzard's party frames at scale 1, yet the slider scaled them anyway, and their offsets grew along with them. In attach mode the slider now only stores its value, which applies once the mode is switched off.
|
||||||
|
- **HoT ticks no longer clear the line of sight mark.** A tick needs no line of sight. Only a cast starting on the unit or a direct heal landing clears the mark.
|
||||||
|
- **pfUI's `HealStop`.** pfUI sends the command with a capital S, Heal Box only knew `Healstop`, so a cancelled pfUI heal stayed on the bar until its cast time ran out. Commands are now compared regardless of upper and lower case.
|
||||||
|
- **Language change, empty buttons, pet spells.** After switching the language, Dead, Ghost and Offline stayed in the old language until the next group change. A button cleared in the options, or holding a spell you no longer know, kept the tint and the cooldown clock of its old spell. A spell dragged from the pet's spellbook was stored by its slot number, which belongs to a different spell in your own spellbook; it is now refused with a note in the chat.
|
||||||
|
|
||||||
|
**Performance**
|
||||||
|
|
||||||
|
- **Redraws are collected once per frame.** Seven places still redrew all ten plates and forty raid cells on every event: every HealComm message from another healer, every tick of your own HoT, every direct heal, every absorb, cast start and cast end, and every aura check with a change. With several HealComm users in a raid that was several full sweeps a second, more than 1.4.6 had saved. These places now only note the affected name; at the end of the frame the collected names are drawn once (`FBHealBox_MarkDirty`, `FBHealBox_FlushDirty`). A burst of ten messages costs one redraw of the units concerned. The raid module looks the cell up by name instead of searching forty cells. The full sweep at most once a second stays as a safety net.
|
||||||
|
- **Mana only redraws the mana strip.** `UNIT_MANA` fires for every mana user in the raid every two seconds, and each one recomputed health, prediction, shield, colour and text of a plate or cell. Now only the strip is updated. Rage, energy and focus are registered as well, so with *Show rage, energy, focus* those strips no longer lag behind.
|
||||||
|
- **Range per unit, not per button.** In a full raid up to 160 buttons asked the range one by one, although nearly all heals reach equally far. Each pass now asks once per unit and range. The red out of range tint moved into the 0.5 second range pass: it was only evaluated on `SPELL_UPDATE_USABLE`, which does not fire at full mana, so a player running out of range stayed untinted.
|
||||||
|
- **Spellbook read once per burst.** At login and when zoning, `PLAYER_ENTERING_WORLD` and several `SPELLS_CHANGED` arrive back to back, and each one read the whole spellbook including every tooltip right away. That now happens once, in the next frame. The full setup at login ran twice (`ADDON_LOADED` and `VARIABLES_LOADED`); it runs once now, unless the saved settings only arrive with the second event.
|
||||||
|
- **Cooldown sweep compares numbers.** Its key was built as a string for every button on every pass, during the global cooldown for every single button. Start and duration are compared as numbers now.
|
||||||
|
- **Smart Damage rests while it is off.** The module listened to the combat log, `UNIT_HEALTH` and target changes even in its default off state, and read the spellbook on every `SPELLS_CHANGED`. Now it registers those events only when switched on, and it reads the spellbook only when switched on or when you open the options.
|
||||||
|
|
||||||
|
**Robustness**
|
||||||
|
|
||||||
|
- **Global names with an `FB` prefix.** `icon` (a missing `local`, never used, now removed), `panel` (the options window, under one of the most common names there are), `Spell`, `ClassIcon`, `LowHP`, `VeryLowHP`, `NamePlateWidth`, `NamePlateHeight`, `MaxButtonCount`, `MMButton` and the option widgets such as `ScaleSlider` and `MaxButtonSlider` were plain globals. Another addon with a global `panel` or `Spell` could break Heal Box. They are now `FBPanel`, `FBClassSpells`, `FBClassIcon`, `FBLowHP`, `FBVeryLowHP`, `FBNamePlateWidth`, `FBNamePlateHeight`, `FBMaxButtonCount`, `FBMinimapButton`, `FBScaleSlider` and so on.
|
||||||
|
- **Modules no longer depend on each other.** Smart Damage looked for the mana ticker's tab and placed itself below it; without the ticker file there were no Smart Damage options at all, although both modules are meant to be removable. The core now manages the shared *Extras* tab (`FBHealBox_ExtrasSection`), and each module gets its own section. The ticker only learned about new cells through `UpdateNames`; when the raid grid rebuilt on a pure `RAID_ROSTER_UPDATE`, for example when crossing the threshold, the spark was missing or ran on someone else's cell. The raid module now fires the new hook `RaidRoster` after every rebuild.
|
||||||
|
- **Errors are no longer swallowed.** An error in a module hook aborted the whole core routine that ran it. Every hook now runs protected; the first error of each hook appears in the chat, further ones with `/fbp debug`. The protected range and line of sight sweeps switched to protected single calls on any error, a future programming error included, without a word. With `/fbp debug` the error now shows, and if the same sweep fails three times in a row, so that the single calls do not help either, it is reported once even without debug mode.
|
||||||
|
- **Button passes run protected.** After the first successful range query the range was asked without protection for every spell, for the buttons as well. If the client threw for one button spell only, the error came back every half second. The button passes of core and raid grid now run protected like the range sweep, and whether the range may be asked without protection is decided per spell: a spell the client throws for takes the fallback on its own, the others keep using `IsSpellInRange`. Smart Damage's hook on `UseAction` is protected too: an error is reported once, and the key press goes through unchanged.
|
||||||
|
- **Combat log templates with numbered placeholders.** If a client wrote its combat log templates with positions such as `%1$s`, the pattern kept the `$` and every search with it threw an error. Numbered placeholders in their natural order are now removed; should a language swap the order, the English fallback applies.
|
||||||
|
- **HealComm in battlegrounds and with limits.** In battlegrounds HealComm-1.0 sends over `BATTLEGROUND`; over `RAID` nobody is reached there. Heal Box now does the same. Amounts and cast times from other addons are capped at 20000 and 10 seconds (`FBCOMM_MAX_AMOUNT`, `FBCOMM_MAX_CAST_MS`), so a broken message cannot fill a bar for a long time.
|
||||||
|
- **Your own heal on yourself.** "Your Flash Heal heals you for 1240." also matched the pattern for heals on others and went to a unit called "you"; your own plate kept its prediction until the cast ended. The pattern for heals on yourself is checked first now.
|
||||||
|
- **Spell button tooltip.** It used `SpellBookFrame.bookType`, so a warlock who last had the pet tab open saw pet spells there. It always shows your own spellbook now.
|
||||||
|
- **Drag and drop remembers less.** The spell last picked up from the spellbook was only forgotten through `ClearCursor`. With an action, a macro or an item on the cursor afterwards, the old spell could still land on a button. Picking up or placing actions, macros and items now clears it as well.
|
||||||
|
- **Minimap button.** The old code passed `math.rad(225)` to `cos` and `sin`, which take degrees in WoW; the button ended up at about four degrees, on the left of the minimap. It stays there, but dragging it with the right mouse button now saves its spot per character (`HealBox.MinimapPos`). Before, it jumped back after every reload.
|
||||||
|
- **Saved data no longer grows without end.** `HealBox.MobHP`, Smart Damage's mob health per type, grew by every mob type and level while leveling. It now keeps at most 400 types (`FBDMG_MOBHP_MAX`) and drops the ones not seen for the longest time. `FBBuffPresent` kept every name ever scanned; after every roster change, names that left the group are dropped now, together with their buff timers and foreign HoT marks.
|
||||||
|
|
||||||
|
**Cleaned up**
|
||||||
|
|
||||||
|
- **Dead code removed:** `FBGetSpellID` (which also read an undefined global `spellRank`), `HealBoxButton_OnEvent`, `FBUnitGUID`, `FBHealBox_UpdateButtonCooldown`, `FBRaid_InRaid`, `FBDropDown`, `FBDropDownButtonValue`, `FBTIMER_COLOR_BUFF`, `FBRaidOptionsTab`, and the second assignment of `FBHealBox2` to `FBHealBoxPet5`; `CreateFrame` with a name already creates these globals.
|
||||||
|
- **Outdated texts fixed:** the *Buff icons* tooltip still described the clock with quadrants in all five languages; since 1.4.4.2 the icon fades from top to bottom in 32 steps. The ticker's load message pointed to a tab called *Ticker*, which is *Extras*. The XML comment named only two of the four scripts. The README spoke of two tabs and did not know the hooks `Suppress`, `ButtonStates`, `BuffIcons` and `RefreshNames`.
|
||||||
|
- **Duplicate logic merged:** the raid module's copies of the bar helpers (`FBRaid_SetValues`, `FBRaid_SetMax`, `FBRaid_SetColor`) are gone, the cells use the core's helpers. The two nearly identical slider factories of ticker and raid module became one, `FBHealBox_CreateSlider`, which Smart Damage now uses instead of its hand built slider as well. The double loop over groups and positions, about ten times in the raid module, became flat lists of cells. The defaults stood twice in the core and had already drifted apart (`HealComm` was missing in one of them); there is one table now, `FBHealBoxDefaults`, filled in by a loop as in the modules.
|
||||||
|
- **Small things:** the comment on ae, oe and ue now says what is true: accents are fine, characters outside Latin-1 are not reliably in the default fonts. That is why the Smart Healing tooltips use the middle dot instead of "•". SuperWoW is detected in one place instead of two. `## OptionalDeps: SuperWoW` is gone from the `.toc`; SuperWoW is a client extension, not an addon, so the line had no effect. The learning branch at a shield break could never run, because the absorb handler raises the maximum beforehand; it is gone.
|
||||||
|
|
||||||
|
**Good to know**
|
||||||
|
|
||||||
|
- A HoT cast from the action bar or a macro now shows its timer and its prediction with your first tick, about three seconds after the cast, instead of right away. Casts through the Heal Box buttons are confirmed immediately, as before.
|
||||||
|
- A shield cast from the action bar can no longer be told apart from another priest's and gets no button timer and no Weakened Soul. Cast it through the buttons to have both.
|
||||||
|
- A HoT, shield or buff cast through the buttons is confirmed once the cast has gone through and its aura appears. A click that fails (out of range, line of sight, global cooldown) leaves nothing behind.
|
||||||
|
- Smart Damage keeps the values it learned with older versions: minimum damage values are read with the new, safe formula, and mob health estimates are still used outside raids.
|
||||||
|
- If you edited the class spell lists or the HP thresholds in your own copy: they are called `FBClassSpells.Name`, `FBLowHP` and `FBVeryLowHP` now.
|
||||||
|
- A red line "Error in …" in the chat means a module or a sweep hit a Lua error. The addon keeps running; the line names the place, which helps with a bug report.
|
||||||
|
|
||||||
|
### Deutsch
|
||||||
|
|
||||||
|
**Behoben**
|
||||||
|
|
||||||
|
- **Geschwaechte Seele wird angezeigt.** Der rote Timer fuer Geschwaechte Seele auf dem Schildbutton wurde aus dem Schildeintrag berechnet, und der wird in dem Moment geloescht, in dem der Schild bricht, also genau dann, wenn die Seele ueberhaupt zaehlt. Zu sehen war sie deshalb so gut wie nie. Sie laeuft jetzt in einer eigenen Tabelle (`FBWeakenedSoul`) 15 Sekunden nach deinem eigenen Machtwort: Schild, auf Plaketten und Raidzellen gleichermassen.
|
||||||
|
- **HoTs anderer Heiler zaehlen nicht mehr als deine.** Jeder HoT, der nur als Buff zu sehen war, wurde als eigener eingetragen, mit deinem hoechsten Rang und voller Laufzeit. Er fuellte Vorhersagebalken und Buttontimer, auch wenn es die Verjuengung eines anderen Druiden war. Ein solcher HoT ist jetzt vorlaeufig und zaehlt nirgends, bis dein eigener erster Tick (`… from your Rejuvenation.`) ihn bestaetigt. Kommt binnen eines Tickintervalls plus `FBPREDICT_HOT_CONFIRM_GRACE` (1,5) Sekunden keiner von dir, wird er verworfen und als fremd gemerkt, solange der Buff bleibt. Ein Tick von dir fuer einen HoT, der gar nicht verfolgt wird, nimmt ihn sofort auf. `/fbp` kennzeichnet vorlaeufige HoTs mit `(?)`.
|
||||||
|
- **Schilde anderer Priester zaehlen nicht mehr als deine.** Ein nur als Buff gesehener Schild bekam deinen gelernten Absorbwert und zeigte deinen Timer. Er bekommt jetzt den Tooltipwert, und nur Schilde, die du ueber die Heal Box Buttons wirkst, bekommen den Buttontimer und starten die Geschwaechte Seele.
|
||||||
|
- **Smart Healing laesst Gruppenheilungen und Zauber mit Abklingzeit in Ruhe.** Ein belegtes Gebet der Heilung oder eine Kettenheilung wurde nach dem fehlenden Leben der einen angeklickten Einheit abgerangt; ueber einem vollen Spieler hiess das Rang 1, egal wie der Rest der Gruppe aussah. Zauber mit Abklingzeit wie Heiliger Schock wurden ebenfalls abgerangt und verbrauchten dann die volle Abklingzeit fuer einen kleinen Rang. Beide gehen jetzt wie belegt raus: Die bekannten Faelle stehen in `FBSmartSkip`, und jeder Zauber, dessen Tooltip eine Abklingzeit ueber dem globalen Cooldown nennt, bleibt ebenfalls unberuehrt. Innerhalb einer Heilkette werden sie auch nie gewaehlt. Tooltiphilfe und Debugausgabe sagen das in allen fuenf Sprachen.
|
||||||
|
- **Smart Healing bewertet niedrige Raenge richtig.** In Vanilla bekommen Raenge, die unter Stufe 20 gelernt werden, nur einen gekuerzten Anteil an +Heilung, je Stufe unter 20 sind es 3,75 Prozent weniger. Die Schaetzung rechnete den vollen Anteil drauf; mit viel +Heilung sah ein Geringes Heilen Rang 3 so deutlich staerker aus, als es ist, und Smart Healing waehlte Raenge, die zu wenig heilten. Die Lernstufen der betroffenen Raenge stehen in `FBRankLearnLevel`, der Bonus wird entsprechend gekuerzt.
|
||||||
|
- **Der Tooltipscanner liest Zauberzeit und Reichweite an der richtigen Stelle.** In 1.12 steht die Zauberzeit links in Zeile 3 und die Reichweite rechts in Zeile 2. Der Scanner suchte die Zauberzeit rechts und die Reichweite links, also genau vertauscht. Die Reichweite fand sich nie, damit lief die genaue Abstandspruefung ueber UnitXP (genutzt, wenn der Client kein `IsSpellInRange` hat) nie. Die Zauberzeit fand sich nur fuer die Hoechstraenge ueber einen Rueckfallscan, alle anderen Raenge gewichteten den Ausruestungsbonus mit dem Ersatzwert 2,5 Sekunden. Zauberzeit, Reichweite und jetzt auch die Abklingzeit werden gemeinsam aus beiden Spalten der ersten fuenf Tooltipzeilen gelesen und je Zauberbuchplatz gemerkt. Die Speicher fuer Reichweite und Manapreis werden jetzt auch geleert, wenn du einen neuen Rang lernst, denn der verschiebt die Plaetze dahinter. `/fbp` nennt die drei Werte fuer jeden beobachteten Zauber.
|
||||||
|
- **Sichtlinienfehler markieren nur die angeklickte Einheit.** Ohne UnitXP ging der Fehler an das letzte Buttonziel der vergangenen zwei Sekunden, sonst an dein freundliches Ziel, sonst an dich selbst. Ein Angriffszauber ohne Sicht direkt nach einer Heilung graute den gerade geheilten Spieler aus, und ohne Heilklick bekam deine eigene Plakette das Auge. Jetzt wird nur das Ziel des Klicks markiert, der den Fehler ausgeloest hat: bis `FBLOS_ERROR_WINDOW` (1) Sekunde nach dem Klick, bei Zaubern mit Zauberzeit bis eine Sekunde nach dem Castende, denn der Server prueft die Sicht am Ende eines Casts noch einmal. Ein Cast, der durchgeht, eine Unterbrechung, eine andere Fehlermeldung oder ein anderer Zauber, der anlaeuft, beendet das Warten, und deine eigene Plakette wird nie markiert.
|
||||||
|
- **Klassentabellen in jeder Clientsprache.** `UnitClass` liefert zuerst den lokalisierten Klassennamen, und genau den hat sich das Addon gemerkt. Alle nach Klasse geschluesselten Tabellen (Zauberlisten, Buff-Wache, Dispelfarben, Klassenicon, Smart Damage) nutzen den englischen Namen; auf einem deutschen, franzoesischen oder spanischen Client blieben sie deshalb leer, und die Dispelfaerbung fiel komplett aus. Die Klasse kommt jetzt aus dem englischen Token; Chatzeilen und Optionsfenster zeigen weiter den lokalisierten Namen (`FBClassLocal`). Zauberlisten und Tooltipmuster bleiben englisch, siehe README.
|
||||||
|
- **Der Skalierungsregler verschiebt die Anzeige nicht mehr.** `SetScale` liest die Ankerversaetze im neuen Massstab, beim Ziehen am Regler wanderten Plaketten und Raidraster deshalb weg und sprangen erst nach dem naechsten Laden oder Rosterwechsel zurueck. Beide werden direkt nach dem Skalieren neu verankert; das Raidraster nur bei echter Aenderung und nie, waehrend du es gerade ziehst.
|
||||||
|
- **Drag & Drop auf die Minibuttons im Raid.** Der Klickhandler der vier Minibuttons benutzte die Variable der Schleife, die sie erzeugt. Lua 5.0, die Version im Client 1.12, teilt diese Variable zwischen allen in der Schleife erzeugten Funktionen; jeder Minibutton sah ihren Endwert, und ein Zauber, egal auf welchen gezogen, landete auf Button 4. Der Handler nimmt jetzt den eigenen Index des Buttons.
|
||||||
|
- **Ein Klick gilt nur fuer den Cast, den er ausloest.** Ziel und Rang eines Klicks auf einen Heal Box Button galten zwei und drei Sekunden lang fuer jeden folgenden Cast, auch nach einem gescheiterten Klick und fuer Casts von der Aktionsleiste. Eine Blitzheilung von der Leiste kurz nach einem Klick wurde fuer den angeklickten Spieler mit dem angeklickten Rang verbucht und so ueber HealComm gemeldet, und nach einem gescheiterten Klick auf den Schild galt der Schild eines anderen Priesters auf demselben Spieler als deiner, sobald sich dort irgendeine Aura aenderte. Ein Klick gehoert jetzt nur zu dem Zauber, der gleich danach anlaeuft oder durchgeht (`FBPREDICT_CLICK_TIME`, 2 Sekunden); ein Fehlschlag, eine Fehlermeldung oder ein anderer Zauber verwirft ihn. Ein Klick, waehrend noch ein anderer Zauber gewirkt wird, wartet auf den naechsten Castbeginn; Spamklicks und die Zauberwarteschlange von Clientmods lassen den laufenden Cast so unberuehrt. Fehlermeldungen und gescheiterte Casts beantworten immer den juengsten Versuch; damit klar ist, welcher das ist, zaehlt Heal Box jetzt jeden Versuch ueber Hooks auf `UseAction`, `CastSpellByName` und `CastSpell`, die nur zaehlen und alles weiterreichen. HoTs, Schilde und Buffs werden erst bestaetigt, wenn der Cast durchgegangen ist.
|
||||||
|
- **Direktheilungen werden gelernt.** Der Server meldet das Castende in der Regel, bevor die Heilung im Combatlog steht, und dann war der Cast schon vergessen. Die Selbstkorrektur der Direktheilungen lernte deshalb so gut wie nie etwas. Ein beendeter Cast wartet jetzt bis zu zwei Sekunden auf seine Zeile.
|
||||||
|
- **Der Mindestschaden von Smart Damage ist wieder sicher.** Als Mindestschaden eines Rangs galt der kleinste bisher gesehene Treffer. Nach einem einzigen hohen Wurf lag er ueber dem echten Minimum (Smite Rang 1 macht 13 bis 17), und der gewaehlte Rang toetete nicht. Gelernt wird weiter der kleinste normale Treffer, er beweist jetzt aber nur einen Bonus: Treffer minus Hoechstwert des Tooltips, und nur der kommt auf das Minimum des Tooltips. Es bleibt beim kleinsten Treffer, weil Verstaerker wie Curse of Shadow oder Power Infusion nur manche Treffer heben. Gespeicherte Werte gelten unveraendert weiter.
|
||||||
|
- **Die eigene Lebensschaetzung von Smart Damage bleibt aus Raids heraus.** Dort zeigt der Combatlog den Schaden der anderen Gruppen nicht vollstaendig, jede Messung fiel zu niedrig aus, und bei Mobtypen, die man nur im Raid trifft, war die Schaetzung viel zu klein. Im Raid misst das Modul jetzt nicht und nutzt seine Schaetzung auch nicht; echte Werte, MobHealth3 und MobInfo-2 gelten weiter. Ausserhalb von Raids zaehlen jetzt auch der Schaden freundlicher Spieler ausserhalb deiner Gruppe und der Schaden ueber Zeit anderer Spieler.
|
||||||
|
- **Raidraster.** Eine Zelle, die ein neuer Spieler uebernahm, behielt den roten Angriffsrahmen ihres Vorgaengers bis zum naechsten feindlichen Ziel; die Zellen legen diesen Zustand jetzt bei jedem Rosterwechsel ab. Die Schalter *Klassenfarben* und *Buff-Icons* im Reiter *Allgemein* erreichen das Raster sofort statt erst beim naechsten Rosterwechsel. Und `/fbp raid` waehrend eines Raidtests laesst die Testgeister nicht mehr im Hintergrund atmen; das Raster wurde dann bis zum naechsten Laden fuenfmal je Sekunde neu gezeichnet.
|
||||||
|
- **Blizzards Gruppenfenster bleiben versteckt, wenn ein anderes Addon sie versteckt hat.** Mit *Blizzard-Gruppenfenster aus* auf aus (die Vorgabe) holte jede Gruppenaenderung die Fenster wieder hervor. Heal Box nimmt jetzt nur zurueck, was es selbst versteckt hat. Gespeicherte Einstellungen mit dieser Option und dem Anheftmodus zugleich sperrten im Optionsfenster beide Schalter; beim Laden gewinnt jetzt der Anheftmodus.
|
||||||
|
- **Skalierungsregler im Anheftmodus.** Dort haengen die Buttons im Massstab 1 an Blizzards Gruppenfenstern, der Regler skalierte sie trotzdem, und ihre Versaetze wuchsen mit. Im Anheftmodus merkt sich der Regler jetzt nur seinen Wert, der gilt, sobald der Modus endet.
|
||||||
|
- **HoT-Ticks loeschen die Sichtlinienmarke nicht mehr.** Ein Tick braucht keine Sicht. Nur ein Cast, der auf der Einheit anlaeuft, oder eine angekommene Direktheilung loescht die Marke.
|
||||||
|
- **`HealStop` von pfUI.** pfUI schickt den Befehl mit grossem S, Heal Box kannte nur `Healstop`; eine abgebrochene Heilung aus pfUI blieb so bis zum Ende ihrer Zauberzeit auf dem Balken. Befehle werden jetzt unabhaengig von grossen und kleinen Buchstaben verglichen.
|
||||||
|
- **Sprachwechsel, leere Buttons, Begleiterzauber.** Nach einem Sprachwechsel blieben Tot, Geist und Offline bis zum naechsten Gruppenwechsel in der alten Sprache. Ein Button, dessen Belegung im Optionsfenster geleert wurde oder dessen Zauber du nicht mehr kennst, behielt Toenung und Abklingzeituhr seines alten Zaubers. Ein Zauber aus dem Zauberbuch des Begleiters wurde mit seiner Platznummer gemerkt, die im eigenen Zauberbuch zu einem anderen Zauber gehoert; er wird jetzt mit einem Hinweis im Chat abgelehnt.
|
||||||
|
|
||||||
|
**Leistung**
|
||||||
|
|
||||||
|
- **Neuzeichnen einmal je Frame gesammelt.** Sieben Stellen zeichneten bei jedem Ereignis noch alle zehn Plaketten und vierzig Raidzellen neu: jede HealComm-Nachricht eines anderen Heilers, jeder Tick deines eigenen HoTs, jede Direktheilung, jeder Absorb, Castbeginn und Castende und jeder Auraabgleich mit Aenderung. Mit mehreren Nutzern von HealComm im Raid waren das mehrere volle Durchlaeufe je Sekunde, mehr als 1.4.6 eingespart hatte. Diese Stellen merken jetzt nur den betroffenen Namen vor; am Ende des Frames werden die gesammelten Namen einmal gezeichnet (`FBHealBox_MarkDirty`, `FBHealBox_FlushDirty`). Eine Salve aus zehn Nachrichten kostet ein Neuzeichnen der betroffenen Einheiten. Das Raidmodul schlaegt die Zelle ueber den Namen nach, statt vierzig Zellen abzusuchen. Der volle Durchlauf hoechstens einmal je Sekunde bleibt als Sicherheitsnetz.
|
||||||
|
- **Mana zeichnet nur noch den Manastreifen.** `UNIT_MANA` feuert im Raid fuer jeden Manabenutzer alle zwei Sekunden, und jedes davon rechnete Leben, Vorhersage, Schild, Farbe und Text einer Plakette oder Zelle neu. Jetzt wird nur der Streifen nachgefuehrt. Wut, Energie und Fokus sind ebenfalls angemeldet, mit *Wut, Energie, Fokus zeigen* hinken diese Streifen nicht mehr hinterher.
|
||||||
|
- **Reichweite je Einheit statt je Button.** Im vollen Raid fragten bis zu 160 Buttons die Reichweite einzeln ab, obwohl fast alle Heilzauber gleich weit reichen. Jeder Durchgang fragt jetzt einmal je Einheit und Reichweite. Die rote Toenung ausser Reichweite laeuft im Reichweitentakt von 0,5 Sekunden mit: Bewertet wurde sie nur bei `SPELL_UPDATE_USABLE`, das bei vollem Mana nicht feuert, ein Mitspieler, der aus der Reichweite lief, blieb dann ungetoent.
|
||||||
|
- **Zauberbuch einmal je Salve gelesen.** Beim Login und beim Zonen kommen `PLAYER_ENTERING_WORLD` und mehrere `SPELLS_CHANGED` kurz hintereinander, und jedes davon las das ganze Zauberbuch samt aller Tooltips sofort. Das geschieht jetzt einmal, im naechsten Frame. Die volle Einrichtung beim Login lief zweimal (`ADDON_LOADED` und `VARIABLES_LOADED`); jetzt laeuft sie einmal, ausser die gespeicherten Einstellungen kommen erst mit dem zweiten Ereignis.
|
||||||
|
- **Cooldown-Uhr vergleicht Zahlen.** Ihr Schluessel wurde je Button und Durchgang als String gebaut, im globalen Cooldown fuer jeden einzelnen Button. Beginn und Dauer werden jetzt als Zahlen verglichen.
|
||||||
|
- **Smart Damage ruht, solange es aus ist.** Das Modul hoerte auch im Standardzustand aus auf Combatlog, `UNIT_HEALTH` und Zielwechsel und las bei jedem `SPELLS_CHANGED` das Zauberbuch. Jetzt meldet es diese Ereignisse erst beim Einschalten an und liest das Zauberbuch erst beim Einschalten oder wenn du die Optionen oeffnest.
|
||||||
|
|
||||||
|
**Robustheit**
|
||||||
|
|
||||||
|
- **Globale Namen mit `FB` versehen.** `icon` (ein fehlendes `local`, nie benutzt, jetzt entfernt), `panel` (das Optionsfenster, unter einem der haeufigsten Namen ueberhaupt), `Spell`, `ClassIcon`, `LowHP`, `VeryLowHP`, `NamePlateWidth`, `NamePlateHeight`, `MaxButtonCount`, `MMButton` und die Bedienelemente wie `ScaleSlider` und `MaxButtonSlider` waren einfache Globals. Ein anderes Addon mit globalem `panel` oder `Spell` konnte Heal Box lahmlegen. Sie heissen jetzt `FBPanel`, `FBClassSpells`, `FBClassIcon`, `FBLowHP`, `FBVeryLowHP`, `FBNamePlateWidth`, `FBNamePlateHeight`, `FBMaxButtonCount`, `FBMinimapButton`, `FBScaleSlider` und so weiter.
|
||||||
|
- **Module haengen nicht mehr voneinander ab.** Smart Damage suchte den Reiter des Mana-Tickers und setzte sich darunter; ohne Tickerdatei gab es gar keine Optionen fuer Smart Damage, obwohl beide Module einzeln entfernbar sein sollen. Den gemeinsamen Reiter *Extras* verwaltet jetzt der Kern (`FBHealBox_ExtrasSection`), und jedes Modul bekommt darin einen eigenen Abschnitt. Der Ticker erfuhr von neuen Zellen nur ueber `UpdateNames`; baute das Raidraster nach einem reinen `RAID_ROSTER_UPDATE` um, etwa beim Ueberschreiten der Schwelle, fehlte der Funke oder lief auf der Zelle eines anderen Spielers. Das Raidmodul ruft jetzt nach jedem Umbau den neuen Hook `RaidRoster`.
|
||||||
|
- **Fehler werden nicht mehr verschluckt.** Ein Fehler in einem Modulhook brach den ganzen Ablauf des Kerns ab, der ihn ausgeloest hatte. Jeder Hook laeuft jetzt geschuetzt; der erste Fehler je Hook erscheint im Chat, weitere mit `/fbp debug`. Die geschuetzten Durchlaeufe fuer Reichweite und Sichtlinie schalteten bei jedem Fehler, auch einem kuenftigen Programmierfehler, wortlos auf geschuetzte Einzelaufrufe um. Mit `/fbp debug` steht der Fehler jetzt im Chat, und scheitert derselbe Durchlauf dreimal in Folge, helfen also auch die Einzelaufrufe nicht, meldet er sich einmal auch ohne Debugmodus.
|
||||||
|
- **Durchlaeufe ueber die Buttons laufen geschuetzt.** Nach der ersten erfolgreichen Abfrage wurde die Reichweite fuer jeden Zauber ungeschuetzt gefragt, auch fuer die Buttons. Warf der Client nur fuer den Zauber eines Buttons, kam der Fehler jede halbe Sekunde wieder. Die Durchlaeufe ueber die Buttons von Kern und Raidraster laufen jetzt geschuetzt wie der Reichweitendurchlauf, und ob die Reichweite ungeschuetzt gefragt werden darf, entscheidet sich je Zauber: Ein Zauber, fuer den der Client wirft, nimmt allein den Rueckfallweg, die anderen fragen weiter `IsSpellInRange`. Auch der Hook von Smart Damage auf `UseAction` ist geschuetzt: Ein Fehler wird einmal gemeldet, und der Tastendruck geht unveraendert durch.
|
||||||
|
- **Combatlogvorlagen mit nummerierten Platzhaltern.** Schrieb ein Client seine Vorlagen mit Positionen wie `%1$s`, blieb das `$` im Muster stehen, und jede Suche damit warf einen Fehler. Nummerierte Platzhalter in natuerlicher Folge werden jetzt entfernt; stellt eine Sprache die Folge um, greift der englische Rueckfall.
|
||||||
|
- **HealComm im Schlachtfeld und mit Grenzen.** Im Schlachtfeld sendet HealComm-1.0 ueber `BATTLEGROUND`; ueber `RAID` erreicht man dort niemanden. Heal Box macht es jetzt genauso. Betraege und Zauberzeiten aus anderen Addons werden auf 20000 und 10 Sekunden begrenzt (`FBCOMM_MAX_AMOUNT`, `FBCOMM_MAX_CAST_MS`); eine kaputte Nachricht kann so keinen Balken lange fuellen.
|
||||||
|
- **Eigene Heilung auf dich selbst.** "Your Flash Heal heals you for 1240." passte auch auf das Muster fuer Heilungen auf andere und ging an eine Einheit namens "you"; deine eigene Plakette behielt ihre Vorhersage dann bis zum Castende. Das Muster fuer Heilungen auf dich wird jetzt zuerst geprueft.
|
||||||
|
- **Tooltip der Zauberbuttons.** Er nahm `SpellBookFrame.bookType`; ein Hexenmeister, der zuletzt den Begleiterreiter offen hatte, sah dort Begleiterzauber. Jetzt immer das eigene Zauberbuch.
|
||||||
|
- **Drag & Drop merkt sich weniger.** Der zuletzt aus dem Zauberbuch genommene Zauber wurde nur ueber `ClearCursor` vergessen. Lag danach eine Aktion, ein Makro oder ein Gegenstand am Cursor, konnte trotzdem der alte Zauber auf einem Button landen. Aufnehmen oder Ablegen von Aktionen, Makros und Gegenstaenden loescht ihn jetzt ebenfalls.
|
||||||
|
- **Minimap-Button.** Der alte Code gab `math.rad(225)` an `cos` und `sin`, die in WoW mit Grad rechnen; der Button landete bei etwa vier Grad, links an der Minimap. Dort bleibt er, aber mit der rechten Maustaste gezogen merkt er sich seine Stelle jetzt je Charakter (`HealBox.MinimapPos`). Vorher sprang er nach jedem Laden zurueck.
|
||||||
|
- **Gespeicherte Daten wachsen nicht mehr endlos.** `HealBox.MobHP`, das Mobleben je Typ fuer Smart Damage, wuchs beim Leveln um jeden Mobtyp und jede Stufe. Jetzt bleiben hoechstens 400 Typen (`FBDMG_MOBHP_MAX`), die am laengsten nicht gesehenen fallen weg. `FBBuffPresent` behielt jeden je gescannten Namen; nach jedem Rosterwechsel fallen Namen, die nicht mehr in der Gruppe sind, jetzt heraus, samt ihrer Bufftimer und Fremdmarken fuer HoTs.
|
||||||
|
|
||||||
|
**Aufgeraeumt**
|
||||||
|
|
||||||
|
- **Toter Code entfernt:** `FBGetSpellID` (das zudem eine undefinierte globale `spellRank` las), `HealBoxButton_OnEvent`, `FBUnitGUID`, `FBHealBox_UpdateButtonCooldown`, `FBRaid_InRaid`, `FBDropDown`, `FBDropDownButtonValue`, `FBTIMER_COLOR_BUFF`, `FBRaidOptionsTab` und die zweite Zuweisung von `FBHealBox2` bis `FBHealBoxPet5`; `CreateFrame` mit Namen legt diese Globals schon an.
|
||||||
|
- **Veraltete Texte korrigiert:** Der Tooltip *Buff-Icons* beschrieb in allen fuenf Sprachen noch die Uhr mit Quadranten; seit 1.4.4.2 blendet das Icon in 32 Stufen von oben nach unten ab. Die Ladezeile des Tickers nannte einen Reiter *Ticker*, er heisst *Extras*. Der Kommentar in der XML nannte nur zwei der vier Skripte. Die README sprach von zwei Reitern und kannte die Hooks `Suppress`, `ButtonStates`, `BuffIcons` und `RefreshNames` nicht.
|
||||||
|
- **Doppelte Logik zusammengelegt:** Die Kopien der Balkenhelfer im Raidmodul (`FBRaid_SetValues`, `FBRaid_SetMax`, `FBRaid_SetColor`) sind weg, die Zellen nutzen die Helfer des Kerns. Aus den zwei fast gleichen Sliderfabriken von Ticker und Raidmodul wurde eine, `FBHealBox_CreateSlider`, die jetzt auch Smart Damage statt seines handgebauten Reglers nutzt. Die doppelte Schleife ueber Gruppen und Plaetze, rund zehnmal im Raidmodul, wurde zu flachen Zellenlisten. Die Vorgaben standen im Kern zweimal und waren schon auseinandergelaufen (`HealComm` fehlte in einer davon); jetzt gibt es eine Tabelle, `FBHealBoxDefaults`, die eine Schleife nachzieht wie in den Modulen.
|
||||||
|
- **Kleinigkeiten:** Der Kommentar zu ae, oe und ue sagt jetzt, was stimmt: Akzente sind kein Problem, Zeichen ausserhalb von Latin-1 sind in den Standardschriften nicht sicher enthalten. Deshalb nutzen die Tooltips von Smart Healing den Mittelpunkt statt "•". SuperWoW wird an einer Stelle erkannt statt an zweien. `## OptionalDeps: SuperWoW` ist aus der `.toc` verschwunden; SuperWoW ist eine Clienterweiterung, kein Addon, die Zeile wirkte nie. Der Lernzweig beim Bruch eines Schildes konnte nie laufen, weil die Absorbauswertung das Maximum schon vorher anhebt; er ist entfernt.
|
||||||
|
|
||||||
|
**Gut zu wissen**
|
||||||
|
|
||||||
|
- Ein HoT von der Aktionsleiste oder aus einem Makro zeigt Timer und Vorhersage jetzt mit deinem ersten Tick, also etwa drei Sekunden nach dem Cast, statt sofort. Casts ueber die Heal Box Buttons sind wie bisher sofort bestaetigt.
|
||||||
|
- Ein Schild von der Aktionsleiste laesst sich nicht mehr von dem eines anderen Priesters unterscheiden und bekommt weder Buttontimer noch Geschwaechte Seele. Ueber die Buttons gewirkt gibt es beides.
|
||||||
|
- Ein HoT, Schild oder Buff ueber die Buttons gilt als bestaetigt, sobald der Cast durchgegangen ist und seine Aura erscheint. Ein gescheiterter Klick (ausser Reichweite, keine Sicht, globaler Cooldown) hinterlaesst nichts.
|
||||||
|
- Smart Damage behaelt, was es mit aelteren Versionen gelernt hat: Mindestschaeden werden mit der neuen, sicheren Rechnung gelesen, Lebensschaetzungen gelten ausserhalb von Raids weiter.
|
||||||
|
- Wer die Zauberlisten der Klassen oder die Lebensschwellen in der eigenen Kopie angepasst hat: Sie heissen jetzt `FBClassSpells.Name`, `FBLowHP` und `FBVeryLowHP`.
|
||||||
|
- Eine rote Zeile "Fehler in …" im Chat bedeutet, dass ein Modul oder ein Durchlauf auf einen Lua-Fehler gestossen ist. Das Addon laeuft weiter; die Zeile nennt die Stelle, das hilft bei einer Fehlermeldung.
|
||||||
|
|
||||||
|
|
||||||
|
## 1.4.6 (2026-10-06)
|
||||||
|
|
||||||
|
Performance pass over the display loop, with no change in behaviour: only the units that actually changed are redrawn, and two loops that ran empty five times a second now stop early.
|
||||||
|
|
||||||
|
### English
|
||||||
|
|
||||||
|
**Performance**
|
||||||
|
|
||||||
|
- **Only the units that changed are redrawn.** The 0.2 second pass used to set a single dirty flag: if any heal over time ticked anywhere, everything was redrawn, which in a full raid meant forty cells plus ten plates although exactly one unit had changed. The pass now collects the affected unit names in a reused table and hands them to `FBHealBox_RefreshUnitsByName`, and the raid module picks up the same list through the new `RefreshNames` hook. With several HoTs running this turns three to five full sweeps a second into at most one plus a handful of single-unit updates.
|
||||||
|
- **A full sweep stays as a safety net.** At most once a second, and only while something is actually changing, the old full refresh still runs, so a name that does not match a plate for any reason can never leave a stale bar behind for longer than that.
|
||||||
|
- **Empty leftovers are cleared.** When the last heal over time or the last foreign heal on a unit expires, the now-empty sub-table is removed instead of being left behind. Several places read `FBHoTs[name]` as "is anything running on this unit", and an empty table answered yes.
|
||||||
|
- **Raid spell timers skip cells with nothing to show.** The intent to skip was already in the code but the result was thrown away two lines later, so the button loop ran anyway: in a full raid that was 160 do-nothing calls five times a second. The cell is now skipped outright, exactly as the plates already did.
|
||||||
|
- **Spell timers get an early out.** When no heal over time and no shield of yours is running anywhere, the plate loop no longer asks every slot for its unit and name five times a second; it only looks where a timer still has to be cleared. Classes without HoTs and the time between fights benefit.
|
||||||
|
|
||||||
|
**Checked and left alone**
|
||||||
|
|
||||||
|
- The three `OnUpdate` loops do no unnecessary work. The prediction checks three dirty flags and two counters per frame, the mana ticker leaves at its gate (a full mana bar means no pass at all), and the raid ghost ticker is hidden outside test mode. Event handling filters unit events through a lookup table rather than walking every frame.
|
||||||
|
- The global cooldown has been drawn as a sweep since 1.4.5.1, which means every visible button gets a fresh sweep after every cast. That is the intended behaviour and the animation runs in the client, not in Lua, so it stays. Should it ever feel heavy in a dense raid, `FBCD_SHOW_MIN` set to 2 limits the sweep to real cooldowns again.
|
||||||
|
|
||||||
|
### Deutsch
|
||||||
|
|
||||||
|
**Leistung**
|
||||||
|
|
||||||
|
- **Nur noch die Einheiten neu zeichnen, bei denen sich etwas geaendert hat.** Der 0,2-Sekunden-Takt setzte bisher ein einziges Dirty-Flag: Lief irgendwo ein HoT-Tick ab, wurde alles neu gezeichnet, im Vierzigerraid also vierzig Zellen und zehn Plaketten, obwohl sich bei genau einer Einheit etwas geaendert hatte. Der Takt sammelt die betroffenen Namen jetzt in einer wiederverwendeten Tabelle und reicht sie an `FBHealBox_RefreshUnitsByName`; das Raidmodul bekommt dieselbe Liste ueber den neuen Hook `RefreshNames`. Mit mehreren laufenden HoTs werden aus drei bis fuenf vollen Durchlaeufen je Sekunde hoechstens einer plus eine Handvoll Einzel-Updates.
|
||||||
|
- **Der volle Durchlauf bleibt als Sicherheitsnetz.** Hoechstens einmal je Sekunde, und nur solange sich ueberhaupt etwas aendert, laeuft er weiterhin. Ein Name, der aus irgendeinem Grund zu keiner Plakette passt, kann so nie laenger als eine Sekunde einen alten Balken stehen lassen.
|
||||||
|
- **Leere Reste werden weggeraeumt.** Laeuft der letzte HoT oder die letzte fremde Heilung auf einer Einheit ab, verschwindet die nun leere Untertabelle, statt liegen zu bleiben. Mehrere Stellen lesen `FBHoTs[name]` als "laeuft da ueberhaupt etwas", und eine leere Tabelle hat darauf mit ja geantwortet.
|
||||||
|
- **Raid-Zaubertimer ueberspringen Zellen ohne Anzeige.** Die Absicht zu ueberspringen stand schon im Code, das Ergebnis wurde aber zwei Zeilen spaeter wieder verworfen, sodass die Buttonschleife trotzdem lief: im Vierzigerraid 160 Leeraufrufe fuenfmal je Sekunde. Die Zelle wird jetzt wirklich uebersprungen, genau wie es die Plaketten laengst machen.
|
||||||
|
- **Zaubertimer steigen frueher aus.** Laeuft nirgends ein eigener HoT und kein eigener Schild, fragt die Plakettenschleife nicht mehr fuenfmal je Sekunde jeden Slot nach Einheit und Namen, sondern schaut nur noch dort hinein, wo ein Timer wegzuraeumen ist. Davon profitieren Klassen ohne HoTs und die Zeit zwischen den Kaempfen.
|
||||||
|
|
||||||
|
**Geprueft und so gelassen**
|
||||||
|
|
||||||
|
- Die drei `OnUpdate`-Schleifen arbeiten nicht unnoetig. Die Vorhersage prueft je Frame drei Dirty-Flags und zwei Zaehler, der Mana-Ticker steigt am Torwaechter aus (voller Manabalken heisst gar kein Durchlauf), und der Geister-Ticker im Raid ist ausserhalb des Testmodus versteckt. Die Ereignisverarbeitung filtert Unit-Events ueber eine Nachschlagetabelle, statt je Frame zu suchen.
|
||||||
|
- Der globale Cooldown laeuft seit 1.4.5.1 als Uhr mit, das heisst nach jedem Zauber bekommt jeder sichtbare Button eine neue Uhr gesetzt. Das ist das gewollte Verhalten, und die Animation laeuft im Client, nicht in Lua, deshalb bleibt es so. Sollte es im dichten Raid doch schwer wirken, beschraenkt `FBCD_SHOW_MIN` auf 2 die Uhr wieder auf echte Abklingzeiten.
|
||||||
|
|
||||||
|
|
||||||
|
## 1.4.5.3 (2026-10-05)
|
||||||
|
|
||||||
|
A readability option suggested by a user: the area behind the bars can be given a solid background, so the game world no longer shows through where health is missing.
|
||||||
|
|
||||||
|
### English
|
||||||
|
|
||||||
|
**New**
|
||||||
|
|
||||||
|
- **Bar background.** New slider *Bar background* on the *General* tab, 0 to 100 per cent in steps of 5. At 0, which is the default, nothing changes: the plate stays see-through and grass, sky or stone show through the empty part of the health bar. Turned up, a quiet dark grey surface sits behind the bars, so the green of the health bar stands on a fixed background. At 100 the plate is opaque. The shade is `FBBAR_BG_COLOR` (0.15 grey) and the setting is kept per character in `HealBox.BarBG`.
|
||||||
|
- **Where it sits.** The texture hangs on the lowest of the four stacked bars, the incoming-heal bar, on the `BACKGROUND` layer. That puts it under the prediction, the shield, the health and the mana bar, and it is shown and hidden together with them, so nothing is left behind on a plate that is currently empty or hidden by the attach mode. At 0 per cent no texture is set at all, rather than a fully transparent one.
|
||||||
|
- **Raid cells need nothing.** They already have their own backdrop at 80 per cent black, so there is no world shining through there; the slider deliberately only touches the plates.
|
||||||
|
|
||||||
|
**Thanks**
|
||||||
|
|
||||||
|
- The idea and a working patch came from a user who finds the translucent bar hard to read. The patch used `WHITE8X8` plus `SetVertexColor`; the version shipped here uses `SetTexture(r, g, b, a)`, which creates a solid colour directly in 1.12 and is what the mana strip already does. Same result, no texture file involved.
|
||||||
|
|
||||||
|
### Deutsch
|
||||||
|
|
||||||
|
**Neu**
|
||||||
|
|
||||||
|
- **Balkenhintergrund.** Neuer Regler *Balkenhintergrund* im Reiter *Allgemein*, 0 bis 100 Prozent in Fuenferschritten. Bei 0, dem Standard, aendert sich nichts: Die Plakette bleibt durchscheinend, durch den leeren Teil des Lebensbalkens sieht man Gras, Himmel oder Stein. Hochgedreht liegt eine ruhige dunkelgraue Flaeche hinter den Balken, das Gruen des Lebensbalkens steht dann auf festem Grund. Bei 100 ist die Plakette undurchsichtig. Der Grundton ist `FBBAR_BG_COLOR` (0,15 Grau), die Einstellung bleibt je Charakter in `HealBox.BarBG` gespeichert.
|
||||||
|
- **Wo die Flaeche haengt.** Die Textur sitzt auf der untersten der vier gestapelten Balken, der Heilvorhersage, auf der Ebene `BACKGROUND`. Damit liegt sie unter Vorhersage, Schild, Leben und Mana, und sie wird zusammen mit ihnen ein- und ausgeblendet; auf einer leeren oder im Anheftmodus versteckten Plakette bleibt also nichts stehen. Bei 0 Prozent wird gar keine Textur gesetzt statt einer voellig durchsichtigen.
|
||||||
|
- **Raidzellen brauchen nichts.** Sie haben bereits ihren eigenen Hintergrund mit 80 Prozent Schwarz, dort scheint keine Welt durch; der Regler fasst bewusst nur die Plaketten an.
|
||||||
|
|
||||||
|
**Dank**
|
||||||
|
|
||||||
|
- Idee und ein lauffaehiger Patch kamen von einem Nutzer, dem der durchscheinende Balken schlecht lesbar ist. Der Patch benutzte `WHITE8X8` mit `SetVertexColor`; hier ausgeliefert wird `SetTexture(r, g, b, a)`, das in 1.12 direkt eine Vollfarbe erzeugt und genau das ist, was der Manastreifen ohnehin schon macht. Gleiches Ergebnis, ohne Texturdatei.
|
||||||
|
|
||||||
|
|
||||||
|
## 1.4.5.2 (2026-09-12)
|
||||||
|
|
||||||
|
One fix: a running HoT no longer pulls Smart Healing down a rank.
|
||||||
|
|
||||||
|
### English
|
||||||
|
|
||||||
|
**Fixed**
|
||||||
|
|
||||||
|
- **A HoT on the target no longer talks Smart Healing into a lower rank.** The full healing still owed by a running HoT was subtracted from the deficit as if it had already landed, so a ticking Renew could turn a Heal rank 4 into a Lesser Heal. Only healing that arrives right away is deducted now, meaning direct heals and spells reported over HealComm, roughly one to three seconds out; HoTs stay out of the calculation because they spread their healing over up to fifteen seconds. They are of course still shown on the bar, and the rule that HoTs are never downranked themselves is untouched.
|
||||||
|
|
||||||
|
### Deutsch
|
||||||
|
|
||||||
|
**Behoben**
|
||||||
|
|
||||||
|
- **Ein HoT auf dem Ziel redet Smart Healing keinen kleineren Rang mehr ein.** Die noch offene Heilung eines laufenden HoT wurde vom Fehlbetrag abgezogen, als waere sie schon angekommen; ein tickendes Erneuerung konnte so aus einem Heilen Rang 4 ein Geringes Heilen machen. Abgezogen wird jetzt nur noch Heilung, die gleich ankommt, also Direktheilungen und ueber HealComm gemeldete Zauber, grob ein bis drei Sekunden; HoTs bleiben aus der Rechnung heraus, weil sie ihre Heilung ueber bis zu fuenfzehn Sekunden verteilen. Angezeigt werden sie auf dem Balken selbstverstaendlich weiterhin, und die Regel, dass HoTs selbst nie abgerangt werden, bleibt unberuehrt.
|
||||||
|
|
||||||
|
|
||||||
|
## 1.4.5.1 (2026-09-11)
|
||||||
|
|
||||||
|
Button and ticker fixes: the mana ticker spark moves smoothly again, and the global cooldown no longer greys out every button but runs as a sweep instead.
|
||||||
|
|
||||||
|
### English
|
||||||
|
|
||||||
|
**Fixed**
|
||||||
|
|
||||||
|
- **The mana ticker spark moves smoothly again.** The spark was only redrawn once it had travelled half a pixel. That sounds frugal, but it crosses the bar in five seconds, roughly 20 pixels per second, so at 60 frames it advanced on every second frame at best and, depending on rounding, sometimes after one frame and sometimes after two. That uneven step was the stutter, and the fixed 0.03 second redraw step introduced in 1.4.5 made it worse. The threshold is now effectively gone (0.05 px) and the spark is drawn every frame again, which doubles its motion from 30 to 60 steps per second with an even gap.
|
||||||
|
- **Drawing every frame still costs nothing.** Each spark remembers the width and height of its bar and re-reads them four times a second (`FBTICK_GEOM_STEP`) instead of asking the frame on every pass, and the gate check sits in front of it all: with a full mana bar there is no pass at all.
|
||||||
|
- **The global cooldown no longer darkens every button.** After casting anything, the client reports every spell as unusable for the length of the global cooldown. Taken literally, that turned all icons dark grey for a second and a half after every cast, as if nothing were available at all. A running cooldown no longer than the global one (`FBCD_MIN_DURATION`) is no longer treated as a reason to darken a button. Blue for missing mana, red for out of range and grey for a spell that really cannot be cast, for instance in the wrong shapeshift form, all work as before. This affects the plates and the raid cells alike, both go through `FBHealBox_ButtonUsable`.
|
||||||
|
- **It runs as a sweep instead.** Not showing it at all was the other half of the inconsistency: an instant like Renew or Abolish Disease left every button untouched, while Power Word: Shield, which has a real cooldown in 1.12, showed one. The sweep is the calm way to show a short wait, so after every cast you watch it run out on all buttons, the way the action bars do it.
|
||||||
|
- **Two thresholds instead of one.** The display threshold moved into its own constant `FBCD_SHOW_MIN` (0, show every running cooldown) and is no longer tied to `FBCD_MIN_DURATION` (2), which now only answers whether a cooldown is a reason to darken a button. The two were the same value before, which is why showing the global cooldown and not darkening for it could not be had at the same time. Setting `FBCD_SHOW_MIN` to 2 restores the quiet display. A cooldown is also only shown when one is really running (`cd[1] > 0`), and the sweep starts in the very next frame because the button pass is not throttled.
|
||||||
|
|
||||||
|
### Deutsch
|
||||||
|
|
||||||
|
**Behoben**
|
||||||
|
|
||||||
|
- **Der Funke im Manabalken laeuft wieder rund.** Neu gezeichnet wurde er erst, wenn er einen halben Pixel weitergewandert war. Das klingt sparsam, er braucht fuer den Balken aber fuenf Sekunden, also rund 20 Pixel je Sekunde: Bei 60 Bildern kam er damit bestenfalls in jedem zweiten Frame voran und je nach Rundung mal nach einem, mal nach zwei Frames. Genau dieser ungleiche Schritt war das Ruckeln, und der feste Zeichentakt von 0,03 Sekunden aus 1.4.5 hat es verstaerkt. Die Schwelle ist jetzt praktisch weg (0,05 px) und gezeichnet wird wieder in jedem Frame, das verdoppelt die Bewegung von 30 auf 60 gleichmaessige Schritte je Sekunde.
|
||||||
|
- **Das Zeichnen je Frame kostet trotzdem nichts.** Jeder Funke merkt sich Breite und Hoehe seines Balkens und liest sie viermal je Sekunde nach (`FBTICK_GEOM_STEP`), statt sie bei jedem Durchlauf zu erfragen, und der Torwaechter sitzt weiterhin davor: Bei vollem Manabalken laeuft gar kein Durchlauf.
|
||||||
|
- **Der globale Cooldown dunkelt nicht mehr alle Buttons ab.** Nach jedem gewirkten Zauber meldet der Client fuer die Dauer des globalen Cooldowns saemtliche Zauber als nicht nutzbar. Woertlich genommen wurden dadurch nach jedem Zauber anderthalb Sekunden lang alle Symbole dunkelgrau, als waere gar nichts mehr verfuegbar. Eine laufende Abklingzeit, die nicht laenger ist als der globale Cooldown (`FBCD_MIN_DURATION`), gilt jetzt nicht mehr als Grund zum Abdunkeln. Blau fuer fehlendes Mana, Rot fuer ausser Reichweite und Grau fuer einen Zauber, der wirklich nicht geht, etwa in der falschen Gestalt, arbeiten unveraendert weiter. Das gilt fuer Plaketten und Raidzellen gleichermassen, beide laufen ueber `FBHealBox_ButtonUsable`.
|
||||||
|
- **Stattdessen laeuft er als Uhr mit.** Ihn gar nicht zu zeigen war die andere Haelfte der Ungereimtheit: Ein Instant wie Erneuerung oder Krankheit aufheben liess alle Buttons unberuehrt, waehrend Machtwort: Schild, das in 1.12 eine echte Abklingzeit hat, eine Uhr zeigte. Die Uhr ist die ruhige Art, eine kurze Wartezeit anzuzeigen: Nach jedem Zauber laeuft sie auf allen Buttons ab, so wie es die Aktionsleisten machen.
|
||||||
|
- **Zwei Schwellen statt einer.** Die Anzeigeschwelle sitzt jetzt in einer eigenen Konstante `FBCD_SHOW_MIN` (0, also jede laufende Abklingzeit zeigen) und haengt nicht mehr an `FBCD_MIN_DURATION` (2), die nur noch beantwortet, ob eine Abklingzeit ein Grund zum Abdunkeln ist. Vorher war beides derselbe Wert, deshalb liess sich "globalen Cooldown zeigen" und "wegen ihm nicht abdunkeln" nicht gleichzeitig haben. Wer `FBCD_SHOW_MIN` auf 2 setzt, hat die ruhige Anzeige zurueck. Gezeigt wird ausserdem nur, wenn wirklich eine Abklingzeit laeuft (`cd[1] > 0`), und die Uhr startet im naechsten Frame, weil der Button-Durchgang nicht gedrosselt ist.
|
||||||
|
|
||||||
|
|
||||||
|
## 1.4.5 (2026-09-08)
|
||||||
|
|
||||||
Three additions around the frames and the prediction: Blizzard's party frames can go away, the resource bar is no longer reserved for mana, and gear healing is counted where an API can supply it. Plus a performance pass with no change in behaviour.
|
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.
|
||||||
|
|
||||||
@@ -25,7 +264,7 @@ Three additions around the frames and the prediction: Blizzard's party frames ca
|
|||||||
- **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.
|
- **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.
|
- **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.
|
- **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.
|
- **Smaller things.** The range spell of the first assigned button is remembered instead of being searched over ten slots on every range check (invalidated on rebinding and on a spellbook rebuild). The ticker redraws on a fixed 0.03 second step instead of every frame (taken back in 1.4.5.1, it made the spark stutter). Blizzard's party frames are re-evaluated in the same collection point as the name updates instead of on every event of a burst. Two `or {}` fallbacks in loops no longer allocate a throwaway table.
|
||||||
|
|
||||||
### Deutsch
|
### Deutsch
|
||||||
|
|
||||||
@@ -48,7 +287,7 @@ Three additions around the frames and the prediction: Blizzard's party frames ca
|
|||||||
- **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.
|
- **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.
|
- **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.
|
- **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.
|
- **Kleinigkeiten.** Der Reichweiten-Zauber des ersten belegten Buttons wird gemerkt, statt bei jeder Pruefung ueber zehn Plaetze zu suchen (verworfen beim Umbelegen und beim Neuaufbau des Zauberbuchs). Der Ticker zeichnet in einem festen Takt von 0,03 Sekunden statt in jedem Frame (in 1.4.5.1 zurueckgenommen, der Funke ruckelte dadurch). Blizzards Gruppenfenster werden im selben Sammelpunkt wie die Namen neu bewertet statt bei jedem Ereignis einer Salve. Zwei `or {}`-Rueckfaelle in Schleifen legen keine Wegwerf-Tabelle mehr an.
|
||||||
|
|
||||||
|
|
||||||
## 1.4.4.3 (2026-09-08)
|
## 1.4.4.3 (2026-09-08)
|
||||||
|
|||||||
+1950
-857
File diff suppressed because it is too large
Load Diff
+4
-3
@@ -1,11 +1,12 @@
|
|||||||
## Interface: 11200
|
## Interface: 11200
|
||||||
## Title: Heal Box Vanilla |cFFFFFF00v1.4.5|r
|
## Title: Heal Box Vanilla |cFFFFFF00v1.4.7|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.5
|
## Version: 1.4.7
|
||||||
## SavedVariablesPerCharacter: HealBox
|
## SavedVariablesPerCharacter: HealBox
|
||||||
## OptionalDeps: SuperWoW
|
# SuperWoW ist eine Client-Erweiterung, kein Addon. OptionalDeps wirkt darauf
|
||||||
|
# nicht; das Addon erkennt SuperWoW zur Laufzeit.
|
||||||
|
|
||||||
FBHealBox.lua
|
FBHealBox.lua
|
||||||
FBHealBox_Raid.lua
|
FBHealBox_Raid.lua
|
||||||
|
|||||||
+4
-3
@@ -4,9 +4,10 @@
|
|||||||
Original: "Heal Box" von Dourd (Argent Dawn EU) - UI Overhauled.
|
Original: "Heal Box" von Dourd (Argent Dawn EU) - UI Overhauled.
|
||||||
Vanilla-Portierung und Funktionserweiterung 09/2026 von Mquadrat.
|
Vanilla-Portierung und Funktionserweiterung 09/2026 von Mquadrat.
|
||||||
-->
|
-->
|
||||||
<!-- Die Lua-Dateien laedt ausschliesslich die .toc (FBHealBox.lua,
|
<!-- Die Lua-Dateien laedt ausschliesslich die .toc: FBHealBox.lua (Kern),
|
||||||
FBHealBox_Raid.lua). Ein <Script file="..."/> hier wuerde den Kern
|
FBHealBox_Raid.lua, FBHealBox_Ticker.lua und FBHealBox_Damage.lua
|
||||||
ein zweites Mal ausfuehren. -->
|
(Module, einzeln entfernbar). Ein <Script file="..."/> hier wuerde
|
||||||
|
den Kern ein zweites Mal ausfuehren. -->
|
||||||
|
|
||||||
<Frame name="FBHealBoxEventFrame" parent="UIParent">
|
<Frame name="FBHealBoxEventFrame" parent="UIParent">
|
||||||
<Scripts>
|
<Scripts>
|
||||||
|
|||||||
+160
-51
@@ -12,12 +12,16 @@
|
|||||||
-- 2) MobHealth3 MobHealth3:GetUnitHealth(unit)
|
-- 2) MobHealth3 MobHealth3:GetUnitHealth(unit)
|
||||||
-- 3) MobInfo-2 MobHealth_GetTargetCurHP()/MaxHP()
|
-- 3) MobInfo-2 MobHealth_GetTargetCurHP()/MaxHP()
|
||||||
-- 4) eigene Schaetzung Lebenspunkte je Prozent aus beobachtetem Schaden
|
-- 4) eigene Schaetzung Lebenspunkte je Prozent aus beobachtetem Schaden
|
||||||
-- (eigener, Gruppe, Begleiter) und dem Prozentabfall des Ziels, erst ab
|
-- (eigener, Gruppe, Begleiter, andere freundliche Spieler, auch deren
|
||||||
-- FBDMG_MIN_DROP Prozent Abfall, Maximum ueber alle Messungen (Fehler
|
-- DoTs) und dem Prozentabfall des Ziels, erst ab FBDMG_MIN_DROP Prozent
|
||||||
-- nur nach oben, also in die sichere Richtung), gemerkt je Name:Stufe.
|
-- Abfall, Maximum ueber alle Messungen (Fehler nur nach oben, also in
|
||||||
|
-- die sichere Richtung), gemerkt je Name:Stufe. Im Raid wird weder
|
||||||
|
-- gemessen noch geschaetzt: Der Combatlog zeigt den Schaden der anderen
|
||||||
|
-- Raidgruppen nicht vollstaendig, jede Messung fiele dort zu niedrig aus.
|
||||||
--
|
--
|
||||||
-- Schaden je Rang: Mindestschaden aus dem Tooltip ("86 to 98 Holy damage"),
|
-- Schaden je Rang: Mindestschaden aus dem Tooltip ("86 to 98 Holy damage"),
|
||||||
-- nachgelernt aus eigenen Treffern ohne Teilwiderstand. Entscheidung:
|
-- angehoben um den Bonus, den der kleinste eigene Treffer ohne Crit und
|
||||||
|
-- Teilwiderstand beweist (FBDmg_MinDamage). Entscheidung:
|
||||||
-- Mindestschaden >= Ziel-Leben (bei Prozent: Obergrenze) x (1 + Aufschlag).
|
-- Mindestschaden >= Ziel-Leben (bei Prozent: Obergrenze) x (1 + Aufschlag).
|
||||||
-- ==========================================================================
|
-- ==========================================================================
|
||||||
|
|
||||||
@@ -26,6 +30,8 @@ FBHealBox_DamageLoaded = true;
|
|||||||
|
|
||||||
FBDMG_MIN_DROP = 3; -- Prozent Abfall, ab dem eine Messung zaehlt
|
FBDMG_MIN_DROP = 3; -- Prozent Abfall, ab dem eine Messung zaehlt
|
||||||
FBDMG_LASTCAST_SEC = 4; -- Sek., wie lange ein eigener Cast fuers Lernen gilt
|
FBDMG_LASTCAST_SEC = 4; -- Sek., wie lange ein eigener Cast fuers Lernen gilt
|
||||||
|
FBDMG_MOBHP_MAX = 400; -- gemerkte Mobtypen, darueber fallen die aeltesten weg
|
||||||
|
FBDMG_SECTION_H = 180; -- px, Hoehe des Abschnitts im Reiter "Extras"
|
||||||
|
|
||||||
FBDamageDefaults = {
|
FBDamageDefaults = {
|
||||||
Enabled = 0, -- Smart Damage an/aus (bewusst aus)
|
Enabled = 0, -- Smart Damage an/aus (bewusst aus)
|
||||||
@@ -160,6 +166,9 @@ FBDmgAnchorPct = nil; -- Prozent des Ziels beim letzten Messpunkt
|
|||||||
FBDmgAccum = 0; -- Schaden auf das Ziel seit dem Messpunkt
|
FBDmgAccum = 0; -- Schaden auf das Ziel seit dem Messpunkt
|
||||||
FBDmgTargetName = nil;
|
FBDmgTargetName = nil;
|
||||||
FBDmgLastCast = nil; -- { spell, rank, t } fuer das Lernen aus dem Combatlog
|
FBDmgLastCast = nil; -- { spell, rank, t } fuer das Lernen aus dem Combatlog
|
||||||
|
FBDmgActive = false; -- Ereignisse registriert (Smart Damage an)
|
||||||
|
FBDmgSpellsDirty = true; -- Zauberbuch noch nicht (neu) gelesen
|
||||||
|
FBDmgMobCount = 0; -- Eintraege in HealBox.MobHP
|
||||||
|
|
||||||
function FBDmg_Cfg()
|
function FBDmg_Cfg()
|
||||||
if (not HealBox.Damage) then FBDmg_ApplyDefaults(); end
|
if (not HealBox.Damage) then FBDmg_ApplyDefaults(); end
|
||||||
@@ -171,11 +180,37 @@ function FBDmg_ApplyDefaults()
|
|||||||
for k, v in pairs(FBDamageDefaults) do
|
for k, v in pairs(FBDamageDefaults) do
|
||||||
if (HealBox.Damage[k] == nil) then HealBox.Damage[k] = v; end
|
if (HealBox.Damage[k] == nil) then HealBox.Damage[k] = v; end
|
||||||
end
|
end
|
||||||
if (not HealBox.MobHP) then HealBox.MobHP = {}; end -- [Name:Stufe] = { ppp, n }
|
if (not HealBox.MobHP) then HealBox.MobHP = {}; end -- [Name:Stufe] = { ppp, n, seen }
|
||||||
if (not HealBox.DmgMemory) then HealBox.DmgMemory = {}; end -- [Zauber|Rang] = gelernter Mindestschaden
|
if (not HealBox.DmgMemory) then HealBox.DmgMemory = {}; end -- [Zauber|Rang] = kleinster normaler Treffer
|
||||||
|
FBDmg_PruneMobHP();
|
||||||
return true;
|
return true;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Gemerkte Mobtypen begrenzen. HealBox.MobHP wuchs bis 1.4.6 beim Leveln um
|
||||||
|
-- jeden Mobtyp und jede Stufe, ohne je zu schrumpfen. Ueber der Grenze
|
||||||
|
-- fallen die am laengsten nicht gesehenen Eintraege weg, und zwar bis auf
|
||||||
|
-- drei Viertel der Grenze, damit nicht jeder neue Mob eine Sortierung
|
||||||
|
-- ausloest. Eintraege aus aelteren Versionen ohne Zeitstempel gelten als
|
||||||
|
-- die aeltesten.
|
||||||
|
function FBDmg_SeenOf(e)
|
||||||
|
if (type(e) == "table") and e.seen then return e.seen; end
|
||||||
|
return 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function FBDmg_PruneMobHP()
|
||||||
|
local t = HealBox.MobHP;
|
||||||
|
if (not t) then FBDmgMobCount = 0; return; end
|
||||||
|
local keys = {};
|
||||||
|
for k in pairs(t) do table.insert(keys, k); end
|
||||||
|
local n = table.getn(keys);
|
||||||
|
FBDmgMobCount = n;
|
||||||
|
if (n <= FBDMG_MOBHP_MAX) then return; end
|
||||||
|
table.sort(keys, function(a, b) return FBDmg_SeenOf(t[a]) < FBDmg_SeenOf(t[b]); end);
|
||||||
|
local drop = n - math.floor(FBDMG_MOBHP_MAX * 0.75);
|
||||||
|
for i = 1, drop do t[keys[i]] = nil; end
|
||||||
|
FBDmgMobCount = n - drop;
|
||||||
|
end
|
||||||
|
|
||||||
-- ==========================================================================
|
-- ==========================================================================
|
||||||
-- [ Zauberbuch: Raenge und Schaden ]
|
-- [ Zauberbuch: Raenge und Schaden ]
|
||||||
-- ==========================================================================
|
-- ==========================================================================
|
||||||
@@ -204,13 +239,22 @@ function FBDmg_ScanSpells()
|
|||||||
i = i + 1;
|
i = i + 1;
|
||||||
end
|
end
|
||||||
FBDmgSlotCache = {};
|
FBDmgSlotCache = {};
|
||||||
|
FBDmgSpellsDirty = false;
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Mindestschaden eines Rangs: gelernt (Treffer ohne Teilwiderstand), sonst Tooltip
|
-- Mindestschaden eines Rangs. Gelernt wird der kleinste eigene Treffer ohne
|
||||||
|
-- Crit und Teilwiderstand. Jeder Treffer liegt hoechstens beim Hoechstwert
|
||||||
|
-- des Tooltips plus Bonus, der Bonus ist also mindestens Treffer minus
|
||||||
|
-- Hoechstwert, und so viel liegt sicher auch auf dem Minimum. Der kleinste
|
||||||
|
-- Treffer, weil Verstaerker wie Curse of Shadow oder Power Infusion nur
|
||||||
|
-- manche Treffer heben; ein einzelner verstaerkter Treffer darf den Wert
|
||||||
|
-- nicht dauerhaft hochziehen. Bis 1.4.6 galt der kleinste Treffer selbst als
|
||||||
|
-- Mindestschaden; nach einem einzigen hohen Wurf lag er ueber dem echten
|
||||||
|
-- Minimum, und der gewaehlte Rang toetete nicht.
|
||||||
function FBDmg_MinDamage(spell, entry)
|
function FBDmg_MinDamage(spell, entry)
|
||||||
local learned = HealBox.DmgMemory and HealBox.DmgMemory[spell.."|"..entry.rank];
|
local learned = HealBox.DmgMemory and HealBox.DmgMemory[spell.."|"..entry.rank];
|
||||||
if (learned and learned > entry.min) then return learned; end
|
if (not learned) then return entry.min; end
|
||||||
return entry.min;
|
return math.max(entry.min, learned - (entry.max - entry.min));
|
||||||
end
|
end
|
||||||
|
|
||||||
-- ==========================================================================
|
-- ==========================================================================
|
||||||
@@ -248,10 +292,14 @@ function FBDmg_TargetHP(unit)
|
|||||||
local ok2, max = pcall(MobHealth_GetTargetMaxHP);
|
local ok2, max = pcall(MobHealth_GetTargetMaxHP);
|
||||||
if (ok and ok2 and cur and max and max > 100) then return cur, max, "mi2"; end
|
if (ok and ok2 and cur and max and max > 100) then return cur, max, "mi2"; end
|
||||||
end
|
end
|
||||||
-- eigene Schaetzung: Prozent-Obergrenze x Lebenspunkte je Prozent
|
-- eigene Schaetzung: Prozent-Obergrenze x Lebenspunkte je Prozent. Nicht
|
||||||
|
-- im Raid: Dort wird nicht gemessen (FBDmg_OnTargetHealth), und was
|
||||||
|
-- fruehere Versionen dort gemessen haben, fiel zu niedrig aus.
|
||||||
|
if (GetNumRaidMembers() > 0) then return nil; end
|
||||||
local key = FBDmg_MobKey(unit);
|
local key = FBDmg_MobKey(unit);
|
||||||
local est = key and HealBox.MobHP and HealBox.MobHP[key];
|
local est = key and HealBox.MobHP and HealBox.MobHP[key];
|
||||||
if (est and est.ppp and est.ppp > 0) then
|
if (est and est.ppp and est.ppp > 0) then
|
||||||
|
est.seen = time();
|
||||||
local pct = UnitHealth(unit) or 0;
|
local pct = UnitHealth(unit) or 0;
|
||||||
return math.ceil((pct + 1) * est.ppp), math.ceil(100 * est.ppp), "est";
|
return math.ceil((pct + 1) * est.ppp), math.ceil(100 * est.ppp), "est";
|
||||||
end
|
end
|
||||||
@@ -264,6 +312,8 @@ function FBDmg_ResetTarget()
|
|||||||
FBDmgTargetName = nil;
|
FBDmgTargetName = nil;
|
||||||
FBDmgAnchorPct = nil;
|
FBDmgAnchorPct = nil;
|
||||||
FBDmgAccum = 0;
|
FBDmgAccum = 0;
|
||||||
|
-- Im Raid wird nicht vermessen (siehe Kopf der Datei)
|
||||||
|
if (GetNumRaidMembers() > 0) then FBDmg_UpdateSourceText(); return; end
|
||||||
if (UnitExists("target") and UnitCanAttack and UnitCanAttack("player", "target") and not FBDmg_HasRealValues("target")) then
|
if (UnitExists("target") and UnitCanAttack and UnitCanAttack("player", "target") and not FBDmg_HasRealValues("target")) then
|
||||||
FBDmgTargetName = UnitName("target");
|
FBDmgTargetName = UnitName("target");
|
||||||
FBDmgAnchorPct = UnitHealth("target");
|
FBDmgAnchorPct = UnitHealth("target");
|
||||||
@@ -281,6 +331,13 @@ end
|
|||||||
function FBDmg_OnTargetHealth()
|
function FBDmg_OnTargetHealth()
|
||||||
if (not FBDmgTargetName) or (not FBDmgAnchorPct) then return; end
|
if (not FBDmgTargetName) or (not FBDmgAnchorPct) then return; end
|
||||||
if (FBDmg_HasRealValues("target")) then return; end
|
if (FBDmg_HasRealValues("target")) then return; end
|
||||||
|
-- Mitten im Kampf einem Raid beigetreten: Messung verwerfen. Bis 1.4.6
|
||||||
|
-- wurde auch im Raid gemessen; bei Mobtypen, die man nur dort trifft,
|
||||||
|
-- war dann keine Messung sauber und die Schaetzung viel zu niedrig.
|
||||||
|
if (GetNumRaidMembers() > 0) then
|
||||||
|
FBDmgTargetName = nil; FBDmgAnchorPct = nil; FBDmgAccum = 0;
|
||||||
|
return;
|
||||||
|
end
|
||||||
local pct = UnitHealth("target") or 0;
|
local pct = UnitHealth("target") or 0;
|
||||||
local drop = FBDmgAnchorPct - pct;
|
local drop = FBDmgAnchorPct - pct;
|
||||||
if (drop >= FBDMG_MIN_DROP and FBDmgAccum > 0) then
|
if (drop >= FBDMG_MIN_DROP and FBDmgAccum > 0) then
|
||||||
@@ -290,12 +347,15 @@ function FBDmg_OnTargetHealth()
|
|||||||
if (not HealBox.MobHP) then HealBox.MobHP = {}; end
|
if (not HealBox.MobHP) then HealBox.MobHP = {}; end
|
||||||
local e = HealBox.MobHP[key];
|
local e = HealBox.MobHP[key];
|
||||||
if (not e) then
|
if (not e) then
|
||||||
HealBox.MobHP[key] = { ppp = ppp, n = 1 };
|
HealBox.MobHP[key] = { ppp = ppp, n = 1, seen = time() };
|
||||||
|
FBDmgMobCount = FBDmgMobCount + 1;
|
||||||
|
if (FBDmgMobCount > FBDMG_MOBHP_MAX) then FBDmg_PruneMobHP(); end
|
||||||
else
|
else
|
||||||
-- Maximum: Fehler nur nach oben (fremder, nicht gezaehlter Schaden
|
-- Maximum: Fehler nur nach oben (fremder, nicht gezaehlter Schaden
|
||||||
-- wuerde die Schaetzung sonst nach unten ziehen)
|
-- wuerde die Schaetzung sonst nach unten ziehen)
|
||||||
if (ppp > e.ppp) then e.ppp = ppp; end
|
if (ppp > e.ppp) then e.ppp = ppp; end
|
||||||
e.n = (e.n or 0) + 1;
|
e.n = (e.n or 0) + 1;
|
||||||
|
e.seen = time();
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
FBDmgAnchorPct = pct;
|
FBDmgAnchorPct = pct;
|
||||||
@@ -326,6 +386,9 @@ function FBDmg_ParseLine(msg)
|
|||||||
-- "Kobold suffers 50 Shadow damage from your Shadow Word: Pain."
|
-- "Kobold suffers 50 Shadow damage from your Shadow Word: Pain."
|
||||||
_, _, victim, amount = string.find(msg, "^(.-) suffers (%d+) .- damage from your");
|
_, _, victim, amount = string.find(msg, "^(.-) suffers (%d+) .- damage from your");
|
||||||
if (victim) then return victim, tonumber(amount), nil, "self"; end
|
if (victim) then return victim, tonumber(amount), nil, "self"; end
|
||||||
|
-- "Kobold suffers 50 Shadow damage from Bob's Shadow Word: Pain."
|
||||||
|
_, _, victim, amount = string.find(msg, "^(.-) suffers (%d+) .- damage from .-'s ");
|
||||||
|
if (victim) then return victim, tonumber(amount), nil, "other"; end
|
||||||
-- "Bob's Fireball hits Kobold for 200." / crits (Gruppe, Begleiter)
|
-- "Bob's Fireball hits Kobold for 200." / crits (Gruppe, Begleiter)
|
||||||
_, _, victim, amount = string.find(msg, "^.-'s .- hits (.-) for (%d+)");
|
_, _, victim, amount = string.find(msg, "^.-'s .- hits (.-) for (%d+)");
|
||||||
if (not victim) then _, _, victim, amount = string.find(msg, "^.-'s .- crits (.-) for (%d+)"); end
|
if (not victim) then _, _, victim, amount = string.find(msg, "^.-'s .- crits (.-) for (%d+)"); end
|
||||||
@@ -345,7 +408,8 @@ function FBDmg_OnCombatLog(msg)
|
|||||||
local victim, amount, spell, who = FBDmg_ParseLine(msg);
|
local victim, amount, spell, who = FBDmg_ParseLine(msg);
|
||||||
if (not victim) then return; end
|
if (not victim) then return; end
|
||||||
FBDmg_NoteDamage(victim, amount);
|
FBDmg_NoteDamage(victim, amount);
|
||||||
-- Mindestschaden lernen: eigener Zauber, kein Crit, kein Teilwiderstand
|
-- Kleinsten Treffer lernen (siehe FBDmg_MinDamage): eigener Zauber, kein
|
||||||
|
-- Crit, kein Teilwiderstand
|
||||||
if (who == "self" and spell and FBDmgLastCast and FBDmgLastCast.spell == spell
|
if (who == "self" and spell and FBDmgLastCast and FBDmgLastCast.spell == spell
|
||||||
and (GetTime() - FBDmgLastCast.t) <= FBDMG_LASTCAST_SEC
|
and (GetTime() - FBDmgLastCast.t) <= FBDMG_LASTCAST_SEC
|
||||||
and not string.find(msg, "crits") and not string.find(msg, "resisted")) then
|
and not string.find(msg, "crits") and not string.find(msg, "resisted")) then
|
||||||
@@ -353,7 +417,6 @@ function FBDmg_OnCombatLog(msg)
|
|||||||
if (not HealBox.DmgMemory) then HealBox.DmgMemory = {}; end
|
if (not HealBox.DmgMemory) then HealBox.DmgMemory = {}; end
|
||||||
local old = HealBox.DmgMemory[key];
|
local old = HealBox.DmgMemory[key];
|
||||||
if (not old) or (amount < old) then
|
if (not old) or (amount < old) then
|
||||||
-- kleinster beobachteter Volltreffer = sicherer Mindestschaden
|
|
||||||
HealBox.DmgMemory[key] = amount;
|
HealBox.DmgMemory[key] = amount;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -444,7 +507,15 @@ function FBDmg_HookUseAction()
|
|||||||
FBHealBox_UseActionHooked = true;
|
FBHealBox_UseActionHooked = true;
|
||||||
local origUseAction = UseAction;
|
local origUseAction = UseAction;
|
||||||
UseAction = function(slot, checkCursor, onSelf)
|
UseAction = function(slot, checkCursor, onSelf)
|
||||||
if (FBDmg_TryDownrank(slot, checkCursor, onSelf)) then return; end
|
-- Geschuetzt wie die Hooks des Kerns: Ein Fehler in der Rangwahl wird
|
||||||
|
-- gemeldet und darf den Tastendruck nicht verschlucken, der Aufruf
|
||||||
|
-- laeuft dann unveraendert weiter
|
||||||
|
local ok, done = pcall(FBDmg_TryDownrank, slot, checkCursor, onSelf);
|
||||||
|
if (not ok) then
|
||||||
|
FBHealBox_ReportError("Smart Damage", done);
|
||||||
|
done = false;
|
||||||
|
end
|
||||||
|
if (done) then return; end
|
||||||
origUseAction(slot, checkCursor, onSelf);
|
origUseAction(slot, checkCursor, onSelf);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -454,24 +525,72 @@ end
|
|||||||
-- ==========================================================================
|
-- ==========================================================================
|
||||||
|
|
||||||
FBDmgFrame = CreateFrame("Frame", "FBHealBoxDamageFrame", UIParent);
|
FBDmgFrame = CreateFrame("Frame", "FBHealBoxDamageFrame", UIParent);
|
||||||
|
-- Immer: Zauberbuch geaendert. Das kostet nichts, ausgeschaltet wird nur
|
||||||
|
-- vorgemerkt.
|
||||||
FBDmgFrame:RegisterEvent("PLAYER_ENTERING_WORLD");
|
FBDmgFrame:RegisterEvent("PLAYER_ENTERING_WORLD");
|
||||||
FBDmgFrame:RegisterEvent("SPELLS_CHANGED");
|
FBDmgFrame:RegisterEvent("SPELLS_CHANGED");
|
||||||
FBDmgFrame:RegisterEvent("ACTIONBAR_SLOT_CHANGED");
|
|
||||||
FBDmgFrame:RegisterEvent("PLAYER_TARGET_CHANGED");
|
-- Nur solange Smart Damage an ist (FBDmg_UpdateActive). Bis 1.4.6 liefen
|
||||||
FBDmgFrame:RegisterEvent("UNIT_HEALTH");
|
-- Combatlog, UNIT_HEALTH und Zielwechsel auch im Standardzustand aus
|
||||||
for _, ev in ipairs({
|
-- durch dieses Modul.
|
||||||
|
FBDmgActiveEvents = {
|
||||||
|
"ACTIONBAR_SLOT_CHANGED", "PLAYER_TARGET_CHANGED", "UNIT_HEALTH",
|
||||||
"CHAT_MSG_SPELL_SELF_DAMAGE", "CHAT_MSG_COMBAT_SELF_HITS",
|
"CHAT_MSG_SPELL_SELF_DAMAGE", "CHAT_MSG_COMBAT_SELF_HITS",
|
||||||
"CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE", "CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE",
|
"CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE", "CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE",
|
||||||
"CHAT_MSG_SPELL_PARTY_DAMAGE", "CHAT_MSG_COMBAT_PARTY_HITS",
|
"CHAT_MSG_SPELL_PARTY_DAMAGE", "CHAT_MSG_COMBAT_PARTY_HITS",
|
||||||
"CHAT_MSG_SPELL_PET_DAMAGE", "CHAT_MSG_COMBAT_PET_HITS",
|
"CHAT_MSG_SPELL_PET_DAMAGE", "CHAT_MSG_COMBAT_PET_HITS",
|
||||||
}) do FBDmgFrame:RegisterEvent(ev); end
|
-- Spieler ausserhalb der Gruppe, die denselben Gegner angreifen
|
||||||
|
"CHAT_MSG_SPELL_FRIENDLYPLAYER_DAMAGE", "CHAT_MSG_COMBAT_FRIENDLYPLAYER_HITS",
|
||||||
|
};
|
||||||
|
|
||||||
|
function FBDmg_UpdateActive()
|
||||||
|
local on = (FBDmg_Cfg().Enabled == 1) and (not FBAddonSuppressed);
|
||||||
|
if (on == FBDmgActive) then return; end
|
||||||
|
FBDmgActive = on;
|
||||||
|
for _, ev in ipairs(FBDmgActiveEvents) do
|
||||||
|
if (on) then FBDmgFrame:RegisterEvent(ev); else FBDmgFrame:UnregisterEvent(ev); end
|
||||||
|
end
|
||||||
|
if (on) then
|
||||||
|
-- Was waehrend der Pause auf den Leisten passiert ist, weiss das
|
||||||
|
-- Modul nicht: Slots neu lesen, Zauberbuch bei Bedarf auch.
|
||||||
|
FBDmgSlotCache = {};
|
||||||
|
if (FBDmgSpellsDirty) then FBDmg_ScheduleScan(); end
|
||||||
|
FBDmg_ResetTarget();
|
||||||
|
else
|
||||||
|
FBDmgTargetName = nil; FBDmgAnchorPct = nil; FBDmgAccum = 0;
|
||||||
|
FBDmgLastCast = nil;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Zauberbuch im naechsten Frame lesen, einmal je Salve. Beim Login kommen
|
||||||
|
-- PLAYER_ENTERING_WORLD und mehrere SPELLS_CHANGED kurz hintereinander,
|
||||||
|
-- bis 1.4.6 las jedes davon alle Schadenszauber samt Tooltips sofort. Der
|
||||||
|
-- OnUpdate haengt nur, solange etwas ansteht.
|
||||||
|
function FBDmg_ScheduleScan()
|
||||||
|
FBDmgSpellsDirty = true;
|
||||||
|
-- Gelesen wird, wenn das Modul an ist oder jemand die Liste gerade sieht
|
||||||
|
if (FBDmgActive) or (FBPanel and FBPanel:IsVisible()) then
|
||||||
|
FBDmgFrame:SetScript("OnUpdate", FBDmg_OnUpdate);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function FBDmg_OnUpdate()
|
||||||
|
FBDmgFrame:SetScript("OnUpdate", nil);
|
||||||
|
if (FBAddonSuppressed) or (not FBDmgSpellsDirty) then return; end
|
||||||
|
if (FBDmgActive) then
|
||||||
|
FBDmg_ScanSpells();
|
||||||
|
FBDmg_UpdateSpellText();
|
||||||
|
FBDmg_ResetTarget();
|
||||||
|
else
|
||||||
|
-- Ausgeschaltet, Optionen offen: liest bei Bedarf selbst
|
||||||
|
FBDmg_UpdateSpellText();
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
FBDmgFrame:SetScript("OnEvent", function()
|
FBDmgFrame:SetScript("OnEvent", function()
|
||||||
if (FBAddonSuppressed) then return; end
|
if (FBAddonSuppressed) then return; end
|
||||||
if (event == "PLAYER_ENTERING_WORLD" or event == "SPELLS_CHANGED") then
|
if (event == "PLAYER_ENTERING_WORLD" or event == "SPELLS_CHANGED") then
|
||||||
FBDmg_ScanSpells();
|
FBDmg_ScheduleScan();
|
||||||
FBDmg_UpdateSpellText();
|
|
||||||
FBDmg_ResetTarget();
|
|
||||||
elseif (event == "ACTIONBAR_SLOT_CHANGED") then
|
elseif (event == "ACTIONBAR_SLOT_CHANGED") then
|
||||||
if (arg1) then FBDmgSlotCache[arg1] = nil; else FBDmgSlotCache = {}; end
|
if (arg1) then FBDmgSlotCache[arg1] = nil; else FBDmgSlotCache = {}; end
|
||||||
elseif (event == "PLAYER_TARGET_CHANGED") then
|
elseif (event == "PLAYER_TARGET_CHANGED") then
|
||||||
@@ -503,13 +622,16 @@ end
|
|||||||
|
|
||||||
function FBDmg_UpdateSourceText()
|
function FBDmg_UpdateSourceText()
|
||||||
-- nur, wenn das Optionsfenster offen ist (sonst je UNIT_HEALTH des Ziels umsonst)
|
-- nur, wenn das Optionsfenster offen ist (sonst je UNIT_HEALTH des Ziels umsonst)
|
||||||
if (FBDmgSourceText and panel and panel:IsVisible()) then
|
if (FBDmgSourceText and FBPanel and FBPanel:IsVisible()) then
|
||||||
FBDmgSourceText:SetText(format(FBT("DMG_SRC"), FBDmg_SourceText()));
|
FBDmgSourceText:SetText(format(FBT("DMG_SRC"), FBDmg_SourceText()));
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function FBDmg_UpdateSpellText()
|
function FBDmg_UpdateSpellText()
|
||||||
if (not FBDmgSpellText) then return; end
|
if (not FBDmgSpellText) then return; end
|
||||||
|
-- Ausgeschaltet liest das Modul das Zauberbuch erst, wenn jemand die
|
||||||
|
-- Optionen ansieht
|
||||||
|
if (FBDmgSpellsDirty and FBPanel and FBPanel:IsVisible()) then FBDmg_ScanSpells(); end
|
||||||
local list = {};
|
local list = {};
|
||||||
for _, n in ipairs(FBDamageSpells[FBClass] or {}) do
|
for _, n in ipairs(FBDamageSpells[FBClass] or {}) do
|
||||||
if (FBDmgSpellRanks[n]) then table.insert(list, n.." ("..table.getn(FBDmgSpellRanks[n])..")"); end
|
if (FBDmgSpellRanks[n]) then table.insert(list, n.." ("..table.getn(FBDmgSpellRanks[n])..")"); end
|
||||||
@@ -519,16 +641,12 @@ function FBDmg_UpdateSpellText()
|
|||||||
FBDmgSpellText:SetText(format(FBT("DMG_SPELLS"), shown));
|
FBDmgSpellText:SetText(format(FBT("DMG_SPELLS"), shown));
|
||||||
end
|
end
|
||||||
|
|
||||||
function FBDmg_UpdateMarginText()
|
-- Eigener Abschnitt im Reiter "Extras", den der Kern verwaltet. Bis 1.4.6
|
||||||
if (FBDmgMarginSlider and FBDmgMarginSlider.Text) then
|
-- suchte das Modul den Reiter des Mana-Tickers und setzte sich 232 px
|
||||||
FBDmgMarginSlider.Text:SetText(format(FBT("DMG_MARGIN"), math.floor(FBDmgMarginSlider:GetValue() + 0.5)));
|
-- darunter; ohne Tickerdatei gab es fuer Smart Damage gar keine Optionen.
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function FBDmg_BuildOptions()
|
function FBDmg_BuildOptions()
|
||||||
local tab = FBHealBox_FindOptionsTab("TAB_TICKER");
|
local tab, y = FBHealBox_ExtrasSection(FBDMG_SECTION_H);
|
||||||
if (not tab) then return; end
|
if (not tab) then return; end
|
||||||
local y = FBOPT_CONTENT_Y - 232; -- unter dem Ticker-Abschnitt
|
|
||||||
|
|
||||||
FBDmgHeader = tab:CreateFontString(nil, "OVERLAY", "GameFontNormal");
|
FBDmgHeader = tab:CreateFontString(nil, "OVERLAY", "GameFontNormal");
|
||||||
FBDmgHeader:SetPoint("TOPLEFT", tab, "TOPLEFT", 35, y);
|
FBDmgHeader:SetPoint("TOPLEFT", tab, "TOPLEFT", 35, y);
|
||||||
@@ -536,25 +654,12 @@ function FBDmg_BuildOptions()
|
|||||||
|
|
||||||
FBDmgEnabledCheck = FBHealBox_CreateCheck("FBHealBoxDmgEnabledCheck", tab, 34, y - 20, "DMG_ENABLED", "DMG_ENABLED_TIP", function()
|
FBDmgEnabledCheck = FBHealBox_CreateCheck("FBHealBoxDmgEnabledCheck", tab, 34, y - 20, "DMG_ENABLED", "DMG_ENABLED_TIP", function()
|
||||||
FBDmg_Cfg().Enabled = FBDmgEnabledCheck:GetChecked() and 1 or 0;
|
FBDmg_Cfg().Enabled = FBDmgEnabledCheck:GetChecked() and 1 or 0;
|
||||||
|
FBDmg_UpdateActive();
|
||||||
end);
|
end);
|
||||||
FBDmgEnabledCheck:SetChecked(nil);
|
FBDmgEnabledCheck:SetChecked(nil);
|
||||||
|
|
||||||
FBDmgMarginSlider = CreateFrame("Slider", "FBDmgMarginSlider", tab, "OptionsSliderTemplate");
|
FBDmgMarginSlider = FBHealBox_CreateSlider("FBDmgMarginSlider", tab, 268, y - 40, "DMG_MARGIN",
|
||||||
FBDmgMarginSlider:SetWidth(170);
|
FBDmg_Cfg, "Margin", 0, 50, 5, false, nil, nil, 170);
|
||||||
FBDmgMarginSlider:SetHeight(16);
|
|
||||||
FBDmgMarginSlider:SetPoint("TOPLEFT", 268, y - 40);
|
|
||||||
FBDmgMarginSlider:SetMinMaxValues(0, 50);
|
|
||||||
FBDmgMarginSlider:SetValueStep(5);
|
|
||||||
FBDmgMarginSlider:SetValue(FBDmg_Cfg().Margin or 20);
|
|
||||||
FBDmgMarginSlider.Text = FBDmgMarginSlider:CreateFontString(nil, "BACKGROUND", "GameFontNormal");
|
|
||||||
FBDmgMarginSlider.Text:SetPoint("CENTER", 0, 15);
|
|
||||||
getglobal("FBDmgMarginSliderLow"):SetText("0");
|
|
||||||
getglobal("FBDmgMarginSliderHigh"):SetText("50");
|
|
||||||
FBDmgMarginSlider:SetScript("OnValueChanged", function()
|
|
||||||
FBDmg_Cfg().Margin = math.floor(FBDmgMarginSlider:GetValue() + 0.5);
|
|
||||||
FBDmg_UpdateMarginText();
|
|
||||||
end);
|
|
||||||
FBDmg_UpdateMarginText();
|
|
||||||
|
|
||||||
FBDmgSourceText = tab:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
|
FBDmgSourceText = tab:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
|
||||||
FBDmgSourceText:SetPoint("TOPLEFT", tab, "TOPLEFT", 40, y - 80);
|
FBDmgSourceText:SetPoint("TOPLEFT", tab, "TOPLEFT", 40, y - 80);
|
||||||
@@ -574,10 +679,11 @@ function FBDmg_BuildOptions()
|
|||||||
FBDmg_UpdateSpellText();
|
FBDmg_UpdateSpellText();
|
||||||
FBDmg_SyncOptions();
|
FBDmg_SyncOptions();
|
||||||
-- beim Oeffnen des Fensters die Zielzeile auffrischen (Vor-Hook auf OnShow)
|
-- beim Oeffnen des Fensters die Zielzeile auffrischen (Vor-Hook auf OnShow)
|
||||||
local prevShow = panel:GetScript("OnShow");
|
local prevShow = FBPanel:GetScript("OnShow");
|
||||||
panel:SetScript("OnShow", function()
|
FBPanel:SetScript("OnShow", function()
|
||||||
if (prevShow) then prevShow(); end
|
if (prevShow) then prevShow(); end
|
||||||
FBDmg_UpdateSourceText();
|
FBDmg_UpdateSourceText();
|
||||||
|
FBDmg_UpdateSpellText();
|
||||||
end);
|
end);
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -585,6 +691,7 @@ function FBDmg_SyncOptions()
|
|||||||
local cfg = FBDmg_Cfg();
|
local cfg = FBDmg_Cfg();
|
||||||
if (FBDmgEnabledCheck) then FBDmgEnabledCheck:SetChecked(cfg.Enabled == 1); end
|
if (FBDmgEnabledCheck) then FBDmgEnabledCheck:SetChecked(cfg.Enabled == 1); end
|
||||||
if (FBDmgMarginSlider) then FBDmgMarginSlider:SetValue(cfg.Margin or 20); end
|
if (FBDmgMarginSlider) then FBDmgMarginSlider:SetValue(cfg.Margin or 20); end
|
||||||
|
FBDmg_UpdateActive();
|
||||||
return true;
|
return true;
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -592,7 +699,7 @@ function FBDmg_ApplyLocale()
|
|||||||
if (FBDmgHeader) then FBDmgHeader:SetText(FBT("DMG_HEADER")); end
|
if (FBDmgHeader) then FBDmgHeader:SetText(FBT("DMG_HEADER")); end
|
||||||
if (FBDmgEnabledCheck) then FBDmgEnabledCheck.Text:SetText(FBT("DMG_ENABLED")); FBDmgEnabledCheck.tooltipText = FBT("DMG_ENABLED_TIP"); end
|
if (FBDmgEnabledCheck) then FBDmgEnabledCheck.Text:SetText(FBT("DMG_ENABLED")); FBDmgEnabledCheck.tooltipText = FBT("DMG_ENABLED_TIP"); end
|
||||||
if (FBDmgInfoText) then FBDmgInfoText:SetText(FBT("DMG_INFO")); end
|
if (FBDmgInfoText) then FBDmgInfoText:SetText(FBT("DMG_INFO")); end
|
||||||
FBDmg_UpdateMarginText();
|
FBHealBox_SliderText(FBDmgMarginSlider);
|
||||||
FBDmg_UpdateSourceText();
|
FBDmg_UpdateSourceText();
|
||||||
FBDmg_UpdateSpellText();
|
FBDmg_UpdateSpellText();
|
||||||
return true;
|
return true;
|
||||||
@@ -604,8 +711,10 @@ end
|
|||||||
|
|
||||||
FBHealBox_RegisterHook("Loaded", function()
|
FBHealBox_RegisterHook("Loaded", function()
|
||||||
DEFAULT_CHAT_FRAME:AddMessage("|cFFFFFF00"..FBADDON_NAME..":|r "..FBT("DMG_LOADED"));
|
DEFAULT_CHAT_FRAME:AddMessage("|cFFFFFF00"..FBADDON_NAME..":|r "..FBT("DMG_LOADED"));
|
||||||
|
FBDmg_UpdateActive();
|
||||||
return true;
|
return true;
|
||||||
end);
|
end);
|
||||||
|
FBHealBox_RegisterHook("Suppress", function() FBDmg_UpdateActive(); return true; end);
|
||||||
FBHealBox_RegisterHook("Defaults", function() return FBDmg_ApplyDefaults(); end);
|
FBHealBox_RegisterHook("Defaults", function() return FBDmg_ApplyDefaults(); end);
|
||||||
FBHealBox_RegisterHook("SyncOptions", function() return FBDmg_SyncOptions(); end);
|
FBHealBox_RegisterHook("SyncOptions", function() return FBDmg_SyncOptions(); end);
|
||||||
FBHealBox_RegisterHook("ApplyLocale", function() return FBDmg_ApplyLocale(); end);
|
FBHealBox_RegisterHook("ApplyLocale", function() return FBDmg_ApplyLocale(); end);
|
||||||
@@ -620,7 +729,7 @@ FBHealBox_RegisterHook("Slash", function(msg)
|
|||||||
if (msg == "damage" or msg == "dmg") then
|
if (msg == "damage" or msg == "dmg") then
|
||||||
local cfg = FBDmg_Cfg();
|
local cfg = FBDmg_Cfg();
|
||||||
if (cfg.Enabled == 1) then cfg.Enabled = 0; else cfg.Enabled = 1; end
|
if (cfg.Enabled == 1) then cfg.Enabled = 0; else cfg.Enabled = 1; end
|
||||||
FBDmg_SyncOptions();
|
FBDmg_SyncOptions(); -- schaltet auch die Ereignisse um
|
||||||
local key = "DMG_OFF";
|
local key = "DMG_OFF";
|
||||||
if (cfg.Enabled == 1) then key = "DMG_ON"; end
|
if (cfg.Enabled == 1) then key = "DMG_ON"; end
|
||||||
DEFAULT_CHAT_FRAME:AddMessage("|cFFFFFF00"..FBADDON_NAME..":|r "..FBT(key));
|
DEFAULT_CHAT_FRAME:AddMessage("|cFFFFFF00"..FBADDON_NAME..":|r "..FBT(key));
|
||||||
|
|||||||
+230
-250
@@ -284,12 +284,18 @@ FBLocale["deDE"].RAID_LOADED = "Raidmodus-Modul geladen: Reiter |cFFFFFFFF
|
|||||||
FBRaidCells = {}; -- [g][pos] = Zelle
|
FBRaidCells = {}; -- [g][pos] = Zelle
|
||||||
FBRaidGroups = {}; -- [g] = Gruppenblock-Frame
|
FBRaidGroups = {}; -- [g] = Gruppenblock-Frame
|
||||||
FBRaidUnitCell = {}; -- ["raid12"] = Zelle (nach jedem Roster-Update neu)
|
FBRaidUnitCell = {}; -- ["raid12"] = Zelle (nach jedem Roster-Update neu)
|
||||||
|
-- Flache Listen statt der doppelten Schleife ueber Gruppen und Plaetze, die
|
||||||
|
-- bis 1.4.6 rund zehnmal im Modul stand:
|
||||||
|
FBRaidAllCells = {}; -- jede je erzeugte Zelle (Aufraeumen, Buttons)
|
||||||
|
FBRaidActiveCells = {}; -- belegte Zellen der aktuellen Anzeige
|
||||||
|
FBRaidNameCell = {}; -- [Name] = Zelle (fuer den Hook "RefreshNames")
|
||||||
FBRaidMembers = 0; -- Anzahl Mitglieder in der aktuellen Anzeige
|
FBRaidMembers = 0; -- Anzahl Mitglieder in der aktuellen Anzeige
|
||||||
FBRaidUsedGroups = 0; -- Anzahl belegter Gruppen
|
FBRaidUsedGroups = 0; -- Anzahl belegter Gruppen
|
||||||
FBRaidTestMode = 0; -- 0 | 20 | 40
|
FBRaidTestMode = 0; -- 0 | 20 | 40
|
||||||
FBRaidTestGhosts = {}; -- [i] = Geist-Datensatz (Testmodus)
|
FBRaidTestGhosts = {}; -- [i] = Geist-Datensatz (Testmodus)
|
||||||
FBRaidTickAccum = 0;
|
FBRaidTickAccum = 0;
|
||||||
FBRaidDragging = false;
|
FBRaidDragging = false;
|
||||||
|
FBRaidAppliedScale = nil; -- zuletzt gesetzte Skalierung (FBRaid_LayoutAll)
|
||||||
|
|
||||||
function FBRaid_Cfg()
|
function FBRaid_Cfg()
|
||||||
if (not HealBox.Raid) then FBRaid_ApplyDefaults(); end
|
if (not HealBox.Raid) then FBRaid_ApplyDefaults(); end
|
||||||
@@ -380,12 +386,6 @@ function FBRaid_BuildTestGhosts(count)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function FBRaid_InRaid()
|
|
||||||
local n = GetNumRaidMembers();
|
|
||||||
return (n and n > 0);
|
|
||||||
end
|
|
||||||
|
|
||||||
-- true, wenn das Raster ueberhaupt gezeigt werden soll
|
|
||||||
-- true, wenn das Raster ueberhaupt gezeigt werden soll: Raidmodus an,
|
-- true, wenn das Raster ueberhaupt gezeigt werden soll: Raidmodus an,
|
||||||
-- Anzeige an, und entweder Raid-Test oder ein Raid mit mindestens
|
-- Anzeige an, und entweder Raid-Test oder ein Raid mit mindestens
|
||||||
-- MinPlayers Mitgliedern
|
-- MinPlayers Mitgliedern
|
||||||
@@ -664,7 +664,12 @@ function FBRaid_CreateCell(g, pos)
|
|||||||
if (FBDragSpell) then
|
if (FBDragSpell) then
|
||||||
local side = "L";
|
local side = "L";
|
||||||
if (arg1 == "RightButton" or IsShiftKeyDown()) then side = "R"; end
|
if (arg1 == "RightButton" or IsShiftKeyDown()) then side = "R"; end
|
||||||
if (FBHealBox_DropSpell(i, side)) then return; end
|
-- Nicht die Schleifenvariable i verwenden: Lua 5.0 (Client
|
||||||
|
-- 1.12) teilt sie zwischen allen hier erzeugten Closures, alle
|
||||||
|
-- vier Buttons saehen ihren Endwert und legten den Zauber
|
||||||
|
-- auf Button 4. b ist dagegen je Durchlauf eine neue lokale
|
||||||
|
-- Variable.
|
||||||
|
if (FBHealBox_DropSpell(b.btnIndex, side)) then return; end
|
||||||
end
|
end
|
||||||
if (FBRaidTestMode > 0) then
|
if (FBRaidTestMode > 0) then
|
||||||
DEFAULT_CHAT_FRAME:AddMessage("|cFFFFFF00"..FBADDON_NAME..":|r "..FBT("RAID_TEST_CLICK"));
|
DEFAULT_CHAT_FRAME:AddMessage("|cFFFFFF00"..FBADDON_NAME..":|r "..FBT("RAID_TEST_CLICK"));
|
||||||
@@ -687,7 +692,11 @@ end
|
|||||||
|
|
||||||
function FBRaid_GetCell(g, pos)
|
function FBRaid_GetCell(g, pos)
|
||||||
if (not FBRaidCells[g]) then FBRaidCells[g] = {}; end
|
if (not FBRaidCells[g]) then FBRaidCells[g] = {}; end
|
||||||
if (not FBRaidCells[g][pos]) then FBRaidCells[g][pos] = FBRaid_CreateCell(g, pos); end
|
if (not FBRaidCells[g][pos]) then
|
||||||
|
local c = FBRaid_CreateCell(g, pos);
|
||||||
|
FBRaidCells[g][pos] = c;
|
||||||
|
table.insert(FBRaidAllCells, c);
|
||||||
|
end
|
||||||
return FBRaidCells[g][pos];
|
return FBRaidCells[g][pos];
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -735,21 +744,25 @@ function FBRaid_UpdateRoster()
|
|||||||
FBRaidRosterDirty = false;
|
FBRaidRosterDirty = false;
|
||||||
local cfg = FBRaid_Cfg();
|
local cfg = FBRaid_Cfg();
|
||||||
FBRaidUnitCell = {};
|
FBRaidUnitCell = {};
|
||||||
|
FBRaidActiveCells = {};
|
||||||
|
FBRaidNameCell = {};
|
||||||
FBRaidMembers = 0;
|
FBRaidMembers = 0;
|
||||||
local perGroup = {};
|
local perGroup = {};
|
||||||
for g = 1, FBRAID_GROUPS do perGroup[g] = 0; end
|
for g = 1, FBRAID_GROUPS do perGroup[g] = 0; end
|
||||||
|
|
||||||
-- alle Zellen zuruecksetzen
|
-- alle Zellen zuruecksetzen
|
||||||
for g = 1, FBRAID_GROUPS do
|
for _, c in ipairs(FBRaidAllCells) do
|
||||||
for pos = 1, FBRAID_PER_GROUP do
|
c.unit = nil; c.name = nil; c.ghost = nil; c.index = nil;
|
||||||
if (FBRaidCells[g] and FBRaidCells[g][pos]) then
|
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;
|
||||||
local c = FBRaidCells[g][pos];
|
c.vHp = nil; c.vShield = nil; c.vInc = nil; c.vMp = nil;
|
||||||
c.unit = nil; c.name = nil; c.ghost = nil; c.index = nil;
|
-- Rahmenzustand gehoert dem alten Bewohner. Ohne Reset behielt eine
|
||||||
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;
|
-- wiederverwendete Zelle den roten Angriffsrahmen, und FBRaid_CheckAggro
|
||||||
c.vHp = nil; c.vShield = nil; c.vInc = nil; c.vMp = nil;
|
-- sah sie als inaktive Zelle nie wieder an.
|
||||||
c:Hide();
|
if (c.underAttack or c.buffMissing) then
|
||||||
end
|
c.underAttack = nil; c.buffMissing = nil;
|
||||||
|
FBRaid_ApplyBorder(c);
|
||||||
end
|
end
|
||||||
|
c:Hide();
|
||||||
end
|
end
|
||||||
|
|
||||||
if (FBRaid_IsActive()) then
|
if (FBRaid_IsActive()) then
|
||||||
@@ -768,6 +781,8 @@ function FBRaid_UpdateRoster()
|
|||||||
if (HealBox.ClassColors == 1) then col = FBClassColor(m.class); end
|
if (HealBox.ClassColors == 1) then col = FBClassColor(m.class); end
|
||||||
if (col) then c.NameText:SetTextColor(col.r, col.g, col.b, 1); else c.NameText:SetTextColor(1, 1, 1, 1); end
|
if (col) then c.NameText:SetTextColor(col.r, col.g, col.b, 1); else c.NameText:SetTextColor(1, 1, 1, 1); end
|
||||||
FBRaidUnitCell[m.unit] = c;
|
FBRaidUnitCell[m.unit] = c;
|
||||||
|
table.insert(FBRaidActiveCells, c);
|
||||||
|
if (m.name) then FBRaidNameCell[m.name] = c; end
|
||||||
FBRaidMembers = FBRaidMembers + 1;
|
FBRaidMembers = FBRaidMembers + 1;
|
||||||
c:Show();
|
c:Show();
|
||||||
end
|
end
|
||||||
@@ -784,6 +799,11 @@ function FBRaid_UpdateRoster()
|
|||||||
FBRaid_SyncButtons();
|
FBRaid_SyncButtons();
|
||||||
FBRaid_RefreshAll();
|
FBRaid_RefreshAll();
|
||||||
FBRaid_Tick(true);
|
FBRaid_Tick(true);
|
||||||
|
-- Andere Module (Mana-Ticker) sammeln ihre Zellen neu ein. Bis 1.4.6
|
||||||
|
-- erfuhren sie davon nur ueber "UpdateNames"; baute das Raster nach einem
|
||||||
|
-- reinen RAID_ROSTER_UPDATE um (etwa beim Ueberschreiten der Schwelle),
|
||||||
|
-- fehlte der Funke oder lief auf der Zelle eines anderen Spielers.
|
||||||
|
FBHealBox_RunHook("RaidRoster");
|
||||||
end
|
end
|
||||||
|
|
||||||
-- ==========================================================================
|
-- ==========================================================================
|
||||||
@@ -818,16 +838,28 @@ function FBRaid_ApplyCellSize(c, cfg)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
FBRaidLaidStrip = nil; -- Breite des Streifens fuer die Buff-Icons beim letzten Legen
|
||||||
|
|
||||||
function FBRaid_LayoutAll()
|
function FBRaid_LayoutAll()
|
||||||
local cfg = FBRaid_Cfg();
|
local cfg = FBRaid_Cfg();
|
||||||
local rowW = FBRaid_RowWidth(cfg);
|
local rowW = FBRaid_RowWidth(cfg);
|
||||||
|
FBRaidLaidStrip = FBRaid_BuffStrip(cfg);
|
||||||
local headH = 0;
|
local headH = 0;
|
||||||
if (cfg.Headers == 1) then headH = FBRAID_HEADER_H; end
|
if (cfg.Headers == 1) then headH = FBRAID_HEADER_H; end
|
||||||
local blockH = headH + FBRAID_PER_GROUP * cfg.CellH + (FBRAID_PER_GROUP - 1) * cfg.CellGap;
|
local blockH = headH + FBRAID_PER_GROUP * cfg.CellH + (FBRAID_PER_GROUP - 1) * cfg.CellGap;
|
||||||
local titleH = 0;
|
local titleH = 0;
|
||||||
if (cfg.ShowTitle == 1) then titleH = FBRAID_TITLE_H + 2; FBRaidFrame.Title:Show(); else FBRaidFrame.Title:Hide(); end
|
if (cfg.ShowTitle == 1) then titleH = FBRAID_TITLE_H + 2; FBRaidFrame.Title:Show(); else FBRaidFrame.Title:Hide(); end
|
||||||
|
|
||||||
FBRaidFrame:SetScale(cfg.Scale or 1);
|
-- SetScale wertet die Ankerversaetze im neuen Massstab aus. Ohne erneutes
|
||||||
|
-- Verankern wanderte das Raster beim Ziehen am Regler und sprang erst
|
||||||
|
-- beim naechsten Rosterwechsel zurueck. Nur bei echter Aenderung, und
|
||||||
|
-- nie waehrend das Raster gerade gezogen wird.
|
||||||
|
local scale = cfg.Scale or 1;
|
||||||
|
if (FBRaidAppliedScale ~= scale) then
|
||||||
|
FBRaidAppliedScale = scale;
|
||||||
|
FBRaidFrame:SetScale(scale);
|
||||||
|
if (not FBRaidDragging) then FBRaid_RestorePosition(); end
|
||||||
|
end
|
||||||
|
|
||||||
local perRow = cfg.GroupsPerRow;
|
local perRow = cfg.GroupsPerRow;
|
||||||
if (perRow < 1) then perRow = 1; end
|
if (perRow < 1) then perRow = 1; end
|
||||||
@@ -907,27 +939,10 @@ end
|
|||||||
-- [ Zelleninhalt ]
|
-- [ Zelleninhalt ]
|
||||||
-- ==========================================================================
|
-- ==========================================================================
|
||||||
|
|
||||||
-- Zellenfarbe / Maxima / Text nur bei Aenderung setzen
|
-- Farbe, Werte und Maxima der Balken setzen die Helfer des Kerns
|
||||||
function FBRaid_SetColor(c, key, r, g, b, a)
|
-- (FBHealBox_SetBarColor, FBHealBox_SetBarValues, FBHealBox_SetBarMax): Die
|
||||||
if (c.colorKey == key) then return; end
|
-- Zelle traegt dieselben Felder wie eine Plakette. Bis 1.4.6 standen hier
|
||||||
c.colorKey = key;
|
-- Kopien davon. Nur der HP-Text ist eigen, er kann ganz verschwinden.
|
||||||
c.HealthBar:SetStatusBarColor(r, g, b, a);
|
|
||||||
end
|
|
||||||
|
|
||||||
function FBRaid_SetValues(c, hp, shieldTop, incTop)
|
|
||||||
if (c.vHp ~= hp) then c.vHp = hp; c.HealthBar:SetValue(hp); end
|
|
||||||
if (c.vShield ~= shieldTop) then c.vShield = shieldTop; c.ShieldBar:SetValue(shieldTop); end
|
|
||||||
if (c.vInc ~= incTop) then c.vInc = incTop; c.IncHealBar:SetValue(incTop); end
|
|
||||||
end
|
|
||||||
|
|
||||||
function FBRaid_SetMax(c, hpMax)
|
|
||||||
if (c.lastMax == hpMax) then return; end
|
|
||||||
c.lastMax = hpMax;
|
|
||||||
c.HealthBar:SetMinMaxValues(0, hpMax);
|
|
||||||
c.ShieldBar:SetMinMaxValues(0, hpMax);
|
|
||||||
c.IncHealBar:SetMinMaxValues(0, hpMax);
|
|
||||||
end
|
|
||||||
|
|
||||||
function FBRaid_SetText(c, text)
|
function FBRaid_SetText(c, text)
|
||||||
if (c.lastText == text) then return; end
|
if (c.lastText == text) then return; end
|
||||||
c.lastText = text;
|
c.lastText = text;
|
||||||
@@ -948,21 +963,21 @@ function FBRaid_UpdateCell(c, auraChanged)
|
|||||||
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
|
c.lastPct = nil; c.lastDef = nil; -- Zahlenspeicher gilt nicht mehr
|
||||||
FBRaid_SetMax(c, hpMax);
|
FBHealBox_SetBarMax(c, hpMax);
|
||||||
FBRaid_SetValues(c, 0, 0, 0);
|
FBHealBox_SetBarValues(c, 0, 0, 0);
|
||||||
FBRaid_SetColor(c, "state", 0.5, 0.5, 0.5, 1);
|
FBHealBox_SetBarColor(c, "state", 0.5, 0.5, 0.5, 1);
|
||||||
if (c.manaShown ~= false) then c.manaShown = false; c.ManaBar:Hide(); end
|
if (c.manaShown ~= false) then c.manaShown = false; c.ManaBar:Hide(); end
|
||||||
return;
|
return;
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Leben und Schichten
|
-- Leben und Schichten
|
||||||
FBRaid_SetMax(c, hpMax);
|
FBHealBox_SetBarMax(c, hpMax);
|
||||||
local inc, shield = FBRaid_Incoming(c);
|
local inc, shield = FBRaid_Incoming(c);
|
||||||
local shieldTop = hp + shield;
|
local shieldTop = hp + shield;
|
||||||
if (shieldTop > hpMax) then shieldTop = hpMax; end
|
if (shieldTop > hpMax) then shieldTop = hpMax; end
|
||||||
local incTop = shieldTop + inc;
|
local incTop = shieldTop + inc;
|
||||||
if (incTop > hpMax) then incTop = hpMax; end
|
if (incTop > hpMax) then incTop = hpMax; end
|
||||||
FBRaid_SetValues(c, hp, shieldTop, incTop);
|
FBHealBox_SetBarValues(c, hp, shieldTop, incTop);
|
||||||
|
|
||||||
-- HP-Text. Verglichen wird die Zahl, nicht der fertige Text: sonst baut
|
-- HP-Text. Verglichen wird die Zahl, nicht der fertige Text: sonst baut
|
||||||
-- jedes UNIT_HEALTH einen String, der meist sofort wieder verworfen wird.
|
-- jedes UNIT_HEALTH einen String, der meist sofort wieder verworfen wird.
|
||||||
@@ -984,15 +999,7 @@ function FBRaid_UpdateCell(c, auraChanged)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Mana
|
-- Mana
|
||||||
local mp, mpMax, hasMana, ptype = FBRaid_Mana(c);
|
FBRaid_UpdateCellMana(c, cfg);
|
||||||
if (cfg.ManaBar == 1 and hasMana and mpMax > 0) then
|
|
||||||
FBHealBox_SetPowerColor(c.ManaBar, c, ptype);
|
|
||||||
if (c.lastMpMax ~= mpMax) then c.lastMpMax = mpMax; c.ManaBar:SetMinMaxValues(0, mpMax); end
|
|
||||||
if (c.vMp ~= mp) then c.vMp = mp; c.ManaBar:SetValue(mp); end
|
|
||||||
if (c.manaShown ~= true) then c.manaShown = true; c.ManaBar:Show(); end
|
|
||||||
elseif (c.manaShown ~= false) then
|
|
||||||
c.manaShown = false; c.ManaBar:Hide();
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Farbe: Dispel schlaegt HP-Stand (Debuff nur bei Aura-Aenderung neu suchen)
|
-- Farbe: Dispel schlaegt HP-Stand (Debuff nur bei Aura-Aenderung neu suchen)
|
||||||
if (auraChanged or (not c.dispelKnown) or c.ghost) then
|
if (auraChanged or (not c.dispelKnown) or c.ghost) then
|
||||||
@@ -1003,16 +1010,39 @@ function FBRaid_UpdateCell(c, auraChanged)
|
|||||||
local dtype = c.dispelType;
|
local dtype = c.dispelType;
|
||||||
if (dtype and FBDispelColors[dtype]) then
|
if (dtype and FBDispelColors[dtype]) then
|
||||||
local col = FBDispelColors[dtype];
|
local col = FBDispelColors[dtype];
|
||||||
FBRaid_SetColor(c, dtype, col[1], col[2], col[3], col[4]);
|
FBHealBox_SetBarColor(c, dtype, col[1], col[2], col[3], col[4]);
|
||||||
elseif (frac > LowHP) then
|
elseif (frac > FBLowHP) then
|
||||||
FBRaid_SetColor(c, "green", 0, 1, 0, 1);
|
FBHealBox_SetBarColor(c, "green", 0, 1, 0, 1);
|
||||||
elseif (frac > VeryLowHP) then
|
elseif (frac > FBVeryLowHP) then
|
||||||
FBRaid_SetColor(c, "yellow", 1, 0.9, 0, 1);
|
FBHealBox_SetBarColor(c, "yellow", 1, 0.9, 0, 1);
|
||||||
else
|
else
|
||||||
FBRaid_SetColor(c, "red", 1, 0, 0, 1);
|
FBHealBox_SetBarColor(c, "red", 1, 0, 0, 1);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Manastreifen einer Zelle. Eigener Weg fuer UNIT_MANA: Das feuert im Raid
|
||||||
|
-- fuer jeden Manabenutzer alle zwei Sekunden, bis 1.4.6 rechnete jedes davon
|
||||||
|
-- die ganze Zelle neu (Leben, Vorhersage, Schild, Farbe, Text).
|
||||||
|
function FBRaid_UpdateCellMana(c, cfg)
|
||||||
|
local mp, mpMax, hasMana, ptype = FBRaid_Mana(c);
|
||||||
|
if (cfg.ManaBar == 1 and hasMana and mpMax > 0) then
|
||||||
|
FBHealBox_SetPowerColor(c.ManaBar, c, ptype);
|
||||||
|
if (c.lastMpMax ~= mpMax) then c.lastMpMax = mpMax; c.ManaBar:SetMinMaxValues(0, mpMax); end
|
||||||
|
if (c.vMp ~= mp) then c.vMp = mp; c.ManaBar:SetValue(mp); end
|
||||||
|
if (c.manaShown ~= true) then c.manaShown = true; c.ManaBar:Show(); end
|
||||||
|
elseif (c.manaShown ~= false) then
|
||||||
|
c.manaShown = false; c.ManaBar:Hide();
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Schmaler Pfad: nur das Mana, und nur bei lebenden, verbundenen Einheiten
|
||||||
|
-- (Tot, Geist, offline blendet FBRaid_UpdateCell den Streifen aus)
|
||||||
|
function FBRaid_UpdateCellManaOnly(c)
|
||||||
|
if (not c) or (not c.unit) or (not c:IsShown()) then return; end
|
||||||
|
if (FBRaid_State(c)) then return; end
|
||||||
|
FBRaid_UpdateCellMana(c, FBRaid_Cfg());
|
||||||
|
end
|
||||||
|
|
||||||
-- Rahmen: Angegriffener (rot) vor Buff-Wache (orange) vor normal
|
-- Rahmen: Angegriffener (rot) vor Buff-Wache (orange) vor normal
|
||||||
function FBRaid_ApplyBorder(c)
|
function FBRaid_ApplyBorder(c)
|
||||||
local col = FBBUFF_NORMAL_COLOR;
|
local col = FBBUFF_NORMAL_COLOR;
|
||||||
@@ -1037,24 +1067,17 @@ end
|
|||||||
function FBRaid_CheckAggro(tt)
|
function FBRaid_CheckAggro(tt)
|
||||||
if (not FBRaid_IsActive()) then return false; end
|
if (not FBRaid_IsActive()) then return false; end
|
||||||
local any = false;
|
local any = false;
|
||||||
for g = 1, FBRAID_GROUPS do
|
for _, c in ipairs(FBRaidActiveCells) do
|
||||||
if (FBRaidCells[g]) then
|
local flag = false;
|
||||||
for pos = 1, FBRAID_PER_GROUP do
|
if (HealBox.AggroMark == 1 and c:IsShown()) then
|
||||||
local c = FBRaidCells[g][pos];
|
if (c.ghost) then flag = (c.ghost.aggro == true);
|
||||||
if (c and c.unit) then
|
elseif (tt) then flag = FBHealBox_UnitIsAggroFast(c.unit, c.name, tt); end
|
||||||
local flag = false;
|
|
||||||
if (HealBox.AggroMark == 1 and c:IsShown()) then
|
|
||||||
if (c.ghost) then flag = (c.ghost.aggro == true);
|
|
||||||
elseif (tt) then flag = FBHealBox_UnitIsAggroFast(c.unit, c.name, tt); end
|
|
||||||
end
|
|
||||||
if (c.underAttack ~= flag) then
|
|
||||||
c.underAttack = flag;
|
|
||||||
FBRaid_ApplyBorder(c);
|
|
||||||
end
|
|
||||||
if (flag) then any = true; end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
if (c.underAttack ~= flag) then
|
||||||
|
c.underAttack = flag;
|
||||||
|
FBRaid_ApplyBorder(c);
|
||||||
|
end
|
||||||
|
if (flag) then any = true; end
|
||||||
end
|
end
|
||||||
return any;
|
return any;
|
||||||
end
|
end
|
||||||
@@ -1069,18 +1092,11 @@ end
|
|||||||
function FBRaid_UpdateBuffIcons()
|
function FBRaid_UpdateBuffIcons()
|
||||||
if (not FBRaid_IsActive()) then return; end
|
if (not FBRaid_IsActive()) then return; end
|
||||||
local on = (FBRaid_Cfg().BuffIcons == 1);
|
local on = (FBRaid_Cfg().BuffIcons == 1);
|
||||||
for g = 1, FBRAID_GROUPS do
|
for _, c in ipairs(FBRaidAllCells) do
|
||||||
if (FBRaidCells[g]) then
|
if (on and c.unit and c:IsShown()) then
|
||||||
for pos = 1, FBRAID_PER_GROUP do
|
FBHealBox_UpdateBuffIcons(c, c.name, c.ghost, FBRAID_BUFFICON_SIZE, FBRAID_BUFFICON_ROWS, FBRAID_BUFFICON_MAX);
|
||||||
local c = FBRaidCells[g][pos];
|
else
|
||||||
if (c) then
|
FBHealBox_UpdateBuffIcons(c, nil, nil, FBRAID_BUFFICON_SIZE, FBRAID_BUFFICON_ROWS, FBRAID_BUFFICON_MAX);
|
||||||
if (on and c.unit and c:IsShown()) then
|
|
||||||
FBHealBox_UpdateBuffIcons(c, c.name, c.ghost, FBRAID_BUFFICON_SIZE, FBRAID_BUFFICON_ROWS, FBRAID_BUFFICON_MAX);
|
|
||||||
else
|
|
||||||
FBHealBox_UpdateBuffIcons(c, nil, nil, FBRAID_BUFFICON_SIZE, FBRAID_BUFFICON_ROWS, FBRAID_BUFFICON_MAX);
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1088,28 +1104,25 @@ end
|
|||||||
-- HoT-/Schild-Timer auf den Mini-Buttons (Hook "SpellTimers")
|
-- HoT-/Schild-Timer auf den Mini-Buttons (Hook "SpellTimers")
|
||||||
function FBRaid_UpdateSpellTimers(now)
|
function FBRaid_UpdateSpellTimers(now)
|
||||||
local on = (HealBox.SpellTimers == 1) and FBRaid_IsActive();
|
local on = (HealBox.SpellTimers == 1) and FBRaid_IsActive();
|
||||||
for g = 1, FBRAID_GROUPS do
|
for _, c in ipairs(FBRaidAllCells) do
|
||||||
if (FBRaidCells[g]) then
|
local shown = on and c.unit and c:IsShown() and (c.ghost or FBHoTs[c.name] or FBShields[c.name]
|
||||||
for pos = 1, FBRAID_PER_GROUP do
|
or (FBWeakenedSoul and FBWeakenedSoul[c.name]));
|
||||||
local c = FBRaidCells[g][pos];
|
-- Nichts anzuzeigen und nichts mehr wegzuraeumen: Zelle
|
||||||
if (c) then
|
-- ueberspringen. Vorher lief die Buttonschleife auch dann
|
||||||
-- ohne verfolgten HoT/Schild auf der Einheit nur einmal ausblenden
|
-- durch, im Vierzigerraid 160 Leeraufrufe fuenfmal je
|
||||||
local shown = on and c.unit and c:IsShown() and (c.ghost or FBHoTs[c.name] or FBShields[c.name]);
|
-- Sekunde. Der Kern macht es bei den Plaketten genauso.
|
||||||
if (not shown and not c.timersShown) then shown = nil; end
|
if (shown or c.timersShown) then
|
||||||
c.timersShown = shown and true or false;
|
c.timersShown = (shown and true) or false;
|
||||||
if (shown == nil) then shown = false; end
|
for i = 1, FBRAID_MAX_BUTTONS do
|
||||||
for i = 1, FBRAID_MAX_BUTTONS do
|
local b = c.buttons[i];
|
||||||
local b = c.buttons[i];
|
if (shown and b:IsShown()) then
|
||||||
if (shown and b:IsShown()) then
|
local text, color = FBHealBox_SpellTimerFor(b.spellBase, c.name, now, c.ghost, i);
|
||||||
local text, color = FBHealBox_SpellTimerFor(b.spellBase, c.name, now, c.ghost, i);
|
if (not text and b.spellBaseR) then
|
||||||
if (not text and b.spellBaseR) then
|
text, color = FBHealBox_SpellTimerFor(b.spellBaseR, c.name, now, nil, i);
|
||||||
text, color = FBHealBox_SpellTimerFor(b.spellBaseR, c.name, now, nil, i);
|
|
||||||
end
|
|
||||||
FBHealBox_SetButtonTimer(b, text, color);
|
|
||||||
else
|
|
||||||
FBHealBox_SetButtonTimer(b, nil);
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
FBHealBox_SetButtonTimer(b, text, color);
|
||||||
|
else
|
||||||
|
FBHealBox_SetButtonTimer(b, nil);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1117,101 +1130,74 @@ function FBRaid_UpdateSpellTimers(now)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function FBRaid_UpdateCooldowns()
|
function FBRaid_UpdateCooldowns()
|
||||||
for g = 1, FBRAID_GROUPS do
|
for _, c in ipairs(FBRaidAllCells) do
|
||||||
if (FBRaidCells[g]) then
|
for i = 1, FBRAID_MAX_BUTTONS do
|
||||||
for pos = 1, FBRAID_PER_GROUP do
|
local b = c.buttons[i];
|
||||||
local c = FBRaidCells[g][pos];
|
b.cdStart = nil;
|
||||||
if (c) then
|
FBHealBox_UpdateButtonState(b, "SPELL_UPDATE_COOLDOWN");
|
||||||
for i = 1, FBRAID_MAX_BUTTONS do
|
|
||||||
local b = c.buttons[i];
|
|
||||||
b.cdKey = nil;
|
|
||||||
FBHealBox_UpdateButtonState(b, "SPELL_UPDATE_COOLDOWN");
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Button-Zustaende der sichtbaren Zellen (Hook "ButtonStates")
|
-- Button-Zustaende der sichtbaren Zellen (Hook "ButtonStates"). Laeuft
|
||||||
|
-- geschuetzt wie der Durchlauf des Kerns, siehe FBHealBox_UpdateButtonStates.
|
||||||
|
function FBRaid_ButtonStates(event)
|
||||||
|
local ok, err = pcall(FBRaid_UpdateButtonStates, event);
|
||||||
|
FBHealBox_SweepResult("FBRaid_UpdateButtonStates", ok, err);
|
||||||
|
end
|
||||||
|
|
||||||
function FBRaid_UpdateButtonStates(event)
|
function FBRaid_UpdateButtonStates(event)
|
||||||
if (not FBRaid_IsActive()) then return; end
|
if (not FBRaid_IsActive()) then return; end
|
||||||
local nBtn = FBRaid_Cfg().Buttons or 0;
|
local nBtn = FBRaid_Cfg().Buttons or 0;
|
||||||
for g = 1, FBRAID_GROUPS do
|
for _, c in ipairs(FBRaidActiveCells) do
|
||||||
if (FBRaidCells[g]) then
|
if (c:IsShown()) then
|
||||||
for pos = 1, FBRAID_PER_GROUP do
|
for i = 1, nBtn do FBHealBox_UpdateButtonState(c.buttons[i], event); end
|
||||||
local c = FBRaidCells[g][pos];
|
|
||||||
if (c and c.unit and c:IsShown()) then
|
|
||||||
for i = 1, nBtn do FBHealBox_UpdateButtonState(c.buttons[i], event); end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function FBRaid_RefreshAll()
|
function FBRaid_RefreshAll()
|
||||||
if (not FBRaid_IsActive()) then return; end
|
if (not FBRaid_IsActive()) then return; end
|
||||||
for g = 1, FBRAID_GROUPS do
|
for _, c in ipairs(FBRaidActiveCells) do FBRaid_UpdateCell(c); end
|
||||||
if (FBRaidCells[g]) then
|
|
||||||
for pos = 1, FBRAID_PER_GROUP do
|
|
||||||
local c = FBRaidCells[g][pos];
|
|
||||||
if (c and c.unit) then FBRaid_UpdateCell(c); end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function FBRaid_RefreshBuffBorders()
|
function FBRaid_RefreshBuffBorders()
|
||||||
for g = 1, FBRAID_GROUPS do
|
for _, c in ipairs(FBRaidActiveCells) do FBRaid_UpdateBuffBorder(c); end
|
||||||
if (FBRaidCells[g]) then
|
|
||||||
for pos = 1, FBRAID_PER_GROUP do
|
|
||||||
local c = FBRaidCells[g][pos];
|
|
||||||
if (c and c.unit) then FBRaid_UpdateBuffBorder(c); end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Buttons einer Zelle an die Belegung angleichen (Icons, Zauber, Rechtsklick)
|
-- Buttons einer Zelle an die Belegung angleichen (Icons, Zauber, Rechtsklick)
|
||||||
function FBRaid_SyncButtons()
|
function FBRaid_SyncButtons()
|
||||||
local rightOn = (HealBox.RightClick == 1);
|
local rightOn = (HealBox.RightClick == 1);
|
||||||
for g = 1, FBRAID_GROUPS do
|
for _, c in ipairs(FBRaidAllCells) do
|
||||||
if (FBRaidCells[g]) then
|
for i = 1, FBRAID_MAX_BUTTONS do
|
||||||
for pos = 1, FBRAID_PER_GROUP do
|
local b = c.buttons[i];
|
||||||
local c = FBRaidCells[g][pos];
|
b.TargetUnit = c.unit;
|
||||||
if (c) then
|
b.spellName = FBDropDownButton[i];
|
||||||
for i = 1, FBRAID_MAX_BUTTONS do
|
b.id = FBActiveSpellIDs[i];
|
||||||
local b = c.buttons[i];
|
if (FBDropDownButtonIcon[i]) then
|
||||||
b.TargetUnit = c.unit;
|
b.icon:SetTexture(FBDropDownButtonIcon[i]);
|
||||||
b.spellName = FBDropDownButton[i];
|
else
|
||||||
b.id = FBActiveSpellIDs[i];
|
b.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark");
|
||||||
if (FBDropDownButtonIcon[i]) then
|
end
|
||||||
b.icon:SetTexture(FBDropDownButtonIcon[i]);
|
if (rightOn) then
|
||||||
else
|
b.spellNameR = FBDropDownButtonR[i];
|
||||||
b.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark");
|
b.idR = FBActiveSpellIDsR[i];
|
||||||
end
|
else
|
||||||
if (rightOn) then
|
b.spellNameR = nil;
|
||||||
b.spellNameR = FBDropDownButtonR[i];
|
b.idR = nil;
|
||||||
b.idR = FBActiveSpellIDsR[i];
|
end
|
||||||
else
|
if (b.subIcon) then
|
||||||
b.spellNameR = nil;
|
if (b.spellNameR and FBDropDownButtonIconR[i]) then
|
||||||
b.idR = nil;
|
b.subIcon:SetTexture(FBDropDownButtonIconR[i]);
|
||||||
end
|
b.subIcon:Show();
|
||||||
if (b.subIcon) then
|
else
|
||||||
if (b.spellNameR and FBDropDownButtonIconR[i]) then
|
b.subIcon:Hide();
|
||||||
b.subIcon:SetTexture(FBDropDownButtonIconR[i]);
|
|
||||||
b.subIcon:Show();
|
|
||||||
else
|
|
||||||
b.subIcon:Hide();
|
|
||||||
end
|
|
||||||
end
|
|
||||||
b.cdKey = nil;
|
|
||||||
b.colorState = nil;
|
|
||||||
if (b.spellName) then b.spellBase = FBPredict_SplitCast(b.spellName); else b.spellBase = nil; end
|
|
||||||
if (b.spellNameR) then b.spellBaseR = FBPredict_SplitCast(b.spellNameR); else b.spellBaseR = nil; end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
b.cdStart = nil;
|
||||||
|
b.colorState = nil;
|
||||||
|
if (b.spellName) then b.spellBase = FBPredict_SplitCast(b.spellName); else b.spellBase = nil; end
|
||||||
|
if (b.spellNameR) then b.spellBaseR = FBPredict_SplitCast(b.spellNameR); else b.spellBaseR = nil; end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1224,6 +1210,9 @@ end
|
|||||||
-- Die Taktdauer ist entsprechend kuerzer, der volle Durchlauf dauert also
|
-- Die Taktdauer ist entsprechend kuerzer, der volle Durchlauf dauert also
|
||||||
-- weiterhin FBRAID_TICK Sekunden. force = true macht alles auf einmal.
|
-- weiterhin FBRAID_TICK Sekunden. force = true macht alles auf einmal.
|
||||||
FBRaidTickSlice = 0;
|
FBRaidTickSlice = 0;
|
||||||
|
-- Fehlerzaehler je Scheibe: Ein Fehler, der nur in einer Scheibe steckt,
|
||||||
|
-- wuerde sonst von den gelingenden anderen immer wieder zurueckgesetzt.
|
||||||
|
FBRaidSweepKey = {};
|
||||||
|
|
||||||
-- Der Durchlauf laeuft geschuetzt, aber nur einmal je Tick statt einmal je
|
-- Der Durchlauf laeuft geschuetzt, aber nur einmal je Tick statt einmal je
|
||||||
-- Zelle: im Vierzigerraid ein pcall alle 0,125 Sekunden statt achtzig je
|
-- Zelle: im Vierzigerraid ein pcall alle 0,125 Sekunden statt achtzig je
|
||||||
@@ -1233,30 +1222,26 @@ function FBRaid_Tick(force)
|
|||||||
if (not FBRaid_IsActive()) then return; end
|
if (not FBRaid_IsActive()) then return; end
|
||||||
local slice = FBRaidTickSlice;
|
local slice = FBRaidTickSlice;
|
||||||
FBRaidTickSlice = math.mod(FBRaidTickSlice + 1, FBRAID_TICK_SLICES);
|
FBRaidTickSlice = math.mod(FBRaidTickSlice + 1, FBRAID_TICK_SLICES);
|
||||||
if (not pcall(FBRaid_TickSweep, slice, force)) then
|
local ok, err = pcall(FBRaid_TickSweep, slice, force);
|
||||||
if (FBHealBox_ApiFailed) then FBHealBox_ApiFailed(); end
|
local key = FBRaidSweepKey[slice];
|
||||||
end
|
if (not key) then key = "FBRaid_TickSweep "..slice; FBRaidSweepKey[slice] = key; end
|
||||||
|
FBHealBox_SweepResult(key, ok, err);
|
||||||
end
|
end
|
||||||
|
|
||||||
function FBRaid_TickSweep(slice, force)
|
function FBRaid_TickSweep(slice, force)
|
||||||
for g = 1, FBRAID_GROUPS do
|
for _, c in ipairs(FBRaidActiveCells) do
|
||||||
if (FBRaidCells[g]) and (force or (math.mod(g - 1, FBRAID_TICK_SLICES) == slice)) then
|
if (force or (math.mod(c.group - 1, FBRAID_TICK_SLICES) == slice)) and c:IsShown() then
|
||||||
for pos = 1, FBRAID_PER_GROUP do
|
local faded = false;
|
||||||
local c = FBRaidCells[g][pos];
|
if (HealBox.RangeFade == 1) then faded = (not FBRaid_InRange(c)); end
|
||||||
if (c and c.unit and c:IsShown()) then
|
if (force or c.rangeFaded ~= faded) then
|
||||||
local faded = false;
|
c.rangeFaded = faded;
|
||||||
if (HealBox.RangeFade == 1) then faded = (not FBRaid_InRange(c)); end
|
if (faded) then c:SetAlpha(FBRANGE_ALPHA); else c:SetAlpha(1); end
|
||||||
if (force or c.rangeFaded ~= faded) then
|
end
|
||||||
c.rangeFaded = faded;
|
local blocked = false;
|
||||||
if (faded) then c:SetAlpha(FBRANGE_ALPHA); else c:SetAlpha(1); end
|
if (HealBox.LOSIcon == 1) then blocked = FBRaid_LOSBlocked(c); end
|
||||||
end
|
if (force or c.losBlocked ~= blocked) then
|
||||||
local blocked = false;
|
c.losBlocked = blocked;
|
||||||
if (HealBox.LOSIcon == 1) then blocked = FBRaid_LOSBlocked(c); end
|
if (blocked) then c.LOSIcon:Show(); else c.LOSIcon:Hide(); end
|
||||||
if (force or c.losBlocked ~= blocked) then
|
|
||||||
c.losBlocked = blocked;
|
|
||||||
if (blocked) then c.LOSIcon:Show(); else c.LOSIcon:Hide(); end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1276,6 +1261,8 @@ FBRaidEventFrame:RegisterEvent("UNIT_MANA");
|
|||||||
FBRaidEventFrame:RegisterEvent("UNIT_MAXMANA");
|
FBRaidEventFrame:RegisterEvent("UNIT_MAXMANA");
|
||||||
FBRaidEventFrame:RegisterEvent("UNIT_DISPLAYPOWER");
|
FBRaidEventFrame:RegisterEvent("UNIT_DISPLAYPOWER");
|
||||||
FBRaidEventFrame:RegisterEvent("UNIT_AURA");
|
FBRaidEventFrame:RegisterEvent("UNIT_AURA");
|
||||||
|
-- Wut, Energie und Fokus (nur mit "Wut, Energie, Fokus zeigen" ausgewertet)
|
||||||
|
for ev in pairs(FBPowerEvents) do FBRaidEventFrame:RegisterEvent(ev); end
|
||||||
|
|
||||||
FBRaidRosterDirty = false;
|
FBRaidRosterDirty = false;
|
||||||
|
|
||||||
@@ -1288,8 +1275,14 @@ FBRaidEventFrame:SetScript("OnEvent", function()
|
|||||||
return;
|
return;
|
||||||
end
|
end
|
||||||
if (FBRaidTestMode > 0) then return; end
|
if (FBRaidTestMode > 0) then return; end
|
||||||
|
if (FBPowerEvents[event] and HealBox.PowerBar ~= 1) then return; end
|
||||||
local c = FBRaidUnitCell[arg1];
|
local c = FBRaidUnitCell[arg1];
|
||||||
if (not c) then return; end
|
if (not c) then return; end
|
||||||
|
-- Mana (und Wut, Energie, Fokus): nur der Streifen, nicht die ganze Zelle
|
||||||
|
if (event == "UNIT_MANA" or event == "UNIT_MAXMANA" or FBPowerEvents[event]) then
|
||||||
|
FBRaid_UpdateCellManaOnly(c);
|
||||||
|
return;
|
||||||
|
end
|
||||||
FBRaid_UpdateCell(c, (event == "UNIT_AURA"));
|
FBRaid_UpdateCell(c, (event == "UNIT_AURA"));
|
||||||
if (event == "UNIT_AURA") then FBRaid_UpdateBuffBorder(c); end
|
if (event == "UNIT_AURA") then FBRaid_UpdateBuffBorder(c); end
|
||||||
end);
|
end);
|
||||||
@@ -1368,45 +1361,12 @@ end
|
|||||||
|
|
||||||
FBRaidSliders = {}; -- key -> Slider (fuer Beschriftung und Sync)
|
FBRaidSliders = {}; -- key -> Slider (fuer Beschriftung und Sync)
|
||||||
|
|
||||||
function FBRaid_SliderText(slider)
|
-- Regler baut der Kern (FBHealBox_CreateSlider); bis 1.4.6 stand hier eine
|
||||||
if (not slider or not slider.Text) then return; end
|
-- fast gleiche Kopie davon, ebenso im Mana-Ticker.
|
||||||
local v = slider:GetValue();
|
|
||||||
local shown;
|
|
||||||
if (slider.decimals) then shown = format("%.1f", v); else shown = tostring(math.floor(v + 0.5)); end
|
|
||||||
slider.Text:SetText(format(FBT(slider.labelKey), shown));
|
|
||||||
end
|
|
||||||
|
|
||||||
function FBRaid_CreateSlider(name, parent, x, y, labelKey, cfgKey, minV, maxV, step, decimals, onChange)
|
|
||||||
local s = CreateFrame("Slider", name, parent, "OptionsSliderTemplate");
|
|
||||||
s:SetWidth(128);
|
|
||||||
s:SetHeight(16);
|
|
||||||
s:SetPoint("TOPLEFT", x, y);
|
|
||||||
s:SetMinMaxValues(minV, maxV);
|
|
||||||
s:SetValueStep(step);
|
|
||||||
s.labelKey = labelKey;
|
|
||||||
s.cfgKey = cfgKey;
|
|
||||||
s.decimals = decimals;
|
|
||||||
s.Text = s:CreateFontString(nil, "BACKGROUND", "GameFontNormal");
|
|
||||||
s.Text:SetPoint("CENTER", 0, 15);
|
|
||||||
getglobal(name.."Low"):SetText(tostring(minV));
|
|
||||||
getglobal(name.."High"):SetText(tostring(maxV));
|
|
||||||
s:SetValue(FBRaid_Cfg()[cfgKey] or minV);
|
|
||||||
FBRaid_SliderText(s);
|
|
||||||
s:SetScript("OnValueChanged", function()
|
|
||||||
local v = s:GetValue();
|
|
||||||
if (not s.decimals) then v = math.floor(v + 0.5); end
|
|
||||||
FBRaid_Cfg()[s.cfgKey] = v;
|
|
||||||
FBRaid_SliderText(s);
|
|
||||||
if (onChange) then onChange(); end
|
|
||||||
end);
|
|
||||||
FBRaidSliders[cfgKey] = s;
|
|
||||||
return s;
|
|
||||||
end
|
|
||||||
|
|
||||||
function FBRaid_BuildOptions()
|
function FBRaid_BuildOptions()
|
||||||
local tab = FBHealBox_AddOptionsTab("TAB_RAID");
|
local tab = FBHealBox_AddOptionsTab("TAB_RAID");
|
||||||
if (not tab) then return; end
|
if (not tab) then return; end
|
||||||
FBRaidOptionsTab = tab;
|
|
||||||
local y = FBOPT_CONTENT_Y - 8;
|
local y = FBOPT_CONTENT_Y - 8;
|
||||||
|
|
||||||
FBRaidEnabledCheck = FBHealBox_CreateCheck("FBHealBoxRaidEnabledCheck", tab, 40, y, "RAID_ENABLED", "RAID_ENABLED_TIP", function()
|
FBRaidEnabledCheck = FBHealBox_CreateCheck("FBHealBoxRaidEnabledCheck", tab, 40, y, "RAID_ENABLED", "RAID_ENABLED_TIP", function()
|
||||||
@@ -1499,16 +1459,16 @@ function FBRaid_BuildOptions()
|
|||||||
|
|
||||||
-- Schieberegler (Beschriftung sitzt ueber dem Regler)
|
-- Schieberegler (Beschriftung sitzt ueber dem Regler)
|
||||||
local sy = y - 180;
|
local sy = y - 180;
|
||||||
FBRaid_CreateSlider("FBRaidGroupsPerRowSlider", tab, 75, sy, "RAID_GROUPSPERROW", "GroupsPerRow", 1, 8, 1, false, FBRaid_LayoutAll);
|
FBHealBox_CreateSlider("FBRaidGroupsPerRowSlider", tab, 75, sy, "RAID_GROUPSPERROW", FBRaid_Cfg, "GroupsPerRow", 1, 8, 1, false, FBRaid_LayoutAll, FBRaidSliders);
|
||||||
FBRaid_CreateSlider("FBRaidScaleSlider", tab, 260, sy, "RAID_SCALE", "Scale", 0.5, 1.5, 0.1, true, FBRaid_LayoutAll);
|
FBHealBox_CreateSlider("FBRaidScaleSlider", tab, 260, sy, "RAID_SCALE", FBRaid_Cfg, "Scale", 0.5, 1.5, 0.1, true, FBRaid_LayoutAll, FBRaidSliders);
|
||||||
FBRaid_CreateSlider("FBRaidCellWSlider", tab, 75, sy - 50, "RAID_CELLW", "CellW", 50, 120, 1, false, FBRaid_LayoutAll);
|
FBHealBox_CreateSlider("FBRaidCellWSlider", tab, 75, sy - 50, "RAID_CELLW", FBRaid_Cfg, "CellW", 50, 120, 1, false, FBRaid_LayoutAll, FBRaidSliders);
|
||||||
FBRaid_CreateSlider("FBRaidCellHSlider", tab, 260, sy - 50, "RAID_CELLH", "CellH", 14, 32, 1, false, FBRaid_LayoutAll);
|
FBHealBox_CreateSlider("FBRaidCellHSlider", tab, 260, sy - 50, "RAID_CELLH", FBRaid_Cfg, "CellH", 14, 32, 1, false, FBRaid_LayoutAll, FBRaidSliders);
|
||||||
FBRaid_CreateSlider("FBRaidButtonsSlider", tab, 75, sy - 100, "RAID_BUTTONS", "Buttons", 0, FBRAID_MAX_BUTTONS, 1, false, FBRaid_LayoutAll);
|
FBHealBox_CreateSlider("FBRaidButtonsSlider", tab, 75, sy - 100, "RAID_BUTTONS", FBRaid_Cfg, "Buttons", 0, FBRAID_MAX_BUTTONS, 1, false, FBRaid_LayoutAll, FBRaidSliders);
|
||||||
FBRaid_CreateSlider("FBRaidBtnSizeSlider", tab, 260, sy - 100, "RAID_BTNSIZE", "ButtonSize", 12, 28, 1, false, FBRaid_LayoutAll);
|
FBHealBox_CreateSlider("FBRaidBtnSizeSlider", tab, 260, sy - 100, "RAID_BTNSIZE", FBRaid_Cfg, "ButtonSize", 12, 28, 1, false, FBRaid_LayoutAll, FBRaidSliders);
|
||||||
FBRaid_CreateSlider("FBRaidCellGapSlider", tab, 75, sy - 150, "RAID_CELLGAP", "CellGap", 0, 10, 1, false, FBRaid_LayoutAll);
|
FBHealBox_CreateSlider("FBRaidCellGapSlider", tab, 75, sy - 150, "RAID_CELLGAP", FBRaid_Cfg, "CellGap", 0, 10, 1, false, FBRaid_LayoutAll, FBRaidSliders);
|
||||||
FBRaid_CreateSlider("FBRaidGroupGapSlider", tab, 260, sy - 150, "RAID_GROUPGAP", "GroupGap", 0, 20, 1, false, FBRaid_LayoutAll);
|
FBHealBox_CreateSlider("FBRaidGroupGapSlider", tab, 260, sy - 150, "RAID_GROUPGAP", FBRaid_Cfg, "GroupGap", 0, 20, 1, false, FBRaid_LayoutAll, FBRaidSliders);
|
||||||
-- Schwelle: ab wie vielen Mitgliedern die Raid-Ansicht uebernimmt
|
-- Schwelle: ab wie vielen Mitgliedern die Raid-Ansicht uebernimmt
|
||||||
FBRaid_CreateSlider("FBRaidMinPlayersSlider", tab, 75, sy - 200, "RAID_MINPLAYERS", "MinPlayers", 2, 40, 1, false, function() FBUpdateNames(); end);
|
FBHealBox_CreateSlider("FBRaidMinPlayersSlider", tab, 75, sy - 200, "RAID_MINPLAYERS", FBRaid_Cfg, "MinPlayers", 2, 40, 1, false, function() FBUpdateNames(); end, FBRaidSliders);
|
||||||
|
|
||||||
-- Hinweis zu den Buttons
|
-- Hinweis zu den Buttons
|
||||||
FBRaidInfoText = tab:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall");
|
FBRaidInfoText = tab:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall");
|
||||||
@@ -1546,7 +1506,7 @@ function FBRaid_ApplyLocale()
|
|||||||
if (FBRaidTitleCheck) then FBRaidTitleCheck.Text:SetText(FBT("RAID_SHOWTITLE")); FBRaidTitleCheck.tooltipText = FBT("RAID_SHOWTITLE_TIP"); end
|
if (FBRaidTitleCheck) then FBRaidTitleCheck.Text:SetText(FBT("RAID_SHOWTITLE")); FBRaidTitleCheck.tooltipText = FBT("RAID_SHOWTITLE_TIP"); end
|
||||||
if (FBRaidBuffIconsCheck) then FBRaidBuffIconsCheck.Text:SetText(FBT("RAID_BUFFICONS")); FBRaidBuffIconsCheck.tooltipText = FBT("RAID_BUFFICONS_TIP"); end
|
if (FBRaidBuffIconsCheck) then FBRaidBuffIconsCheck.Text:SetText(FBT("RAID_BUFFICONS")); FBRaidBuffIconsCheck.tooltipText = FBT("RAID_BUFFICONS_TIP"); end
|
||||||
if (FBRaidInfoText) then FBRaidInfoText:SetText(FBT("RAID_INFO")); end
|
if (FBRaidInfoText) then FBRaidInfoText:SetText(FBT("RAID_INFO")); end
|
||||||
for _, s in pairs(FBRaidSliders) do FBRaid_SliderText(s); end
|
for _, s in pairs(FBRaidSliders) do FBHealBox_SliderText(s); end
|
||||||
FBRaid_UpdateHPTextLabel();
|
FBRaid_UpdateHPTextLabel();
|
||||||
FBRaid_UpdateTestLabel();
|
FBRaid_UpdateTestLabel();
|
||||||
if (FBRaidFrame and FBRaidFrame.Title) then FBRaidFrame.Title.text:SetText(FBT("RAID_TITLE").." ("..FBRaidMembers..")"); end
|
if (FBRaidFrame and FBRaidFrame.Title) then FBRaidFrame.Title.text:SetText(FBT("RAID_TITLE").." ("..FBRaidMembers..")"); end
|
||||||
@@ -1583,6 +1543,18 @@ FBHealBox_RegisterHook("ActiveToggle", function()
|
|||||||
FBRaid_UpdateVisibility();
|
FBRaid_UpdateVisibility();
|
||||||
return true;
|
return true;
|
||||||
end);
|
end);
|
||||||
|
-- Nur die Zellen anfassen, deren Einheit sich geaendert hat. Der Kern
|
||||||
|
-- schickt die Namensliste mit, die Zelle kommt direkt aus FBRaidNameCell:
|
||||||
|
-- Bis 1.4.6 wurden dafuer alle vierzig Zellen abgesucht.
|
||||||
|
FBHealBox_RegisterHook("RefreshNames", function(names)
|
||||||
|
if (not FBRaid_IsActive()) or (not names) then return true; end
|
||||||
|
for name in pairs(names) do
|
||||||
|
local c = FBRaidNameCell[name];
|
||||||
|
if (c) then FBRaid_UpdateCell(c); end
|
||||||
|
end
|
||||||
|
return true;
|
||||||
|
end);
|
||||||
|
|
||||||
FBHealBox_RegisterHook("RefreshAllBars", function()
|
FBHealBox_RegisterHook("RefreshAllBars", function()
|
||||||
FBRaid_RefreshAll();
|
FBRaid_RefreshAll();
|
||||||
return true;
|
return true;
|
||||||
@@ -1594,8 +1566,15 @@ end);
|
|||||||
FBHealBox_RegisterHook("Aggro", function(tt) return FBRaid_CheckAggro(tt); end);
|
FBHealBox_RegisterHook("Aggro", function(tt) return FBRaid_CheckAggro(tt); end);
|
||||||
FBHealBox_RegisterHook("SpellTimers", function(now) FBRaid_UpdateSpellTimers(now); return true; end);
|
FBHealBox_RegisterHook("SpellTimers", function(now) FBRaid_UpdateSpellTimers(now); return true; end);
|
||||||
FBHealBox_RegisterHook("Cooldowns", function() FBRaid_UpdateCooldowns(); return true; end);
|
FBHealBox_RegisterHook("Cooldowns", function() FBRaid_UpdateCooldowns(); return true; end);
|
||||||
FBHealBox_RegisterHook("ButtonStates", function(ev) FBRaid_UpdateButtonStates(ev); return true; end);
|
FBHealBox_RegisterHook("ButtonStates", function(ev) FBRaid_ButtonStates(ev); return true; end);
|
||||||
FBHealBox_RegisterHook("BuffIcons", function() FBRaid_UpdateBuffIcons(); return true; end);
|
FBHealBox_RegisterHook("BuffIcons", function()
|
||||||
|
-- Der Schalter "Buff-Icons" des Kerns aendert die Breite des Streifens
|
||||||
|
-- links der Zellen. Bis 1.4.6 rueckte das Raster erst beim naechsten
|
||||||
|
-- Rosterwechsel nach.
|
||||||
|
if (FBRaidLaidStrip and FBRaid_BuffStrip(FBRaid_Cfg()) ~= FBRaidLaidStrip) then FBRaid_LayoutAll(); end
|
||||||
|
FBRaid_UpdateBuffIcons();
|
||||||
|
return true;
|
||||||
|
end);
|
||||||
FBHealBox_RegisterHook("Status", function()
|
FBHealBox_RegisterHook("Status", function()
|
||||||
local cfg = FBRaid_Cfg();
|
local cfg = FBRaid_Cfg();
|
||||||
local state = FBT("FBP_STATE_OFF");
|
local state = FBT("FBP_STATE_OFF");
|
||||||
@@ -1608,7 +1587,8 @@ FBHealBox_RegisterHook("Slash", function(msg)
|
|||||||
if (msg == "raid") then
|
if (msg == "raid") then
|
||||||
local cfg = FBRaid_Cfg();
|
local cfg = FBRaid_Cfg();
|
||||||
if (cfg.Enabled == 1) then cfg.Enabled = 0; else cfg.Enabled = 1; end
|
if (cfg.Enabled == 1) then cfg.Enabled = 0; else cfg.Enabled = 1; end
|
||||||
if (cfg.Enabled == 0 and FBRaidTestMode > 0) then FBRaidTestMode = 0; end
|
-- wie der Schalter im Reiter: SetTest haelt auch die Atmung der Geister an
|
||||||
|
if (cfg.Enabled == 0 and FBRaidTestMode > 0) then FBRaid_SetTest(0); end
|
||||||
FBRaid_SyncOptions();
|
FBRaid_SyncOptions();
|
||||||
FBUpdateNames();
|
FBUpdateNames();
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
+46
-65
@@ -46,7 +46,6 @@ FBTickerDefaults = {
|
|||||||
-- [ Texte ]
|
-- [ Texte ]
|
||||||
-- ==========================================================================
|
-- ==========================================================================
|
||||||
|
|
||||||
FBLocale["enUS"].TAB_TICKER = "Extras";
|
|
||||||
FBLocale["enUS"].TICK_HEADER = "Mana ticker";
|
FBLocale["enUS"].TICK_HEADER = "Mana ticker";
|
||||||
FBLocale["enUS"].TICK_ENABLED = "Mana ticker";
|
FBLocale["enUS"].TICK_ENABLED = "Mana ticker";
|
||||||
FBLocale["enUS"].TICK_ENABLED_TIP = "A spark travels across your own mana bar every 2 seconds, in step with the server's mana regeneration tick. Cast right after the spark reaches the end and you lose no regeneration. Needs the mana bar to be on.";
|
FBLocale["enUS"].TICK_ENABLED_TIP = "A spark travels across your own mana bar every 2 seconds, in step with the server's mana regeneration tick. Cast right after the spark reaches the end and you lose no regeneration. Needs the mana bar to be on.";
|
||||||
@@ -60,11 +59,10 @@ FBLocale["enUS"].TICK_STATUS = "Ticker: %s, next tick in %.1f s%s";
|
|||||||
FBLocale["enUS"].TICK_SYNCED = "synced";
|
FBLocale["enUS"].TICK_SYNCED = "synced";
|
||||||
FBLocale["enUS"].TICK_UNSYNCED = "waiting for first tick";
|
FBLocale["enUS"].TICK_UNSYNCED = "waiting for first tick";
|
||||||
FBLocale["enUS"].TICK_STATUS_FSR = ", five-second rule %.1f s";
|
FBLocale["enUS"].TICK_STATUS_FSR = ", five-second rule %.1f s";
|
||||||
FBLocale["enUS"].TICK_LOADED = "Mana ticker module loaded: tab |cFFFFFFFFTicker|r in the options, /fbp ticker";
|
FBLocale["enUS"].TICK_LOADED = "Mana ticker module loaded: section in tab |cFFFFFFFFExtras|r, /fbp ticker";
|
||||||
FBLocale["enUS"].TICK_ON = "Mana ticker |cFF00FF00on|r.";
|
FBLocale["enUS"].TICK_ON = "Mana ticker |cFF00FF00on|r.";
|
||||||
FBLocale["enUS"].TICK_OFF = "Mana ticker |cFFFF0000off|r.";
|
FBLocale["enUS"].TICK_OFF = "Mana ticker |cFFFF0000off|r.";
|
||||||
|
|
||||||
FBLocale["deDE"].TAB_TICKER = "Extras";
|
|
||||||
FBLocale["deDE"].TICK_HEADER = "Mana-Ticker";
|
FBLocale["deDE"].TICK_HEADER = "Mana-Ticker";
|
||||||
FBLocale["deDE"].TICK_ENABLED = "Mana-Ticker";
|
FBLocale["deDE"].TICK_ENABLED = "Mana-Ticker";
|
||||||
FBLocale["deDE"].TICK_ENABLED_TIP = "Ein Funke wandert alle 2 Sekunden ueber deinen eigenen Manastreifen, im Takt des Regenerationsticks des Servers. Wer direkt nach dem Funken am Ende castet, verliert keine Regeneration. Braucht den eingeschalteten Manabalken.";
|
FBLocale["deDE"].TICK_ENABLED_TIP = "Ein Funke wandert alle 2 Sekunden ueber deinen eigenen Manastreifen, im Takt des Regenerationsticks des Servers. Wer direkt nach dem Funken am Ende castet, verliert keine Regeneration. Braucht den eingeschalteten Manabalken.";
|
||||||
@@ -75,7 +73,6 @@ FBLocale["deDE"].TICK_OFFSET = "Tick-Vorlauf: |cFFFFFFFF%s s";
|
|||||||
|
|
||||||
-- Weitere Sprachen (Spanisch, Franzoesisch, Italienisch)
|
-- Weitere Sprachen (Spanisch, Franzoesisch, Italienisch)
|
||||||
|
|
||||||
FBLocale["esES"].TAB_TICKER = "Extras";
|
|
||||||
FBLocale["esES"].TICK_HEADER = "Ticker de maná";
|
FBLocale["esES"].TICK_HEADER = "Ticker de maná";
|
||||||
FBLocale["esES"].TICK_ENABLED = "Ticker de maná";
|
FBLocale["esES"].TICK_ENABLED = "Ticker de maná";
|
||||||
FBLocale["esES"].TICK_ENABLED_TIP = "Una chispa recorre tu propia barra de maná cada 2 segundos, al compás del pulso de regeneración de maná del servidor. Lanza justo después de que la chispa llegue al final y no perderás regeneración. Requiere la barra de maná activada.";
|
FBLocale["esES"].TICK_ENABLED_TIP = "Una chispa recorre tu propia barra de maná cada 2 segundos, al compás del pulso de regeneración de maná del servidor. Lanza justo después de que la chispa llegue al final y no perderás regeneración. Requiere la barra de maná activada.";
|
||||||
@@ -93,7 +90,6 @@ FBLocale["esES"].TICK_LOADED = "Módulo de ticker de maná cargado: pesta
|
|||||||
FBLocale["esES"].TICK_ON = "Ticker de maná |cFF00FF00activado|r.";
|
FBLocale["esES"].TICK_ON = "Ticker de maná |cFF00FF00activado|r.";
|
||||||
FBLocale["esES"].TICK_OFF = "Ticker de maná |cFFFF0000desactivado|r.";
|
FBLocale["esES"].TICK_OFF = "Ticker de maná |cFFFF0000desactivado|r.";
|
||||||
|
|
||||||
FBLocale["frFR"].TAB_TICKER = "Extras";
|
|
||||||
FBLocale["frFR"].TICK_HEADER = "Ticker de mana";
|
FBLocale["frFR"].TICK_HEADER = "Ticker de mana";
|
||||||
FBLocale["frFR"].TICK_ENABLED = "Ticker de mana";
|
FBLocale["frFR"].TICK_ENABLED = "Ticker de mana";
|
||||||
FBLocale["frFR"].TICK_ENABLED_TIP = "Une étincelle parcourt votre propre barre de mana toutes les 2 secondes, au rythme du tick de régénération de mana du serveur. Lancez juste après que l'étincelle atteint la fin et vous ne perdez aucune régénération. Nécessite la barre de mana activée.";
|
FBLocale["frFR"].TICK_ENABLED_TIP = "Une étincelle parcourt votre propre barre de mana toutes les 2 secondes, au rythme du tick de régénération de mana du serveur. Lancez juste après que l'étincelle atteint la fin et vous ne perdez aucune régénération. Nécessite la barre de mana activée.";
|
||||||
@@ -111,7 +107,6 @@ FBLocale["frFR"].TICK_LOADED = "Module ticker de mana chargé : onglet |cF
|
|||||||
FBLocale["frFR"].TICK_ON = "Ticker de mana |cFF00FF00activé|r.";
|
FBLocale["frFR"].TICK_ON = "Ticker de mana |cFF00FF00activé|r.";
|
||||||
FBLocale["frFR"].TICK_OFF = "Ticker de mana |cFFFF0000désactivé|r.";
|
FBLocale["frFR"].TICK_OFF = "Ticker de mana |cFFFF0000désactivé|r.";
|
||||||
|
|
||||||
FBLocale["itIT"].TAB_TICKER = "Extra";
|
|
||||||
FBLocale["itIT"].TICK_HEADER = "Ticker del mana";
|
FBLocale["itIT"].TICK_HEADER = "Ticker del mana";
|
||||||
FBLocale["itIT"].TICK_ENABLED = "Ticker del mana";
|
FBLocale["itIT"].TICK_ENABLED = "Ticker del mana";
|
||||||
FBLocale["itIT"].TICK_ENABLED_TIP = "Una scintilla attraversa la tua barra del mana ogni 2 secondi, a tempo con il tick di rigenerazione del mana del server. Lancia subito dopo che la scintilla arriva in fondo e non perdi rigenerazione. Richiede la barra del mana attiva.";
|
FBLocale["itIT"].TICK_ENABLED_TIP = "Una scintilla attraversa la tua barra del mana ogni 2 secondi, a tempo con il tick di rigenerazione del mana del server. Lancia subito dopo che la scintilla arriva in fondo e non perdi rigenerazione. Richiede la barra del mana attiva.";
|
||||||
@@ -134,7 +129,7 @@ FBLocale["deDE"].TICK_STATUS = "Ticker: %s, naechster Tick in %.1f s%s";
|
|||||||
FBLocale["deDE"].TICK_SYNCED = "synchron";
|
FBLocale["deDE"].TICK_SYNCED = "synchron";
|
||||||
FBLocale["deDE"].TICK_UNSYNCED = "wartet auf ersten Tick";
|
FBLocale["deDE"].TICK_UNSYNCED = "wartet auf ersten Tick";
|
||||||
FBLocale["deDE"].TICK_STATUS_FSR = ", Fuenf-Sekunden-Regel %.1f s";
|
FBLocale["deDE"].TICK_STATUS_FSR = ", Fuenf-Sekunden-Regel %.1f s";
|
||||||
FBLocale["deDE"].TICK_LOADED = "Mana-Ticker-Modul geladen: Reiter |cFFFFFFFFTicker|r in den Optionen, /fbp ticker";
|
FBLocale["deDE"].TICK_LOADED = "Mana-Ticker-Modul geladen: Abschnitt im Reiter |cFFFFFFFFExtras|r, /fbp ticker";
|
||||||
FBLocale["deDE"].TICK_ON = "Mana-Ticker |cFF00FF00an|r.";
|
FBLocale["deDE"].TICK_ON = "Mana-Ticker |cFF00FF00an|r.";
|
||||||
FBLocale["deDE"].TICK_OFF = "Mana-Ticker |cFFFF0000aus|r.";
|
FBLocale["deDE"].TICK_OFF = "Mana-Ticker |cFFFF0000aus|r.";
|
||||||
|
|
||||||
@@ -351,7 +346,8 @@ end
|
|||||||
|
|
||||||
function FBTicker_Draw()
|
function FBTicker_Draw()
|
||||||
if (not FBTicker.gate) then return; end
|
if (not FBTicker.gate) then return; end
|
||||||
local frac, mode = FBTicker_Progress(GetTime());
|
local now = GetTime();
|
||||||
|
local frac, mode = FBTicker_Progress(now);
|
||||||
if (not frac) then
|
if (not frac) then
|
||||||
FBTicker_HideAll();
|
FBTicker_HideAll();
|
||||||
return;
|
return;
|
||||||
@@ -364,8 +360,17 @@ function FBTicker_Draw()
|
|||||||
local bar, s = e.bar, e.spark;
|
local bar, s = e.bar, e.spark;
|
||||||
if (s and bar) then
|
if (s and bar) then
|
||||||
if (bar:IsShown()) then
|
if (bar:IsShown()) then
|
||||||
local bw = bar:GetWidth() or 0;
|
-- Breite und Hoehe aendern sich nur beim Umbauen der Anzeige.
|
||||||
local bh = bar:GetHeight() or 0;
|
-- Sie werden deshalb viermal je Sekunde nachgelesen und
|
||||||
|
-- dazwischen gemerkt; so kostet das Zeichnen je Frame fast
|
||||||
|
-- nichts mehr und darf wieder in jedem Frame laufen.
|
||||||
|
if (not e.geomT) or ((now - e.geomT) >= FBTICK_GEOM_STEP) then
|
||||||
|
e.geomT = now;
|
||||||
|
e.bw = bar:GetWidth() or 0;
|
||||||
|
e.bh = bar:GetHeight() or 0;
|
||||||
|
end
|
||||||
|
local bw = e.bw or 0;
|
||||||
|
local bh = e.bh or 0;
|
||||||
if (bw > w and bh > 0) then
|
if (bw > w and bh > 0) then
|
||||||
if (e.w ~= w or e.h ~= bh) then
|
if (e.w ~= w or e.h ~= bh) then
|
||||||
e.w = w; e.h = bh;
|
e.w = w; e.h = bh;
|
||||||
@@ -376,10 +381,16 @@ function FBTicker_Draw()
|
|||||||
e.mode = mode;
|
e.mode = mode;
|
||||||
s:SetTexture(col[1], col[2], col[3], col[4]);
|
s:SetTexture(col[1], col[2], col[3], col[4]);
|
||||||
end
|
end
|
||||||
-- Anker nur setzen, wenn der Funke mindestens einen halben
|
-- Anker setzen, sobald sich die Position ueberhaupt
|
||||||
-- Pixel weitergewandert ist
|
-- geaendert hat. Eine Schwelle von einem halben Pixel
|
||||||
|
-- klingt sparsam, der Funke wandert aber nur rund 20 px
|
||||||
|
-- je Sekunde: bei 60 Bildern kam er damit nur in jedem
|
||||||
|
-- zweiten Frame voran, und je nach Rundung mal nach einem,
|
||||||
|
-- mal nach zwei Frames. Genau das sah ruckelig aus. Die
|
||||||
|
-- Feinrundung auf ganze Bildpunkte macht ohnehin die
|
||||||
|
-- Oberflaeche selbst.
|
||||||
local x = frac * (bw - w);
|
local x = frac * (bw - w);
|
||||||
if (not e.x) or (math.abs(x - e.x) >= 0.5) then
|
if (not e.x) or (math.abs(x - e.x) >= 0.05) then
|
||||||
e.x = x;
|
e.x = x;
|
||||||
s:ClearAllPoints();
|
s:ClearAllPoints();
|
||||||
s:SetPoint("LEFT", bar, "LEFT", x, 0);
|
s:SetPoint("LEFT", bar, "LEFT", x, 0);
|
||||||
@@ -422,70 +433,36 @@ FBTickerFrame:SetScript("OnEvent", function()
|
|||||||
end
|
end
|
||||||
FBTicker_UpdateGate();
|
FBTicker_UpdateGate();
|
||||||
end);
|
end);
|
||||||
-- Der Funke wandert in fuenf Sekunden ueber den Balken, ein Neuzeichnen in
|
-- Gezeichnet wird in jedem Frame. Ein fester Takt spart zwar Durchlaeufe,
|
||||||
-- jedem Frame bringt dabei kein sichtbar weicheres Bild. Ein fester Takt von
|
-- macht die Bewegung aber sichtbar stufig: der Funke braucht fuer den Balken
|
||||||
-- 0,03 Sekunden (rund 33 Bilder je Sekunde) spart auf schnellen Rechnern die
|
-- fuenf Sekunden, jede ausgelassene Position sieht man sofort. Teuer ist das
|
||||||
-- Haelfte der Durchlaeufe samt der Breiten- und Hoehenabfragen je Balken.
|
-- Zeichnen nicht mehr, weil die Balkenmasse gemerkt werden und der Ausstieg
|
||||||
FBTickerDrawAccum = 0;
|
-- ueber das Gate davor sitzt (voller Manabalken = gar kein Durchlauf).
|
||||||
FBTICK_DRAW_STEP = 0.03;
|
FBTICK_GEOM_STEP = 0.25; -- Sek.: so oft werden Breite und Hoehe nachgelesen
|
||||||
|
|
||||||
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
|
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);
|
||||||
|
|
||||||
-- ==========================================================================
|
-- ==========================================================================
|
||||||
-- [ Options-Reiter "Ticker" ]
|
-- [ Abschnitt im Reiter "Extras" ]
|
||||||
|
--
|
||||||
|
-- Den Reiter verwaltet der Kern (FBHealBox_ExtrasSection); er wird mit
|
||||||
|
-- Smart Damage geteilt, jedes Modul funktioniert aber auch allein.
|
||||||
-- ==========================================================================
|
-- ==========================================================================
|
||||||
|
|
||||||
FBTickerSliders = {};
|
FBTickerSliders = {};
|
||||||
|
FBTICK_SECTION_H = 232; -- px, Hoehe des Abschnitts
|
||||||
function FBTicker_SliderText(s)
|
|
||||||
if (not s or not s.Text) then return; end
|
|
||||||
local v = s:GetValue();
|
|
||||||
local shown;
|
|
||||||
if (s.decimals) then shown = format("%.1f", v); else shown = tostring(math.floor(v + 0.5)); end
|
|
||||||
s.Text:SetText(format(FBT(s.labelKey), shown));
|
|
||||||
end
|
|
||||||
|
|
||||||
function FBTicker_CreateSlider(name, parent, x, y, labelKey, cfgKey, minV, maxV, step, decimals)
|
|
||||||
local s = CreateFrame("Slider", name, parent, "OptionsSliderTemplate");
|
|
||||||
s:SetWidth(128);
|
|
||||||
s:SetHeight(16);
|
|
||||||
s:SetPoint("TOPLEFT", x, y);
|
|
||||||
s:SetMinMaxValues(minV, maxV);
|
|
||||||
s:SetValueStep(step);
|
|
||||||
s.labelKey = labelKey;
|
|
||||||
s.cfgKey = cfgKey;
|
|
||||||
s.decimals = decimals;
|
|
||||||
s.Text = s:CreateFontString(nil, "BACKGROUND", "GameFontNormal");
|
|
||||||
s.Text:SetPoint("CENTER", 0, 15);
|
|
||||||
getglobal(name.."Low"):SetText(tostring(minV));
|
|
||||||
getglobal(name.."High"):SetText(tostring(maxV));
|
|
||||||
s:SetValue(FBTicker_Cfg()[cfgKey] or minV);
|
|
||||||
FBTicker_SliderText(s);
|
|
||||||
s:SetScript("OnValueChanged", function()
|
|
||||||
local v = s:GetValue();
|
|
||||||
if (s.decimals) then v = math.floor(v * 10 + 0.5) / 10; else v = math.floor(v + 0.5); end
|
|
||||||
FBTicker_Cfg()[s.cfgKey] = v;
|
|
||||||
FBTicker_SliderText(s);
|
|
||||||
end);
|
|
||||||
FBTickerSliders[cfgKey] = s;
|
|
||||||
return s;
|
|
||||||
end
|
|
||||||
|
|
||||||
function FBTicker_BuildOptions()
|
function FBTicker_BuildOptions()
|
||||||
local tab = FBHealBox_AddOptionsTab("TAB_TICKER");
|
local tab, top = FBHealBox_ExtrasSection(FBTICK_SECTION_H);
|
||||||
if (not tab) then return; end
|
if (not tab) then return; end
|
||||||
-- Abschnittskopf: der Reiter "Extras" wird mit Smart Damage geteilt
|
|
||||||
FBTickerHeader = tab:CreateFontString(nil, "OVERLAY", "GameFontNormal");
|
FBTickerHeader = tab:CreateFontString(nil, "OVERLAY", "GameFontNormal");
|
||||||
FBTickerHeader:SetPoint("TOPLEFT", tab, "TOPLEFT", 35, FBOPT_CONTENT_Y);
|
FBTickerHeader:SetPoint("TOPLEFT", tab, "TOPLEFT", 35, top);
|
||||||
FBTickerHeader:SetText(FBT("TICK_HEADER"));
|
FBTickerHeader:SetText(FBT("TICK_HEADER"));
|
||||||
local y = FBOPT_CONTENT_Y - 26;
|
local y = top - 26;
|
||||||
|
|
||||||
FBTickerEnabledCheck = FBHealBox_CreateCheck("FBHealBoxTickerEnabledCheck", tab, 40, y, "TICK_ENABLED", "TICK_ENABLED_TIP", function()
|
FBTickerEnabledCheck = FBHealBox_CreateCheck("FBHealBoxTickerEnabledCheck", tab, 40, y, "TICK_ENABLED", "TICK_ENABLED_TIP", function()
|
||||||
FBTicker_Cfg().Enabled = FBTickerEnabledCheck:GetChecked() and 1 or 0;
|
FBTicker_Cfg().Enabled = FBTickerEnabledCheck:GetChecked() and 1 or 0;
|
||||||
@@ -498,9 +475,9 @@ function FBTicker_BuildOptions()
|
|||||||
end);
|
end);
|
||||||
|
|
||||||
local sy = y - 60;
|
local sy = y - 60;
|
||||||
FBTicker_CreateSlider("FBTickerToleranceSlider", tab, 75, sy, "TICK_TOLERANCE", "Tolerance", 0.1, 0.6, 0.1, true);
|
FBHealBox_CreateSlider("FBTickerToleranceSlider", tab, 75, sy, "TICK_TOLERANCE", FBTicker_Cfg, "Tolerance", 0.1, 0.6, 0.1, true, nil, FBTickerSliders);
|
||||||
FBTicker_CreateSlider("FBTickerOffsetSlider", tab, 260, sy, "TICK_OFFSET", "Offset", 0.0, 0.5, 0.1, true);
|
FBHealBox_CreateSlider("FBTickerOffsetSlider", tab, 260, sy, "TICK_OFFSET", FBTicker_Cfg, "Offset", 0.0, 0.5, 0.1, true, nil, FBTickerSliders);
|
||||||
FBTicker_CreateSlider("FBTickerSparkWSlider", tab, 75, sy - 46, "TICK_SPARKW", "SparkW", 1, 4, 1, false);
|
FBHealBox_CreateSlider("FBTickerSparkWSlider", tab, 75, sy - 46, "TICK_SPARKW", FBTicker_Cfg, "SparkW", 1, 4, 1, false, nil, FBTickerSliders);
|
||||||
|
|
||||||
FBTickerInfoText = tab:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall");
|
FBTickerInfoText = tab:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall");
|
||||||
FBTickerInfoText:SetPoint("TOPLEFT", tab, "TOPLEFT", 35, sy - 84);
|
FBTickerInfoText:SetPoint("TOPLEFT", tab, "TOPLEFT", 35, sy - 84);
|
||||||
@@ -526,7 +503,7 @@ function FBTicker_ApplyLocale()
|
|||||||
if (FBTickerEnabledCheck) then FBTickerEnabledCheck.Text:SetText(FBT("TICK_ENABLED")); FBTickerEnabledCheck.tooltipText = FBT("TICK_ENABLED_TIP"); end
|
if (FBTickerEnabledCheck) then FBTickerEnabledCheck.Text:SetText(FBT("TICK_ENABLED")); FBTickerEnabledCheck.tooltipText = FBT("TICK_ENABLED_TIP"); end
|
||||||
if (FBTickerFSRCheck) then FBTickerFSRCheck.Text:SetText(FBT("TICK_FSR")); FBTickerFSRCheck.tooltipText = FBT("TICK_FSR_TIP"); end
|
if (FBTickerFSRCheck) then FBTickerFSRCheck.Text:SetText(FBT("TICK_FSR")); FBTickerFSRCheck.tooltipText = FBT("TICK_FSR_TIP"); end
|
||||||
if (FBTickerInfoText) then FBTickerInfoText:SetText(FBT("TICK_INFO")); end
|
if (FBTickerInfoText) then FBTickerInfoText:SetText(FBT("TICK_INFO")); end
|
||||||
for _, s in pairs(FBTickerSliders) do FBTicker_SliderText(s); end
|
for _, s in pairs(FBTickerSliders) do FBHealBox_SliderText(s); end
|
||||||
return true;
|
return true;
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -549,6 +526,10 @@ FBHealBox_RegisterHook("Defaults", function() return FBTicker_ApplyDefaults(); e
|
|||||||
FBHealBox_RegisterHook("SyncOptions", function() return FBTicker_SyncOptions(); end);
|
FBHealBox_RegisterHook("SyncOptions", function() return FBTicker_SyncOptions(); end);
|
||||||
FBHealBox_RegisterHook("ApplyLocale", function() return FBTicker_ApplyLocale(); end);
|
FBHealBox_RegisterHook("ApplyLocale", function() return FBTicker_ApplyLocale(); end);
|
||||||
FBHealBox_RegisterHook("UpdateNames", function() FBTicker_CollectBars(); FBTicker_UpdateGate(); return true; end);
|
FBHealBox_RegisterHook("UpdateNames", function() FBTicker_CollectBars(); FBTicker_UpdateGate(); return true; end);
|
||||||
|
-- Das Raidraster baut auch ohne "UpdateNames" um (reines RAID_ROSTER_UPDATE,
|
||||||
|
-- etwa beim Ueberschreiten der Schwelle). Ohne diesen Hook fehlte der Funke
|
||||||
|
-- dann oder lief auf der Zelle eines anderen Spielers.
|
||||||
|
FBHealBox_RegisterHook("RaidRoster", function() FBTicker_CollectBars(); FBTicker_UpdateGate(); return true; end);
|
||||||
FBHealBox_RegisterHook("ActiveToggle", function() FBTicker_UpdateGate(); FBTicker_Draw(); return true; end);
|
FBHealBox_RegisterHook("ActiveToggle", function() FBTicker_UpdateGate(); FBTicker_Draw(); return true; end);
|
||||||
FBHealBox_RegisterHook("Status", function()
|
FBHealBox_RegisterHook("Status", function()
|
||||||
local state = FBT("TICK_UNSYNCED");
|
local state = FBT("TICK_UNSYNCED");
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Heal Box Vanilla
|
# Heal Box Vanilla
|
||||||
|
|
||||||
ADDON DOCUMENTATION · VERSION 1.4.5 · World of Warcraft CLIENT 1.12.1
|
ADDON DOCUMENTATION · VERSION 1.4.7 · 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.
|
||||||
|
|
||||||
@@ -10,7 +10,8 @@ Party, pet and self heal display with quick-cast buttons for healers. One name p
|
|||||||
|
|
||||||
<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="842" height="1103" alt="Screenshot 2026-09-09 080054" src="https://github.com/user-attachments/assets/61ef0883-fee6-4cab-98bb-240bb1a03e71" />
|
<img width="843" height="1105" alt="Screenshot 2026-10-08 165554" src="https://github.com/user-attachments/assets/989adb05-28b3-4eb3-8212-ef01286f81ab" />
|
||||||
|
|
||||||
|
|
||||||
\---
|
\---
|
||||||
|
|
||||||
@@ -48,6 +49,8 @@ While the addon sleeps, all other `/fbp` commands answer with the same hint, bec
|
|||||||
|
|
||||||
Detection uses the client's English class token (`WARRIOR`, `ROGUE`, `HUNTER`) and falls back to the displayed class name in five languages, so it also works on localized clients.
|
Detection uses the client's English class token (`WARRIOR`, `ROGUE`, `HUNTER`) and falls back to the displayed class name in five languages, so it also works on localized clients.
|
||||||
|
|
||||||
|
Since 1.4.7 the same token also decides the class internally: the addon always works with the English class name (`Priest`, `Druid` and so on), while chat lines and the options window still show the name your client uses. Before, a German client stored *Priester*, and every table keyed by class stayed empty there, so dispel colouring did not work at all. It now works on every client language, as does the class icon. The spell lists and the tooltip patterns of the prediction are still English, see [Troubleshooting](#troubleshooting).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## The display
|
## The display
|
||||||
@@ -66,7 +69,7 @@ If your current hostile target is targeting a group member, that member's plate
|
|||||||
|
|
||||||
### Line of sight
|
### Line of sight
|
||||||
|
|
||||||
While a unit is out of your line of sight an **eye badge** (`FBLOS_ICON`, the Blind icon) sits on the top-left corner of its plate. Vanilla has no API for this, so two paths are used: with the **UnitXP SP3** client mod installed the addon asks `UnitXP("inSight", "player", unit)` every half second, live and exact. Without it, the addon watches for the *not in line of sight* error after one of your heals and marks the unit you tried to heal for `FBLOS_TIMEOUT` (8) seconds; the mark is cleared as soon as a cast on that unit starts or one of your heals or HoT ticks lands on it. `/fbp` reports which path is active. Option *Line of sight*; badge position via `FBLOS_ICON_X/Y`.
|
While a unit is out of your line of sight an **eye badge** (`FBLOS_ICON`, the Blind icon) sits on the top-left corner of its plate. Vanilla has no API for this, so two paths are used: with the **UnitXP SP3** client mod installed the addon asks `UnitXP("inSight", "player", unit)` every half second, live and exact. Without it, the addon watches for the *not in line of sight* error after a click on one of your Heal Box buttons and marks that button's unit for `FBLOS_TIMEOUT` (8) seconds; the mark is cleared as soon as a cast on that unit starts or one of your direct heals lands on it. A tick of your HoT leaves it alone, because ticks need no line of sight. The error has to answer that very click: it counts for up to `FBLOS_ERROR_WINDOW` (1) second after the click, and for a spell with a cast time until one second after the cast ends, because the server checks line of sight again when the cast finishes. A cast that goes through, a cast that is interrupted, another error message or another spell starting ends the wait. Errors from spells on your action bars therefore mark nobody, and your own plate is never marked. `/fbp` reports which path is active. Option *Line of sight*; badge position via `FBLOS_ICON_X/Y`.
|
||||||
|
|
||||||
### Pets
|
### Pets
|
||||||
|
|
||||||
@@ -102,7 +105,7 @@ If someone carries a debuff **your** class can remove, their health bar takes th
|
|||||||
|Shaman|Poison, Disease|
|
|Shaman|Poison, Disease|
|
||||||
|Druid|Curse (purple), Poison|
|
|Druid|Curse (purple), Poison|
|
||||||
|
|
||||||
The thresholds for the HP colours are `LowHP` (0.6) and `VeryLowHP` (0.3) near the top of the file.
|
The thresholds for the HP colours are `FBLowHP` (0.6) and `FBVeryLowHP` (0.3) near the top of the file.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -110,11 +113,13 @@ The thresholds for the HP colours are `LowHP` (0.6) and `VeryLowHP` (0.3) near t
|
|||||||
|
|
||||||
Up to ten buttons sit next to each plate, each showing its spell's icon. A **left click** casts that spell on exactly this group member, no matter who you currently have targeted.
|
Up to ten buttons sit next to each plate, each showing its spell's icon. A **left click** casts that spell on exactly this group member, no matter who you currently have targeted.
|
||||||
|
|
||||||
**Assigning by drag and drop.** Open the spellbook, drag a spell and drop it on any heal button, on a raid mini button, or on a field in the *Buttons* tab; that button number takes the spell on every plate. With the right-click spell enabled, dropping with the right mouse button, or with Shift held while dropping, fills the right-click side. Spells outside the class list (Dispel Magic, say) are accepted too and keep their icon after a reload. Vanilla has no `GetCursorInfo()`, so the addon remembers what `PickupSpell` last put on the cursor.
|
**Assigning by drag and drop.** Open the spellbook, drag a spell and drop it on any heal button, on a raid mini button, or on a field in the *Buttons* tab; that button number takes the spell on every plate. With the right-click spell enabled, dropping with the right mouse button, or with Shift held while dropping, fills the right-click side. Spells outside the class list (Dispel Magic, say) are accepted too and keep their icon after a reload. Vanilla has no `GetCursorInfo()`, so the addon remembers what `PickupSpell` last put on the cursor. Spells from the pet's spellbook are refused with a note in the chat, because every query of a button (tooltip, cooldown, range, casting) goes to your own spellbook.
|
||||||
|
|
||||||
**Right-click spell (optional).** Each button can carry a second spell for **right click** (Flash Heal left, Greater Heal right, say), which doubles the density without adding buttons. This is off by default and is enabled only through the switch on the *Buttons* tab. When on, a second column appears in the assignment and a small icon in the bottom-right corner of every button shows its right-click spell; the tooltip lists it as well. Switching it off keeps the assignments, it just stops the buttons from reacting to right click.
|
**Right-click spell (optional).** Each button can carry a second spell for **right click** (Flash Heal left, Greater Heal right, say), which doubles the density without adding buttons. This is off by default and is enabled only through the switch on the *Buttons* tab. When on, a second column appears in the assignment and a small icon in the bottom-right corner of every button shows its right-click spell; the tooltip lists it as well. Switching it off keeps the assignments, it just stops the buttons from reacting to right click.
|
||||||
|
|
||||||
**Smart Healing (off by default).** With *Smart Healing* on, a click casts the lowest rank of the assigned spell whose expected heal covers the target's missing health, minus healing already on the way, plus the *Safety margin* (default 20 %). Expected heals come from the learned values of the prediction where available, otherwise from the tooltip average. It never goes above the rank you assigned, applies to direct heals only, and below 30 % health it always casts the assigned rank. **Heal over time spells are never downranked**, whatever the class: Renew, Rejuvenation, Regrowth, Tranquility, Lifebloom, Wild Growth, Riptide and Earth Shield always go out at the rank you assigned. A HoT spreads its healing over many seconds, so the health missing at the moment of the click says nothing about which rank fits, and a downranked HoT keeps ticking too weakly for its whole duration. Mixed spells such as Regrowth count as HoTs as well. Shields and buffs such as Fortitude are likewise cast as assigned, and a spell only qualifies at all if its tooltip describes a heal.
|
**Smart Healing (off by default).** With *Smart Healing* on, a click casts the lowest rank of the assigned spell whose expected heal covers the target's missing health, minus healing already on the way, plus the *Safety margin* (default 20 %). Expected heals come from the learned values of the prediction where available, otherwise from the tooltip average. It never goes above the rank you assigned, applies to single target direct heals only, and below 30 % health it always casts the assigned rank. **Group heals and spells with a cooldown are cast as assigned**: Prayer of Healing, Chain Heal, Binding Heal, Circle of Healing, Prayer of Mending, Holy Nova, Holy Shock and Lay on Hands (`FBSmartSkip`), plus any spell whose tooltip names a cooldown longer than the global one. The health missing on the one plate you clicked says nothing about what a whole group needs, and a small rank of a cooldown spell burns the full cooldown all the same. **Heal over time spells are never downranked**, whatever the class: Renew, Rejuvenation, Regrowth, Tranquility, Lifebloom, Wild Growth, Riptide and Earth Shield always go out at the rank you assigned. A HoT spreads its healing over many seconds, so the health missing at the moment of the click says nothing about which rank fits, and a downranked HoT keeps ticking too weakly for its whole duration. Mixed spells such as Regrowth count as HoTs as well. Shields and buffs such as Fortitude are likewise cast as assigned, and a spell only qualifies at all if its tooltip describes a heal.
|
||||||
|
|
||||||
|
**A running HoT does not count as incoming healing.** Only what lands right away is subtracted: direct heals and spells reported over HealComm, so one to three seconds out. The healing still owed by a ticking Renew stays out of it. Counting it in full would make the deficit look tiny and turn a Heal rank 4 into a Lesser Heal, although the target needs health now and not in a quarter of a minute. The HoT is still shown on the bar, it just does not take part in the rank decision.
|
||||||
|
|
||||||
**Heal chains (new in 1.4.4.3).** Downranking is not limited to the assigned spell. Within a *heal chain* the spell itself may change, so a click on Greater Heal can go out as Lesser Heal rank 3 when that covers the deficit. The chains hold the single-target direct heals of one class:
|
**Heal chains (new in 1.4.4.3).** Downranking is not limited to the assigned spell. Within a *heal chain* the spell itself may change, so a click on Greater Heal can go out as Lesser Heal rank 3 when that covers the deficit. The chains hold the single-target direct heals of one class:
|
||||||
|
|
||||||
@@ -129,9 +134,11 @@ Everything in the chain is a candidate, and the one with the smallest expected h
|
|||||||
|
|
||||||
The *Smartcross* switch on the *Buttons* tab turns chain switching off and on, `/fbp smartcross` does the same from chat. With it off, Smart Healing stays on the assigned spell and only lowers its rank, the way it worked before 1.4.4.3. The chains live in `FBHealChains` near the Smart Healing code and can be edited freely; spells you do not want swapped simply come out of the list. Downsides: the estimate ignores crits, and with burst damage or when you want to overheal on purpose (a tank before a big hit) the lower rank can fall short. Leave it off whenever overhealing is what you want. `/fbp debug` prints every decision, `/fbp` shows the state.
|
The *Smartcross* switch on the *Buttons* tab turns chain switching off and on, `/fbp smartcross` does the same from chat. With it off, Smart Healing stays on the assigned spell and only lowers its rank, the way it worked before 1.4.4.3. The chains live in `FBHealChains` near the Smart Healing code and can be edited freely; spells you do not want swapped simply come out of the list. Downsides: the estimate ignores crits, and with burst damage or when you want to overheal on purpose (a tank before a big hit) the lower rank can fall short. Leave it off whenever overhealing is what you want. `/fbp debug` prints every decision, `/fbp` shows the state.
|
||||||
|
|
||||||
**Cooldowns.** Every button shows the usual cooldown sweep for its spell. The global cooldown is not shown (`FBCD_MIN_DURATION`). Option *Cooldowns on buttons*.
|
**Cooldowns.** Every button shows the usual cooldown sweep for its spell, the global cooldown included: after every cast you watch the short wait run out on all buttons, the way the action bars do it.
|
||||||
|
|
||||||
**HoT and shield timers.** The button of a spell shows, for its unit, the remaining seconds of your own HoT (green) or shield (blue) of that spell. When Power Word: Shield is used up, the same button shows Weakened Soul in red until the target can be shielded again. The left-click spell is checked first, then the right-click spell. Only your own effects are tracked. Option *HoT and shield timers*.
|
What the global cooldown must never do is darken the icons. While it runs, the client reports every spell as unusable, so taken literally all buttons would go grey for a second and a half and then snap back to bright after every single cast. That is why the two are handled by separate thresholds: `FBCD_SHOW_MIN` (0) decides from which length the sweep runs, `FBCD_MIN_DURATION` (2) the length up to which a cooldown is not treated as a reason to darken a button. Setting `FBCD_SHOW_MIN` to 2 leaves the global cooldown out of the display again. Option *Cooldowns on buttons*.
|
||||||
|
|
||||||
|
**HoT and shield timers.** The button of a spell shows, for its unit, the remaining seconds of your own HoT (green) or shield (blue) of that spell. When Power Word: Shield is used up, the same button shows Weakened Soul in red until the target can be shielded again. The left-click spell is checked first, then the right-click spell. Only your own effects are tracked: a HoT that the addon only sees as a buff gets its timer once your first tick of it shows up in the combat log, and shield and Weakened Soul follow shields you cast through the Heal Box buttons, since a shield from the action bar cannot be told apart from another priest's (see [Heal over time](#heal-over-time) and [Absorb shields](#absorb-shields)). Option *HoT and shield timers*.
|
||||||
|
|
||||||
**Buff icons left of the bar.** Buffs with a duration that sit on your buttons (Fortitude, Divine Spirit, Fear Ward, Inner Fire, left or right click) appear as small 8 px icons on the **outer left side** of the plate while the buff is up, stacked two high: the first at the top next to the plate, the second below it, the third at the top of the next column to the left, and so on. The icon visually tracks remaining time in **32 vertical steps** (`FBBUFFICON_STEPS = 32`): as time runs out, the icon turns black and white and shades darker from top to bottom. Fresh buff: fully coloured. Half time left: top half grey. A quarter left: top three quarters grey. This 32-step vertical wipe provides much higher visual precision (e.g. updating approximately every 56 seconds for a 30-minute buff instead of every 7.5 minutes) while saving performance by using a single dynamically cropped desaturated overlay (`ic.qTex`) and dark wash (`ic.wTex`). Hovering an icon shows the buff name and the remaining time. The remaining time is exact on yourself (buff API, re-read on every `PLAYER_AURAS_CHANGED` and once a second in between, because a refresh of a running buff fires no event; a recast therefore resets the clock) and counted from your own cast on others; a buff cast by someone else stays fully coloured (time unknown). Up to six icons per plate (`FBBUFFICON_MAX`). Option *Buff icons left of the bar*, on by default. Raid cells show the same duration icons outside their left edge at 6 px in a 3 by 4 grid (twelve slots, columns filling from the cell outward), and the grid reserves the room for them between the groups. After a `/reload` or a group change the addon scans all units once, so existing buffs show up without waiting for an aura event. `/fbp buffs` lists the tracked buffs and their state on you.
|
**Buff icons left of the bar.** Buffs with a duration that sit on your buttons (Fortitude, Divine Spirit, Fear Ward, Inner Fire, left or right click) appear as small 8 px icons on the **outer left side** of the plate while the buff is up, stacked two high: the first at the top next to the plate, the second below it, the third at the top of the next column to the left, and so on. The icon visually tracks remaining time in **32 vertical steps** (`FBBUFFICON_STEPS = 32`): as time runs out, the icon turns black and white and shades darker from top to bottom. Fresh buff: fully coloured. Half time left: top half grey. A quarter left: top three quarters grey. This 32-step vertical wipe provides much higher visual precision (e.g. updating approximately every 56 seconds for a 30-minute buff instead of every 7.5 minutes) while saving performance by using a single dynamically cropped desaturated overlay (`ic.qTex`) and dark wash (`ic.wTex`). Hovering an icon shows the buff name and the remaining time. The remaining time is exact on yourself (buff API, re-read on every `PLAYER_AURAS_CHANGED` and once a second in between, because a refresh of a running buff fires no event; a recast therefore resets the clock) and counted from your own cast on others; a buff cast by someone else stays fully coloured (time unknown). Up to six icons per plate (`FBBUFFICON_MAX`). Option *Buff icons left of the bar*, on by default. Raid cells show the same duration icons outside their left edge at 6 px in a 3 by 4 grid (twelve slots, columns filling from the cell outward), and the grid reserves the room for them between the groups. After a `/reload` or a group change the addon scans all units once, so existing buffs show up without waiting for an aura event. `/fbp buffs` lists the tracked buffs and their state on you.
|
||||||
|
|
||||||
@@ -191,7 +198,7 @@ All raid settings live in `HealBox.Raid`. `/fbp raidtest 20`, `/fbp raidtest 40`
|
|||||||
|
|
||||||
### How it hooks in
|
### How it hooks in
|
||||||
|
|
||||||
The core exposes `FBHealBox_RegisterHook(name, fn)` and runs the hooks at fixed points: `Defaults`, `SyncOptions`, `ApplyLocale`, `UpdateNames`, `RefreshAllBars`, `ButtonsChanged`, `ActiveToggle`, `Status`, `Slash`, `Loaded`, `Aggro`, `SpellTimers` and `Cooldowns`. `FBHealBox_AddOptionsTab(labelKey)` adds a tab to the options window. The raid module registers its roster refresh on `UpdateNames`, its cell refresh on `RefreshAllBars` (so the heal prediction reaches raid cells for free), and its slash commands on `Slash`. Raid units are added to `FBPredictUnits`, which lets HoT and shield confirmation via `UNIT_AURA` work for `raid1` to `raid40`. Pets are not shown in raid mode.
|
The core exposes `FBHealBox_RegisterHook(name, fn)` and runs the hooks at fixed points: `Defaults`, `SyncOptions`, `ApplyLocale`, `Loaded`, `Status`, `Slash`, `Suppress`, `ActiveToggle`, `UpdateNames`, `RaidRoster`, `RefreshAllBars`, `RefreshNames`, `ButtonsChanged`, `ButtonStates`, `Cooldowns`, `SpellTimers`, `BuffIcons` and `Aggro`. Every hook runs protected: an error in one module is reported once in the chat (further ones with `/fbp debug`) and stops neither the core nor the other modules. `FBHealBox_AddOptionsTab(labelKey)` adds a tab to the options window, `FBHealBox_ExtrasSection(height)` hands out a section of the shared *Extras* tab, and `FBHealBox_CreateSlider(…)` builds a slider bound to a settings table. The raid module registers its roster refresh on `UpdateNames`, its cell refresh on `RefreshAllBars` and `RefreshNames` (so the heal prediction reaches raid cells for free, and only the cells whose unit changed are redrawn), and its slash commands on `Slash`. After every rebuild of the grid it fires `RaidRoster`, which the mana ticker uses to find your cell again. Raid units are added to `FBPredictUnits`, which lets HoT and shield confirmation via `UNIT_AURA` work for `raid1` to `raid40`. Pets are not shown in raid mode.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -213,7 +220,7 @@ There is no API for this in 1.12, so the module watches `UNIT_MANA` for the play
|
|||||||
|Tick offset|0.0 to 0.5 s. Runs the spark earlier to compensate latency if it arrives late compared to your mana jumps|
|
|Tick offset|0.0 to 0.5 s. Runs the spark earlier to compensate latency if it arrives late compared to your mana jumps|
|
||||||
|Spark width|1 to 4 px|
|
|Spark width|1 to 4 px|
|
||||||
|
|
||||||
`/fbp ticker` toggles the ticker; `/fbp` reports whether the grid is synced, the time to the next tick and a running five-second rule. Settings live in `HealBox.Ticker`. The ticker shares the *Extras* tab with Smart Damage.
|
`/fbp ticker` toggles the ticker; `/fbp` reports whether the grid is synced, the time to the next tick and a running five-second rule. Settings live in `HealBox.Ticker`. The ticker shares the *Extras* tab with Smart Damage: the core manages the tab, each module gets its own section, and either module works without the other.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -223,7 +230,7 @@ Rank selection for **attack spells on any action bar**, in its own module `FBHea
|
|||||||
|
|
||||||
### How it works
|
### How it works
|
||||||
|
|
||||||
Every bar and key binding ends in `UseAction(slot)`. The module hooks that function, reads the spell and rank in the slot from a tooltip scan, and decides. Damage per rank is the **minimum** damage from the spell's tooltip ("86 to 98 Holy damage"), raised by the smallest full hit you have actually landed with that rank (crits and partial resists are not counted). A rank qualifies if its minimum damage covers the target's remaining health plus the *Safety margin* (default 20 %). Macros with `/cast` are not affected.
|
Every bar and key binding ends in `UseAction(slot)`. The module hooks that function, reads the spell and rank in the slot from a tooltip scan, and decides. Damage per rank is the **minimum** damage from the spell's tooltip ("86 to 98 Holy damage"), raised by the bonus that your smallest normal hit with that rank proves (crits and partial resists are not counted): every hit is at most the tooltip's maximum plus your bonus, so the minimum is at least the tooltip's minimum plus *smallest hit minus maximum*. The smallest hit, because boosts such as Curse of Shadow or Power Infusion only raise some hits; a single boosted hit must not lift the value for good. Up to 1.4.6 the smallest hit itself counted as the minimum, and after a single high roll the chosen rank could fall short. A rank qualifies if its minimum damage covers the target's remaining health plus the *Safety margin* (default 20 %). Macros with `/cast` are not affected.
|
||||||
|
|
||||||
The target's remaining health comes from the first source that answers:
|
The target's remaining health comes from the first source that answers:
|
||||||
|
|
||||||
@@ -234,7 +241,7 @@ The target's remaining health comes from the first source that answers:
|
|||||||
|MobInfo-2|`MobHealth_GetTargetCurHP()` knows the mob|as good as that addon|
|
|MobInfo-2|`MobHealth_GetTargetCurHP()` knows the mob|as good as that addon|
|
||||||
|Own estimate|The addon has fought this mob type (name and level) before|see below|
|
|Own estimate|The addon has fought this mob type (name and level) before|see below|
|
||||||
|
|
||||||
**Own estimate.** On percent-only servers the addon learns *health points per percent* for each mob type: it adds up the damage it can see in the combat log (yours, your party's, pets') and divides by the drop in the target's percentage, but only once the drop reaches 3 % to keep the 1 % rounding out of it. Of all measurements the **highest** is kept, because damage from raid members outside your party is invisible and would otherwise pull the estimate down; erring high only costs a slightly bigger rank. The remaining health is then the upper edge of the current percent times that value. The estimate is saved per character in `HealBox.MobHP` and improves with every fight; until a type has been measured, Smart Damage leaves that target alone.
|
**Own estimate.** On percent-only servers the addon learns *health points per percent* for each mob type: it adds up the damage it can see in the combat log (yours, your party's and pets', and that of other friendly players, damage over time included) and divides by the drop in the target's percentage, but only once the drop reaches 3 % to keep the 1 % rounding out of it. Of all measurements the **highest** is kept, because damage the combat log does not show (from players out of range, say) would otherwise pull the estimate down; erring high only costs a slightly bigger rank. In a raid the addon neither measures nor uses the estimate: the combat log does not show all damage of the other groups there, so every measurement would come out too low. Up to 1.4.6 it measured in raids too, and for mob types you only meet there no clean measurement existed; such values from older versions are therefore ignored in raids. Real values, MobHealth3 and MobInfo-2 still count there. The remaining health is then the upper edge of the current percent times that value. The estimate is saved per character in `HealBox.MobHP` and improves with every fight; until a type has been measured, Smart Damage leaves that target alone. At most `FBDMG_MOBHP_MAX` (400) mob types are kept; beyond that, the ones not seen for the longest time are dropped.
|
||||||
|
|
||||||
### Section *Smart Damage* on the *Extras* tab
|
### Section *Smart Damage* on the *Extras* tab
|
||||||
|
|
||||||
@@ -247,6 +254,8 @@ The target's remaining health comes from the first source that answers:
|
|||||||
|
|
||||||
Spells per class: Priest Smite, Holy Fire, Mind Blast; Druid Wrath, Starfire, Moonfire; Shaman Lightning Bolt, Chain Lightning, Earth/Flame/Frost Shock; Paladin Holy Shock, Hammer of Wrath, Exorcism, Holy Wrath; Mage Fireball, Frostbolt, Fire Blast, Scorch, Pyroblast; Warlock Shadow Bolt, Searing Pain, Immolate, Soul Fire, Conflagrate; Hunter Arcane Shot, Aimed Shot (list `FBDamageSpells`). `/fbp damage` toggles, `/fbp debug` logs every decision with the health source used. Note for hunters: the addon does not load for that class, so Smart Damage only runs after `/fbp forceload`, see [Which classes it loads for](#which-classes-it-loads-for).
|
Spells per class: Priest Smite, Holy Fire, Mind Blast; Druid Wrath, Starfire, Moonfire; Shaman Lightning Bolt, Chain Lightning, Earth/Flame/Frost Shock; Paladin Holy Shock, Hammer of Wrath, Exorcism, Holy Wrath; Mage Fireball, Frostbolt, Fire Blast, Scorch, Pyroblast; Warlock Shadow Bolt, Searing Pain, Immolate, Soul Fire, Conflagrate; Hunter Arcane Shot, Aimed Shot (list `FBDamageSpells`). `/fbp damage` toggles, `/fbp debug` logs every decision with the health source used. Note for hunters: the addon does not load for that class, so Smart Damage only runs after `/fbp forceload`, see [Which classes it loads for](#which-classes-it-loads-for).
|
||||||
|
|
||||||
|
While Smart Damage is off, the module listens neither to the combat log nor to the target's health, and it reads the attack spells from the spellbook only when you open the options.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Options window
|
## Options window
|
||||||
@@ -257,9 +266,9 @@ Opened through the **minimap button**:
|
|||||||
|-|-|
|
|-|-|
|
||||||
|Left click|Toggle the options window|
|
|Left click|Toggle the options window|
|
||||||
|Shift + left click|Show/hide the entire display|
|
|Shift + left click|Show/hide the entire display|
|
||||||
|Hold right and drag|Move the minimap button|
|
|Hold right and drag|Move the minimap button; the spot is saved per character|
|
||||||
|
|
||||||
The window has two tabs.
|
The window has two tabs of its own, *Buttons* and *General*. The modules add *Raid mode* and *Extras* (mana ticker and Smart Damage).
|
||||||
|
|
||||||
### Tab *Buttons*
|
### Tab *Buttons*
|
||||||
|
|
||||||
@@ -283,9 +292,11 @@ The window has two tabs.
|
|||||||
|
|
||||||
**Default party frames**: instead of the addon's own plates, the buttons attach to Blizzard's default party frames (`PartyMemberFrameN`); pet buttons attach to `PetFrame` and `PartyMemberFrameNPetFrame`. The addon's name plates and bars are hidden; the heal prediction keeps working invisibly.
|
**Default party frames**: instead of the addon's own plates, the buttons attach to Blizzard's default party frames (`PartyMemberFrameN`); pet buttons attach to `PetFrame` and `PartyMemberFrameNPetFrame`. The addon's name plates and bars are hidden; the heal prediction keeps working invisibly.
|
||||||
|
|
||||||
|
**Bar background**: how solid the area behind the bars is, 0 to 100 per cent in steps of 5. Default 0, which is the old look: where health is missing, the game world shows through the plate. Turn it up and a quiet dark grey surface (`FBBAR_BG_COLOR`) sits behind the bars, so the green of the health bar stands on a fixed background instead of on grass, sky or stone. At 100 the plate is opaque. Suggested by a user who found the see-through bar hard to read, and it is worth a try for anyone playing on a bright screen or in a cluttered zone.
|
||||||
|
|
||||||
**Mana bar**: shows or hides the mana strip inside the health bar. On by default.
|
**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.
|
**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 immediately brings back the frames the addon hid itself; frames another addon has hidden stay hidden. A class the addon does not load for gets them back too. Should saved settings have both options on (from an old version, or edited by hand), the attach mode wins at login.
|
||||||
|
|
||||||
**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 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.
|
||||||
|
|
||||||
@@ -358,6 +369,8 @@ The heart of the addon. Three independent sources feed the bars.
|
|||||||
|
|
||||||
`SPELLCAST_START` provides the spell name and the cast time in milliseconds, regardless of whether the cast came from a Heal Box button, the action bar or a macro. No hook on `CastSpellByName` is required. The preview disappears on `SPELLCAST_STOP`, `_FAILED` and `_INTERRUPTED`; pushback (`SPELLCAST_DELAYED`) extends it.
|
`SPELLCAST_START` provides the spell name and the cast time in milliseconds, regardless of whether the cast came from a Heal Box button, the action bar or a macro. No hook on `CastSpellByName` is required. The preview disappears on `SPELLCAST_STOP`, `_FAILED` and `_INTERRUPTED`; pushback (`SPELLCAST_DELAYED`) extends it.
|
||||||
|
|
||||||
|
The target is the unit of the Heal Box button you clicked, provided the same spell starts within `FBPREDICT_CLICK_TIME` (2 seconds) after the click; a click made while another spell is still being cast waits for the next start, which also suits the spell queue of client mods. A cast from the action bar or a macro goes to your friendly target, otherwise to yourself. A click counts for one cast only: once its spell has started, gone through or failed, the next cast no longer belongs to it. An error message or a failed cast always answers the latest attempt. To know which one that is, the addon counts every attempt, including those from the action bar, macros and the spellbook; for that it hooks `UseAction`, `CastSpellByName` and `CastSpell`, counts, and passes everything on unchanged. Up to 1.4.6 the target of a click stayed valid for two seconds and its rank for three, for every following cast, even after a failed click.
|
||||||
|
|
||||||
Instants deliberately get **no** prediction: the healing has landed before a bar could show it.
|
Instants deliberately get **no** prediction: the healing has landed before a bar could show it.
|
||||||
|
|
||||||
### Heal over time
|
### Heal over time
|
||||||
@@ -365,11 +378,11 @@ Instants deliberately get **no** prediction: the healing has landed before a bar
|
|||||||
`UnitBuff()` reports no remaining duration for other units, so the addon keeps its own books:
|
`UnitBuff()` reports no remaining duration for other units, so the addon keeps its own books:
|
||||||
|
|
||||||
1. The button registers the cast including target and rank.
|
1. The button registers the cast including target and rank.
|
||||||
2. `UNIT_AURA` confirms the application by comparing the **buff texture** with the spellbook icon (locale independent, no tooltip scan per event).
|
2. Once the cast has gone through (`SPELLCAST_STOP`), `UNIT_AURA` confirms the application by comparing the **buff texture** with the spellbook icon (locale independent, no tooltip scan per event). A click that fails (out of range, no line of sight, global cooldown) confirms nothing, so another healer's HoT or shield on the same target does not pass as yours.
|
||||||
3. What is shown is `remaining ticks × healing per tick`, with the remaining ticks derived from `(expiry − GetTime()) / interval`. The bar therefore counts down tick by tick.
|
3. What is shown is `remaining ticks × healing per tick`, with the remaining ticks derived from `(expiry − GetTime()) / interval`. The bar therefore counts down tick by tick.
|
||||||
4. If the buff disappears early (dispel, death, overwritten), the display is gone immediately.
|
4. If the buff disappears early (dispel, death, overwritten), the display is gone immediately.
|
||||||
|
|
||||||
HoTs cast from the action bar are recognised as well, then with the highest known rank; the first combat log tick straightens the value out.
|
HoTs the addon only sees as a buff (cast from the action bar, from a macro, or by another healer with the same spell) are noted **provisionally** with your highest known rank. They count neither in the prediction nor as a button timer until your own first tick arrives (`… from your Renew.`), which confirms the HoT and straightens out the value. If none of yours arrives within one tick interval plus `FBPREDICT_HOT_CONFIRM_GRACE` (1.5) seconds, the HoT belongs to someone else: it is dropped and not picked up again for as long as that buff stays. If a tick of yours arrives for a HoT that is not being tracked at all, it is added on the spot with one interval less to run. `/fbp` marks provisional HoTs with `(?)`. Up to 1.4.6 every HoT seen this way counted as yours, with your highest rank and its full duration.
|
||||||
|
|
||||||
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).
|
||||||
|
|
||||||
@@ -377,6 +390,8 @@ The tick interval cannot be read from the tooltip in Vanilla and therefore lives
|
|||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
|
The cast time comes from the tooltip of each rank, and so do range and cooldown (`/fbp` lists all three per spell). Ranks learned below level 20 only get part of the bonus, just as in the game: 3.75 per cent less for every level below 20, so Lesser Heal rank 3, learned at level 10, gets 62.5 per cent. The tooltip does not say at which level a rank is learned, so these ranks are listed in `FBRankLearnLevel`. Without that cut Smart Healing would think small ranks with a lot of +healing far stronger than they are.
|
||||||
|
|
||||||
`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.
|
`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
|
||||||
@@ -387,6 +402,8 @@ If you absorb more than the tooltip allows (heal gear), the maximum is corrected
|
|||||||
|
|
||||||
Fully absorbed hits report no number in Vanilla. The remaining value then stands until the buff drops and the display is cleared. Likewise absorbs on group members only count as far as the combat log shows them at all; the aura check catches the drift at the end.
|
Fully absorbed hits report no number in Vanilla. The remaining value then stands until the buff drops and the display is cleared. Likewise absorbs on group members only count as far as the combat log shows them at all; the aura check catches the drift at the end.
|
||||||
|
|
||||||
|
A shield the addon only sees as a buff (another priest's, or yours from the action bar) is shown with its tooltip value, because nobody knows the caster's gear; your learned value only applies to shields cast through the Heal Box buttons. Those are also the only ones that get the button timer and start **Weakened Soul**. Weakened Soul runs in a table of its own for `FBWEAKENED_SOUL_SEC` (15) seconds, independent of the shield, so it stays visible when the shield breaks. Up to 1.4.6 it was worked out from the shield entry, which is removed exactly when the shield breaks, so it hardly ever showed.
|
||||||
|
|
||||||
### Self-correction and learned values
|
### Self-correction and learned values
|
||||||
|
|
||||||
Tooltips in 1.12 only provide base values **without** +healing, and there is no API for spell power. The combat log, on the other hand, tells the truth:
|
Tooltips in 1.12 only provide base values **without** +healing, and there is no API for spell power. The combat log, on the other hand, tells the truth:
|
||||||
@@ -399,7 +416,7 @@ Tooltips in 1.12 only provide base values **without** +healing, and there is no
|
|||||||
|
|
||||||
All of it lands per spell **and rank** in `HealBox.PredictMemory` and survives logout.
|
All of it lands per spell **and rank** in `HealBox.PredictMemory` and survives logout.
|
||||||
|
|
||||||
Two safeguards keep that memory clean. **Crits are not learned**: the crit wording makes the spell name come through the pattern as "Flash Heal critically", which is in no watch list. And learning only happens with a **confirmed rank**, that is on casts through the Heal Box buttons; otherwise a rank 3 cast from the action bar would be attributed to the maximum rank and drag the prediction down. The live display still corrects itself either way; only the persistent memory is protected.
|
Two safeguards keep that memory clean. **Crits are not learned**: the crit wording makes the spell name come through the pattern as "Flash Heal critically", which is in no watch list. And learning only happens with a **confirmed rank**, that is on casts through the Heal Box buttons; otherwise a rank 3 cast from the action bar would be attributed to the maximum rank and drag the prediction down. The live display still corrects itself either way; only the persistent memory is protected. The heal usually appears in the combat log only after the cast has ended, so a finished cast waits `FBPREDICT_CLICK_TIME` (2) seconds for its line. Up to 1.4.6 only a cast still running was matched, and direct heals were hardly ever learned.
|
||||||
|
|
||||||
What a spell can do is decided by its own tooltip, and a spell may be several things at once. Regrowth, for instance, provides an instant portion *and* a HoT, and is treated as both.
|
What a spell can do is decided by its own tooltip, and a spell may be several things at once. Regrowth, for instance, provides an instant portion *and* a HoT, and is treated as both.
|
||||||
|
|
||||||
@@ -418,11 +435,11 @@ HealComm-1.0 broadcasts plain text through `SendAddonMessage` with the prefix `H
|
|||||||
|`GrpHealstop` · `GrpHealdelay/<ms>/`|Same for group heals|
|
|`GrpHealstop` · `GrpHealdelay/<ms>/`|Same for group heals|
|
||||||
|`Renew` · `Reju` · `Regr` `/<target>/<duration>/`|HoT applied|
|
|`Renew` · `Reju` · `Regr` `/<target>/<duration>/`|HoT applied|
|
||||||
|
|
||||||
Messages go to the raid, otherwise to the party, otherwise nowhere. The amounts are the self-corrected combat log values, so arguably more accurate than what a real HealComm estimates with ItemBonusLib.
|
Messages go to the raid, otherwise to the party, otherwise nowhere. In a battleground they go over the `BATTLEGROUND` channel, as HealComm-1.0 does it, because `RAID` reaches nobody there. The amounts are the self-corrected combat log values, so arguably more accurate than what a real HealComm estimates with ItemBonusLib.
|
||||||
|
|
||||||
A few details: on a successful cast end **no** `Healstop` is sent; HealComm receivers expire the entry themselves at cast time. Prayer of Healing correctly goes out as `GrpHeal` with every target in range. And a HoT cast from the action bar is reported after the fact on the first own combat log tick, with the duration still remaining, because only "… from **your** Renew" proves that it is yours.
|
A few details: on a successful cast end **no** `Healstop` is sent; HealComm receivers expire the entry themselves at cast time. Prayer of Healing correctly goes out as `GrpHeal` with every target in range. And a HoT cast from the action bar is reported after the fact on the first own combat log tick, with the duration still remaining, because only "… from **your** Renew" proves that it is yours. Incoming commands are read regardless of upper and lower case; pfUI, for example, sends `HealStop`.
|
||||||
|
|
||||||
On receive, your own messages are filtered by sender name, and since HealComm stores incoming heals per caster nothing can double up, not even when a real HealComm is broadcasting alongside. HoT messages carry only durations and no amounts; HealComm does not count them in its own `getHeal`, and neither does this addon.
|
On receive, your own messages are filtered by sender name, and since HealComm stores incoming heals per caster nothing can double up, not even when a real HealComm is broadcasting alongside. HoT messages carry only durations and no amounts; HealComm does not count them in its own `getHeal`, and neither does this addon. Values from other addons are capped: amounts at `FBCOMM_MAX_AMOUNT` (20000), cast times and delays at `FBCOMM_MAX_CAST_MS` (10 seconds), so a broken message cannot fill a bar for minutes.
|
||||||
|
|
||||||
**The protocol knows nothing about absorb shields**: those stay local.
|
**The protocol knows nothing about absorb shields**: those stay local.
|
||||||
|
|
||||||
@@ -467,6 +484,7 @@ Everything lives in the `HealBox` table, saved **per character**:
|
|||||||
|`ButtonSpacing`|Gap between the buttons in px (0 to 20)|
|
|`ButtonSpacing`|Gap between the buttons in px (0 to 20)|
|
||||||
|`RowSpacing`|Gap between the plates in px (0 to 20)|
|
|`RowSpacing`|Gap between the plates in px (0 to 20)|
|
||||||
|`ManaBar`|1 = mana strip on, 0 = off|
|
|`ManaBar`|1 = mana strip on, 0 = off|
|
||||||
|
|`BarBG`|Opacity of the bar background in per cent, 0 to 100. 0 (default) keeps the see-through look|
|
||||||
|`ShowPets`|1 = pet plates on, 0 = off|
|
|`ShowPets`|1 = pet plates on, 0 = off|
|
||||||
|`SpellChoiceR[1..10]`|Cast string per button for right click|
|
|`SpellChoiceR[1..10]`|Cast string per button for right click|
|
||||||
|`RightClick`|1 = right-click spell on, 0 = off (default)|
|
|`RightClick`|1 = right-click spell on, 0 = off (default)|
|
||||||
@@ -484,12 +502,15 @@ Everything lives in the `HealBox` table, saved **per character**:
|
|||||||
|`WatchBuff`|Spell name of the buff watch, or nil|
|
|`WatchBuff`|Spell name of the buff watch, or nil|
|
||||||
|`BuffWatchPets`|1 = buff watch also on pets, 0 = players only (default)|
|
|`BuffWatchPets`|1 = buff watch also on pets, 0 = players only (default)|
|
||||||
|`PosX` · `PosY`|Top-left corner of the player plate in screen pixels|
|
|`PosX` · `PosY`|Top-left corner of the player plate in screen pixels|
|
||||||
|
|`MinimapPos`|Position of the minimap button as an offset from the minimap centre, saved once you drag it with the right mouse button. Without it the button keeps its old spot|
|
||||||
|`Ticker`|Sub-table with the mana ticker settings (see [Mana ticker](#mana-ticker))|
|
|`Ticker`|Sub-table with the mana ticker settings (see [Mana ticker](#mana-ticker))|
|
||||||
|`Damage`|Sub-table with the Smart Damage settings; `MobHP` and `DmgMemory` hold the learned mob health and minimum damage values (see [Smart Damage](#smart-damage))|
|
|`Damage`|Sub-table with the Smart Damage settings (see [Smart Damage](#smart-damage))|
|
||||||
|
|`MobHP`|Smart Damage's learned health per percent for each mob type (`Name:Level`), at most `FBDMG_MOBHP_MAX` entries|
|
||||||
|
|`DmgMemory`|Smart Damage's smallest normal hit per spell and rank, the basis of the learned minimum damage|
|
||||||
|`Raid`|Sub-table with every raid-mode setting (see [Raid mode](#raid-mode)), including `PosX` / `PosY` of the grid|
|
|`Raid`|Sub-table with every raid-mode setting (see [Raid mode](#raid-mode)), including `PosX` / `PosY` of the grid|
|
||||||
|`PredictMemory`|Learned heal values per spell and rank|
|
|`PredictMemory`|Learned heal values per spell and rank|
|
||||||
|
|
||||||
Missing keys, for example in an old `HealBox` table from 1.4, are filled in by `FBHealBox_ApplyDefaults()` on load. Test mode is deliberately **not** saved.
|
Missing keys, for example in an old `HealBox` table from 1.4, are filled in by `FBHealBox_ApplyDefaults()` on load, from the one defaults table `FBHealBoxDefaults`. Test mode is deliberately **not** saved.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -499,11 +520,12 @@ Every knob is a global at the top of its own section and can be changed without
|
|||||||
|
|
||||||
|Constant|Default|Effect|
|
|Constant|Default|Effect|
|
||||||
|-|-|-|
|
|-|-|-|
|
||||||
|`LowHP` · `VeryLowHP`|0.6 · 0.3|Thresholds for yellow and red|
|
|`FBLowHP` · `FBVeryLowHP`|0.6 · 0.3|Thresholds for yellow and red|
|
||||||
|`NamePlateWidth` · `NamePlateHeight`|120 · 28|Size of one plate|
|
|`FBNamePlateWidth` · `FBNamePlateHeight`|120 · 28|Size of one plate|
|
||||||
|`FBMANA_BAR_HEIGHT`|5|Height of the mana strip in px|
|
|`FBMANA_BAR_HEIGHT`|5|Height of the mana strip in px|
|
||||||
|`FBMANA_BAR_COLOR`|`{0.15, 0.4, 1, 1}`|Colour of the mana strip|
|
|`FBMANA_BAR_COLOR`|`{0.15, 0.4, 1, 1}`|Colour of the mana strip|
|
||||||
|`FBMANA_BG_ALPHA`|0.35|Dark strip behind missing mana (0 = off)|
|
|`FBMANA_BG_ALPHA`|0.35|Dark strip behind missing mana (0 = off)|
|
||||||
|
|`FBBAR_BG_COLOR`|0.15 · 0.15 · 0.15|Shade of the bar background; how solid it sits is the `BarBG` option|
|
||||||
|`FBPET_NAME_COLOR`|`{0.75, 0.85, 1, 1}`|Name colour on pet plates|
|
|`FBPET_NAME_COLOR`|`{0.75, 0.85, 1, 1}`|Name colour on pet plates|
|
||||||
|`FBPET_INDENT`|12|Indent (and width reduction) of pet plates|
|
|`FBPET_INDENT`|12|Indent (and width reduction) of pet plates|
|
||||||
|`FBPET_ICON` · `FBPET_ICON_SIZE`|footprint · 12|Paw icon in front of pet names|
|
|`FBPET_ICON` · `FBPET_ICON_SIZE`|footprint · 12|Paw icon in front of pet names|
|
||||||
@@ -511,11 +533,13 @@ Every knob is a global at the top of its own section and can be changed without
|
|||||||
|`FBLOS_ICON` · `FBLOS_ICON_SIZE`|Blind icon · 12|Line-of-sight badge|
|
|`FBLOS_ICON` · `FBLOS_ICON_SIZE`|Blind icon · 12|Line-of-sight badge|
|
||||||
|`FBLOS_ICON_X` · `FBLOS_ICON_Y`|-3 · 3|Badge offset from the plate's top-left corner|
|
|`FBLOS_ICON_X` · `FBLOS_ICON_Y`|-3 · 3|Badge offset from the plate's top-left corner|
|
||||||
|`FBLOS_TIMEOUT`|8|Seconds a line-of-sight error stays marked without UnitXP|
|
|`FBLOS_TIMEOUT`|8|Seconds a line-of-sight error stays marked without UnitXP|
|
||||||
|
|`FBLOS_ERROR_WINDOW`|1.0|Seconds after the click (or after the end of the cast) in which a line of sight error still belongs to the clicked unit|
|
||||||
|`FBNAME_WIDTH_FULL` · `FBNAME_WIDTH_ICON`|78 · 60|Width of the name box without / with a visible debuff icon|
|
|`FBNAME_WIDTH_FULL` · `FBNAME_WIDTH_ICON`|78 · 60|Width of the name box without / with a visible debuff icon|
|
||||||
|`FBRANGE_ALPHA` · `FBRANGE_INTERVAL`|0.5 · 0.5|Faded opacity and check interval of the range fading|
|
|`FBRANGE_ALPHA` · `FBRANGE_INTERVAL`|0.5 · 0.5|Faded opacity and check interval of the range fading|
|
||||||
|`FBBUFF_MISSING_COLOR`|`{1, 0.5, 0, 1}`|Border colour when the watched buff is missing|
|
|`FBBUFF_MISSING_COLOR`|`{1, 0.5, 0, 1}`|Border colour when the watched buff is missing|
|
||||||
|`FBAGGRO_COLOR`|`{1, 0.15, 0.15, 1}`|Border colour for the attacked member|
|
|`FBAGGRO_COLOR`|`{1, 0.15, 0.15, 1}`|Border colour for the attacked member|
|
||||||
|`FBCD_MIN_DURATION`|2|Cooldowns shorter than this (the global cooldown) are not shown|
|
|`FBCD_MIN_DURATION`|2|Length of the global cooldown: a cooldown up to this length does not darken a button|
|
||||||
|
|`FBCD_SHOW_MIN`|0|From which length the cooldown sweep runs. 0 shows every cooldown including the global one, 2 leaves it out|
|
||||||
|`FBTIMER_COLOR_HOT` · `_SHIELD` · `_WS`|green · blue · red|Timer colours on the buttons|
|
|`FBTIMER_COLOR_HOT` · `_SHIELD` · `_WS`|green · blue · red|Timer colours on the buttons|
|
||||||
|`FBBUFFICON_SIZE` · `FBBUFFICON_GAP` · `FBBUFFICON_MAX` · `FBBUFFICON_XOFF`|8 · 1 · 6 · -2|Buff icons left of the plate|
|
|`FBBUFFICON_SIZE` · `FBBUFFICON_GAP` · `FBBUFFICON_MAX` · `FBBUFFICON_XOFF`|8 · 1 · 6 · -2|Buff icons left of the plate|
|
||||||
|`FBBUFFICON_STEPS` · `FBBUFFICON_GREY`|32 · 0.30|Duration progress steps (32) and grey tint when client cannot desaturate|
|
|`FBBUFFICON_STEPS` · `FBBUFFICON_GREY`|32 · 0.30|Duration progress steps (32) and grey tint when client cannot desaturate|
|
||||||
@@ -525,23 +549,31 @@ Every knob is a global at the top of its own section and can be changed without
|
|||||||
|`FBBuffWatchSpells` · `FBBuffAlternates`|(table)|Buffs offered per class, and which group version counts as the same|
|
|`FBBuffWatchSpells` · `FBBuffAlternates`|(table)|Buffs offered per class, and which group version counts as the same|
|
||||||
|`FBPartyUnit` · `FBLayoutOrder`|(table)|The ten slots and their display order|
|
|`FBPartyUnit` · `FBLayoutOrder`|(table)|The ten slots and their display order|
|
||||||
|`FBTestGhosts`|(table)|Names and values of the test-mode ghosts|
|
|`FBTestGhosts`|(table)|Names and values of the test-mode ghosts|
|
||||||
|`MaxButtonCount`|10|Maximum number of buttons|
|
|`FBMaxButtonCount`|10|Maximum number of buttons|
|
||||||
|`FBMENU_BTN_HEIGHT` · `FBMENU_ICON_SIZE`|17 · 16|Row height and icon size in the menu|
|
|`FBMENU_BTN_HEIGHT` · `FBMENU_ICON_SIZE`|17 · 16|Row height and icon size in the menu|
|
||||||
|`FBMENU_MOUSE_PAD`|14|Tolerance zone around the menus|
|
|`FBMENU_MOUSE_PAD`|14|Tolerance zone around the menus|
|
||||||
|`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_HOT_CONFIRM_GRACE`|1.5|Seconds after the first expected tick in which a HoT seen only as a buff may still be confirmed by a tick of yours; after that it counts as someone else's|
|
||||||
|`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|
|
|`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|
|
|`FBTICK_GEOM_STEP`|0.25|How often the ticker re-reads the bar size (the spark itself is drawn every frame)|
|
||||||
|`FBPREDICT_CONFIRM_TIME`|3.0|Time to wait for the aura confirmation|
|
|`FBPREDICT_CONFIRM_TIME`|3.0|Time to wait for the aura confirmation once the cast has gone through|
|
||||||
|`FBPREDICT_TARGET_TIME`|2.0|Lifetime of the remembered cast target|
|
|`FBPREDICT_CLICK_TIME`|2.0|Seconds in which the server's answer (spell start, cast end, error, heal in the combat log) still belongs to a click on a Heal Box button; with a cast time counted from the end of the cast|
|
||||||
|`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)|
|
|`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|
|
||||||
|
|`FBSmartSkip`|(table)|Group heals and cooldown spells that Smart Healing always casts as assigned (spells with a cooldown in their tooltip are left alone anyway)|
|
||||||
|
|`FBRankLearnLevel`|(table)|Learning level of the ranks below level 20, for the reduced share of +healing|
|
||||||
|`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`|
|
||||||
|`FBLocale`|`enUS`, `deDE`, `esES`, `frFR`, `itIT`|Every visible string, per language|
|
|`FBLocale`|`enUS`, `deDE`, `esES`, `frFR`, `itIT`|Every visible string, per language|
|
||||||
|
|`FBHealBoxDefaults`|(table)|Default of every setting; missing keys are filled in from here|
|
||||||
|
|`FBCOMM_MAX_AMOUNT` · `FBCOMM_MAX_CAST_MS`|20000 · 10000|Caps for amounts and cast times (ms) in HealComm messages from others|
|
||||||
|
|`FBMINIMAP_ANGLE` · `FBMINIMAP_RADIUS`|4 · 80|Default spot of the minimap button, in degrees as WoW's `cos` and `sin` take them|
|
||||||
|
|`FBSWEEP_FAIL_REPORT`|3|After this many failures in a row a range or line of sight sweep is reported in the chat|
|
||||||
|
|`FBDMG_MOBHP_MAX`|400|Mob types kept for Smart Damage's own health estimate|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -562,6 +594,7 @@ Every knob is a global at the top of its own section and can be changed without
|
|||||||
|`FBHealBox_SetPlateVisible(f, visible)`|Shows or hides all bars of a plate (party-frame mode)|
|
|`FBHealBox_SetPlateVisible(f, visible)`|Shows or hides all bars of a plate (party-frame mode)|
|
||||||
|`FBHealBox_UpdateUnit(unit, frame)`|Writes HP, shield, prediction, mana and dispel colour into a plate|
|
|`FBHealBox_UpdateUnit(unit, frame)`|Writes HP, shield, prediction, mana and dispel colour into a plate|
|
||||||
|`FBHealBox_UpdateMana(unit, frame)`|The mana strip: shown only for mana users|
|
|`FBHealBox_UpdateMana(unit, frame)`|The mana strip: shown only for mana users|
|
||||||
|
|`FBHealBox_UpdateUnitMana(unit, frame)`|Narrow path for mana, rage, energy and focus events: only the strip, not the whole plate|
|
||||||
|`FBHealBox_DispelType(unit)`|First debuff your class can remove: type, texture, stacks, or nil|
|
|`FBHealBox_DispelType(unit)`|First debuff your class can remove: type, texture, stacks, or nil|
|
||||||
|`FBHealBox_UpdateDebuffIcon(frame, tex, count)`|Debuff icon and stack count|
|
|`FBHealBox_UpdateDebuffIcon(frame, tex, count)`|Debuff icon and stack count|
|
||||||
|`FBHealBox_CastOn(button, castString)`|Casts a button's spell (left or right) on its target|
|
|`FBHealBox_CastOn(button, castString)`|Casts a button's spell (left or right) on its target|
|
||||||
@@ -574,20 +607,26 @@ Every knob is a global at the top of its own section and can be changed without
|
|||||||
|`FBHealBox_SpellCastSeconds(id)`|Cast time from the tooltip (0 = instant), cached per spellbook slot|
|
|`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_ApplyBlizzParty()` · `FBHealBox_HideBlizzPartyActive()`|Hides or restores Blizzard's party frames, including the lock against the attach mode|
|
||||||
|`FBHealBox_SetPowerColor(bar, cache, ptype)`|Colours a resource bar for mana, rage, focus or energy|
|
|`FBHealBox_SetPowerColor(bar, cache, ptype)`|Colours a resource bar for mana, rage, focus or energy|
|
||||||
|
|`FBHealBox_ApplyBarBG(f)` · `FBHealBox_ApplyBarBGAll()`|Sets the background behind a plate's bars from the `BarBG` option|
|
||||||
|
|`FBHealBox_RefreshUnitsByName(names)`|Redraws only the plates whose unit is in the name set; the raid module gets the same set through the `RefreshNames` hook|
|
||||||
|`FBPredict_ScanPlayerBuffTimes()`|Reads all of your own buff timers once per frame into a texture-to-seconds map|
|
|`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_ApiFailed()`|Puts range, distance and line of sight back to the protected single call after a sweep threw|
|
||||||
|
|`FBHealBox_SweepResult(where, ok, err)` · `FBHealBox_ReportError(where, err)`|Evaluates a protected sweep; reports errors once in the chat, further ones with `/fbp debug`|
|
||||||
|`FBHealBox_UpperTex(tex)`|Upper-cased texture path, remembered, so `strupper` does not allocate per call|
|
|`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_UpdateAllCooldowns()`|Cooldown sweep|
|
||||||
|`FBHealBox_ShowTab(n)` · `FBHealBox_ApplyRightClickLayout()`|Options tabs; show/hide the right-click column|
|
|`FBHealBox_ShowTab(n)` · `FBHealBox_ApplyRightClickLayout()`|Options tabs; show/hide the right-click column|
|
||||||
|
|`FBHealBox_ExtrasSection(height)` · `FBHealBox_CreateSlider(…)` · `FBHealBox_SliderText(s)`|Shared *Extras* tab and slider factory for the modules|
|
||||||
|`FBHealBox_PlateMouseDown(f)` · `FBHealBox_PlateMouseUp(f)` · `FBHealBox_RunPlateAction(f, action)`|Click and drag on a plate|
|
|`FBHealBox_PlateMouseDown(f)` · `FBHealBox_PlateMouseUp(f)` · `FBHealBox_RunPlateAction(f, action)`|Click and drag on a plate|
|
||||||
|`FBHealBox_RefreshAllBars()`|Updates all ten|
|
|`FBHealBox_RefreshAllBars()`|Updates all ten|
|
||||||
|
|`FBHealBox_MarkDirty(name)` · `FBHealBox_FlushDirty()`|Collection point for redraws: events note the affected name, drawing happens once per frame|
|
||||||
|`FBUpdateNames()`|Names and visibility after a group or pet change, then re-layout|
|
|`FBUpdateNames()`|Names and visibility after a group or pet change, then re-layout|
|
||||||
|`FBSlotActive(p)`|Is slot p to be shown right now?|
|
|`FBSlotActive(p)`|Is slot p to be shown right now?|
|
||||||
|`FBHealBox_Layout()`|Stacks the visible plates (owner, then pet) with `RowSpacing`|
|
|`FBHealBox_Layout()`|Stacks the visible plates (owner, then pet) with `RowSpacing`|
|
||||||
|`FBHealBox_ApplyButtonSpacing()`|Re-chains all buttons with `ButtonSpacing`|
|
|`FBHealBox_ApplyButtonSpacing()`|Re-chains all buttons with `ButtonSpacing`|
|
||||||
|`FBHealBox_SavePosition()` · `FBHealBox_RestorePosition()`|Plate position in the saved variables|
|
|`FBHealBox_SavePosition()` · `FBHealBox_RestorePosition()`|Plate position in the saved variables|
|
||||||
|
|`FBHealBox_PlaceMinimapButton(b)` · `FBHealBox_SaveMinimapButton(b)`|Minimap button position|
|
||||||
|`FBHealBox_ApplyDefaults()` · `FBHealBox_SyncOptions()`|Fill missing settings; align the options window with them|
|
|`FBHealBox_ApplyDefaults()` · `FBHealBox_SyncOptions()`|Fill missing settings; align the options window with them|
|
||||||
|`FBHealBox_ApplyNameColor(unit, f)` · `FBHealBox_ApplyAllNameColors()`|Name in class colour / pet colour|
|
|`FBHealBox_ApplyNameColor(unit, f)` · `FBHealBox_ApplyAllNameColors()`|Name in class colour / pet colour|
|
||||||
|`FBHealBox_SetWatchBuff(name)` · `FBHealBox_HasWatchBuff(unit)` · `FBHealBox_CheckWatchBuff(unit, f)`|Buff watch: select, test one unit, colour the border|
|
|`FBHealBox_SetWatchBuff(name)` · `FBHealBox_HasWatchBuff(unit)` · `FBHealBox_CheckWatchBuff(unit, f)`|Buff watch: select, test one unit, colour the border|
|
||||||
@@ -622,7 +661,7 @@ The display never calls `UnitExists`, `UnitName`, `UnitHealth` or `UnitMana` dir
|
|||||||
|`FBHealBoxButtonsChanged()`|Refreshes icons and assignment without rebuilding|
|
|`FBHealBoxButtonsChanged()`|Refreshes icons and assignment without rebuilding|
|
||||||
|`FBLoadSpellData()`|Scans the spellbook, collects all ranks|
|
|`FBLoadSpellData()`|Scans the spellbook, collects all ranks|
|
||||||
|`FBApplySpellChoice(i, castString)`|Assigns a spell to a button|
|
|`FBApplySpellChoice(i, castString)`|Assigns a spell to a button|
|
||||||
|`HealBoxButton_OnEvent(…)`|Tints the icon by mana, cooldown and range|
|
|`FBHealBox_UpdateButtonStates(event)` · `FBHealBox_UpdateButtonState(b, event)`|Tints the icons by mana, cooldown and range; range is asked once per unit and range per pass (`FBHealBox_ButtonInRange`). The pass itself runs protected (`FBHealBox_ButtonStatesSweep`)|
|
||||||
|
|
||||||
### Spell menu
|
### Spell menu
|
||||||
|
|
||||||
@@ -654,21 +693,27 @@ The four functions that feed the bars. All of them expect a **player name**, not
|
|||||||
|-|-|
|
|-|-|
|
||||||
|`FBPredict_GetSpellInfo(bookID, name)`|Parses the spellbook tooltip (direct / HoT / shield)|
|
|`FBPredict_GetSpellInfo(bookID, name)`|Parses the spellbook tooltip (direct / HoT / shield)|
|
||||||
|`FBPredict_BuildWatch()`|Builds the watch list after every spellbook scan|
|
|`FBPredict_BuildWatch()`|Builds the watch list after every spellbook scan|
|
||||||
|`FBPredict_NoteCast(castString, target)`|Registers target and rank **before** the cast|
|
|`FBPredict_NoteCast(castString, target)`|Registers target and rank **before** the cast (`FBPredictClick`)|
|
||||||
|`FBPredict_CastStart(spell, castMs)` · `FBPredict_CastEnd()`|Start and end a direct heal|
|
|`FBPredict_TakeClick(spell, castMs)` · `FBPredict_ClickDone()` · `FBPredict_ClickFailed(interrupted)`|What becomes of the click on cast start, cast end and failure (`FBPredictClick`, `FBPredictCastClick`)|
|
||||||
|
|`FBPredict_HookAttempts()`|Counts every cast attempt (`UseAction`, `CastSpellByName`, `CastSpell`) in `FBPredictClickSeq`|
|
||||||
|
|`FBPredict_ConfirmPending()`|Confirms HoT, shield and buff of a click whose cast went through|
|
||||||
|
|`FBPredict_CastStart(spell, castMs)` · `FBPredict_CastEnd(success)`|Start and end a direct heal; a successful one stays in `FBPredictLastDirect` for its combat log line|
|
||||||
|`FBPredict_ScanUnit(unit)`|Aura check: confirm application, detect removal|
|
|`FBPredict_ScanUnit(unit)`|Aura check: confirm application, detect removal|
|
||||||
|`FBPredict_StartHoT(…)` · `FBPredict_StartShield(…)`|Arm the tracking|
|
|`FBPredict_StartHoT(…)` · `FBPredict_StartShield(…)`|Arm the tracking|
|
||||||
|`FBPredict_ParseCombat(event, msg)`|Combat log evaluation|
|
|`FBPredict_ParseCombat(event, msg)`|Combat log evaluation|
|
||||||
|`FBPredict_OnTick(…)` · `FBPredict_OnDirectHeal(…)` · `FBPredict_OnAbsorb(…)`|The three correction paths|
|
|`FBPredict_OnTick(…)` · `FBPredict_OnDirectHeal(…)` · `FBPredict_OnAbsorb(…)`|The three correction paths|
|
||||||
|`FBPredict_Remember(…)` · `FBPredict_Remembered(…)`|Write and read the learned values|
|
|`FBPredict_Remember(…)` · `FBPredict_Remembered(…)`|Write and read the learned values|
|
||||||
|`FBPredict_TicksLeft(e, now)`|Remaining ticks of a HoT|
|
|`FBPredict_TicksLeft(e, now)`|Remaining ticks of a HoT|
|
||||||
|
|`FBPredict_Expire()`|The 0.2 second pass: expiries, timers, notes the affected names|
|
||||||
|
|`FBPredict_PruneNames()`|After roster changes, drops names that left the group from the buff and HoT bookkeeping|
|
||||||
|
|
||||||
### HealComm
|
### HealComm
|
||||||
|
|
||||||
|Function|Purpose|
|
|Function|Purpose|
|
||||||
|-|-|
|
|-|-|
|
||||||
|`FBComm_Enabled()`|Is the sync switched on?|
|
|`FBComm_Enabled()`|Is the sync switched on?|
|
||||||
|`FBComm_Send(msg)`|Raw send to raid or party|
|
|`FBComm_Send(msg)` · `FBComm_InBattleground()`|Raw send to raid, party or battleground|
|
||||||
|
|`FBComm_Clamp(v, max)`|Caps values from other healers' messages|
|
||||||
|`FBComm_SendHealStart(…)`|`Heal` or `GrpHeal`|
|
|`FBComm_SendHealStart(…)`|`Heal` or `GrpHeal`|
|
||||||
|`FBComm_SendHealStop()` · `FBComm_SendHealDelay(ms)`|Interrupt and pushback|
|
|`FBComm_SendHealStop()` · `FBComm_SendHealDelay(ms)`|Interrupt and pushback|
|
||||||
|`FBComm_SendHoT(spell, target, dur)`|`Renew` / `Reju` / `Regr`|
|
|`FBComm_SendHoT(spell, target, dur)`|`Renew` / `Reju` / `Regr`|
|
||||||
@@ -689,14 +734,18 @@ The four functions that feed the bars. All of them expect a **player name**, not
|
|||||||
|
|
||||||
**Nothing shows up at all after login.** Check the chat for the orange line naming your class: on a warrior, rogue or hunter the addon stays asleep on purpose. `/fbp forceload` shows it anyway, see [Which classes it loads for](#which-classes-it-loads-for).
|
**Nothing shows up at all after login.** Check the chat for the orange line naming your class: on a warrior, rogue or hunter the addon stays asleep on purpose. `/fbp forceload` shows it anyway, see [Which classes it loads for](#which-classes-it-loads-for).
|
||||||
|
|
||||||
**Smart Healing does not downrank a spell.** Heal over time spells are excluded on purpose, and so are shields, buffs and any spell whose tooltip does not describe a heal. If it downranks but never leaves the assigned spell, the spell is not in any heal chain, or `/fbp smartcross` is off. Below 30 % health the assigned rank is always used. `/fbp debug` prints the reason for every decision.
|
**Smart Healing does not downrank a spell.** Heal over time spells are excluded on purpose, and so are shields, buffs, group heals, spells with a cooldown and any spell whose tooltip does not describe a heal. If it downranks but never leaves the assigned spell, the spell is not in any heal chain, or `/fbp smartcross` is off. Below 30 % health the assigned rank is always used. `/fbp debug` prints the reason for every decision.
|
||||||
|
|
||||||
**A spell does not appear in the menu.** It is not in your class's spell list (`Spell.Name` near the top of the file), or not learned yet. The list can be extended freely.
|
**A spell does not appear in the menu.** It is not in your class's spell list (`FBClassSpells.Name` near the top of the file), or not learned yet. The list can be extended freely.
|
||||||
|
|
||||||
|
**Client in another language.** Class detection, dispel colouring and the class icon work on every client. The spell lists (`FBClassSpells.Name`, buff watch, Smart Damage) hold English spell names, and the prediction reads English tooltips. On a German, French or Spanish client the spell menu therefore stays empty, and the prediction and Smart Healing do not recognise the spells. Spells assigned by drag and drop from the spellbook still work on the buttons.
|
||||||
|
|
||||||
**Learned absorb values are capped.** A remembered absorb larger than 1.5 times the tooltip value is treated as a counting error and dropped on load (`FBPredict_SanitizeMemory`); values from versions before 1.4.2 that were doubled by the old double load clean themselves up this way.
|
**Learned absorb values are capped.** A remembered absorb larger than 1.5 times the tooltip value is treated as a counting error and dropped on load (`FBPredict_SanitizeMemory`); values from versions before 1.4.2 that were doubled by the old double load clean themselves up this way.
|
||||||
|
|
||||||
**No prediction for a particular spell.** Run `/fbp`: if the spell is not among the spells read, the tooltip parser did not recognise it. Wording can differ on custom servers; the patterns all sit in `FBPredict_GetSpellInfo`.
|
**No prediction for a particular spell.** Run `/fbp`: if the spell is not among the spells read, the tooltip parser did not recognise it. Wording can differ on custom servers; the patterns all sit in `FBPredict_GetSpellInfo`.
|
||||||
|
|
||||||
|
**A red line "Error in …" in the chat.** A module or a sweep threw a Lua error. The addon keeps running: the faulty hook is skipped for that call, a failing range, line of sight or button sweep falls back to protected single calls. The first message of each kind always shows, further ones only with `/fbp debug`. The line names the place, which helps with a bug report.
|
||||||
|
|
||||||
**Combat log corrections do not take.** The patterns are built from the client's global strings (`PERIODICAURAHEALOTHERSELF`, `HEALEDSELFOTHER`, `ABSORB_TRAILER`) and otherwise fall back to English defaults. `/fbp debug` shows whether corrections arrive.
|
**Combat log corrections do not take.** The patterns are built from the client's global strings (`PERIODICAURAHEALOTHERSELF`, `HEALEDSELFOTHER`, `ABSORB_TRAILER`) and otherwise fall back to English defaults. `/fbp debug` shows whether corrections arrive.
|
||||||
|
|
||||||
**Values are too low.** Before the first observed heal only the tooltip base value without +healing is available. A single cast through the buttons is enough to settle it.
|
**Values are too low.** Before the first observed heal only the tooltip base value without +healing is available. A single cast through the buttons is enough to settle it.
|
||||||
@@ -709,7 +758,7 @@ The four functions that feed the bars. All of them expect a **player name**, not
|
|||||||
|
|
||||||
## Class spells
|
## Class spells
|
||||||
|
|
||||||
The preset lists, freely extensible in `Spell.Name`:
|
The preset lists, freely extensible in `FBClassSpells.Name`:
|
||||||
|
|
||||||
|Class|Spells|
|
|Class|Spells|
|
||||||
|-|-|
|
|-|-|
|
||||||
@@ -734,6 +783,11 @@ Entries that do not exist do no harm: if the spellbook scan does not find them,
|
|||||||
* heal prediction for direct heals, remaining HoT ticks and absorb shields, self-correcting from the combat log
|
* 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.7: the complete code review. Fixes: Weakened Soul visible, other healers' HoTs and shields no longer counted as yours, range and cast time read from the right place in the tooltip, Smart Healing leaves group heals and cooldown spells alone and rates ranks below level 20 correctly, line of sight errors only mark the clicked unit, class tables on every client language, scale slider no longer moves the plates, drag and drop on raid mini buttons fixed, clicks only count for the cast they started, direct heals are learned, Smart Damage's minimum damage is safe again and its own health estimate stays out of raids. Performance: redraws collected once per frame, mana events only redraw the mana strip, range asked once per unit, spellbook re-read once per burst, Smart Damage idle while off. Robustness: generic globals renamed with an `FB` prefix, Smart Damage works without the ticker, errors in modules and sweeps reported, battleground channel and limits for HealComm, dead code and duplicate helpers removed; see CHANGELOG
|
||||||
|
* 1.4.6: performance pass without functional change (only changed units are redrawn via the `RefreshNames` hook, raid spell timers skip idle cells, spell timers leave early when nothing is running); see CHANGELOG
|
||||||
|
* 1.4.5.3: adjustable background behind the plate bars, so the game world no longer shows through where health is missing; see CHANGELOG
|
||||||
|
* 1.4.5.2: a running HoT no longer counts as incoming healing when Smart Healing picks a rank; see CHANGELOG
|
||||||
|
* 1.4.5.1: mana ticker spark no longer stutters (movement threshold and redraw step), and the global cooldown no longer darkens every button but is shown as a sweep instead (own threshold `FBCD_SHOW_MIN`); see CHANGELOG
|
||||||
* 1.4.5: Blizzard's party frames can be hidden (mutually exclusive with the attach mode), rage, energy and focus in the resource bar, and the equipment healing bonus via ClassicAPI in the prediction, plus a performance pass without functional change (player buffs read once per frame, staggered raid range and line-of-sight sweeps, fewer protected calls, no throwaway strings in the raid health text); see CHANGELOG
|
* 1.4.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
|
||||||
@@ -745,14 +799,14 @@ Entries that do not exist do no harm: if the spellbook scan does not find them,
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Heal Box Vanilla v1.4.5 · original by Dourd, UI Overhauled · ported to Vanilla and extended 09/2026 by Mquadrat
|
Heal Box Vanilla v1.4.7 · 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.5 · World of Warcraft CLIENT 1.12.1
|
ADDON DOKUMENTATION · VERSION 1.4.7 · 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.
|
||||||
|
|
||||||
@@ -792,6 +846,8 @@ Solange das Addon ruht, antworten alle anderen `/fbp`-Befehle mit demselben Hinw
|
|||||||
|
|
||||||
Erkannt wird über das englische Klassen-Token des Clients (`WARRIOR`, `ROGUE`, `HUNTER`), mit Rückfall auf den angezeigten Klassennamen in fünf Sprachen, damit die Sperre auch auf lokalisierten Clients greift.
|
Erkannt wird über das englische Klassen-Token des Clients (`WARRIOR`, `ROGUE`, `HUNTER`), mit Rückfall auf den angezeigten Klassennamen in fünf Sprachen, damit die Sperre auch auf lokalisierten Clients greift.
|
||||||
|
|
||||||
|
Seit 1.4.7 bestimmt dasselbe Token auch intern die Klasse: Das Addon rechnet immer mit dem englischen Klassennamen (`Priest`, `Druid` und so weiter), Chatzeilen und Optionsfenster zeigen weiter den Namen deines Clients. Vorher stand auf einem deutschen Client *Priester* drin, und alle nach Klasse geschlüsselten Tabellen blieben dort leer; die Dispel-Färbung fiel komplett aus. Sie funktioniert jetzt in jeder Clientsprache, ebenso das Klassenicon. Die Zauberlisten und die Tooltipmuster der Vorhersage sind weiterhin englisch, siehe [Fehlersuche](#fehlersuche).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Die Anzeige
|
## Die Anzeige
|
||||||
@@ -810,7 +866,7 @@ Hat dein aktuelles feindliches Ziel ein Gruppenmitglied im Ziel, bekommt dessen
|
|||||||
|
|
||||||
### Sichtlinie
|
### Sichtlinie
|
||||||
|
|
||||||
Solange eine Einheit außerhalb deiner Sichtlinie ist, sitzt ein **Augen-Abzeichen** (`FBLOS_ICON`, das Blenden-Icon) auf der linken oberen Ecke ihrer Plakette. Vanilla hat dafür keine API, deshalb zwei Wege: Ist der Client-Mod **UnitXP SP3** installiert, fragt das Addon alle halbe Sekunde `UnitXP("inSight", "player", unit)` ab, live und exakt. Ohne ihn achtet das Addon auf die Fehlermeldung *nicht in Sichtlinie* nach einer eigenen Heilung und markiert die Einheit, die du heilen wolltest, für `FBLOS_TIMEOUT` (8) Sekunden; die Markierung verschwindet, sobald ein Cast auf sie startet oder eine eigene Heilung bzw. ein HoT-Tick dort ankommt. `/fbp` zeigt, welcher Weg aktiv ist. Option *Sichtlinie*; Position des Abzeichens über `FBLOS_ICON_X/Y`.
|
Solange eine Einheit außerhalb deiner Sichtlinie ist, sitzt ein **Augen-Abzeichen** (`FBLOS_ICON`, das Blenden-Icon) auf der linken oberen Ecke ihrer Plakette. Vanilla hat dafür keine API, deshalb zwei Wege: Ist der Client-Mod **UnitXP SP3** installiert, fragt das Addon alle halbe Sekunde `UnitXP("inSight", "player", unit)` ab, live und exakt. Ohne ihn achtet das Addon auf die Fehlermeldung *nicht in Sichtlinie* nach einem Klick auf einen deiner Heal Box Buttons und markiert die Einheit dieses Buttons für `FBLOS_TIMEOUT` (8) Sekunden; die Markierung verschwindet, sobald ein Cast auf sie startet oder eine eigene Direktheilung dort ankommt. Der Tick eines HoTs lässt sie stehen, denn Ticks brauchen keine Sicht. Die Meldung muss genau diesen Klick beantworten: Sie zählt bis `FBLOS_ERROR_WINDOW` (1) Sekunde nach dem Klick, bei einem Zauber mit Zauberzeit bis eine Sekunde nach dem Castende, denn der Server prüft die Sicht am Ende des Casts noch einmal. Ein Cast, der durchgeht, eine Unterbrechung, eine andere Fehlermeldung oder ein anderer Zauber, der anläuft, beendet das Warten. Fehler von Zaubern auf der Aktionsleiste markieren deshalb niemanden, und deine eigene Plakette wird nie markiert. `/fbp` zeigt, welcher Weg aktiv ist. Option *Sichtlinie*; Position des Abzeichens über `FBLOS_ICON_X/Y`.
|
||||||
|
|
||||||
### Begleiter
|
### Begleiter
|
||||||
|
|
||||||
@@ -846,7 +902,7 @@ Hat jemand einen Debuff, den **deine** Klasse entfernen kann, färbt sich sein L
|
|||||||
|Schamane|Gift, Krankheit|
|
|Schamane|Gift, Krankheit|
|
||||||
|Druide|Fluch (violett), Gift|
|
|Druide|Fluch (violett), Gift|
|
||||||
|
|
||||||
Die Schwellwerte für die HP-Farben stehen als `LowHP` (0.6) und `VeryLowHP` (0.3) am Dateianfang.
|
Die Schwellwerte für die HP-Farben stehen als `FBLowHP` (0.6) und `FBVeryLowHP` (0.3) am Dateianfang.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -854,11 +910,13 @@ Die Schwellwerte für die HP-Farben stehen als `LowHP` (0.6) und `VeryLowHP` (0.
|
|||||||
|
|
||||||
Rechts neben jeder Plakette liegen bis zu zehn Buttons, jeder mit dem Icon seines Zaubers. Ein **Linksklick** wirkt den Zauber auf genau dieses Gruppenmitglied, unabhängig davon, wen du gerade im Ziel hast.
|
Rechts neben jeder Plakette liegen bis zu zehn Buttons, jeder mit dem Icon seines Zaubers. Ein **Linksklick** wirkt den Zauber auf genau dieses Gruppenmitglied, unabhängig davon, wen du gerade im Ziel hast.
|
||||||
|
|
||||||
**Belegen per Drag & Drop.** Zauberbuch öffnen, einen Zauber ziehen und auf einen beliebigen Heil-Button, einen Raid-Mini-Button oder ein Feld im Reiter *Buttons* fallen lassen; diese Buttonnummer übernimmt den Zauber auf allen Plaketten. Ist der Rechtsklick-Zauber aktiv, füllt ein Ablegen mit der rechten Maustaste oder mit gehaltener Shift-Taste die Rechtsklick-Seite. Auch Zauber außerhalb der Klassenliste (etwa Magie bannen) werden angenommen und behalten ihr Icon über einen Reload. Vanilla hat kein `GetCursorInfo()`, deshalb merkt sich das Addon, was `PickupSpell` zuletzt an den Cursor gehängt hat.
|
**Belegen per Drag & Drop.** Zauberbuch öffnen, einen Zauber ziehen und auf einen beliebigen Heil-Button, einen Raid-Mini-Button oder ein Feld im Reiter *Buttons* fallen lassen; diese Buttonnummer übernimmt den Zauber auf allen Plaketten. Ist der Rechtsklick-Zauber aktiv, füllt ein Ablegen mit der rechten Maustaste oder mit gehaltener Shift-Taste die Rechtsklick-Seite. Auch Zauber außerhalb der Klassenliste (etwa Magie bannen) werden angenommen und behalten ihr Icon über einen Reload. Vanilla hat kein `GetCursorInfo()`, deshalb merkt sich das Addon, was `PickupSpell` zuletzt an den Cursor gehängt hat. Zauber aus dem Zauberbuch des Begleiters werden mit einem Hinweis im Chat abgelehnt, denn jede Abfrage eines Buttons (Tooltip, Abklingzeit, Reichweite, Wirken) geht an dein eigenes Zauberbuch.
|
||||||
|
|
||||||
**Rechtsklick-Zauber (optional).** Jeder Button kann einen zweiten Zauber für **Rechtsklick** tragen (etwa Blitzheilung links, Große Heilung rechts), was die Anzeige verdichtet, ohne Buttons hinzuzufügen. Das ist standardmäßig aus und wird ausschließlich über den Schalter im Reiter *Buttons* eingeschaltet. Eingeschaltet erscheint eine zweite Spalte in der Belegung, und ein kleines Icon unten rechts auf jedem Button zeigt seinen Rechtsklick-Zauber; der Tooltip nennt ihn ebenfalls. Ausschalten behält die Belegung, die Buttons reagieren nur nicht mehr auf Rechtsklick.
|
**Rechtsklick-Zauber (optional).** Jeder Button kann einen zweiten Zauber für **Rechtsklick** tragen (etwa Blitzheilung links, Große Heilung rechts), was die Anzeige verdichtet, ohne Buttons hinzuzufügen. Das ist standardmäßig aus und wird ausschließlich über den Schalter im Reiter *Buttons* eingeschaltet. Eingeschaltet erscheint eine zweite Spalte in der Belegung, und ein kleines Icon unten rechts auf jedem Button zeigt seinen Rechtsklick-Zauber; der Tooltip nennt ihn ebenfalls. Ausschalten behält die Belegung, die Buttons reagieren nur nicht mehr auf Rechtsklick.
|
||||||
|
|
||||||
**Smart Healing (standardmäßig aus).** Mit *Smart Healing* wirkt ein Klick den niedrigsten Rang des belegten Zaubers, dessen erwartete Heilung das fehlende Leben des Ziels abzüglich schon eingehender Heilung plus *Sicherheitsaufschlag* (Standard 20 %) deckt. Die erwartete Heilung stammt aus den gelernten Werten der Vorhersage, wo vorhanden, sonst aus dem Tooltip-Mittelwert. Nie über dem belegten Rang, nur für Direktheilungen, und unter 30 % Leben immer der belegte Rang. **Zauber mit Heilung über Zeit werden nie abgerangt**, egal welcher Klasse: Erneuerung, Verjüngung, Nachwachsen, Gelassenheit, Lebensblüte, Wildwuchs, Springflut und Erdschild gehen immer im belegten Rang raus. Ein HoT verteilt seine Heilung über viele Sekunden, das im Moment des Klicks fehlende Leben sagt also nichts darüber aus, welcher Rang passt, und ein abgerangter HoT tickt die volle Laufzeit zu schwach. Gemischte Zauber wie Nachwachsen zählen ebenfalls als HoT. Schilde und Buffs wie Seelenstärke gehen genauso wie belegt raus, und ein Zauber kommt überhaupt nur in Frage, wenn sein Tooltip eine Heilung beschreibt.
|
**Smart Healing (standardmäßig aus).** Mit *Smart Healing* wirkt ein Klick den niedrigsten Rang des belegten Zaubers, dessen erwartete Heilung das fehlende Leben des Ziels abzüglich schon eingehender Heilung plus *Sicherheitsaufschlag* (Standard 20 %) deckt. Die erwartete Heilung stammt aus den gelernten Werten der Vorhersage, wo vorhanden, sonst aus dem Tooltip-Mittelwert. Nie über dem belegten Rang, nur für Direktheilungen auf ein Ziel, und unter 30 % Leben immer der belegte Rang. **Gruppenheilungen und Zauber mit Abklingzeit gehen wie belegt raus**: Gebet der Heilung, Kettenheilung, Heilige Nova, Heiliger Schock, Handauflegung und die übrigen Einträge in `FBSmartSkip`, dazu jeder Zauber, dessen Tooltip eine Abklingzeit über dem globalen Cooldown nennt. Das fehlende Leben auf der einen angeklickten Plakette sagt nichts über den Bedarf einer ganzen Gruppe, und ein kleiner Rang eines Zaubers mit Abklingzeit verbraucht trotzdem die volle Abklingzeit. **Zauber mit Heilung über Zeit werden nie abgerangt**, egal welcher Klasse: Erneuerung, Verjüngung, Nachwachsen, Gelassenheit, Lebensblüte, Wildwuchs, Springflut und Erdschild gehen immer im belegten Rang raus. Ein HoT verteilt seine Heilung über viele Sekunden, das im Moment des Klicks fehlende Leben sagt also nichts darüber aus, welcher Rang passt, und ein abgerangter HoT tickt die volle Laufzeit zu schwach. Gemischte Zauber wie Nachwachsen zählen ebenfalls als HoT. Schilde und Buffs wie Seelenstärke gehen genauso wie belegt raus, und ein Zauber kommt überhaupt nur in Frage, wenn sein Tooltip eine Heilung beschreibt.
|
||||||
|
|
||||||
|
**Ein laufender HoT zählt nicht als eingehende Heilung.** Abgezogen wird nur, was gleich ankommt: Direktheilungen und über HealComm gemeldete Zauber, also ein bis drei Sekunden. Die offene Restheilung eines tickenden Erneuerung bleibt außen vor. Sie voll anzurechnen ließe den Fehlbetrag winzig aussehen und machte aus einem Heilen Rang 4 ein Geringes Heilen, obwohl das Ziel jetzt Leben braucht und nicht in einer Viertelminute. Auf dem Balken wird der HoT weiterhin angezeigt, er geht nur nicht in die Rangwahl ein.
|
||||||
|
|
||||||
**Heilketten (neu in 1.4.4.3).** Abgerangt wird nicht nur innerhalb des belegten Zaubers. Innerhalb einer *Heilkette* darf auch der Zauber selbst wechseln, ein Klick auf Große Heilung kann also als Geringes Heilen Rang 3 rausgehen, wenn das den Fehlbetrag deckt. Die Ketten enthalten die Einzelziel-Direktheilungen einer Klasse:
|
**Heilketten (neu in 1.4.4.3).** Abgerangt wird nicht nur innerhalb des belegten Zaubers. Innerhalb einer *Heilkette* darf auch der Zauber selbst wechseln, ein Klick auf Große Heilung kann also als Geringes Heilen Rang 3 rausgehen, wenn das den Fehlbetrag deckt. Die Ketten enthalten die Einzelziel-Direktheilungen einer Klasse:
|
||||||
|
|
||||||
@@ -873,9 +931,11 @@ Alles in der Kette ist Kandidat, gewonnen hat der mit der kleinsten erwarteten H
|
|||||||
|
|
||||||
Der Schalter *Smartcross* im Reiter *Buttons* schaltet den Kettenwechsel aus und wieder ein, `/fbp smartcross` tut dasselbe aus dem Chat. Aus bleibt Smart Healing beim belegten Zauber und senkt nur dessen Rang, so wie es vor 1.4.4.3 war. Die Ketten stehen in `FBHealChains` direkt beim Smart-Healing-Code und lassen sich frei bearbeiten; Zauber, die nicht getauscht werden sollen, fliegen einfach aus der Liste. Nachteile: Die Schätzung kennt keine Crits, und bei Schadensspitzen oder gewolltem Überheilen (Tank vor einem großen Treffer) kann der kleinere Rang zu wenig sein. Aus lassen, wann immer Overheal gewollt ist. `/fbp debug` zeigt jede Entscheidung, `/fbp` den Zustand.
|
Der Schalter *Smartcross* im Reiter *Buttons* schaltet den Kettenwechsel aus und wieder ein, `/fbp smartcross` tut dasselbe aus dem Chat. Aus bleibt Smart Healing beim belegten Zauber und senkt nur dessen Rang, so wie es vor 1.4.4.3 war. Die Ketten stehen in `FBHealChains` direkt beim Smart-Healing-Code und lassen sich frei bearbeiten; Zauber, die nicht getauscht werden sollen, fliegen einfach aus der Liste. Nachteile: Die Schätzung kennt keine Crits, und bei Schadensspitzen oder gewolltem Überheilen (Tank vor einem großen Treffer) kann der kleinere Rang zu wenig sein. Aus lassen, wann immer Overheal gewollt ist. `/fbp debug` zeigt jede Entscheidung, `/fbp` den Zustand.
|
||||||
|
|
||||||
**Cooldowns.** Jeder Button zeigt die gewohnte Cooldown-Uhr seines Zaubers. Der globale Cooldown wird nicht gezeigt (`FBCD_MIN_DURATION`). Option *Cooldowns auf den Buttons*.
|
**Cooldowns.** Jeder Button zeigt die gewohnte Cooldown-Uhr seines Zaubers, den globalen Cooldown eingeschlossen: Nach jedem Zauber läuft die kurze Wartezeit auf allen Buttons ab, so wie es die Aktionsleisten machen.
|
||||||
|
|
||||||
**HoT- und Schild-Timer.** Der Button eines Zaubers zeigt für seine Einheit die Restsekunden deines eigenen HoTs (grün) oder Schilds (blau) dieses Zaubers. Ist Machtwort: Schild verbraucht, zeigt derselbe Button rot die Geschwächte Seele, bis das Ziel wieder schildbar ist. Geprüft wird zuerst der Linksklick-Zauber, dann der Rechtsklick-Zauber. Nur eigene Effekte werden verfolgt. Option *HoT- und Schild-Timer*.
|
Was der globale Cooldown auf keinen Fall tun darf, ist die Symbole abdunkeln. Solange er läuft, meldet der Client jeden Zauber als nicht nutzbar, wörtlich genommen würden also nach jedem einzelnen Zauber alle Buttons anderthalb Sekunden grau und dann schlagartig wieder hell. Deshalb sind es zwei getrennte Schwellen: `FBCD_SHOW_MIN` (0) entscheidet, ab welcher Länge die Uhr läuft, `FBCD_MIN_DURATION` (2) die Länge, bis zu der eine Abklingzeit nicht als Grund zum Abdunkeln gilt. Wer `FBCD_SHOW_MIN` auf 2 setzt, hat den globalen Cooldown wieder aus der Anzeige. Option *Cooldowns auf den Buttons*.
|
||||||
|
|
||||||
|
**HoT- und Schild-Timer.** Der Button eines Zaubers zeigt für seine Einheit die Restsekunden deines eigenen HoTs (grün) oder Schilds (blau) dieses Zaubers. Ist Machtwort: Schild verbraucht, zeigt derselbe Button rot die Geschwächte Seele, bis das Ziel wieder schildbar ist. Geprüft wird zuerst der Linksklick-Zauber, dann der Rechtsklick-Zauber. Nur eigene Effekte werden verfolgt: Ein HoT, den das Addon nur als Buff sieht, bekommt seinen Timer, sobald dein erster Tick davon im Combatlog steht, und Schild und Geschwächte Seele folgen den Schilden, die du über die Heal Box Buttons wirkst, denn ein Schild von der Aktionsleiste lässt sich nicht von dem eines anderen Priesters unterscheiden (siehe [Heilung über Zeit](#heilung-über-zeit) und [Absorb-Schilde](#absorb-schilde)). Option *HoT- und Schild-Timer*.
|
||||||
|
|
||||||
**Buff-Icons links am Balken.** Buffs mit Laufzeit, die auf deinen Buttons liegen (Seelenstärke, Göttlicher Willen, Furchtzauberschutz, Inneres Feuer, links oder rechts), erscheinen als kleine 8-px-Icons **außen links** neben der Plakette, solange der Buff wirkt, in Zweierstapeln: das erste oben an der Platte, das zweite darunter, das dritte oben in der nächsten Spalte links, und so weiter. Die Restlaufzeit wird visuell in **32 feinen Stufen** (`FBBUFFICON_STEPS = 32`) dargestellt: Mit ablaufender Zeit wird das Icon von oben nach unten schrittweise schwarz-weiß entsättigt und abgedunkelt. Frischer Buff: ganz farbig. Halbe Zeit übrig: obere Hälfte grau. Ein Viertel übrig: obere drei Viertel grau. Diese 32-Stufen-Darstellung bietet eine deutlich höhere Präzision (bei einem 30-Minuten-Buff aktualisiert sich die Anzeige ca. alle 56 Sekunden statt nur alle 7,5 Minuten) und spart gleichzeitig Ressourcen durch den Einsatz einer einzelnen dynamisch beschnittenen Overlay-Textur (`ic.qTex`) und Abdunklung (`ic.wTex`). Mouseover auf ein Icon zeigt Buffname und Restzeit. Die Restzeit ist bei dir selbst exakt (Buff-API, bei jedem `PLAYER_AURAS_CHANGED` und dazwischen einmal je Sekunde neu gelesen, weil ein Refresh eines laufenden Buffs kein Event feuert; ein Neucast stellt die Uhr also zurück) und wird bei anderen ab deinem eigenen Cast gezählt; ein fremd gewirkter Buff bleibt ganz farbig (Zeit unbekannt). Bis zu sechs Icons je Plakette (`FBBUFFICON_MAX`). Option *Buff-Icons links am Balken*, standardmäßig an. Die Raid-Zellen zeigen dieselben Icons außen an ihrer linken Kante mit 6 px in einem 3-mal-4-Raster (zwölf Plätze, Spalten füllen sich von der Zelle nach außen), das Raster hält zwischen den Gruppen Platz dafür frei. Nach einem `/reload` oder Gruppenwechsel scannt das Addon alle Einheiten einmal aktiv, damit vorhandene Buffs sofort erscheinen und nicht erst beim nächsten Aura-Event. `/fbp buffs` listet die verfolgten Buffs und ihren Zustand auf dir.
|
**Buff-Icons links am Balken.** Buffs mit Laufzeit, die auf deinen Buttons liegen (Seelenstärke, Göttlicher Willen, Furchtzauberschutz, Inneres Feuer, links oder rechts), erscheinen als kleine 8-px-Icons **außen links** neben der Plakette, solange der Buff wirkt, in Zweierstapeln: das erste oben an der Platte, das zweite darunter, das dritte oben in der nächsten Spalte links, und so weiter. Die Restlaufzeit wird visuell in **32 feinen Stufen** (`FBBUFFICON_STEPS = 32`) dargestellt: Mit ablaufender Zeit wird das Icon von oben nach unten schrittweise schwarz-weiß entsättigt und abgedunkelt. Frischer Buff: ganz farbig. Halbe Zeit übrig: obere Hälfte grau. Ein Viertel übrig: obere drei Viertel grau. Diese 32-Stufen-Darstellung bietet eine deutlich höhere Präzision (bei einem 30-Minuten-Buff aktualisiert sich die Anzeige ca. alle 56 Sekunden statt nur alle 7,5 Minuten) und spart gleichzeitig Ressourcen durch den Einsatz einer einzelnen dynamisch beschnittenen Overlay-Textur (`ic.qTex`) und Abdunklung (`ic.wTex`). Mouseover auf ein Icon zeigt Buffname und Restzeit. Die Restzeit ist bei dir selbst exakt (Buff-API, bei jedem `PLAYER_AURAS_CHANGED` und dazwischen einmal je Sekunde neu gelesen, weil ein Refresh eines laufenden Buffs kein Event feuert; ein Neucast stellt die Uhr also zurück) und wird bei anderen ab deinem eigenen Cast gezählt; ein fremd gewirkter Buff bleibt ganz farbig (Zeit unbekannt). Bis zu sechs Icons je Plakette (`FBBUFFICON_MAX`). Option *Buff-Icons links am Balken*, standardmäßig an. Die Raid-Zellen zeigen dieselben Icons außen an ihrer linken Kante mit 6 px in einem 3-mal-4-Raster (zwölf Plätze, Spalten füllen sich von der Zelle nach außen), das Raster hält zwischen den Gruppen Platz dafür frei. Nach einem `/reload` oder Gruppenwechsel scannt das Addon alle Einheiten einmal aktiv, damit vorhandene Buffs sofort erscheinen und nicht erst beim nächsten Aura-Event. `/fbp buffs` listet die verfolgten Buffs und ihren Zustand auf dir.
|
||||||
|
|
||||||
@@ -935,7 +995,7 @@ Alle Raid-Einstellungen liegen in `HealBox.Raid`. `/fbp raidtest 20`, `/fbp raid
|
|||||||
|
|
||||||
### Wie er andockt
|
### Wie er andockt
|
||||||
|
|
||||||
Der Kern bietet `FBHealBox_RegisterHook(name, fn)` und ruft die Hooks an festen Stellen: `Defaults`, `SyncOptions`, `ApplyLocale`, `UpdateNames`, `RefreshAllBars`, `ButtonsChanged`, `ActiveToggle`, `Status`, `Slash`, `Loaded`, `Aggro`, `SpellTimers` und `Cooldowns`. `FBHealBox_AddOptionsTab(labelKey)` legt einen Reiter im Optionsfenster an. Das Raid-Modul hängt sein Roster-Update an `UpdateNames`, sein Zellen-Update an `RefreshAllBars` (so erreicht die Heilvorhersage die Raid-Zellen ohne Zusatzaufwand) und seine Slash-Befehle an `Slash`. Die Raid-Einheiten werden in `FBPredictUnits` eingetragen, damit die HoT- und Schild-Bestätigung über `UNIT_AURA` auch für `raid1` bis `raid40` greift. Begleiter werden im Raidmodus nicht angezeigt.
|
Der Kern bietet `FBHealBox_RegisterHook(name, fn)` und ruft die Hooks an festen Stellen: `Defaults`, `SyncOptions`, `ApplyLocale`, `Loaded`, `Status`, `Slash`, `Suppress`, `ActiveToggle`, `UpdateNames`, `RaidRoster`, `RefreshAllBars`, `RefreshNames`, `ButtonsChanged`, `ButtonStates`, `Cooldowns`, `SpellTimers`, `BuffIcons` und `Aggro`. Jeder Hook läuft geschützt: Ein Fehler in einem Modul erscheint einmal im Chat (weitere mit `/fbp debug`) und hält weder den Kern noch die anderen Module an. `FBHealBox_AddOptionsTab(labelKey)` legt einen Reiter im Optionsfenster an, `FBHealBox_ExtrasSection(height)` vergibt einen Abschnitt im gemeinsamen Reiter *Extras*, und `FBHealBox_CreateSlider(…)` baut einen Regler, der an einer Einstellungstabelle hängt. Das Raid-Modul hängt sein Roster-Update an `UpdateNames`, sein Zellen-Update an `RefreshAllBars` und `RefreshNames` (so erreicht die Heilvorhersage die Raid-Zellen ohne Zusatzaufwand, und neu gezeichnet werden nur die Zellen, deren Einheit sich geändert hat) und seine Slash-Befehle an `Slash`. Nach jedem Umbau des Rasters ruft es `RaidRoster`, darüber findet der Mana-Ticker deine Zelle wieder. Die Raid-Einheiten werden in `FBPredictUnits` eingetragen, damit die HoT- und Schild-Bestätigung über `UNIT_AURA` auch für `raid1` bis `raid40` greift. Begleiter werden im Raidmodus nicht angezeigt.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -957,7 +1017,7 @@ In 1.12 gibt es dafür keine API, deshalb beobachtet das Modul `UNIT_MANA` für
|
|||||||
|Tick-Vorlauf|0.0 bis 0.5 s. Lässt den Funken früher loslaufen, um Latenz auszugleichen, falls er später ankommt als deine Manasprünge|
|
|Tick-Vorlauf|0.0 bis 0.5 s. Lässt den Funken früher loslaufen, um Latenz auszugleichen, falls er später ankommt als deine Manasprünge|
|
||||||
|Funkenbreite|1 bis 4 px|
|
|Funkenbreite|1 bis 4 px|
|
||||||
|
|
||||||
`/fbp ticker` schaltet den Ticker um; `/fbp` meldet, ob das Raster synchron ist, die Zeit bis zum nächsten Tick und eine laufende Fünf-Sekunden-Regel. Einstellungen liegen in `HealBox.Ticker`. Der Ticker teilt sich den Reiter *Extras* mit Smart Damage.
|
`/fbp ticker` schaltet den Ticker um; `/fbp` meldet, ob das Raster synchron ist, die Zeit bis zum nächsten Tick und eine laufende Fünf-Sekunden-Regel. Einstellungen liegen in `HealBox.Ticker`. Der Ticker teilt sich den Reiter *Extras* mit Smart Damage: Den Reiter verwaltet der Kern, jedes Modul bekommt darin einen eigenen Abschnitt, und jedes läuft auch ohne das andere.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -967,7 +1027,7 @@ Rangwahl für **Angriffszauber auf jeder Aktionsleiste**, im eigenen Modul `FBHe
|
|||||||
|
|
||||||
### Wie es arbeitet
|
### Wie es arbeitet
|
||||||
|
|
||||||
Jede Leiste und jedes Tastenkürzel endet in `UseAction(slot)`. Das Modul hängt sich davor, liest Zauber und Rang im Slot per Tooltip-Scan und entscheidet. Der Schaden je Rang ist der **Mindestschaden** aus dem Tooltip („86 to 98 Holy damage"), angehoben durch den kleinsten Volltreffer, den du mit diesem Rang tatsächlich gelandet hast (Crits und Teilwiderstände zählen nicht). Ein Rang kommt in Frage, wenn sein Mindestschaden das Restleben des Ziels plus *Sicherheitsaufschlag* (Standard 20 %) deckt. Makros mit `/cast` bleiben unberührt.
|
Jede Leiste und jedes Tastenkürzel endet in `UseAction(slot)`. Das Modul hängt sich davor, liest Zauber und Rang im Slot per Tooltip-Scan und entscheidet. Der Schaden je Rang ist der **Mindestschaden** aus dem Tooltip („86 to 98 Holy damage"), angehoben um den Bonus, den dein kleinster normaler Treffer mit diesem Rang beweist (Crits und Teilwiderstände zählen nicht): Jeder Treffer liegt höchstens beim Höchstwert des Tooltips plus Bonus, der Mindestschaden also mindestens beim Mindestwert des Tooltips plus *kleinster Treffer minus Höchstwert*. Der kleinste Treffer, weil Verstärker wie Curse of Shadow oder Power Infusion nur manche Treffer heben; ein einzelner verstärkter Treffer darf den Wert nicht dauerhaft anheben. Bis 1.4.6 galt der kleinste Treffer selbst als Mindestschaden, nach einem einzigen hohen Wurf reichte der gewählte Rang dann nicht immer. Ein Rang kommt in Frage, wenn sein Mindestschaden das Restleben des Ziels plus *Sicherheitsaufschlag* (Standard 20 %) deckt. Makros mit `/cast` bleiben unberührt.
|
||||||
|
|
||||||
Das Restleben des Ziels liefert die erste Quelle, die antwortet:
|
Das Restleben des Ziels liefert die erste Quelle, die antwortet:
|
||||||
|
|
||||||
@@ -978,7 +1038,7 @@ Das Restleben des Ziels liefert die erste Quelle, die antwortet:
|
|||||||
|MobInfo-2|`MobHealth_GetTargetCurHP()` kennt den Mob|so gut wie dieses Addon|
|
|MobInfo-2|`MobHealth_GetTargetCurHP()` kennt den Mob|so gut wie dieses Addon|
|
||||||
|Eigene Schätzung|Das Addon hat diesen Mobtyp (Name und Stufe) schon einmal bekämpft|siehe unten|
|
|Eigene Schätzung|Das Addon hat diesen Mobtyp (Name und Stufe) schon einmal bekämpft|siehe unten|
|
||||||
|
|
||||||
**Eigene Schätzung.** Auf reinen Prozent-Servern lernt das Addon je Mobtyp die *Lebenspunkte je Prozent*: Es summiert den Schaden, den es im Combatlog sieht (deinen, den deiner Gruppe, den der Begleiter), und teilt durch den Prozentabfall des Ziels, aber erst ab 3 % Abfall, damit die Rundung auf ganze Prozent nicht stört. Von allen Messungen bleibt die **höchste**, weil Schaden von Raidmitgliedern außerhalb deiner Gruppe unsichtbar ist und die Schätzung sonst nach unten zöge; ein zu hoher Wert kostet nur einen etwas größeren Rang. Das Restleben ist dann die Obergrenze des aktuellen Prozentwerts mal diesem Faktor. Die Schätzung wird je Charakter in `HealBox.MobHP` gespeichert und wird mit jedem Kampf besser; bis ein Typ vermessen ist, lässt Smart Damage dieses Ziel in Ruhe.
|
**Eigene Schätzung.** Auf reinen Prozent-Servern lernt das Addon je Mobtyp die *Lebenspunkte je Prozent*: Es summiert den Schaden, den es im Combatlog sieht (deinen, den deiner Gruppe und der Begleiter, den anderer freundlicher Spieler, Schaden über Zeit eingeschlossen), und teilt durch den Prozentabfall des Ziels, aber erst ab 3 % Abfall, damit die Rundung auf ganze Prozent nicht stört. Von allen Messungen bleibt die **höchste**, weil Schaden, den der Combatlog nicht zeigt (etwa von Spielern außer Reichweite), die Schätzung sonst nach unten zöge; ein zu hoher Wert kostet nur einen etwas größeren Rang. Im Raid misst das Addon nicht und nutzt die Schätzung auch nicht: Den Schaden der anderen Gruppen zeigt der Combatlog dort nicht vollständig, jede Messung fiele zu niedrig aus. Bis 1.4.6 maß es auch im Raid, und bei Mobtypen, die man nur dort trifft, gab es keine saubere Messung; solche Werte älterer Versionen bleiben im Raid deshalb unbeachtet. Echte Werte, MobHealth3 und MobInfo-2 gelten dort weiter. Das Restleben ist dann die Obergrenze des aktuellen Prozentwerts mal diesem Faktor. Die Schätzung wird je Charakter in `HealBox.MobHP` gespeichert und wird mit jedem Kampf besser; bis ein Typ vermessen ist, lässt Smart Damage dieses Ziel in Ruhe. Gemerkt werden höchstens `FBDMG_MOBHP_MAX` (400) Mobtypen; darüber fallen die am längsten nicht gesehenen weg.
|
||||||
|
|
||||||
### Abschnitt *Smart Damage* im Reiter *Extras*
|
### Abschnitt *Smart Damage* im Reiter *Extras*
|
||||||
|
|
||||||
@@ -991,6 +1051,8 @@ Das Restleben des Ziels liefert die erste Quelle, die antwortet:
|
|||||||
|
|
||||||
Zauber je Klasse: Priester Göttliche Pein, Heiliges Feuer, Gedankenschlag; Druide Zorn, Sternenfeuer, Mondfeuer; Schamane Blitzschlag, Kettenblitzschlag, Erd-/Flammen-/Frostschock; Paladin Heiliger Schock, Hammer des Zorns, Exorzismus, Heiliger Zorn; Magier Feuerball, Frostblitz, Feuerschlag, Versengen, Pyroschlag; Hexenmeister Schattenblitz, Sengender Schmerz, Feuerbrand, Seelenfeuer, Feuersbrunst; Jäger Arkaner Schuss, Gezielter Schuss (Liste `FBDamageSpells`). `/fbp damage` schaltet um, `/fbp debug` protokolliert jede Entscheidung mit der genutzten Lebensquelle. Hinweis für Jäger: Für diese Klasse lädt das Addon nicht, Smart Damage läuft also erst nach `/fbp forceload`, siehe [Für welche Klassen es lädt](#für-welche-klassen-es-lädt).
|
Zauber je Klasse: Priester Göttliche Pein, Heiliges Feuer, Gedankenschlag; Druide Zorn, Sternenfeuer, Mondfeuer; Schamane Blitzschlag, Kettenblitzschlag, Erd-/Flammen-/Frostschock; Paladin Heiliger Schock, Hammer des Zorns, Exorzismus, Heiliger Zorn; Magier Feuerball, Frostblitz, Feuerschlag, Versengen, Pyroschlag; Hexenmeister Schattenblitz, Sengender Schmerz, Feuerbrand, Seelenfeuer, Feuersbrunst; Jäger Arkaner Schuss, Gezielter Schuss (Liste `FBDamageSpells`). `/fbp damage` schaltet um, `/fbp debug` protokolliert jede Entscheidung mit der genutzten Lebensquelle. Hinweis für Jäger: Für diese Klasse lädt das Addon nicht, Smart Damage läuft also erst nach `/fbp forceload`, siehe [Für welche Klassen es lädt](#für-welche-klassen-es-lädt).
|
||||||
|
|
||||||
|
Solange Smart Damage aus ist, hört das Modul weder auf den Combatlog noch auf das Leben des Ziels, und die Angriffszauber liest es erst aus dem Zauberbuch, wenn du die Optionen öffnest.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Optionsfenster
|
## Optionsfenster
|
||||||
@@ -1001,9 +1063,9 @@ Zu öffnen über den **Minimap-Button**:
|
|||||||
|-|-|
|
|-|-|
|
||||||
|Linksklick|Optionsfenster auf/zu|
|
|Linksklick|Optionsfenster auf/zu|
|
||||||
|Shift + Linksklick|Gesamte Anzeige ein-/ausblenden|
|
|Shift + Linksklick|Gesamte Anzeige ein-/ausblenden|
|
||||||
|Rechts halten und ziehen|Minimap-Button verschieben|
|
|Rechts halten und ziehen|Minimap-Button verschieben; die Stelle bleibt je Charakter gespeichert|
|
||||||
|
|
||||||
Das Fenster hat zwei Reiter.
|
Das Fenster hat zwei eigene Reiter, *Buttons* und *Allgemein*. Die Module ergänzen *Raidmodus* und *Extras* (Mana-Ticker und Smart Damage).
|
||||||
|
|
||||||
### Reiter *Buttons*
|
### Reiter *Buttons*
|
||||||
|
|
||||||
@@ -1027,9 +1089,11 @@ Das Fenster hat zwei Reiter.
|
|||||||
|
|
||||||
**Standard-Gruppenfenster**: statt eigener Plaketten hängen die Buttons an Blizzards Standard-Gruppenfenstern (`PartyMemberFrameN`); die Pet-Buttons an `PetFrame` bzw. `PartyMemberFrameNPetFrame`. Die eigenen Namensplaketten und Balken werden dabei ausgeblendet; die Heilvorhersage arbeitet unsichtbar weiter.
|
**Standard-Gruppenfenster**: statt eigener Plaketten hängen die Buttons an Blizzards Standard-Gruppenfenstern (`PartyMemberFrameN`); die Pet-Buttons an `PetFrame` bzw. `PartyMemberFrameNPetFrame`. Die eigenen Namensplaketten und Balken werden dabei ausgeblendet; die Heilvorhersage arbeitet unsichtbar weiter.
|
||||||
|
|
||||||
|
**Balkenhintergrund**: wie deckend die Fläche hinter den Balken liegt, 0 bis 100 Prozent in Fünferschritten. Standard 0, also das bisherige Bild: Wo Leben fehlt, scheint die Spielwelt durch die Plakette. Hochgedreht liegt eine ruhige dunkelgraue Fläche hinter den Balken (`FBBAR_BG_COLOR`), das Grün des Lebensbalkens steht dann auf festem Grund statt auf Gras, Himmel oder Stein. Bei 100 ist die Plakette undurchsichtig. Angeregt von einem Nutzer, dem der durchscheinende Balken schlecht lesbar war, und einen Versuch wert für alle mit hellem Bildschirm oder unruhiger Umgebung.
|
||||||
|
|
||||||
**Manabalken**: Manastreifen im Lebensbalken an/aus. Standardmäßig an.
|
**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.
|
**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, die das Addon selbst versteckt hat, sofort zurück; was ein anderes Addon versteckt hat, bleibt versteckt. Eine Klasse, für die das Addon nicht lädt, bekommt sie ebenfalls zurück. Stehen in gespeicherten Einstellungen beide Optionen auf an (aus einer alten Version oder von Hand bearbeitet), gewinnt beim Laden der Anheftmodus.
|
||||||
|
|
||||||
**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.
|
**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.
|
||||||
|
|
||||||
@@ -1100,6 +1164,8 @@ Der Kern des Addons. Drei unabhängige Quellen speisen die Balken.
|
|||||||
|
|
||||||
`SPELLCAST_START` liefert Zaubernamen und Castdauer in Millisekunden, unabhängig davon, ob der Cast vom HealBox-Button, der Aktionsleiste oder aus einem Makro kommt. Es braucht dafür keinen Hook auf `CastSpellByName`. Die Vorschau verschwindet bei `SPELLCAST_STOP`, `_FAILED` und `_INTERRUPTED`, Pushback (`SPELLCAST_DELAYED`) verlängert sie.
|
`SPELLCAST_START` liefert Zaubernamen und Castdauer in Millisekunden, unabhängig davon, ob der Cast vom HealBox-Button, der Aktionsleiste oder aus einem Makro kommt. Es braucht dafür keinen Hook auf `CastSpellByName`. Die Vorschau verschwindet bei `SPELLCAST_STOP`, `_FAILED` und `_INTERRUPTED`, Pushback (`SPELLCAST_DELAYED`) verlängert sie.
|
||||||
|
|
||||||
|
Ziel ist die Einheit des angeklickten Heal Box Buttons, sofern derselbe Zauber binnen `FBPREDICT_CLICK_TIME` (2 Sekunden) nach dem Klick anläuft; ein Klick, während noch ein anderer Zauber gewirkt wird, wartet auf den nächsten Castbeginn, das passt auch zur Zauberwarteschlange von Clientmods. Ein Cast von der Aktionsleiste oder aus einem Makro geht an dein freundliches Ziel, sonst an dich selbst. Ein Klick gilt für genau einen Cast: Ist sein Zauber angelaufen, durchgegangen oder gescheitert, gehört der nächste Cast nicht mehr zu ihm. Eine Fehlermeldung oder ein gescheiterter Cast beantwortet immer den jüngsten Versuch. Damit klar ist, welcher das ist, zählt das Addon jeden Versuch mit, auch von der Aktionsleiste, aus Makros und aus dem Zauberbuch; dafür hängt es sich vor `UseAction`, `CastSpellByName` und `CastSpell`, zählt und reicht alles unverändert weiter. Bis 1.4.6 galt das Ziel eines Klicks zwei Sekunden und sein Rang drei Sekunden lang für jeden folgenden Cast, auch nach einem gescheiterten Klick.
|
||||||
|
|
||||||
Instants bekommen bewusst **keine** Vorhersage: Die Heilung ist da, bevor ein Balken sie zeigen könnte.
|
Instants bekommen bewusst **keine** Vorhersage: Die Heilung ist da, bevor ein Balken sie zeigen könnte.
|
||||||
|
|
||||||
### Heilung über Zeit
|
### Heilung über Zeit
|
||||||
@@ -1107,11 +1173,11 @@ Instants bekommen bewusst **keine** Vorhersage: Die Heilung ist da, bevor ein Ba
|
|||||||
`UnitBuff()` liefert für fremde Einheiten keine Restlaufzeit, das Addon führt deshalb selbst Buch:
|
`UnitBuff()` liefert für fremde Einheiten keine Restlaufzeit, das Addon führt deshalb selbst Buch:
|
||||||
|
|
||||||
1. Der Button meldet den Cast samt Ziel und Rang vor.
|
1. Der Button meldet den Cast samt Ziel und Rang vor.
|
||||||
2. `UNIT_AURA` bestätigt die Anwendung über den **Buff-Textur-Vergleich** mit dem Zauberbuch-Icon (locale-unabhängig, kein Tooltip-Scan pro Event).
|
2. Ist der Cast durchgegangen (`SPELLCAST_STOP`), bestätigt `UNIT_AURA` die Anwendung über den **Buff-Textur-Vergleich** mit dem Zauberbuch-Icon (locale-unabhängig, kein Tooltip-Scan pro Event). Ein gescheiterter Klick (außer Reichweite, keine Sicht, globaler Cooldown) bestätigt nichts; ein HoT oder Schild eines anderen Heilers auf demselben Ziel gilt so nicht als deiner.
|
||||||
3. Angezeigt wird `Restticks × Heilung pro Tick`, wobei die Restticks aus `(Ablauf − GetTime()) / Intervall` fallen. Der Balken zählt damit Tick für Tick herunter.
|
3. Angezeigt wird `Restticks × Heilung pro Tick`, wobei die Restticks aus `(Ablauf − GetTime()) / Intervall` fallen. Der Balken zählt damit Tick für Tick herunter.
|
||||||
4. Fällt der Buff vorzeitig weg (Dispel, Tod, Überschrieben), ist die Anzeige sofort weg.
|
4. Fällt der Buff vorzeitig weg (Dispel, Tod, Überschrieben), ist die Anzeige sofort weg.
|
||||||
|
|
||||||
HoTs von der Aktionsleiste werden ebenfalls erkannt, dann mit dem höchsten bekannten Rang; der erste Combatlog-Tick zieht den Wert gerade.
|
HoTs, die das Addon nur als Buff sieht (von der Aktionsleiste, aus einem Makro oder von einem anderen Heiler mit demselben Zauber), werden **vorläufig** mit deinem höchsten bekannten Rang notiert. Sie zählen weder in der Vorhersage noch als Timer auf dem Button, bis dein eigener erster Tick kommt (`… from your Renew.`); der bestätigt den HoT und zieht den Wert gerade. Kommt binnen eines Tickintervalls plus `FBPREDICT_HOT_CONFIRM_GRACE` (1,5) Sekunden keiner von dir, gehört der HoT jemand anderem: Er wird verworfen und nicht wieder aufgenommen, solange dieser Buff bleibt. Kommt ein Tick von dir für einen HoT, der gar nicht verfolgt wird, wird er sofort aufgenommen, mit einem Intervall weniger Restlaufzeit. `/fbp` kennzeichnet vorläufige HoTs mit `(?)`. Bis 1.4.6 galt jeder so erkannte HoT als deiner, mit deinem höchsten Rang und voller Laufzeit.
|
||||||
|
|
||||||
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).
|
||||||
|
|
||||||
@@ -1119,6 +1185,8 @@ Das Tickintervall ist in Vanilla nicht aus dem Tooltip lesbar und steht deshalb
|
|||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
|
Die Zauberzeit stammt aus dem Tooltip jedes einzelnen Rangs, ebenso Reichweite und Abklingzeit (`/fbp` listet alle drei je Zauber). Ränge, die unter Stufe 20 gelernt werden, bekommen wie im Spiel nur einen Teil des Bonus: je Stufe unter 20 sind es 3,75 Prozent weniger, Geringes Heilen Rang 3 (gelernt mit Stufe 10) erhält also 62,5 Prozent. Der Tooltip verrät die Lernstufe eines Rangs nicht, deshalb stehen diese Ränge in `FBRankLearnLevel`. Ohne diesen Abschlag hielte Smart Healing kleine Ränge mit viel +Heilung für deutlich stärker, als sie sind.
|
||||||
|
|
||||||
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.
|
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
|
||||||
@@ -1129,6 +1197,8 @@ Absorbierst du mehr, als der Tooltip hergibt (Heal-Gear), wird das Maximum **nac
|
|||||||
|
|
||||||
Vollständig absorbierte Treffer melden in Vanilla keine Zahl. Der Restwert bleibt dann stehen, bis der Buff fällt und die Anzeige gelöscht wird. Ebenso zählen Absorbs an Gruppenmitgliedern nur, soweit der Combatlog sie überhaupt zeigt; der Aura-Abgleich fängt die Abweichung am Ende wieder ein.
|
Vollständig absorbierte Treffer melden in Vanilla keine Zahl. Der Restwert bleibt dann stehen, bis der Buff fällt und die Anzeige gelöscht wird. Ebenso zählen Absorbs an Gruppenmitgliedern nur, soweit der Combatlog sie überhaupt zeigt; der Aura-Abgleich fängt die Abweichung am Ende wieder ein.
|
||||||
|
|
||||||
|
Ein Schild, den das Addon nur als Buff sieht (der eines anderen Priesters oder deiner von der Aktionsleiste), steht mit seinem Tooltipwert da, denn die Ausrüstung des Wirkers kennt niemand; dein gelernter Wert gilt nur für Schilde, die du über die Heal Box Buttons wirkst. Nur diese bekommen auch den Timer auf dem Button und starten die **Geschwächte Seele**. Die läuft in einer eigenen Tabelle für `FBWEAKENED_SOUL_SEC` (15) Sekunden, unabhängig vom Schild, und bleibt so sichtbar, wenn der Schild bricht. Bis 1.4.6 wurde sie aus dem Schildeintrag berechnet, der genau beim Brechen des Schilds verschwindet; zu sehen war sie deshalb so gut wie nie.
|
||||||
|
|
||||||
### Selbstkorrektur und Lernspeicher
|
### Selbstkorrektur und Lernspeicher
|
||||||
|
|
||||||
Tooltips liefern in 1.12 nur Basiswerte **ohne** +Heilung, und eine API für Zaubermacht gibt es nicht. Der Combatlog liefert dagegen die Wahrheit:
|
Tooltips liefern in 1.12 nur Basiswerte **ohne** +Heilung, und eine API für Zaubermacht gibt es nicht. Der Combatlog liefert dagegen die Wahrheit:
|
||||||
@@ -1141,7 +1211,7 @@ Tooltips liefern in 1.12 nur Basiswerte **ohne** +Heilung, und eine API für Zau
|
|||||||
|
|
||||||
Alles davon landet pro Zauber **und Rang** in `HealBox.PredictMemory` und übersteht den Logout.
|
Alles davon landet pro Zauber **und Rang** in `HealBox.PredictMemory` und übersteht den Logout.
|
||||||
|
|
||||||
Zwei Schutzregeln halten den Speicher sauber. **Crits werden nicht gelernt**: die Crit-Formulierung lässt den Zaubernamen als „Flash Heal critically" durchs Muster fallen, und der steht in keiner Watchlist. Und gelernt wird nur bei **gesichertem Rang**, also bei Casts über die HealBox-Buttons; sonst würde ein Rang-3-Cast von der Aktionsleiste dem Maximalrang zugeschrieben und die Vorhersage nach unten ziehen. Die laufende Anzeige korrigiert sich trotzdem immer, geschützt ist nur der dauerhafte Speicher.
|
Zwei Schutzregeln halten den Speicher sauber. **Crits werden nicht gelernt**: die Crit-Formulierung lässt den Zaubernamen als „Flash Heal critically" durchs Muster fallen, und der steht in keiner Watchlist. Und gelernt wird nur bei **gesichertem Rang**, also bei Casts über die HealBox-Buttons; sonst würde ein Rang-3-Cast von der Aktionsleiste dem Maximalrang zugeschrieben und die Vorhersage nach unten ziehen. Die laufende Anzeige korrigiert sich trotzdem immer, geschützt ist nur der dauerhafte Speicher. Die Heilung steht meist erst nach dem Castende im Combatlog, ein beendeter Cast wartet deshalb noch `FBPREDICT_CLICK_TIME` (2) Sekunden auf seine Zeile. Bis 1.4.6 zählte nur ein noch laufender Cast, Direktheilungen wurden so kaum gelernt.
|
||||||
|
|
||||||
Welcher Zauber was kann, entscheidet der Tooltip selbst; ein Zauber darf mehreres sein. Regrowth etwa liefert Sofortheilung *und* HoT und wird auch so behandelt.
|
Welcher Zauber was kann, entscheidet der Tooltip selbst; ein Zauber darf mehreres sein. Regrowth etwa liefert Sofortheilung *und* HoT und wird auch so behandelt.
|
||||||
|
|
||||||
@@ -1160,11 +1230,11 @@ HealComm-1.0 funkt reinen Klartext über `SendAddonMessage` mit dem Prefix `Heal
|
|||||||
|`GrpHealstop` · `GrpHealdelay/<ms>/`|dito für Gruppenheilung|
|
|`GrpHealstop` · `GrpHealdelay/<ms>/`|dito für Gruppenheilung|
|
||||||
|`Renew` · `Reju` · `Regr` `/<Ziel>/<Dauer>/`|HoT angewendet|
|
|`Renew` · `Reju` · `Regr` `/<Ziel>/<Dauer>/`|HoT angewendet|
|
||||||
|
|
||||||
Gesendet wird ins Raid, sonst in die Gruppe, sonst gar nicht. Die Beträge sind die selbstkorrigierten Combatlog-Werte, also eher genauer als das, was ein echtes HealComm mit ItemBonusLib schätzt.
|
Gesendet wird ins Raid, sonst in die Gruppe, sonst gar nicht. Im Schlachtfeld geht es über den Kanal `BATTLEGROUND`, wie bei HealComm-1.0, denn über `RAID` erreicht man dort niemanden. Die Beträge sind die selbstkorrigierten Combatlog-Werte, also eher genauer als das, was ein echtes HealComm mit ItemBonusLib schätzt.
|
||||||
|
|
||||||
Ein paar Feinheiten: Bei erfolgreichem Castende geht **kein** `Healstop` raus; HealComm-Empfänger lassen den Eintrag selbst zur Castzeit auslaufen. Prayer of Healing geht korrekt als `GrpHeal` mit allen Zielen in Reichweite raus. Und ein HoT von der Aktionsleiste wird beim ersten eigenen Combatlog-Tick nachgemeldet, mit der dann noch verbleibenden Laufzeit, denn erst „… from **your** Renew" beweist, dass er von dir stammt.
|
Ein paar Feinheiten: Bei erfolgreichem Castende geht **kein** `Healstop` raus; HealComm-Empfänger lassen den Eintrag selbst zur Castzeit auslaufen. Prayer of Healing geht korrekt als `GrpHeal` mit allen Zielen in Reichweite raus. Und ein HoT von der Aktionsleiste wird beim ersten eigenen Combatlog-Tick nachgemeldet, mit der dann noch verbleibenden Laufzeit, denn erst „… from **your** Renew" beweist, dass er von dir stammt. Eingehende Befehle liest das Addon unabhängig von großen und kleinen Buchstaben; pfUI etwa schickt `HealStop`.
|
||||||
|
|
||||||
Beim Empfang werden eigene Nachrichten über den Absendernamen gefiltert, und da HealComm eingehende Heilungen pro Caster ablegt, kann sich nichts doppeln, selbst wenn parallel noch ein echtes HealComm mitfunkt. HoT-Nachrichten tragen nur Laufzeiten und keine Beträge; HealComm zählt sie im eigenen `getHeal` nicht mit, hier passiert dasselbe.
|
Beim Empfang werden eigene Nachrichten über den Absendernamen gefiltert, und da HealComm eingehende Heilungen pro Caster ablegt, kann sich nichts doppeln, selbst wenn parallel noch ein echtes HealComm mitfunkt. HoT-Nachrichten tragen nur Laufzeiten und keine Beträge; HealComm zählt sie im eigenen `getHeal` nicht mit, hier passiert dasselbe. Werte anderer Addons werden begrenzt: Beträge auf `FBCOMM_MAX_AMOUNT` (20000), Zauberzeiten und Verzögerungen auf `FBCOMM_MAX_CAST_MS` (10 Sekunden). Eine kaputte Nachricht kann so keinen Balken minutenlang füllen.
|
||||||
|
|
||||||
**Absorb-Schilde kennt das Protokoll nicht**: die bleiben lokal.
|
**Absorb-Schilde kennt das Protokoll nicht**: die bleiben lokal.
|
||||||
|
|
||||||
@@ -1209,6 +1279,7 @@ Alles liegt in der Tabelle `HealBox`, gespeichert **pro Charakter**:
|
|||||||
|`ButtonSpacing`|Abstand der Buttons in px (0 bis 20)|
|
|`ButtonSpacing`|Abstand der Buttons in px (0 bis 20)|
|
||||||
|`RowSpacing`|Abstand der Plaketten in px (0 bis 20)|
|
|`RowSpacing`|Abstand der Plaketten in px (0 bis 20)|
|
||||||
|`ManaBar`|1 = Manastreifen an, 0 = aus|
|
|`ManaBar`|1 = Manastreifen an, 0 = aus|
|
||||||
|
|`BarBG`|Deckkraft des Balkenhintergrunds in Prozent, 0 bis 100. 0 (Standard) behält das durchscheinende Bild|
|
||||||
|`ShowPets`|1 = Pet-Plaketten an, 0 = aus|
|
|`ShowPets`|1 = Pet-Plaketten an, 0 = aus|
|
||||||
|`SpellChoiceR[1..10]`|Cast-String je Button für Rechtsklick|
|
|`SpellChoiceR[1..10]`|Cast-String je Button für Rechtsklick|
|
||||||
|`RightClick`|1 = Rechtsklick-Zauber an, 0 = aus (Standard)|
|
|`RightClick`|1 = Rechtsklick-Zauber an, 0 = aus (Standard)|
|
||||||
@@ -1226,12 +1297,15 @@ Alles liegt in der Tabelle `HealBox`, gespeichert **pro Charakter**:
|
|||||||
|`WatchBuff`|Zaubername der Buff-Wache oder nil|
|
|`WatchBuff`|Zaubername der Buff-Wache oder nil|
|
||||||
|`BuffWatchPets`|1 = Buff-Wache auch für Pets, 0 = nur Spieler (Standard)|
|
|`BuffWatchPets`|1 = Buff-Wache auch für Pets, 0 = nur Spieler (Standard)|
|
||||||
|`PosX` · `PosY`|Linke obere Ecke der Spielerplakette in Bildschirmpixeln|
|
|`PosX` · `PosY`|Linke obere Ecke der Spielerplakette in Bildschirmpixeln|
|
||||||
|
|`MinimapPos`|Position des Minimap-Buttons als Versatz zur Minimap-Mitte, gespeichert, sobald du ihn mit der rechten Maustaste ziehst. Ohne Eintrag bleibt er an der alten Stelle|
|
||||||
|`Ticker`|Untertabelle mit den Mana-Ticker-Einstellungen (siehe [Mana-Ticker](#mana-ticker))|
|
|`Ticker`|Untertabelle mit den Mana-Ticker-Einstellungen (siehe [Mana-Ticker](#mana-ticker))|
|
||||||
|`Damage`|Untertabelle mit den Smart-Damage-Einstellungen; `MobHP` und `DmgMemory` halten gelernte Mob-Leben und Mindestschäden (siehe [Smart Damage](#smart-damage))|
|
|`Damage`|Untertabelle mit den Smart-Damage-Einstellungen (siehe [Smart Damage](#smart-damage))|
|
||||||
|
|`MobHP`|Von Smart Damage gelernte Lebenspunkte je Prozent für jeden Mobtyp (`Name:Stufe`), höchstens `FBDMG_MOBHP_MAX` Einträge|
|
||||||
|
|`DmgMemory`|Kleinster normaler Treffer je Zauber und Rang, Grundlage des gelernten Mindestschadens von Smart Damage|
|
||||||
|`Raid`|Untertabelle mit allen Raidmodus-Einstellungen (siehe [Raidmodus](#raidmodus)), einschließlich `PosX` / `PosY` des Rasters|
|
|`Raid`|Untertabelle mit allen Raidmodus-Einstellungen (siehe [Raidmodus](#raidmodus)), einschließlich `PosX` / `PosY` des Rasters|
|
||||||
|`PredictMemory`|Gelernte Heilwerte je Zauber und Rang|
|
|`PredictMemory`|Gelernte Heilwerte je Zauber und Rang|
|
||||||
|
|
||||||
Fehlende Schlüssel, etwa in einer alten `HealBox`-Tabelle aus 1.4, zieht `FBHealBox_ApplyDefaults()` beim Laden nach. Der Testmodus wird bewusst **nicht** gespeichert.
|
Fehlende Schlüssel, etwa in einer alten `HealBox`-Tabelle aus 1.4, zieht `FBHealBox_ApplyDefaults()` beim Laden nach, aus der einen Vorgabetabelle `FBHealBoxDefaults`. Der Testmodus wird bewusst **nicht** gespeichert.
|
||||||
|
|
||||||
## Konfiguration im Code
|
## Konfiguration im Code
|
||||||
|
|
||||||
@@ -1239,11 +1313,12 @@ Alle Stellschrauben stehen als Globals oben in ihrem jeweiligen Abschnitt und la
|
|||||||
|
|
||||||
|Konstante|Standard|Wirkung|
|
|Konstante|Standard|Wirkung|
|
||||||
|-|-|-|
|
|-|-|-|
|
||||||
|`LowHP` · `VeryLowHP`|0.6 · 0.3|Schwellen für gelb und rot|
|
|`FBLowHP` · `FBVeryLowHP`|0.6 · 0.3|Schwellen für gelb und rot|
|
||||||
|`NamePlateWidth` · `NamePlateHeight`|120 · 28|Größe einer Plakette|
|
|`FBNamePlateWidth` · `FBNamePlateHeight`|120 · 28|Größe einer Plakette|
|
||||||
|`FBMANA_BAR_HEIGHT`|5|Höhe des Manastreifens in px|
|
|`FBMANA_BAR_HEIGHT`|5|Höhe des Manastreifens in px|
|
||||||
|`FBMANA_BAR_COLOR`|`{0.15, 0.4, 1, 1}`|Farbe des Manastreifens|
|
|`FBMANA_BAR_COLOR`|`{0.15, 0.4, 1, 1}`|Farbe des Manastreifens|
|
||||||
|`FBMANA_BG_ALPHA`|0.35|Dunkler Streifen hinter fehlendem Mana (0 = aus)|
|
|`FBMANA_BG_ALPHA`|0.35|Dunkler Streifen hinter fehlendem Mana (0 = aus)|
|
||||||
|
|`FBBAR_BG_COLOR`|0.15 · 0.15 · 0.15|Grundton des Balkenhintergrunds; wie deckend er liegt, regelt die Option `BarBG`|
|
||||||
|`FBPET_NAME_COLOR`|`{0.75, 0.85, 1, 1}`|Namensfarbe auf Pet-Plaketten|
|
|`FBPET_NAME_COLOR`|`{0.75, 0.85, 1, 1}`|Namensfarbe auf Pet-Plaketten|
|
||||||
|`FBPET_INDENT`|12|Einrückung (und Verschmälerung) der Pet-Plaketten|
|
|`FBPET_INDENT`|12|Einrückung (und Verschmälerung) der Pet-Plaketten|
|
||||||
|`FBPET_ICON` · `FBPET_ICON_SIZE`|Fußabdruck · 12|Pfoten-Icon vor Pet-Namen|
|
|`FBPET_ICON` · `FBPET_ICON_SIZE`|Fußabdruck · 12|Pfoten-Icon vor Pet-Namen|
|
||||||
@@ -1251,11 +1326,13 @@ Alle Stellschrauben stehen als Globals oben in ihrem jeweiligen Abschnitt und la
|
|||||||
|`FBLOS_ICON` · `FBLOS_ICON_SIZE`|Blenden-Icon · 12|Sichtlinien-Abzeichen|
|
|`FBLOS_ICON` · `FBLOS_ICON_SIZE`|Blenden-Icon · 12|Sichtlinien-Abzeichen|
|
||||||
|`FBLOS_ICON_X` · `FBLOS_ICON_Y`|-3 · 3|Versatz des Abzeichens von der linken oberen Plattenecke|
|
|`FBLOS_ICON_X` · `FBLOS_ICON_Y`|-3 · 3|Versatz des Abzeichens von der linken oberen Plattenecke|
|
||||||
|`FBLOS_TIMEOUT`|8|Sekunden, die ein Sichtlinien-Fehler ohne UnitXP markiert bleibt|
|
|`FBLOS_TIMEOUT`|8|Sekunden, die ein Sichtlinien-Fehler ohne UnitXP markiert bleibt|
|
||||||
|
|`FBLOS_ERROR_WINDOW`|1.0|Sekunden nach dem Klick (oder nach dem Castende), in denen ein Sichtlinienfehler noch zur angeklickten Einheit gehört|
|
||||||
|`FBNAME_WIDTH_FULL` · `FBNAME_WIDTH_ICON`|78 · 60|Breite der Namensbox ohne / mit sichtbarem Debuff-Icon|
|
|`FBNAME_WIDTH_FULL` · `FBNAME_WIDTH_ICON`|78 · 60|Breite der Namensbox ohne / mit sichtbarem Debuff-Icon|
|
||||||
|`FBRANGE_ALPHA` · `FBRANGE_INTERVAL`|0.5 · 0.5|Deckkraft und Prüfintervall des Reichweiten-Fadings|
|
|`FBRANGE_ALPHA` · `FBRANGE_INTERVAL`|0.5 · 0.5|Deckkraft und Prüfintervall des Reichweiten-Fadings|
|
||||||
|`FBBUFF_MISSING_COLOR`|`{1, 0.5, 0, 1}`|Rahmenfarbe bei fehlendem Wache-Buff|
|
|`FBBUFF_MISSING_COLOR`|`{1, 0.5, 0, 1}`|Rahmenfarbe bei fehlendem Wache-Buff|
|
||||||
|`FBAGGRO_COLOR`|`{1, 0.15, 0.15, 1}`|Rahmenfarbe für den Angegriffenen|
|
|`FBAGGRO_COLOR`|`{1, 0.15, 0.15, 1}`|Rahmenfarbe für den Angegriffenen|
|
||||||
|`FBCD_MIN_DURATION`|2|Kürzere Cooldowns (globaler Cooldown) werden nicht gezeigt|
|
|`FBCD_MIN_DURATION`|2|Länge des globalen Cooldowns: Eine Abklingzeit bis zu dieser Länge dunkelt keinen Button ab|
|
||||||
|
|`FBCD_SHOW_MIN`|0|Ab welcher Länge die Cooldown-Uhr läuft. 0 zeigt jede Abklingzeit samt globalem Cooldown, 2 lässt ihn weg|
|
||||||
|`FBTIMER_COLOR_HOT` · `_SHIELD` · `_WS`|grün · blau · rot|Timerfarben auf den Buttons|
|
|`FBTIMER_COLOR_HOT` · `_SHIELD` · `_WS`|grün · blau · rot|Timerfarben auf den Buttons|
|
||||||
|`FBBUFFICON_SIZE` · `FBBUFFICON_GAP` · `FBBUFFICON_MAX` · `FBBUFFICON_XOFF`|8 · 1 · 6 · -2|Buff-Icons links neben der Plakette|
|
|`FBBUFFICON_SIZE` · `FBBUFFICON_GAP` · `FBBUFFICON_MAX` · `FBBUFFICON_XOFF`|8 · 1 · 6 · -2|Buff-Icons links neben der Plakette|
|
||||||
|`FBBUFFICON_STEPS` · `FBBUFFICON_GREY`|32 · 0.30|Anzahl Ablaufstufen (32) und Grauton, falls Client nicht entsättigen kann|
|
|`FBBUFFICON_STEPS` · `FBBUFFICON_GREY`|32 · 0.30|Anzahl Ablaufstufen (32) und Grauton, falls Client nicht entsättigen kann|
|
||||||
@@ -1265,22 +1342,30 @@ Alle Stellschrauben stehen als Globals oben in ihrem jeweiligen Abschnitt und la
|
|||||||
|`FBBuffWatchSpells` · `FBBuffAlternates`|(Tabelle)|Angebotene Buffs je Klasse und welche Gruppenversion als gleich zählt|
|
|`FBBuffWatchSpells` · `FBBuffAlternates`|(Tabelle)|Angebotene Buffs je Klasse und welche Gruppenversion als gleich zählt|
|
||||||
|`FBPartyUnit` · `FBLayoutOrder`|(Tabelle)|Die zehn Plätze und ihre Anzeigereihenfolge|
|
|`FBPartyUnit` · `FBLayoutOrder`|(Tabelle)|Die zehn Plätze und ihre Anzeigereihenfolge|
|
||||||
|`FBTestGhosts`|(Tabelle)|Namen und Werte der Geister im Testmodus|
|
|`FBTestGhosts`|(Tabelle)|Namen und Werte der Geister im Testmodus|
|
||||||
|`MaxButtonCount`|10|Maximale Buttonzahl|
|
|`FBMaxButtonCount`|10|Maximale Buttonzahl|
|
||||||
|`FBMENU_BTN_HEIGHT` · `FBMENU_ICON_SIZE`|17 · 16|Zeilenhöhe und Icon-Größe im Menü|
|
|`FBMENU_BTN_HEIGHT` · `FBMENU_ICON_SIZE`|17 · 16|Zeilenhöhe und Icon-Größe im Menü|
|
||||||
|`FBMENU_MOUSE_PAD`|14|Toleranzzone um die Menüs|
|
|`FBMENU_MOUSE_PAD`|14|Toleranzzone um die Menüs|
|
||||||
|`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_HOT_CONFIRM_GRACE`|1.5|Sekunden nach dem ersten erwarteten Tick, in denen ein nur als Buff gesehener HoT noch durch einen Tick von dir bestätigt werden kann; danach gilt er als fremd|
|
||||||
|`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|
|
|`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|
|
|`FBTICK_GEOM_STEP`|0.25|Wie oft der Ticker die Balkenmaße nachliest (der Funke selbst wird in jedem Frame gezeichnet)|
|
||||||
|`FBPREDICT_CONFIRM_TIME`|3.0|Wartezeit auf die Aura-Bestätigung|
|
|`FBPREDICT_CONFIRM_TIME`|3.0|Wartezeit auf die Aura-Bestätigung, nachdem der Cast durchgegangen ist|
|
||||||
|`FBPREDICT_TARGET_TIME`|2.0|Gültigkeit des gemerkten Cast-Ziels|
|
|`FBPREDICT_CLICK_TIME`|2.0|Sekunden, in denen die Antwort des Servers (Castbeginn, Castende, Fehler, Heilung im Combatlog) noch zu einem Klick auf einen Heal Box Button gehört; bei Zaubern mit Zauberzeit ab dem Castende gezählt|
|
||||||
|`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)|
|
|`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|
|
||||||
|
|`FBSmartSkip`|(Tabelle)|Gruppenheilungen und Zauber mit Abklingzeit, die Smart Healing immer wie belegt wirkt (Zauber mit Abklingzeit im Tooltip bleiben ohnehin unberührt)|
|
||||||
|
|`FBRankLearnLevel`|(Tabelle)|Lernstufe der Ränge unter Stufe 20, für den gekürzten Anteil an +Heilung|
|
||||||
|`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|
|
||||||
|
|`FBHealBoxDefaults`|(Tabelle)|Vorgabe jeder Einstellung; fehlende Schlüssel kommen von hier|
|
||||||
|
|`FBCOMM_MAX_AMOUNT` · `FBCOMM_MAX_CAST_MS`|20000 · 10000|Grenzen für Beträge und Zauberzeiten (ms) in HealComm-Nachrichten anderer|
|
||||||
|
|`FBMINIMAP_ANGLE` · `FBMINIMAP_RADIUS`|4 · 80|Vorgabestelle des Minimap-Buttons, in Grad, wie `cos` und `sin` in WoW rechnen|
|
||||||
|
|`FBSWEEP_FAIL_REPORT`|3|Nach so vielen Fehlern in Folge meldet sich ein Durchlauf für Reichweite oder Sichtlinie im Chat|
|
||||||
|
|`FBDMG_MOBHP_MAX`|400|Gemerkte Mobtypen für die eigene Lebensschätzung von Smart Damage|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -1301,6 +1386,7 @@ Alle Stellschrauben stehen als Globals oben in ihrem jeweiligen Abschnitt und la
|
|||||||
|`FBHealBox_SetPlateVisible(f, visible)`|Blendet alle Balken einer Plakette ein/aus (Party-Frame-Modus)|
|
|`FBHealBox_SetPlateVisible(f, visible)`|Blendet alle Balken einer Plakette ein/aus (Party-Frame-Modus)|
|
||||||
|`FBHealBox_UpdateUnit(unit, frame)`|Schreibt HP, Schild, Vorhersage, Mana und Dispel-Farbe in eine Plakette|
|
|`FBHealBox_UpdateUnit(unit, frame)`|Schreibt HP, Schild, Vorhersage, Mana und Dispel-Farbe in eine Plakette|
|
||||||
|`FBHealBox_UpdateMana(unit, frame)`|Der Manastreifen: nur bei Mana-Nutzern sichtbar|
|
|`FBHealBox_UpdateMana(unit, frame)`|Der Manastreifen: nur bei Mana-Nutzern sichtbar|
|
||||||
|
|`FBHealBox_UpdateUnitMana(unit, frame)`|Schmaler Weg für Mana, Wut, Energie und Fokus: nur der Streifen, nicht die ganze Plakette|
|
||||||
|`FBHealBox_DispelType(unit)`|Erster von der eigenen Klasse entfernbarer Debuff: Typ, Textur, Stacks, sonst nil|
|
|`FBHealBox_DispelType(unit)`|Erster von der eigenen Klasse entfernbarer Debuff: Typ, Textur, Stacks, sonst nil|
|
||||||
|`FBHealBox_UpdateDebuffIcon(frame, tex, count)`|Debuff-Icon und Stackzahl|
|
|`FBHealBox_UpdateDebuffIcon(frame, tex, count)`|Debuff-Icon und Stackzahl|
|
||||||
|`FBHealBox_CastOn(button, castString)`|Wirkt den Zauber eines Buttons (links oder rechts) auf sein Ziel|
|
|`FBHealBox_CastOn(button, castString)`|Wirkt den Zauber eines Buttons (links oder rechts) auf sein Ziel|
|
||||||
@@ -1313,20 +1399,26 @@ Alle Stellschrauben stehen als Globals oben in ihrem jeweiligen Abschnitt und la
|
|||||||
|`FBHealBox_SpellCastSeconds(id)`|Zauberzeit aus dem Tooltip (0 = Instant), je Zauberbuchplatz gemerkt|
|
|`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_ApplyBlizzParty()` · `FBHealBox_HideBlizzPartyActive()`|Versteckt Blizzards Gruppenfenster oder gibt sie zurück, samt Sperre gegen den Anheftmodus|
|
||||||
|`FBHealBox_SetPowerColor(bar, cache, ptype)`|Färbt einen Ressourcenbalken für Mana, Wut, Fokus oder Energie|
|
|`FBHealBox_SetPowerColor(bar, cache, ptype)`|Färbt einen Ressourcenbalken für Mana, Wut, Fokus oder Energie|
|
||||||
|
|`FBHealBox_ApplyBarBG(f)` · `FBHealBox_ApplyBarBGAll()`|Setzt den Hintergrund hinter den Balken einer Plakette nach der Option `BarBG`|
|
||||||
|
|`FBHealBox_RefreshUnitsByName(names)`|Zeichnet nur die Plaketten neu, deren Einheit in der Namensliste steht; das Raidmodul bekommt dieselbe Liste über den Hook `RefreshNames`|
|
||||||
|`FBPredict_ScanPlayerBuffTimes()`|Liest alle eigenen Bufflaufzeiten einmal je Frame in eine Tabelle Textur nach Sekunden|
|
|`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_ApiFailed()`|Stellt Reichweite, Abstand und Sichtlinie auf den geschützten Einzelaufruf zurück, wenn ein Durchlauf geworfen hat|
|
||||||
|
|`FBHealBox_SweepResult(where, ok, err)` · `FBHealBox_ReportError(where, err)`|Wertet einen geschützten Durchlauf aus; meldet Fehler einmal im Chat, weitere mit `/fbp debug`|
|
||||||
|`FBHealBox_UpperTex(tex)`|Groß geschriebener Texturpfad, gemerkt, damit `strupper` nicht je Aufruf zuteilt|
|
|`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_UpdateAllCooldowns()`|Cooldown-Uhr|
|
||||||
|`FBHealBox_ShowTab(n)` · `FBHealBox_ApplyRightClickLayout()`|Options-Reiter; Rechtsklick-Spalte ein-/ausblenden|
|
|`FBHealBox_ShowTab(n)` · `FBHealBox_ApplyRightClickLayout()`|Options-Reiter; Rechtsklick-Spalte ein-/ausblenden|
|
||||||
|
|`FBHealBox_ExtrasSection(height)` · `FBHealBox_CreateSlider(…)` · `FBHealBox_SliderText(s)`|Gemeinsamer Reiter *Extras* und Reglerfabrik für die Module|
|
||||||
|`FBHealBox_PlateMouseDown(f)` · `FBHealBox_PlateMouseUp(f)` · `FBHealBox_RunPlateAction(f, action)`|Klick und Ziehen auf einer Plakette|
|
|`FBHealBox_PlateMouseDown(f)` · `FBHealBox_PlateMouseUp(f)` · `FBHealBox_RunPlateAction(f, action)`|Klick und Ziehen auf einer Plakette|
|
||||||
|`FBHealBox_RefreshAllBars()`|Aktualisiert alle zehn|
|
|`FBHealBox_RefreshAllBars()`|Aktualisiert alle zehn|
|
||||||
|
|`FBHealBox_MarkDirty(name)` · `FBHealBox_FlushDirty()`|Sammelstelle fürs Neuzeichnen: Ereignisse merken den betroffenen Namen vor, gezeichnet wird einmal je Frame|
|
||||||
|`FBUpdateNames()`|Namen und Sichtbarkeit nach Gruppen- oder Pet-Wechsel, danach neu anordnen|
|
|`FBUpdateNames()`|Namen und Sichtbarkeit nach Gruppen- oder Pet-Wechsel, danach neu anordnen|
|
||||||
|`FBSlotActive(p)`|Ist Platz p gerade anzuzeigen?|
|
|`FBSlotActive(p)`|Ist Platz p gerade anzuzeigen?|
|
||||||
|`FBHealBox_Layout()`|Stapelt die sichtbaren Plaketten (Besitzer, dann Pet) mit `RowSpacing`|
|
|`FBHealBox_Layout()`|Stapelt die sichtbaren Plaketten (Besitzer, dann Pet) mit `RowSpacing`|
|
||||||
|`FBHealBox_ApplyButtonSpacing()`|Verkettet alle Buttons neu mit `ButtonSpacing`|
|
|`FBHealBox_ApplyButtonSpacing()`|Verkettet alle Buttons neu mit `ButtonSpacing`|
|
||||||
|`FBHealBox_SavePosition()` · `FBHealBox_RestorePosition()`|Plattenposition in den SavedVariables|
|
|`FBHealBox_SavePosition()` · `FBHealBox_RestorePosition()`|Plattenposition in den SavedVariables|
|
||||||
|
|`FBHealBox_PlaceMinimapButton(b)` · `FBHealBox_SaveMinimapButton(b)`|Position des Minimap-Buttons|
|
||||||
|`FBHealBox_ApplyDefaults()` · `FBHealBox_SyncOptions()`|Fehlende Einstellungen nachziehen; Optionsfenster daran angleichen|
|
|`FBHealBox_ApplyDefaults()` · `FBHealBox_SyncOptions()`|Fehlende Einstellungen nachziehen; Optionsfenster daran angleichen|
|
||||||
|`FBHealBox_ApplyNameColor(unit, f)` · `FBHealBox_ApplyAllNameColors()`|Name in Klassen- bzw. Pet-Farbe|
|
|`FBHealBox_ApplyNameColor(unit, f)` · `FBHealBox_ApplyAllNameColors()`|Name in Klassen- bzw. Pet-Farbe|
|
||||||
|`FBHealBox_SetWatchBuff(name)` · `FBHealBox_HasWatchBuff(unit)` · `FBHealBox_CheckWatchBuff(unit, f)`|Buff-Wache: wählen, eine Einheit prüfen, Rahmen färben|
|
|`FBHealBox_SetWatchBuff(name)` · `FBHealBox_HasWatchBuff(unit)` · `FBHealBox_CheckWatchBuff(unit, f)`|Buff-Wache: wählen, eine Einheit prüfen, Rahmen färben|
|
||||||
@@ -1361,7 +1453,7 @@ Die Anzeige ruft `UnitExists`, `UnitName`, `UnitHealth` und `UnitMana` nie direk
|
|||||||
|`FBHealBoxButtonsChanged()`|Aktualisiert Icons und Zuordnung ohne Neubau|
|
|`FBHealBoxButtonsChanged()`|Aktualisiert Icons und Zuordnung ohne Neubau|
|
||||||
|`FBLoadSpellData()`|Scannt das Zauberbuch, sammelt alle Ränge|
|
|`FBLoadSpellData()`|Scannt das Zauberbuch, sammelt alle Ränge|
|
||||||
|`FBApplySpellChoice(i, castString)`|Weist einem Button einen Zauber zu|
|
|`FBApplySpellChoice(i, castString)`|Weist einem Button einen Zauber zu|
|
||||||
|`HealBoxButton_OnEvent(…)`|Färbt das Icon nach Mana, Cooldown und Reichweite|
|
|`FBHealBox_UpdateButtonStates(event)` · `FBHealBox_UpdateButtonState(b, event)`|Färbt die Icons nach Mana, Cooldown und Reichweite; die Reichweite wird je Durchgang einmal je Einheit und Reichweite abgefragt (`FBHealBox_ButtonInRange`). Der Durchgang selbst läuft geschützt (`FBHealBox_ButtonStatesSweep`)|
|
||||||
|
|
||||||
### Zauber-Menü
|
### Zauber-Menü
|
||||||
|
|
||||||
@@ -1391,21 +1483,27 @@ Die vier Funktionen, die die Balken speisen. Alle erwarten einen **Spielernamen*
|
|||||||
|-|-|
|
|-|-|
|
||||||
|`FBPredict_GetSpellInfo(bookID, name)`|Wertet den Zauberbuch-Tooltip aus (Direkt / HoT / Schild)|
|
|`FBPredict_GetSpellInfo(bookID, name)`|Wertet den Zauberbuch-Tooltip aus (Direkt / HoT / Schild)|
|
||||||
|`FBPredict_BuildWatch()`|Baut die Watchlist nach jedem Zauberbuch-Scan|
|
|`FBPredict_BuildWatch()`|Baut die Watchlist nach jedem Zauberbuch-Scan|
|
||||||
|`FBPredict_NoteCast(castString, target)`|Merkt Ziel und Rang **vor** dem Cast vor|
|
|`FBPredict_NoteCast(castString, target)`|Merkt Ziel und Rang **vor** dem Cast vor (`FBPredictClick`)|
|
||||||
|`FBPredict_CastStart(spell, castMs)` · `FBPredict_CastEnd()`|Direktheilung starten und beenden|
|
|`FBPredict_TakeClick(spell, castMs)` · `FBPredict_ClickDone()` · `FBPredict_ClickFailed(interrupted)`|Was aus dem Klick bei Castbeginn, Castende und Fehlschlag wird (`FBPredictClick`, `FBPredictCastClick`)|
|
||||||
|
|`FBPredict_HookAttempts()`|Zählt jeden Zauberversuch (`UseAction`, `CastSpellByName`, `CastSpell`) in `FBPredictClickSeq`|
|
||||||
|
|`FBPredict_ConfirmPending()`|Bestätigt HoT, Schild und Buff eines Klicks, dessen Cast durchgegangen ist|
|
||||||
|
|`FBPredict_CastStart(spell, castMs)` · `FBPredict_CastEnd(success)`|Direktheilung starten und beenden; eine erfolgreiche bleibt für ihre Zeile im Combatlog in `FBPredictLastDirect`|
|
||||||
|`FBPredict_ScanUnit(unit)`|Aura-Abgleich: Anwendung bestätigen, Wegfall erkennen|
|
|`FBPredict_ScanUnit(unit)`|Aura-Abgleich: Anwendung bestätigen, Wegfall erkennen|
|
||||||
|`FBPredict_StartHoT(…)` · `FBPredict_StartShield(…)`|Tracking scharfschalten|
|
|`FBPredict_StartHoT(…)` · `FBPredict_StartShield(…)`|Tracking scharfschalten|
|
||||||
|`FBPredict_ParseCombat(event, msg)`|Combatlog-Auswertung|
|
|`FBPredict_ParseCombat(event, msg)`|Combatlog-Auswertung|
|
||||||
|`FBPredict_OnTick(…)` · `FBPredict_OnDirectHeal(…)` · `FBPredict_OnAbsorb(…)`|Die drei Korrekturpfade|
|
|`FBPredict_OnTick(…)` · `FBPredict_OnDirectHeal(…)` · `FBPredict_OnAbsorb(…)`|Die drei Korrekturpfade|
|
||||||
|`FBPredict_Remember(…)` · `FBPredict_Remembered(…)`|Lernspeicher schreiben und lesen|
|
|`FBPredict_Remember(…)` · `FBPredict_Remembered(…)`|Lernspeicher schreiben und lesen|
|
||||||
|`FBPredict_TicksLeft(e, now)`|Restticks eines HoT|
|
|`FBPredict_TicksLeft(e, now)`|Restticks eines HoT|
|
||||||
|
|`FBPredict_Expire()`|Der 0,2-Sekunden-Takt: Abläufe, Timer, merkt betroffene Namen vor|
|
||||||
|
|`FBPredict_PruneNames()`|Streicht nach Rosterwechseln Namen, die nicht mehr in der Gruppe sind, aus der Buff- und HoT-Buchführung|
|
||||||
|
|
||||||
### HealComm
|
### HealComm
|
||||||
|
|
||||||
|Funktion|Zweck|
|
|Funktion|Zweck|
|
||||||
|-|-|
|
|-|-|
|
||||||
|`FBComm_Enabled()`|Ist der Sync eingeschaltet?|
|
|`FBComm_Enabled()`|Ist der Sync eingeschaltet?|
|
||||||
|`FBComm_Send(msg)`|Rohversand ins Raid bzw. in die Gruppe|
|
|`FBComm_Send(msg)` · `FBComm_InBattleground()`|Rohversand ins Raid, in die Gruppe oder ins Schlachtfeld|
|
||||||
|
|`FBComm_Clamp(v, max)`|Begrenzt Werte aus Nachrichten anderer Heiler|
|
||||||
|`FBComm_SendHealStart(…)`|`Heal` bzw. `GrpHeal`|
|
|`FBComm_SendHealStart(…)`|`Heal` bzw. `GrpHeal`|
|
||||||
|`FBComm_SendHealStop()` · `FBComm_SendHealDelay(ms)`|Abbruch und Pushback|
|
|`FBComm_SendHealStop()` · `FBComm_SendHealDelay(ms)`|Abbruch und Pushback|
|
||||||
|`FBComm_SendHoT(spell, target, dur)`|`Renew` / `Reju` / `Regr`|
|
|`FBComm_SendHoT(spell, target, dur)`|`Renew` / `Reju` / `Regr`|
|
||||||
@@ -1417,14 +1515,18 @@ Die vier Funktionen, die die Balken speisen. Alle erwarten einen **Spielernamen*
|
|||||||
|
|
||||||
**Nach dem Einloggen ist gar nichts zu sehen.** Im Chat steht eine orange Zeile mit deiner Klasse: Bei Krieger, Schurke und Jäger schläft das Addon mit Absicht. `/fbp forceload` zeigt es trotzdem an, siehe [Für welche Klassen es lädt](#für-welche-klassen-es-lädt).
|
**Nach dem Einloggen ist gar nichts zu sehen.** Im Chat steht eine orange Zeile mit deiner Klasse: Bei Krieger, Schurke und Jäger schläft das Addon mit Absicht. `/fbp forceload` zeigt es trotzdem an, siehe [Für welche Klassen es lädt](#für-welche-klassen-es-lädt).
|
||||||
|
|
||||||
**Smart Healing rangt einen Zauber nicht ab.** Zauber mit Heilung über Zeit sind bewusst ausgenommen, ebenso Schilde, Buffs und alles, dessen Tooltip keine Heilung beschreibt. Rangt es zwar ab, wechselt aber nie den Zauber, steht der Zauber in keiner Heilkette oder `/fbp smartcross` ist aus. Unter 30 % Leben geht immer der belegte Rang raus. `/fbp debug` schreibt zu jeder Entscheidung den Grund in den Chat.
|
**Smart Healing rangt einen Zauber nicht ab.** Zauber mit Heilung über Zeit sind bewusst ausgenommen, ebenso Schilde, Buffs, Gruppenheilungen, Zauber mit Abklingzeit und alles, dessen Tooltip keine Heilung beschreibt. Rangt es zwar ab, wechselt aber nie den Zauber, steht der Zauber in keiner Heilkette oder `/fbp smartcross` ist aus. Unter 30 % Leben geht immer der belegte Rang raus. `/fbp debug` schreibt zu jeder Entscheidung den Grund in den Chat.
|
||||||
|
|
||||||
**Ein Zauber taucht im Menü nicht auf.** Er steht nicht in der Zauberliste deiner Klasse (`Spell.Name` am Dateianfang) oder ist noch nicht gelernt. Die Liste lässt sich frei erweitern.
|
**Ein Zauber taucht im Menü nicht auf.** Er steht nicht in der Zauberliste deiner Klasse (`FBClassSpells.Name` am Dateianfang) oder ist noch nicht gelernt. Die Liste lässt sich frei erweitern.
|
||||||
|
|
||||||
|
**Client in einer anderen Sprache.** Klassenerkennung, Dispel-Färbung und Klassenicon funktionieren auf jedem Client. Die Zauberlisten (`FBClassSpells.Name`, Buff-Wache, Smart Damage) enthalten englische Zaubernamen, und die Vorhersage liest englische Tooltips. Auf einem deutschen, französischen oder spanischen Client bleibt das Zaubermenü deshalb leer, und Vorhersage und Smart Healing erkennen die Zauber nicht. Zauber, die per Drag & Drop aus dem Zauberbuch belegt werden, funktionieren auf den Buttons trotzdem.
|
||||||
|
|
||||||
**Gelernte Absorb-Werte sind gedeckelt.** Ein gemerkter Absorb über dem 1,5-fachen des Tooltipwerts gilt als Zählfehler und wird beim Laden verworfen (`FBPredict_SanitizeMemory`); die durch die alte Doppelladung verdoppelten Werte aus Versionen vor 1.4.2 räumen sich so von selbst auf.
|
**Gelernte Absorb-Werte sind gedeckelt.** Ein gemerkter Absorb über dem 1,5-fachen des Tooltipwerts gilt als Zählfehler und wird beim Laden verworfen (`FBPredict_SanitizeMemory`); die durch die alte Doppelladung verdoppelten Werte aus Versionen vor 1.4.2 räumen sich so von selbst auf.
|
||||||
|
|
||||||
**Keine Vorhersage für einen bestimmten Zauber.** `/fbp` aufrufen: Steht der Zauber nicht in der Liste der ausgelesenen Zauber, hat der Tooltip-Parser ihn nicht erkannt. Auf abweichenden Servern können die Formulierungen abweichen; die Muster sitzen gebündelt in `FBPredict_GetSpellInfo`.
|
**Keine Vorhersage für einen bestimmten Zauber.** `/fbp` aufrufen: Steht der Zauber nicht in der Liste der ausgelesenen Zauber, hat der Tooltip-Parser ihn nicht erkannt. Auf abweichenden Servern können die Formulierungen abweichen; die Muster sitzen gebündelt in `FBPredict_GetSpellInfo`.
|
||||||
|
|
||||||
|
**Eine rote Zeile "Fehler in …" im Chat.** Ein Modul oder ein Durchlauf hat einen Lua-Fehler geworfen. Das Addon läuft weiter: Der fehlerhafte Hook wird für diesen Aufruf übersprungen, ein scheiternder Durchlauf für Reichweite, Sichtlinie oder Buttons fällt auf geschützte Einzelaufrufe zurück. Die erste Meldung jeder Art erscheint immer, weitere nur mit `/fbp debug`. Die Zeile nennt die Stelle, das hilft bei einer Fehlermeldung.
|
||||||
|
|
||||||
**Combatlog-Korrekturen greifen nicht.** Die Muster werden aus den GlobalStrings des Clients gebaut (`PERIODICAURAHEALOTHERSELF`, `HEALEDSELFOTHER`, `ABSORB_TRAILER`) und fallen sonst auf englische Vorgaben zurück. `/fbp debug` zeigt, ob Korrekturen ankommen.
|
**Combatlog-Korrekturen greifen nicht.** Die Muster werden aus den GlobalStrings des Clients gebaut (`PERIODICAURAHEALOTHERSELF`, `HEALEDSELFOTHER`, `ABSORB_TRAILER`) und fallen sonst auf englische Vorgaben zurück. `/fbp debug` zeigt, ob Korrekturen ankommen.
|
||||||
|
|
||||||
**Werte sind zu niedrig.** Vor der ersten beobachteten Heilung steht nur der Tooltip-Basiswert ohne +Heilung zur Verfügung. Ein einziger Cast über die Buttons genügt zum Einpendeln.
|
**Werte sind zu niedrig.** Vor der ersten beobachteten Heilung steht nur der Tooltip-Basiswert ohne +Heilung zur Verfügung. Ein einziger Cast über die Buttons genügt zum Einpendeln.
|
||||||
@@ -1437,7 +1539,7 @@ Die vier Funktionen, die die Balken speisen. Alle erwarten einen **Spielernamen*
|
|||||||
|
|
||||||
## Klassenzauber
|
## Klassenzauber
|
||||||
|
|
||||||
Die vorbelegten Listen, frei erweiterbar in `Spell.Name`:
|
Die vorbelegten Listen, frei erweiterbar in `FBClassSpells.Name`:
|
||||||
|
|
||||||
|Klasse|Zauber|
|
|Klasse|Zauber|
|
||||||
|-|-|
|
|-|-|
|
||||||
@@ -1462,6 +1564,11 @@ Nicht vorhandene Einträge stören nicht: Findet der Zauberbuch-Scan sie nicht,
|
|||||||
* Heilvorhersage für Direktheilung, HoT-Restticks und Absorb-Schilde, selbstkorrigierend über den Combatlog
|
* 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.7: die vollständige Codeprüfung. Behoben: Geschwächte Seele sichtbar, HoTs und Schilde anderer Heiler zählen nicht mehr als deine, Reichweite und Zauberzeit an der richtigen Stelle im Tooltip gelesen, Smart Healing lässt Gruppenheilungen und Zauber mit Abklingzeit in Ruhe und bewertet Ränge unter Stufe 20 richtig, Sichtlinienfehler markieren nur die angeklickte Einheit, Klassentabellen in jeder Clientsprache, Skalierungsregler verschiebt die Plaketten nicht mehr, Drag & Drop auf die Minibuttons im Raid repariert, ein Klick gilt nur für den Cast, den er auslöst, Direktheilungen werden gelernt, der Mindestschaden von Smart Damage ist wieder sicher, und seine eigene Lebensschätzung bleibt aus Raids heraus. Leistung: Neuzeichnen einmal je Frame gesammelt, Manaereignisse zeichnen nur den Manastreifen, Reichweite einmal je Einheit, Zauberbuch einmal je Salve gelesen, Smart Damage ruht, solange es aus ist. Robustheit: allgemeine Globals mit `FB` versehen, Smart Damage läuft ohne Ticker, Fehler in Modulen und Durchläufen werden gemeldet, Schlachtfeldkanal und Grenzen für HealComm, toter Code und doppelte Helfer entfernt; siehe CHANGELOG
|
||||||
|
* 1.4.6: Leistungsdurchgang ohne Funktionsänderung (nur geänderte Einheiten werden neu gezeichnet, über den Hook `RefreshNames`, Raid-Zaubertimer überspringen stille Zellen, Zaubertimer steigen früher aus); siehe CHANGELOG
|
||||||
|
* 1.4.5.3: Einstellbarer Hintergrund hinter den Balken der Plaketten, damit die Spielwelt nicht mehr durch fehlendes Leben scheint; siehe CHANGELOG
|
||||||
|
* 1.4.5.2: Ein laufender HoT zählt bei der Rangwahl von Smart Healing nicht mehr als anfliegende Heilung; siehe CHANGELOG
|
||||||
|
* 1.4.5.1: Ruckeln des Manafunkens behoben (Bewegungsschwelle und Zeichentakt), der globale Cooldown dunkelt nicht mehr alle Buttons ab und läuft stattdessen als Uhr mit (eigene Schwelle `FBCD_SHOW_MIN`); siehe CHANGELOG
|
||||||
* 1.4.5: Blizzards Gruppenfenster ausblendbar (schließt sich mit dem Anheftmodus gegenseitig aus), Wut, Energie und Fokus im Ressourcenbalken, Heilbonus der Ausrüstung über ClassicAPI in der Vorhersage, dazu ein Leistungsdurchgang ohne Funktionsänderung (Spielerbuffs einmal je Frame, gestaffelte Reichweiten- und Sichtlinienprüfung im Raid, weniger geschützte Aufrufe, keine Wegwerf-Strings im Raid-HP-Text); siehe CHANGELOG
|
* 1.4.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
|
||||||
@@ -1473,7 +1580,7 @@ Nicht vorhandene Einträge stören nicht: Findet der Zauberbuch-Scan sie nicht,
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Heal Box Vanilla v1.4.5 · Original von Dourd, UI Overhauled · Vanilla-Portierung und Erweiterung 09/2026 von Mquadrat
|
Heal Box Vanilla v1.4.7 · Original von Dourd, UI Overhauled · Vanilla-Portierung und Erweiterung 09/2026 von Mquadrat
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user