Buff Interceptions
The buff system includes a powerful interception mechanism that allows buffs to modify, replace, or cancel the application of other buffs.
Interception Structure
Interceptions are defined in the interceptBuffEffects array of a buff:
interceptBuffEffects?: {
buff: Buff; // The buff to intercept
effects: BuffEffect[]; // Effects to trigger instead
cancelApplication: boolean; // Whether to prevent the original buff
}[]
Real Example - Profane Exchange
The best example of interception comes from the Blood school’s Profane Exchange technique:
import { Buff } from 'afnm-types';
import icon from '../assets/buffs/profane-exchange.png';
export const profaneExchangeBuff: Buff = {
name: 'Profane Exchange',
icon: icon,
canStack: false,
stats: undefined,
tooltip:
'You no longer gain {buff}. Instead, lose <num>3%</num> health as <name>True Damage</name> per stack you would have gained.',
onRoundEffects: [],
interceptBuffEffects: [
{
buff: window.modAPI.gameData.techniqueBuffs.blood.bloodCorruption, // Intercept Blood Corruption
effects: [
{
kind: 'damageSelf',
amount: {
value: 0.03,
stat: 'maxhp',
upgradeKey: 'hpCost',
},
damageType: 'true',
},
],
cancelApplication: true, // Prevent the original buff
},
],
stacks: 1,
priority: -1, // Execute before other buffs
};
This intercept completely transforms how Blood Corruption works:
- Normal behavior: Gain Blood Corruption stacks
- With Profane Exchange: Take 3% max HP as true damage instead
- Result: Blood techniques become high-risk, high-reward
Interception Mechanics
Priority System
Interceptions use the buff’s priority value to determine execution order:
- Lower numbers execute first
- Profane Exchange uses
priority: -1to ensure it intercepts before other effects
Multiple Interceptions
A single buff can intercept multiple different buffs:
interceptBuffEffects: [
{
buff: firstBuff,
effects: [
/* effects for first buff */
],
cancelApplication: true,
},
{
buff: secondBuff,
effects: [
/* effects for second buff */
],
cancelApplication: false, // Allow original buff but add effects
},
];
Partial Interception
When cancelApplication: false, the original buff is still applied, but additional effects trigger:
{
buff: targetBuff,
effects: [
{
kind: 'heal',
amount: { value: 0.1, stat: 'power' }
}
],
cancelApplication: false // Original buff applies + healing
}
Guardian Interception
When a buff declares guardianIntercept, it acts as a damage shield that absorbs a percentage of incoming damage before it reaches the owner. When the guardian’s HP reaches zero, the buff is permanently removed.
Guardian Structure
guardianIntercept?: {
percent: Scaling; // Percentage of incoming damage redirected to guardian HP
maxHp: Scaling; // Maximum HP for the guardian, evaluated at buff creation
refreshMode?: 'refresh' | 'extend'; // How re-application combines with existing HP
canUpgrade?: boolean;
onDestroyed?: BuffEffect[]; // Effects fired on the owner when the guardian is destroyed
};
The onDestroyed Hook
When a guardian is destroyed (its HP reaches zero), any onDestroyed effects declared on the guardianIntercept block are executed. This is equivalent to adding a triggeredBuffEffects entry with trigger: 'guardianBroken.${name}', but declared directly on the guardian for convenience.
The effects execute with:
source: The guardian’s owner (the character who has the guardian buff)target: The attacker who destroyed the guardian
// Example: A guardian that explodes when destroyed
{
name: 'Ritual Shield',
icon: shieldIcon,
canStack: false,
guardianIntercept: {
percent: { value: 0.50 }, // Absorb 50% of incoming damage
maxHp: { value: 0.30, stat: 'maxhp' }, // Guardian HP = 30% of max HP
onDestroyed: [
{
kind: 'damage',
amount: { value: 0.25, stat: 'power' },
damageType: 'true',
},
],
},
}
When this guardian is destroyed, it deals 25% of the owner’s power as true damage back to the attacker.
Auto-Generated Tooltip
Tooltips for onDestroyed are auto-generated using the “When destroyed, …” prefix. The trigger description will include the effect details automatically. No custom tooltip is required unless you want different wording than the default.
Advanced Interception Patterns
Stack Conversion
Convert incoming buff stacks into different amounts:
interceptBuffEffects: [
{
buff: incomingBuff,
effects: [
{
kind: 'buffSelf',
buff: differentBuff,
amount: { value: 2, stat: undefined }, // 1 incoming = 2 different
},
],
cancelApplication: true,
},
];
Conditional Interception
Combine with effect conditions for situational interceptions:
interceptBuffEffects: [
{
buff: targetBuff,
effects: [
{
kind: 'damage',
amount: { value: 0.5, stat: 'power' },
condition: {
kind: 'hp',
percentage: 50,
mode: 'less',
},
},
],
cancelApplication: true,
},
];
Resource Redirection
Redirect resource generation to different pools:
interceptBuffEffects: [
{
buff: normalResource,
effects: [
{
kind: 'buffSelf',
buff: alternativeResource,
amount: { value: 1, stat: undefined },
},
{
kind: 'heal',
amount: { value: 0.05, stat: 'maxhp' },
},
],
cancelApplication: true,
},
];
Tooltip Integration
Interceptions do not automatically appear in tooltips, but the variables within them do. Therefore, a custom tooltip must be written to display them.
tooltip: 'You no longer gain {buff}. Instead, lose <num>3%</num> health as <name>True Damage</name> per stack you would have gained.';
The {buff} placeholder is automatically replaced with the intercepted buff’s name in the tooltip system.