For as long as sustains have existed, they have been subject to a major bug: many of them compute a value when first activated, and continue using that original value until deactivated, even when the value should have changed because the actor's spellpower/strength/talent category mastery/etc. changed, allowing all manner of abuses. This bug has also been known for as long as sustains existed, so I always assumed a fix was right around the corner. It's been about eight years, so I think that my assumption was not correct.
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 ItProvisionally 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.
The listcelestial/chants-chantsChant of FortitudeChant of FortressChant of ResistanceChant of Lightcelestial/combatWeapon of Light (melee_project portion only, damage shield portion is fine)
Weapon of Wrathcelestial/crusaderRighteous Strengthcelestial/eclipseDarkest Light (this is more of an active, so there's an argument that it's not an issue)
celestial/guardianRetributioncelestial/hymns-hymnsHymn of ShadowsHymn of DetectionHymn of Perseverancecelestial/radianceSearing Sightcelestial/solSolar Windchronomancy/matterMatter Weavingchronomancy/otherQuantum FeedEntropic FieldCarbon Spikeschronomancy/temporal-archeryPerfect Aimchronomancy/temporal-houndsTemporal Houndscorruption/blightDark Ritualcorruption/bloodBlood Furycorruption/boneBone Shield (The
number of bones isn't subject to this bug, but the regeneration rate of the bones is.)
corruption/demon-seedsCorrosive SlashesShadowmeldBlood Shieldcorruption/demonic-strengthAbyssal Shieldcorruption/rotInfestationcorruption/sanguisugeAbsorb Life (why does this even exist?)
corruption/shadowflameFlame of Urh'Rokcorruption/tormentWillful Tormentor (why isn't this passive?)
OverkillBlood Vengeancecunning/lethalityBlade Flurry (again, though, more of an active)
cunning/shadow-magicShadow Feedcunning/stealthStealthcunning/tacticalExploit Weaknesscursed/endless-huntSurgegolem/arcaneReflective Skinpsionic/augmented-mobilitySkatepsionic/dream-forgeForge Shield (the Forge Armor bonuses)
psionic/dreamingLucid Dreamerpsionic/kinetic-masteryDeflect Projectilespsionic/nightmareNight Terrorpsionic/otherBeyond the Flesh (very specific: gems/mindstars combined with Finer Energy Manipulation mastery items).
Thought-form: BowmanThought-form: WarriorThought-form: Defenderpsionic/psi-fightingAugmentationpsionic/tranceTrance of PurityTrance of Well-BeingTrance of Focusrace/shaloreSecrets of the Eternalsrace/yetiResilient Bodyspell/acid-alchemyAcid Infusionspell/aegisShieldingArcane Shieldspell/aetherPure Aetherspell/airFeather Windspell/arcaneArcane PowerDisruption Shieldspell/conveyanceProbability Travelspell/divinationKeen Sensesspell/earthStone Skinspell/eldritch-shieldEldritch Infusionspell/energy-alchemyLightning InfusionLiving Lightning (movement speed only)
spell/enhancementFiery HandsShock HandsInner Powerspell/fire-alchemyFlame InfusionBody of Fire (resistance and on_melee_hit only)
spell/frost-alchemyFrost InfusionIce Corespell/graveWill o' the WispVampiric Giftspell/iceUttercoldspell/metaSpellcraftQuicken Spellsspell/necrosisBlurred Mortalityspell/otherFrost HandsNecrotic Auraspell/phantasmBlur SightPhantasmal ShieldInvisibilityspell/shadesFrostduskspell/staff-combatDefensive Posturespell/stoneBody of StoneCrystalline Focusspell/stormTempestspell/temporalEssence of Speedspell/wildfireBurning WakeWildfiresteamtech/avoidanceAutomated Cloak Tesselationsteamtech/battlefield-managementSaw WheelsGrinding Shieldsteamtech/butcheryOverheat SawsTempest of Metalsteamtech/furnaceFurnacesteamtech/otherRocket BootsSteam Powered Armoursteamtech/thoughts-of-ironMolten Iron Bloodtechnique/2hweapon-offenseBerserkertechnique/agilityRapid Shottechnique/battle-tacticsTrue 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.
technique/combat-techniques-activePrecise Strikestechnique/field-controlSlow Motiontechnique/grapplingGrappling Stancetechnique/magical-combatArcane Feedtechnique/otherPrecisionMomentumIncendiary Ammunition (Alloyed Munitions penetration bonus only)
Piercing Ammunition (Penetration bonus only)
technique/shield-defenseShield WallLast Standtechnique/sniperConcealmentAimtechnique/strength-of-the-berserkerBerserker 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.
technique/superiorityOnslaught (not that there's any reason to use it anyway)
Shattering Impacttechnique/thuggeryTotal Thuggerytechnique/tireless-combatantPace Yourselftechnique/unarmed-otherStriking Stancewild-gift/antimagicAntimagic Shieldwild-gift/call-of-the-wildMeditationwild-gift/cold-drakeIcy Skinwild-gift/corrosive-bladesCorrosive Nature (acid resistance only)
Acidic Soilwild-gift/eyals-furyNature's Defiancewild-gift/fungusWild Growthwild-gift/harmonyElemental Harmonywild-gift/mindstar-masteryPsibladeswild-gift/oozing-bladesNatural Acid (nature resistance only)
Unstoppable Naturewild-gift/slimeAcidic Skinwild-gift/summon-advancedMaster SummonerClass summaryFinally, 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.
BerserkerBulwarkArcherArcane BladeBrawlerRogueShadowbladeMarauderSkirmisherAlchemistArchmageNecromancerSummonerWyrmicOozemancerStone WardenSun PaladinAnorithilReaverCorruptorDoombringerDemonologistCursedDoomedParadox MageTemporal Warden (but really
Temporal Warden because nobody in their right mind takes temporal hounds)
MindslayerSolipsistPossessorAdventurerSawbutcherGunslingerPsyshotFor addon developers: how to avoid and how to fix this bugThe 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:
tmpid = self:addTemporaryValue("reflect_damage", (t.getReflect(self, t)))
It computes the reflect_damage bonus once, when activated, and never again until reactivated. What we need is for it to compute the reflect_damage value every time it's needed. Strictly, in this specific case, you could do this by recomputing it and re-applying the temporary value every time the actor's spellpower changes. Some sustains do this sort of thing already with callbackOnStatChange. However, it'd be much more maintainable to simply recalculate the value every time the actor's reflect_damage attribute is queried. Perhaps then Actor:addTemporaryValue() would be refactored to take a function as its second argument, which would be called to get the attribute bonus every time it's needed. None of the relevant attributes are indexed often enough for replacing them with functions to be a performance issue.
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.