Damage System
Damage types are stored under damage_types/*.yml. The current damage system uses a multi-stage pipeline instead of one fixed formula. Each damage type can define its own attack, defense, critical, penetration, recovery, and custom expression stages.
Damage type fields
| Field | Description |
|---|---|
id | Damage type id, such as physical, projectile, or spell. |
display_name | Display name. Defaults to id. |
aliases | Optional aliases. |
hard_lock | Whether this damage type strongly takes over matching vanilla damage events. |
allowed_events | Vanilla event/cause allowlist. Empty means unrestricted. |
message / attacker_message / target_message | Combat messages. |
stages | Ordered calculation stages. |
recovery | Post-damage recovery or lifesteal calculation. |
Default damage types include physical, projectile, and spell.
Stage pipeline
Each stage can read attributes from the attacker, target, or context, then add or subtract the calculated result.
| Field | Description |
|---|---|
id | Debug id for the stage. |
kind | FLAT_PERCENT or CUSTOM. |
source | ATTACKER, TARGET, or CONTEXT. |
mode | ADD or SUBTRACT. |
flat_attributes | Flat contribution attributes. |
percent_attributes | Percentage contribution attributes. |
chance_attributes | Chance attributes. |
multiplier_attributes | Multiplier attributes. |
expression | Custom expression when kind=CUSTOM. |
variables | Stage-scoped custom variables, usable by expression when kind=CUSTOM. |
min_result / max_result | Result clamps. |
min_chance / max_chance | Chance clamps. |
min_multiplier / max_multiplier | Multiplier clamps. |
CUSTOM expression variables
When kind: CUSTOM, the expression field may use these variables:
| Variable | Description |
|---|---|
%input% / %base% | Damage value entering this stage. |
%flat% | Aggregated flat_attributes value. |
%percent% | Aggregated percent_attributes value. |
%chance% | Aggregated chance_attributes chance. |
%multiplier% | Aggregated multiplier_attributes multiplier. |
%crit% | 1 when this stage rolled a critical hit, otherwise 0. |
If the expression is empty or fails to evaluate, the stage falls back to a default result: %input% unchanged when there are no chance attributes, otherwise the critical multiplier is applied.
Stage custom variables
Beyond the built-in variables, each stage can declare its own variables for its expression. A variable value may be a number, an expression, or a random numeric config:
- id: overflow_soften
kind: CUSTOM
source: ATTACKER
variables:
soft_cap: 120
overflow: "max(0, %input% - %soft_cap%)"
jitter:
min: 0.95
max: 1.05
expression: "(%input% - %overflow% * 0.5) * %jitter%"Rules:
- A variable may reference built-in variables (such as
%input%and%multiplier%), damage context variables, and any variable declared before it. - Variables resolve in declaration order, so
overflowcan reference the earliersoft_cap. Self-references are rejected. - A variable overrides a built-in or context variable of the same name.
- Variables only apply to the stage that declares them; they are not passed to later stages.
- A random numeric config is rolled once per expression evaluation (all references in that stage see the same value), and re-rolled for every stage and every hit.
- If a variable fails to resolve (a non-numeric text value, or a reference to an undeclared variable), the whole expression fails and the stage result becomes
0. This is existing expression-engine behavior; verify with/ea traceafter editingvariables.
Built-in physical pipeline
The actual bundled damage_types/physical.yml:
id: physical
display_name: "物理伤害"
aliases: [physical_damage, phys]
allowed_events:
- ENTITY_ATTACK
- ENTITY_SWEEP_ATTACK
hard_lock: true
stages:
- id: attack
kind: FLAT_PERCENT
source: ATTACKER
mode: ADD
flat_attributes: [physical_attack]
percent_attributes: [physical_damage_bonus]
- id: crit
kind: CUSTOM
source: ATTACKER
chance_attributes: [physical_crit_rate]
multiplier_attributes: [physical_crit_damage]
expression: "%input% * (1 + (%crit% * (%multiplier% / 100)))"
- id: defense
kind: CUSTOM
source: TARGET
flat_attributes: [physical_defense]
expression: "max(0, %input% - %flat%)"
recovery:
source: ATTACKER
resistance_source: TARGET
flat_attributes: [percentage_lifesteal]
percent_attributes: [lifesteal]
resistance_attributes: [lifesteal_resistance]Stages run in list order, and each stage's output becomes the next stage's input. Setting attacker_message / target_message to an empty string suppresses that message, which reduces chat spam.
Recovery configuration
| Field | Type | Default | Description |
|---|---|---|---|
source | enum | ATTACKER | Where recovery attributes are read from. |
resistance_source | enum | TARGET | Where resistance attributes are read from. |
flat_attributes | list<string> | [] | Flat recovery attributes. |
percent_attributes | list<string> | [] | Percentage recovery attributes, based on final damage. |
resistance_attributes | list<string> | [] | Resistance attributes that reduce recovery. |
expression | string | "" | Custom recovery expression. |
min_result / max_result | double | — | Recovery result clamps. |
Vanilla damage takeover modes
Global vanilla_event_damage.enabled controls the current vanilla event takeover mode:
enabled: true: recommended perfect takeover mode. Attribute does not cancel the vanilla damage event first. Instead, it resolves EA damage synchronously before the event returns and rewrites the final event damage in place. This preserves vanilla side effects such as burning zombies igniting players, iron golem knockback, shields, absorption hearts, thorns, death/stat handling, and other vanilla/plugin event effects.enabled: false: compatibility mode. The old behavior cancels the event and re-applies damage/feedback through Attribute. Use it only when a server needs the legacy behavior or is integrating with special combat plugins.
Perfect takeover changes how damage is applied, not the configured damage-number pipeline. If the result is dodge, event cancellation, or final damage <= 0, the original event is cancelled for that hit. Attribute side effects such as lifesteal, combat messages, and attack cooldown handling are still applied by Attribute.
Synthetic hit feedback
Synthetic feedback mainly matters in compatibility mode. In perfect takeover mode, vanilla usually produces knockback, hurt animation, and sound naturally.
synthetic_hit_feedback:
knockback: true
knockback_strength: 0.4
hurt_sound: true| Field | Description |
|---|---|
knockback | Whether to add knockback feedback. |
knockback_strength | Knockback strength. |
hurt_sound | Whether to play hurt sound feedback. |
Debugging
Use /ea debug and the module's damage debug output to inspect context variables, stage results, final damage, recovery, and event behavior.