Skip to content

Damage & Healing System #100

Description

@FirebrickRed

Summary

Handle damage application and healing during combat. Support multiple input modes (like attack rolls), damage resistance/vulnerability, temporary HP, and death triggers. Integrates with existing entity HP system and adds combat methods to CharacterSheet.

Phase: MVP Combat System
Systems: Combat System, HP Tracking, Dice Rolling

Prerequisites

Goals

  • Multiple damage input modes (auto roll, show mods, player roll, flat amount)
  • Damage resistance (half damage) and vulnerability (double damage)
  • Temporary HP consumed first
  • Death triggers (entities die, players go unconscious)
  • Healing commands with similar flexibility
  • Combat log for all HP changes
  • Add takeDamage() method to CharacterSheet

Commands

Damage Commands

# FLAT DAMAGE - Apply specific amount
/combat damage goblin_chief 14
> Goblin Chief takes 14 slashing damage!
> HP: 22 → 8

# ROLL DAMAGE - Roll dice and apply
/combat damage goblin_chief --roll 2d6+3
> Rolling damage: 2d6+3
> Result: [4][6] + 3 = 13 slashing damage
> Goblin Chief HP: 22 → 9

# SHOW MODS - Display damage modifiers
/combat damage goblin_chief --showmods
> Longsword damage: 1d8 + 3 (STR)
> [Roll and use /combat damage goblin_chief --roll <result> or flat amount]

# PLAYER TOTAL - Player provides final damage
/combat damage goblin_chief --total 17
> Goblin Chief takes 17 damage!
> HP: 22 → 5

Damage Types

# Specify damage type (for resistance/vulnerability)
/combat damage goblin_chief 14 --type fire
> Goblin Chief takes 14 fire damage!
> HP: 22 → 8

# With resistance
/combat damage fire_elemental 14 --type fire
> Fire Elemental has RESISTANCE to fire!
> 14 → 7 fire damage
> HP: 45 → 38

# With vulnerability
/combat damage skeleton 10 --type bludgeoning
> Skeleton is VULNERABLE to bludgeoning!
> 10 → 20 bludgeoning damage
> HP: 13 → 0
> Skeleton is destroyed!

Healing Commands

# Flat healing
/combat heal Alice 10
> Alice healed for 10 HP!
> HP: 15 → 25

# Roll healing
/combat heal Alice --roll 2d8+3
> Rolling healing: 2d8+3
> Result: [5][7] + 3 = 15 HP healed
> Alice HP: 15 → 30 (max: 32)

# Can't exceed max HP
/combat heal Alice 100
> Alice healed for 2 HP! (at max HP)
> HP: 30 → 32

Temporary HP

# Grant temporary HP
/combat temphp Alice 10
> Alice gains 10 temporary HP!
> Temp HP: 0 → 10

# Temp HP absorbed first
/combat damage Alice 15
> Alice takes 15 damage!
> Temp HP absorbs 10: 10 → 0
> Remaining 5 damage to HP: 32 → 27

Damage Calculation with Modifiers

// For weapon damage
int damageBonus = 0;

// Ability modifier (same logic as attack - STR/DEX/finesse)
if (weapon.hasProperty("finesse")) {
    damageBonus += Math.max(strMod, dexMod);
} else if (weapon.hasProperty("ranged")) {
    damageBonus += dexMod;
} else {
    damageBonus += strMod;
}

// Magic weapon bonus (future)
// damageBonus += weapon.getMagicDamageBonus();

// Roll damage dice + bonus
int damage = DiceRoller.parseDiceRoll(weapon.getDamageDice()) + damageBonus;

Critical Hit Damage

// Double the dice, not the modifier
// Longsword crit: 2d8 + 3 (not 2d8 + 6)

String baseDice = weapon.getDamageDice();  // "1d8"
String critDice = doubleDice(baseDice);     // "2d8"
int damage = DiceRoller.parseDiceRoll(critDice) + damageBonus;

Resistance & Vulnerability

// Check target's damage resistances/vulnerabilities
Set<String> resistances = target.getDamageResistances();
Set<String> vulnerabilities = target.getDamageVulnerabilities();
Set<String> immunities = target.getDamageImmunities();

if (immunities.contains(damageType)) {
    damage = 0;
    announce("IMMUNE to " + damageType);
} else if (resistances.contains(damageType)) {
    damage = damage / 2;  // Round down
    announce("RESISTANT to " + damageType);
} else if (vulnerabilities.contains(damageType)) {
    damage = damage * 2;
    announce("VULNERABLE to " + damageType);
}

Death Triggers

Entity Death (0 HP)

if (entity.getCurrentHp() <= 0) {
    entity.setDead(true);
    // Death behavior configured in #82
    broadcast(entity.getDisplayName() + " is defeated!");
    // Remove from combat, trigger loot (#77), etc.
}

Player Unconscious (0 HP)

if (player.getCurrentHealth() <= 0) {
    player.setCurrentHealth(0);  // Don't go negative for MVP
    markAsUnconscious(player);
    broadcast(player.getName() + " falls unconscious!");
    // Triggers death save system (#101)
}

CharacterSheet Combat Methods

// Add to CharacterSheet.java

public void takeDamage(int damage) {
    // Absorb with temp HP first
    if (tempHealth > 0) {
        int absorbed = Math.min(tempHealth, damage);
        tempHealth -= absorbed;
        damage -= absorbed;
    }
    
    // Apply remaining to current HP
    currentHealth = Math.max(0, currentHealth - damage);
}

public void heal(int amount) {
    currentHealth = Math.min(totalHealth, currentHealth + amount);
}

public void setTemporaryHp(int amount) {
    // Temp HP doesn't stack - take higher
    tempHealth = Math.max(tempHealth, amount);
}

public boolean isUnconscious() {
    return currentHealth <= 0;
}

Combat Log Output

[Combat Log]
Round 2 | Alice's Turn
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
DAMAGE: Alice → Goblin Chief
Weapon: Longsword
Damage Roll: 1d8+3 = [6]+3 = 9 slashing
Resistance: None
Final Damage: 9
HP Change: 22 → 13
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

DAMAGE: Goblin Chief → Alice  
Attack: Scimitar
Damage: 7 slashing
Temp HP Absorbed: 5
HP Change: 32 → 30
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Massive Damage (Future)

Future config option:
- If single hit deals >= max HP, instant death
- Or CON save vs instant death
See #104 for config options

Tab Completion

  • /combat damage <TAB> → List valid targets in combat
  • /combat damage target --type <TAB> → List damage types (slashing, fire, etc.)
  • /combat heal <TAB> → List valid targets in combat

Related Issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    characterpertaining to the players charactercombatCombat, HP, initiative, damageenhancementNew feature or requestnpc/entityFor issues pertaining to npc's or monsters and is referred to as entities in the mod pack

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions