Combat Mechanics
Relevant source files
The following files were used as context for generating this wiki page:
- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java
- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java
- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/mechanics/Ballistica.java
- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/Weapon.java
- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/duelist/ElementalStrike.java
- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfWarding.java
- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/DriedRose.java
- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v2_X_Changes.java
- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v1_X_Changes.java
- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v0_9_X_Changes.java
Combat in Shattered Pixel Dungeon is a turn-based system where characters, including the hero, enemies, and allies, engage in attacks and use abilities. The outcome of combat is determined by a combination of character statistics, equipment properties, enchantments, buffs, and debuffs. The core logic for combat is encapsulated within the Char and Hero classes, with support from systems like Weapon for equipment effects and Ballistica for projectile-based attacks.
This document outlines the fundamental mechanics of combat, from initiating an attack to calculating damage and applying special effects. It covers both melee and ranged combat, as well as the role of special abilities and allied characters.
Core Combat Flow
The combat sequence is initiated when the Hero performs an Attack action. This triggers a series of method calls that determine if the attack hits and how much damage is dealt. The process involves calculating attack and defense skills, rolling for damage, and applying any procedural effects from weapons or buffs.
The following diagram illustrates the sequence of a standard hero attack.
Hit Determination
An attack's success is determined by comparing the attacker's attackSkill against the defender's defenseSkill.
attackSkill(Char target): This method calculates the attacker's proficiency. For the hero, it is influenced by their baseattackSkill, rings (e.g., Ring of Accuracy), and temporary buffs or talents likePreciseAssault.defenseSkill(Char enemy): This method calculates the defender's evasiveness. For the hero, it is influenced by their basedefenseSkill, armor properties, rings (e.g., Ring of Evasion), and buffs likeMomentumfor the Freerunner.
The probability of a hit is calculated as attackSkill / (attackSkill + defenseSkill). A random roll determines if the attack connects.
Sources: core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java:464-471, core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java:626-681, core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java:684-726
Damage Calculation
If an attack hits, the next step is to calculate the damage dealt. This involves a damage roll from the attacker, followed by the application of damage reduction from the defender.
This diagram shows the flow of damage calculation from the initial roll to the final application on the target.
Sources: core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java:750-785, core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java:1128-1172
Damage Roll (damageRoll)
The initial damage is determined by the damageRoll method. For the hero, this depends on whether they are using a weapon or fighting unarmed.
- With Weapon: The weapon's
damageRoll(this)method is called, which typically returns a random integer within the weapon's min/max damage range. - Unarmed: The
RingOfForce.damageRoll(this)method is used. - Modifiers: The result is then modified by buffs like
PhysicalEmpowerand various talents.
Sources: core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java:750-785
Damage Reduction (drRoll)
The defender reduces incoming damage using their drRoll method. This value is subtracted from the incoming damage.
- The hero's
drRollis calculated from their armor's damage reduction (DR) range and any blocking value from their weapon. - If the hero's strength (
STR) is less than the requirement for their armor or weapon, the effectiveness of the damage reduction is penalized.
Sources: core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java:729-748
Procedural Effects (proc)
After a successful hit, attackProc is called on the attacker and defenseProc is called on the defender. These methods trigger effects from enchantments, glyphs, and other sources.
attackProc: Triggers weapon enchantments (e.g., Blazing, Vampiric) and certain talents.defenseProc: Triggers armor glyphs (e.g., Stone, Viscosity) and artifact effects.
Sources: core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java:1203-1248, core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java:1251-1275
Special Abilities
Many combat mechanics are driven by special abilities, which can be activated by the player or triggered under certain conditions.
Duelist: Elemental Strike
The Duelist's ElementalStrike is a complex armor ability that unleashes a cone-shaped attack. The effects of the strike are determined by the enchantment on the Duelist's equipped melee weapon.
The ability's execution flow:
- Calculates a
ConeAOEbased on the target position. - Determines the equipped weapon's enchantment.
- Fires visual effects (
MagicMissile) based on the enchantment type. - Executes
preAttackEffect,perCellEffect, andperCharEffectmethods.
The following diagram shows how different enchantments lead to different effects.
Sources: [core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/duelist/ElementalStrike.java]
The effects for each enchantment type are detailed in the table below:
| Enchantment | Effect Description | Source |
|---|---|---|
Blazing | Creates a Fire blob in the cone area, dealing fire damage over time. | ElementalStrike.java:293-297 |
Chilling | Creates a Freezing blob in the cone area, chilling enemies. | ElementalStrike.java:300-304 |
Kinetic | Deals AOE damage based on the damage stored in the Kinetic.ConservedDamage buff. | ElementalStrike.java:362-373 |
Blooming | Creates grass and applies the Roots debuff to enemies in the cone. | ElementalStrike.java:307-339, 376-379 |
Elastic | Knocks back all characters in the cone away from the hero. | ElementalStrike.java:382-398 |
Lucky | Has a chance to drop loot from each enemy hit. | ElementalStrike.java:401-410 |
Projecting | Deals a percentage of the hero's damage roll to secondary targets. | ElementalStrike.java:413-418 |
Corrupting | Has a chance to instantly corrupt enemies with low health. | ElementalStrike.java:426-441 |
Grim | Has a chance to instantly kill enemies with low health. | ElementalStrike.java:444-454 |
| (No Enchantment) | Deals a flat amount of magic damage to all targets in the cone. | ElementalStrike.java:356-359 |
Sources: [core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/duelist/ElementalStrike.java]
Berserker: Rage
The Berserker subclass for the Warrior features a "Rage" mechanic. Historically, this ability has undergone several reworks to balance its power and engagement.
- v0.6.5: Rage is built by taking physical damage and fades over time. It grants bonus damage, and at full rage, the Berserker can activate "berserk" to survive a fatal blow and gain a bonus shield.
- v1.4.0: The berserk ability became manually activated with a lower cooldown. The
Endless Ragetalent was adjusted to grant bonuses when above 100% rage, and a new talent,Deathless Fury, was added to allow for the old automatic activation at a high cooldown cost. - v2.0.0: The
Ring of Energywas updated to also provide a recharging boost to hero armor abilities, indirectly affecting abilities that use charge.
Sources: core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v0_6_X_Changes.java:82-97, core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v1_X_Changes.java:107-118, core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v2_X_Changes.java:1152-1155
Allies in Combat
Allies, such as the Sad Ghost or summoned Wards, participate in combat with their own AI and attack logic.
Dried Rose: The Ghost Hero
The DriedRose artifact summons a GhostHero ally. The ghost's combat effectiveness is tied to the rose's level and the equipment it is given.
- Equipment: The ghost can be equipped with a weapon and armor via the
WndGhostHerointerface. Its ability to use equipment is determined by its strength, which is calculated as13 + level()/2, wherelevel()is the level of the Dried Rose. - Combat Logic: The
GhostHeroextendsDirectableAlly, meaning it can be given commands. It uses standardCharcombat methods (attackSkill,damageRoll,drRoll), but its stats are derived from its own level and any equipped items. - Health and Summoning: The ghost can be summoned when the rose is fully charged. While summoned, the ghost heals over time, but the rose does not recharge. If the ghost dies, the rose's charge is depleted.
Wand of Warding: Wards and Sentries
The WandOfWarding creates allied Ward NPCs that automatically attack enemies within their view distance.
- Creation & Upgrading: Zapping an empty space creates a Tier 1
Ward. Zapping an existingWardupgrades it, increasing its tier, health, and power. Wards can be upgraded to a maximum of Tier 6. - Combat Stats: A
Ward's damage is2 + wandLevelto8 + 4*wandLevel. At Tier 4 and above, they becomeWardSentrys, gaining damage reduction (drRoll) and improved defense skill that scales with dungeon depth. - Energy Limit: The total number of ward tiers a hero can have active is limited by the level of their
WandOfWarding. The maximum energy is2 + wand.level(). Attempting to create a ward beyond this limit will fail.
// From WandOfWarding.java
// Damage calculation for a Ward's zap
int dmg = Hero.heroDamageIntRange( 2 + wandLevel, 8 + 4*wandLevel );
// Total zaps before a low-tier ward expires
if (totalZaps >= (2*tier-1)){
die(this);
}
Ranged Combat
Ranged combat utilizes the Ballistica class to calculate projectile paths. This class determines the trajectory of a projectile from a source to a target, accounting for obstacles and range limits.
Ballistica(source, target, properties): The constructor takes the start and end points, along with properties that define how the projectile interacts with the environment (e.g.,STOP_SOLID,STOP_TARGET).- Path Calculation: It calculates a path as a series of cells. The
distandcollisionPosfields store the final travel distance and impact point. - Usage: It is used for everything from wand zaps and thrown weapons to the cone AOE of the
ElementalStrikeability.
Sources: core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/mechanics/Ballistica.java, core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/duelist/ElementalStrike.java:159-164