Skip to content

Attack Roll System #99

Description

@FirebrickRed

Summary

Handle attack rolls with multiple input modes to accommodate different play styles. Support automatic rolling, modifier display, player-provided rolls, and manual totals. Include critical hit/miss detection and weapon range display.

Phase: MVP Combat System
Systems: Combat System, Dice Rolling, Weapon System

Prerequisites

Goals

  • Multiple attack input modes (auto, show mods, player roll, total)
  • Attack modifier calculation (ability mod + proficiency + magic)
  • Critical hit (nat 20) and critical miss (nat 1) detection
  • Compare to target AC and announce hit/miss
  • Weapon range display for ranged weapons
  • Combat log integration
  • Foundation for advantage/disadvantage (future)

Commands

Attack Modes

# AUTO MODE (default) - Roll d20 and add all modifiers
/combat attack goblin_chief
> Alice attacks Goblin Chief with Longsword!
> Roll: 14 + 5 (STR +3, Prof +2) = 19
> vs AC 15 → HIT!

# SHOW MODS - Display modifiers, player rolls physical dice
/combat attack goblin_chief --showmods
> Attacking Goblin Chief with Longsword
> Your modifiers: +5 (STR +3, Proficiency +2)
> Target AC: 15
> [Roll your d20 and use /combat attack goblin_chief --roll <result>]

# PLAYER ROLL - Player provides d20 result, system adds modifiers
/combat attack goblin_chief --roll 14
> Alice attacks Goblin Chief with Longsword!
> Roll: 14 + 5 (STR +3, Prof +2) = 19
> vs AC 15 → HIT!

# MANUAL TOTAL - Player provides final number (did all math)
/combat attack goblin_chief --total 19
> Alice attacks Goblin Chief with Longsword!
> Attack roll: 19 vs AC 15 → HIT!

Weapon Selection

# Attack with specific weapon (if multiple equipped)
/combat attack goblin_chief --weapon dagger
> Alice attacks Goblin Chief with Dagger!

# Default: Use main hand weapon or last used weapon

Attack Modifier Calculation

int attackBonus = 0;

// 1. Ability modifier (STR for melee, DEX for ranged/finesse)
if (weapon.hasProperty("finesse")) {
    // Player can choose STR or DEX - use higher
    attackBonus += Math.max(strMod, dexMod);
} else if (weapon.hasProperty("ranged")) {
    attackBonus += dexMod;
} else {
    attackBonus += strMod;
}

// 2. Proficiency bonus (if proficient with weapon type)
if (character.isProficientWith(weapon)) {
    attackBonus += proficiencyBonus;
}

// 3. Magic weapon bonus (future)
// attackBonus += weapon.getMagicBonus();

// 4. Other bonuses (Fighting Style, etc. - future)

Critical Hits & Misses

# Natural 20
/combat attack goblin_chief
> Alice attacks Goblin Chief with Longsword!
> Roll: ★ NATURAL 20 ★ + 5 = 25
> CRITICAL HIT! 
> [Proceed to damage with double dice]

# Natural 1
/combat attack goblin_chief
> Alice attacks Goblin Chief with Longsword!
> Roll: ✗ NATURAL 1 ✗ + 5 = 6
> CRITICAL MISS! (Auto-miss regardless of AC)

Critical Damage (MVP: Double Dice)

// On critical hit, damage dice are doubled
// Example: Longsword 1d8+3 becomes 2d8+3
// Future config: Option for "roll twice" instead of "double dice"

Weapon Range Display

# For ranged weapons, show range in attack feedback
/combat attack goblin_chief --weapon longbow
> Alice attacks Goblin Chief with Longbow!
> Range: 150/600 ft | Target distance: ~45 ft (in range)
> Roll: 16 + 5 = 21 vs AC 15 → HIT!

# Out of range warning
/combat attack distant_enemy --weapon shortbow
> ⚠ Warning: Target is ~400 ft away
> Shortbow range: 80/320 ft
> Attack at long range (disadvantage) or beyond max range (impossible)

Hit/Miss Determination

int roll = rollD20();  // or use player-provided roll
int total = roll + attackBonus;
int targetAC = target.getArmorClass();

boolean isNat20 = (roll == 20);
boolean isNat1 = (roll == 1);

if (isNat1) {
    return AttackResult.CRITICAL_MISS;
} else if (isNat20) {
    return AttackResult.CRITICAL_HIT;
} else if (total >= targetAC) {
    return AttackResult.HIT;
} else {
    return AttackResult.MISS;
}

Combat Log Output

[Combat Log]
Round 2 | Alice's Turn
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ATTACK: Alice → Goblin Chief
Weapon: Longsword (1d8 slashing)
Roll: 14 + 5 (STR +3, Prof +2) = 19
Target AC: 15
Result: HIT
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Advantage/Disadvantage (Future Enhancement)

# Stub for future - note in help text
/combat attack goblin_chief --adv
> [Future: Roll 2d20, take higher]

/combat attack goblin_chief --dis  
> [Future: Roll 2d20, take lower]

For MVP, these flags will show a message:

Advantage/disadvantage not yet implemented. 
Roll manually and use --roll or --total.
See issue #61 for tracking.

Right-Click Weapon Attack (Future Enhancement)

Future: Right-click equipped weapon to initiate attack
- Opens target selection
- Uses weapon stats automatically
- See issue #85 for dual interaction system

Entity Attacks

Entities use their defined attacks from YAML:

# From entity YAML
attacks:
  - name: "Scimitar"
    to_hit: +4
    reach: 5
    damage: "1d6+2"
    damage_type: "slashing"
# DM attacking as entity (see #102)
/combat enemy goblin_chief attack Alice
> Goblin Chief attacks Alice with Scimitar!
> Roll: 12 + 4 = 16 vs AC 14 → HIT!

Tab Completion

  • /combat attack <TAB> → List valid targets in combat
  • /combat attack target --weapon <TAB> → List equipped weapons
  • /combat attack target --roll <TAB> → Suggest "1-20"

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