Class BaseBuffTemplate
Abstract base class for all buff templates, defining shared properties, tooltip logic, and effect hooks. Stack and tick hooks are virtual with sensible defaults: stacking delegates to apply/remove, and ticking is a no-op. Derived classes only override what they need (OCP).
public abstract class BaseBuffTemplate : CachedScriptableObject<BaseBuffTemplate>, ICachedObject, ITooltip
- Inheritance
-
ObjectScriptableObjectBaseBuffTemplate
- Implements
- Derived
- Inherited Members
-
ScriptableObject.SetDirty()ScriptableObject.CreateInstance<T>()Object.GetEntityId()Object.GetInstanceID()Object.GetHashCode()Object.InstantiateAsync<T>(T)Object.InstantiateAsync<T>(T, Transform)Object.InstantiateAsync<T>(T, Vector3, Quaternion)Object.InstantiateAsync<T>(T, Transform, Vector3, Quaternion)Object.Instantiate(Object, Vector3, Quaternion)Object.Instantiate(Object, Vector3, Quaternion, Transform)Object.Instantiate(Object)Object.Instantiate(Object, Scene)Object.Instantiate<T>(T, InstantiateParameters)Object.Instantiate<T>(T, Vector3, Quaternion, InstantiateParameters)Object.Instantiate(Object, Transform)Object.Instantiate<T>(T)Object.Instantiate<T>(T, Vector3, Quaternion)Object.Instantiate<T>(T, Vector3, Quaternion, Transform)Object.Instantiate<T>(T, Transform)Object.Destroy(Object)Object.DestroyImmediate(Object)Object.DontDestroyOnLoad(Object)Object.DestroyObject(Object)Object.FindObjectsOfType<T>()Object.FindObjectsByType<T>(FindObjectsSortMode)Object.FindObjectsByType<T>(FindObjectsInactive, FindObjectsSortMode)Object.FindObjectOfType<T>()Object.FindFirstObjectByType<T>()Object.FindAnyObjectByType<T>()Object.FindFirstObjectByType<T>(FindObjectsInactive)Object.FindAnyObjectByType<T>(FindObjectsInactive)Object.FindObjectsByType<T>()Object.FindObjectsByType<T>(FindObjectsInactive)Object.ToString()Object.nameObject.hideFlags
Fields
Description
The description of the buff, shown in tooltips.
public string Description
Field Value
Duration
The duration of the buff in seconds. If 0, the buff may be permanent or event-driven.
public float Duration
Field Value
FXPrefabReference
Addressable reference to the visual effect prefab to instantiate when the buff is applied.
public AssetReferenceGameObject FXPrefabReference
Field Value
- AssetReferenceGameObject
IsDebuff
True if this buff is a debuff (negative effect).
public bool IsDebuff
Field Value
IsPermanent
True if the buff is permanent and does not expire.
public bool IsPermanent
Field Value
MaxStacks
The maximum number of stacks this buff can have.
public uint MaxStacks
Field Value
OnTickEvents
[Header("Event-Condition-Action (ECA) Triggers")]
[Tooltip("Triggers fired each tick. A DoT is an ApplyDamageAction here; a HoT is an ApplyHealAction.")]
public List<BuffTickEvent> OnTickEvents
Field Value
TickRate
The interval in seconds between OnTick calls while the buff is active.
public float TickRate
Field Value
Properties
Icon
The icon for this buff template (loaded at runtime on client).
public Sprite Icon { get; }
Property Value
- Sprite
Name
The name of this buff template (from the ScriptableObject's name).
public string Name { get; }
Property Value
Methods
ApplyResourceTick(Buff, ICharacter, List<BuffAttributeTemplate>, DamageAttributeTemplate)
Applies one round of periodic resource changes, routing health through the damage pipeline so a tick behaves like any other hit.
protected static void ApplyResourceTick(Buff buff, ICharacter target, List<BuffAttributeTemplate> tickAttributes, DamageAttributeTemplate damageAttribute)
Parameters
buffBuffThe buff instance, supplying stacks, attribution and replay state.
targetICharacterThe character the tick lands on.
tickAttributesList<BuffAttributeTemplate>Per-tick resource modifiers. Positive heals, negative damages.
damageAttributeDamageAttributeTemplateDamage type used to resolve resistance when a tick reduces health. Null means the tick bypasses resistance entirely.
Remarks
Why not write the resource directly. Both tick templates used to call
CharacterResourceAttribute.AddToCurrentValue, which clamps the value and raises
an attribute-changed notification and nothing else. That skipped every consequence of
being hurt: resistances were not applied, Immortal was ignored, neither party
entered combat, no OnDamaged event was raised — so a damage-over-time effect
generated no threat at all — and, worst of all, nothing could die of it.
Kill(ICharacter) is only ever reached from inside
Damage, so a DoT drained its victim to zero health and stopped there; the
early-out at the top of Damage then rejected every subsequent hit as
"already dead", leaving a character permanently alive at nothing.
Health only. Damage and Heal operate on the health resource. A tick
against mana, stamina or any other resource has no damage semantics to borrow and keeps
writing the resource directly.
Both sides, side effects on one. The resource mutation runs on the owning client
as well as the server, which is what keeps predicted health in step with the server's.
The triggers hanging off Damage/Heal are passed as suppressed on every
client — replayed or not — and only ever fire on the server. Before this, the flag
tracked replay alone, so the owner's first pass over a tick fired achievements and
combat triggers a second time alongside the server. See
ShouldSuppressTickSideEffects(Buff).
BuildTooltip(TooltipBuilder)
Populates the tooltip builder with this buff's tooltip lines. Override in derived classes to add additional lines.
public virtual void BuildTooltip(TooltipBuilder builder)
Parameters
builderTooltipBuilderThe tooltip builder to populate.
InvokeTickEvents(Buff, ICharacter)
Fires this buff's ECA tick triggers against the character carrying it.
protected void InvokeTickEvents(Buff buff, ICharacter target)
Parameters
buffBuffThe buff instance.
targetICharacterThe character carrying the buff.
Remarks
Initiator is the caster, target is the carrier. That split is what makes an ApplyDamageAction on a tick event behave like a hit rather than like self-harm: the damage lands on the carrier and is credited to whoever applied the buff, which is what generates threat and grants the kill.
When the caster is gone — disconnected, despawned — the carrier stands in as initiator so the trigger still has a character to resolve values and conditions against. The effect continues to land, because a lingering poison is part of the simulation whether or not whoever cast it is still in the scene; it simply credits nobody, and ApplyDamageAction is content with that.
Server only. With state forwarding off, the owner still ticks its own buffs for prediction, but an ECA trigger is a side effect — damage credit, threat, chained effects, achievements — and must run exactly once. The owner's health is corrected by the attribute reconcile; nothing here needs to run on a client.
OnApply(Buff, ICharacter)
Called when the buff is applied to a character. Must be implemented by derived classes. When reached through OnApplyStack(Buff, ICharacter), Stacks still contains the pre-increment stack count; stack-aware templates should account for that ordering or override OnApplyStack(Buff, ICharacter) directly.
public abstract void OnApply(Buff buff, ICharacter target)
Parameters
buffBuffThe buff instance being applied.
targetICharacterThe character receiving the buff.
OnApplyFX(Buff, ICharacter)
Instantiates the FXPrefab on the target when the buff becomes visible on it (client-side only).
public virtual GameObject OnApplyFX(Buff buff, ICharacter target)
Parameters
buffBuffThe simulated buff instance, or null for an observed buff.
targetICharacterThe character receiving the buff.
Returns
- GameObject
The instantiated FX, or null when there is nothing to show.
Remarks
Returns the instance so the caller can own its lifetime. BuffController tracks one instance per template per character and hands it back to OnRemoveFX(GameObject, ICharacter) when the buff leaves; before that the instance was fire-and-forget and outlived the buff it was meant to show — on the owner and on every observer.
buff is null when the FX is driven by the observer-facing list rather
than a simulated buff: observers no longer hold Buff instances for other
characters, only ObservedBuffEntry. Overrides must tolerate that.
Parented under MeshRoot so it follows the model. That root is cleared when the race model (re)loads, which destroys the instance; the controller re-creates it from OnModelReady().
OnApplyStack(Buff, ICharacter)
Called when a stack of the buff is applied. Defaults to delegating to OnApply. Stacks is incremented after this hook returns, so this hook observes the previous stack count. Override in derived classes for custom stacking behavior.
public virtual void OnApplyStack(Buff buff, ICharacter target)
Parameters
buffBuffThe buff instance being stacked.
targetICharacterThe character receiving the stack.
OnLoad(string, string, int)
Called when the buff template is loaded into cache. Loads the icon and FX prefab on the client.
public override void OnLoad(string typeName, string resourceName, int resourceID)
Parameters
typeNamestringThe type name of the resource.
resourceNamestringThe resource name.
resourceIDintThe resource ID.
OnRemove(Buff, ICharacter)
Called when the buff is removed from a character. Must be implemented by derived classes.
public abstract void OnRemove(Buff buff, ICharacter target)
Parameters
buffBuffThe buff instance being removed.
targetICharacterThe character losing the buff.
OnRemoveFX(GameObject, ICharacter)
Tears down an FX instance previously returned by OnApplyFX(Buff, ICharacter) (client-side only).
public virtual void OnRemoveFX(GameObject fxInstance, ICharacter target)
Parameters
fxInstanceGameObjectThe instance to remove. May already be destroyed.
targetICharacterThe character the buff left. May be null during teardown.
OnRemoveStack(Buff, ICharacter)
Called when a stack of the buff is removed. Defaults to delegating to OnRemove. Override in derived classes for custom unstacking behavior.
public virtual void OnRemoveStack(Buff buff, ICharacter target)
Parameters
buffBuffThe buff instance being unstacked.
targetICharacterThe character losing the stack.
OnTick(Buff, ICharacter)
Called on each tick while the buff is active. Fires OnTickEvents.
public virtual void OnTick(Buff buff, ICharacter target)
Parameters
buffBuffThe buff instance.
targetICharacterThe character affected.
Remarks
Derived classes that add their own periodic behaviour must call
base.OnTick(buff, target), or the buff's authored tick events are silently
dropped for that template type.
OnUnload(string, string, int)
Called when the buff template is unloaded from cache. Releases the icon and FX prefab on the client.
public override void OnUnload(string typeName, string resourceName, int resourceID)
Parameters
typeNamestringThe type name of the resource.
resourceNamestringThe resource name.
resourceIDintThe resource ID.
SecondaryTooltip(TooltipBuilder)
Appends additional information to the tooltip (e.g., secondary effects). Override in derived classes.
public virtual void SecondaryTooltip(TooltipBuilder builder)
Parameters
builderTooltipBuilderThe tooltip builder to populate.
Tooltip()
Returns the tooltip string for this buff, including name, description, and secondary details.
public virtual string Tooltip()