Therefore, I have compiled this list of sustains and passives currently in the game that suffer from this bug. I hope it's useful to both developers and players. I believe it is complete, but it's certainly possible that I've missed one.
Poorly chosen color codes:
Bad - The talent suffers from this problem and is affected by a stat that changes frequently, such as the 6 primary stats, defense, spellpower, luck, resistances, armor, and other things that are frequently affected by buffs or equipment. Example: Lucid Dreamer's saves scale with mindpower.
Bad If Players Get It - Like Bad, but the talent is "NPC-only" or old-saves-only, so it's rarely relevant (but still relevant because possessors exist).
Bad With Mastery Items - The talent suffers from this problem, but is only affected by talent level. Changes to talent level reset sustains...unless they come from, say, a mastery bonus on an item. So you can abuse this bug if you have a mastery item (or, in some cases, one of the few items that grants direct bonus talent levels), but not otherwise. Example: Arcane Feed.
This problem does not occur with passives, which do reset upon all mastery and talent level changes. Yes, you could fix these specific talents by making sustains restart upon mastery changes.
Bad With Mastery Items If Players Get It
Provisionally Fine - The talent is almost Bad With Mastery Items but it uses raw talent level instead of real talent level. If changed to use real talent level, it will become Bad With Mastery Items, so it is risky to leave it as-is. Example: Quicken Spells.
Worse - Like Bad, but additionally cannot safely be auto-restarted because restarting it would have side effects. Example: Saw Wheels does a bunch of attacks, and resets its damage bonus, when deactivated.
Bad, Bad With Mastery Items, and Worse are all urgently important to fix. They are differentiated here only for the benefit of players wishing to take advantage of the bugs.
Chant of Fortitude
Chant of Fortress
Chant of Resistance
Chant of Light
Weapon of Light (melee_project portion only, damage shield portion is fine)
Weapon of Wrath
Darkest Light (this is more of an active, so there's an argument that it's not an issue)
Hymn of Shadows
Hymn of Detection
Hymn of Perseverance
Bone Shield (The number of bones isn't subject to this bug, but the regeneration rate of the bones is.)
Absorb Life (why does this even exist?)
Flame of Urh'Rok
Willful Tormentor (why isn't this passive?)
Blade Flurry (again, though, more of an active)
Forge Shield (the Forge Armor bonuses)
Beyond the Flesh (very specific: gems/mindstars combined with Finer Energy Manipulation mastery items).
Trance of Purity
Trance of Well-Being
Trance of Focus
Secrets of the Eternals
Living Lightning (movement speed only)
Body of Fire (resistance and on_melee_hit only)
Will o' the Wisp
Body of Stone
Essence of Speed
Automated Cloak Tesselation
Tempest of Metal
Steam Powered Armour
Molten Iron Blood
True Grit has the bizarre property of updating its effects in callbackOnActBase, which still means they'll be incorrect (in the user's detriment) for most of a turn in which they take more than one instance of damage. Doesn't really fit into any of the classifications above, but seems bad.
Incendiary Ammunition (Alloyed Munitions penetration bonus only)
Piercing Ammunition (Penetration bonus only)
Berserker Rage updates every time the player acts, but their strength/dexterity could change more often than that, which is very slightly relevant if they have retaliating melee attacks as a possessor or adventurer.
Onslaught (not that there's any reason to use it anyway)
Corrosive Nature (acid resistance only)
Natural Acid (nature resistance only)
Finally, for the benefit of players, here's a summary of classes, coloured by the worst-bugged sustain or passive that they have. For example, Sun Paladin has Retribution, whereas the worst one Temporal Warden has is Temporal Hounds, and Doomed has no talents that suffer from this bug.
Categories that every class can get without escorts (Staff Combat, Mindstar Mastery, Harmony, Survival) are excluded for the purposes of this list.
Temporal Warden (but really Temporal Warden because nobody in their right mind takes temporal hounds)
For addon developers: how to avoid and how to fix this bug
The game currently tries to (rather lazily) get around this issue by making sustains and passives reactivate every time something relevant changes. As you can see from the list above, this has not been successful, and furthermore no matter how much you increase the number of things that reactivate talents, it is fundamentally untenable because of interactions between sustains/passives and other sustains/passives. For example, Arcane Power affects spellpower, which in turn affects dozens of other sustains. So the order in which sustains reactivate matters, and players are incentivized to control it!
(Currently sustains reactivate whenever a change is made in the levelup menu, and passives reactivate whenever that happens or when mastery changes.)
Fixing this bug requires individually rewriting each affected sustain and passive. Some can be fixed by using existing features alone (mainly callbacks). Others would need to be fixed by adding new callbacks or special-casing them elsewhere (e.g. Armour Training has specific code in Combat:combatArmor() in order to make it work). Doing that might be the most practical solution; there aren't that many sustains in the game. By adding callbackOnGetResist, callbackOnGetArmor, etc. you wouldn't have to special-case many of the talents at all. And callbacks already support priority, so you don't need to worry about undefined order anymore.
It's hard not to notice that the common thread of suck between almost all bugged sustains and passives is the usage of Actor:addTemporaryValue() or Actor:talentTemporaryValue() to apply their effect. For example, Reflective Skin:
Code: Select all
tmpid = self:addTemporaryValue("reflect_damage", (t.getReflect(self, t)))
However, this would be a significant refactoring so lots of things could go wrong. Additionally, it makes it easy to accidentally introduce a circular dependency between attributes. I would suggest instead deprecating these two functions for passives and sustains entirely.