Version: 1.0 Date: 2026-01-23 Status: Draft Branch: NPCs
This document outlines the turn-based combat system for TalesMUD. Combat occurs in isolated Combat Instances - temporary rooms where players and enemies fight in a Pokemon-style turn-based format. The system supports multi-enemy encounters, multi-player combat, and persistence across disconnections.
- Turn-based combat with initiative-based turn order
- Combat instances - isolated temporary rooms for fights
- Multi-enemy encounters - fight multiple NPCs simultaneously
- Multi-player combat - multiple players can fight together (formal party system later)
- Flee mechanics - chance-based escape system
- Persistence - players return to combat on reconnect
- Loot & XP distribution - rewards on victory
- Current State Analysis
- Architecture Decision
- Core Concepts
- Combat Flow
- Data Models
- Combat Mechanics
- Commands
- Integration Points
- Implementation Phases
- Edge Cases & Error Handling
| Component | Status | Notes |
|---|---|---|
EnemyTrait |
Implemented | Combat stats, aggro, loot config |
EnemyTrait.AggroOnSight |
Implemented | Trigger for aggressive enemies |
EnemyTrait.AttackPower/Defense |
Implemented | Base damage values |
EnemyTrait.XPReward/GoldDrop |
Implemented | Reward configuration |
NPC.State |
Implemented | FSM with "combat" state |
Character.EquippedItems |
Implemented | Weapon/armor slots |
Character.CurrentHitPoints |
Implemented | Health tracking |
| Loot Tables | Implemented | Item drop configuration |
| Item Instance Creation | Implemented | For loot drops |
| Feature | Priority | Complexity |
|---|---|---|
| Combat Instance (Room) | Critical | High |
| Turn-based combat loop | Critical | High |
| Initiative system | Critical | Medium |
| Damage calculation | Critical | Medium |
| Combat commands | Critical | Medium |
| Combat state management | Critical | High |
| Player death handling | High | Medium |
| Flee mechanics | High | Low |
| Multi-enemy support | High | Medium |
| Party combat support | High | High |
| Combat persistence | High | Medium |
| Combat timeout | Medium | Low |
| Combat log | Medium | Low |
Rather than physically moving players between rooms, we use a Combat Instance overlay system:
┌─────────────────────────────────────────────────────────────────┐
│ WORLD ROOM │
│ "Dark Forest Clearing" │
│ │
│ Players: Alice (in combat), Bob │
│ NPCs: Goblin Scout (in combat), Merchant Tom │
│ │
│ [Alice and Goblin Scout are in Combat Instance #abc123] │
└─────────────────────────────────────────────────────────────────┘
│
│ Combat Instance is a parallel state
▼
┌─────────────────────────────────────────────────────────────────┐
│ COMBAT INSTANCE #abc123 │
│ (Isolated combat arena - not a physical room) │
│ │
│ Players: [Alice] │
│ Enemies: [Goblin Scout] │
│ │
│ Turn Order: Alice (12) → Goblin Scout (8) │
│ Current Turn: Alice │
│ │
│ State: active │
└─────────────────────────────────────────────────────────────────┘
- Isolation - Other players cannot interfere with ongoing combat
- Persistence - Combat state survives disconnections
- Multi-combatant - Clean handling of multiple players/enemies
- Map consistency - Players remain "in" their room for world purposes
- No room teleportation - Avoids complex room management
- Combat Lock - NPCs in combat cannot be targeted by non-participants
- Player Lock - Players in combat cannot interact with the world
- Turn Exclusivity - Only current turn holder can act
- Instance Cleanup - Instances are destroyed when combat ends
A combat instance is a temporary, in-memory state machine that manages a fight.
type CombatInstance struct {
ID string // Unique identifier
OriginRoomID string // Room where combat started
// Participants
Players []CombatantRef // Player combatants
Enemies []CombatantRef // NPC combatants
// Turn Management
TurnOrder []CombatantRef // Initiative-sorted order
CurrentTurnIdx int // Index into TurnOrder
TurnStartTime time.Time // For timeout tracking
Round int // Current combat round (starts at 1)
// State
State CombatState // pending, active, victory, defeat, fled
CreatedAt time.Time
LastActionAt time.Time
// Combat Log
Log []CombatLogEntry // History of actions
}
type CombatantRef struct {
ID string // Character or NPC ID
Type CombatantType // "player" or "npc"
Initiative int // Rolled initiative value
IsAlive bool // Still in combat
HasFled bool // Successfully fled
}
type CombatState string
const (
CombatStatePending CombatState = "pending" // Waiting for combat to begin
CombatStateActive CombatState = "active" // Combat in progress
CombatStateVictory CombatState = "victory" // All enemies defeated
CombatStateDefeat CombatState = "defeat" // All players dead
CombatStateFled CombatState = "fled" // All players fled
CombatStateTimeout CombatState = "timeout" // Combat timed out
)Players and NPCs track their combat status:
// Added to Character
type Character struct {
// ... existing fields ...
InCombat bool `json:"inCombat"`
CombatInstanceID string `json:"combatInstanceId,omitempty"`
}
// Added to NPC
type NPC struct {
// ... existing fields ...
InCombat bool `json:"inCombat"`
CombatInstanceID string `json:"combatInstanceId,omitempty"`
}┌─────────────────────────────────────────────────────────────────┐
│ COMBAT INITIATION │
├─────────────────────────────────────────────────────────────────┤
│ │
│ TRIGGER A: Player attacks NPC │
│ > attack goblin │
│ → Check: NPC has EnemyTrait? → Create combat instance │
│ │
│ TRIGGER B: Player enters room with aggressive NPC │
│ → Check: NPC.EnemyTrait.AggroOnSight == true? │
│ → Check: NPC.InCombat == false? │
│ → Auto-create combat instance │
│ │
│ TRIGGER C: NPC detects player in aggro radius │
│ → Check: Player in NPC.EnemyTrait.AggroRadius rooms? │
│ → NPC moves toward player and initiates │
│ │
└─────────────────────────────────────────────────────────────────┘
When combat is triggered:
-
Identify all participants
- Player(s) who triggered or are in the room
- NPC(s) with
AggroOnSightor that were attacked - If NPC has
CallForHelp, add nearby enemies
-
Validate participants
- Skip NPCs already in combat (different instance)
- Skip players already in combat
-
Create combat instance
- Generate unique ID
- Record origin room
-
Roll initiative for all combatants
Initiative = 1d20 + DEX modifier -
Sort turn order by initiative (highest first)
-
Mark all participants as in combat
- Set
InCombat = true - Set
CombatInstanceID
- Set
-
Notify participants
- Display combat start message
- Show turn order
- Show HP status of all combatants
┌─────────────────────────────────────────────────────────────────┐
│ COMBAT ROUND │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Round 1 │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Turn 1: Alice (Player) │ │
│ │ Timer: 60 seconds │ │
│ │ Actions: attack, spell, item, defend, flee │ │
│ │ > attack goblin │ │
│ │ → Roll hit: 1d20 + STR mod vs enemy Defense │ │
│ │ → Calculate damage: Weapon damage + STR mod │ │
│ │ → Apply damage to target │ │
│ │ → Check if target dead │ │
│ │ → End turn │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Turn 2: Goblin Scout (NPC) │ │
│ │ AI Decision: │ │
│ │ 1. If HP < FleeThreshold → attempt flee │ │
│ │ 2. Else → attack weakest player │ │
│ │ → Execute action │ │
│ │ → End turn │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ Check: All enemies dead? → VICTORY │
│ Check: All players dead? → DEFEAT │
│ Check: All players fled? → FLED │
│ Else: Start Round 2 │
│ │
└─────────────────────────────────────────────────────────────────┘
- Each turn has a 60 second time limit
- When timer expires:
- Player: Auto-defend (skip action, gain defense bonus)
- NPC: N/A (AI acts instantly)
- Warning at 15 seconds remaining
- If player is AFK for 3 consecutive turns: auto-flee attempt
- Mark combat state as
victory - Calculate total rewards:
- Sum XP from all defeated enemies
- Sum gold drops
- Roll loot tables for each enemy
- Distribute rewards (see Loot Distribution)
- Drop loot items in origin room
- Clear combat status from all participants
- Destroy combat instance
- Notify players of victory and rewards
- Mark combat state as
defeat - For each dead player:
- Calculate gold loss (configurable %, default 10%)
- Set respawn location (player's bound room or world starting room)
- Restore HP to 50%
- Teleport to respawn location
- Clear combat status from NPCs
- Reset NPC HP (they won)
- Destroy combat instance
- Notify players of defeat
Players can bind to specific rooms (inns, temples, safe houses) using the /bind command. Only rooms with CanBind: true support this.
Room Property:
// Added to Room entity
CanBind bool `json:"canBind"` // If true, players can /bind hereCharacter Property:
// Added to Character entity
BoundRoomID string `json:"boundRoomId,omitempty"` // Respawn locationRespawn Priority:
Character.BoundRoomIDif set and room still exists- World starting room (configured in game settings)
Bind Command:
> bind
You bind your soul to the Sleeping Dragon Inn.
You will respawn here upon death.
Error cases:
- "You cannot bind here." (room doesn't support binding)
- "You are already bound to this location."
- Mark combat state as
fled - For each fled player:
- Already removed from instance
- Back in origin room with reduced HP
- Clear combat status from NPCs
- Reset NPC HP to pre-combat values
- Destroy combat instance
// pkg/entities/combat/instance.go
type CombatInstance struct {
ID string `json:"id"`
OriginRoomID string `json:"originRoomId"`
// Participants
Players []CombatantRef `json:"players"`
Enemies []CombatantRef `json:"enemies"`
// Turn Management
TurnOrder []CombatantRef `json:"turnOrder"`
CurrentTurnIdx int `json:"currentTurnIdx"`
TurnStartTime time.Time `json:"turnStartTime"`
Round int `json:"round"`
// State
State CombatState `json:"state"`
CreatedAt time.Time `json:"createdAt"`
LastActionAt time.Time `json:"lastActionAt"`
// Configuration
TurnTimeoutSec int `json:"turnTimeoutSec"` // Default: 60
// Combat Log
Log []CombatLogEntry `json:"log"`
}
type CombatantRef struct {
ID string `json:"id"`
Type CombatantType `json:"type"` // "player" or "npc"
Name string `json:"name"` // Display name
Initiative int `json:"initiative"`
IsAlive bool `json:"isAlive"`
HasFled bool `json:"hasFled"`
// Snapshot of combat stats at combat start
MaxHP int32 `json:"maxHp"`
CurrentHP int32 `json:"currentHp"`
AttackPower int32 `json:"attackPower"`
Defense int32 `json:"defense"`
// Status effects
DefenseBonus int32 `json:"defenseBonus"` // From defend action
}
type CombatantType string
const (
CombatantTypePlayer CombatantType = "player"
CombatantTypeNPC CombatantType = "npc"
)
type CombatLogEntry struct {
Timestamp time.Time `json:"timestamp"`
Round int `json:"round"`
ActorID string `json:"actorId"`
ActorName string `json:"actorName"`
Action CombatAction `json:"action"`
TargetID string `json:"targetId,omitempty"`
TargetName string `json:"targetName,omitempty"`
Result string `json:"result"` // "hit", "miss", "critical", "fled", "blocked"
Damage int32 `json:"damage,omitempty"`
Message string `json:"message"` // Human-readable description
}type CombatAction string
const (
CombatActionAttack CombatAction = "attack"
CombatActionSpell CombatAction = "spell"
CombatActionItem CombatAction = "item"
CombatActionDefend CombatAction = "defend"
CombatActionFlee CombatAction = "flee"
CombatActionTimeout CombatAction = "timeout" // Forced defend
)// Global combat settings
type CombatConfig struct {
TurnTimeoutSeconds int `json:"turnTimeoutSeconds"` // Default: 60
AFKAutoFleeAfterTurns int `json:"afkAutoFleeAfterTurns"` // Default: 3
DeathGoldLossPercent float64 `json:"deathGoldLossPercent"` // Default: 0.10 (10%)
DeathRespawnHPPercent float64 `json:"deathRespawnHpPercent"` // Default: 0.50 (50%)
FleeBaseChance float64 `json:"fleeBaseChance"` // Default: 0.50 (50%)
FleeDexBonus float64 `json:"fleeDexBonus"` // Per DEX point bonus
DefendBonusPercent float64 `json:"defendBonusPercent"` // Default: 0.50 (50% defense boost)
CriticalHitChance float64 `json:"criticalHitChance"` // Default: 0.05 (5%)
CriticalHitMultiplier float64 `json:"criticalHitMultiplier"` // Default: 2.0
CombatTimeoutMinutes int `json:"combatTimeoutMinutes"` // Default: 30
}Roll at combat start, determines turn order for entire combat:
Initiative = 1d20 + (DEX / 4)
For NPCs: Use NPC.Level as DEX approximation, or add DEX to NPC model
Turn order is fixed for the duration of combat (re-roll only if new combatants join, which doesn't happen in this design).
Phase 1: Melee Only
To Hit Roll:
Roll = 1d20
If Roll == 20: Critical Hit (auto-hit, double damage)
If Roll == 1: Critical Miss (auto-miss)
Hit = Roll + STR modifier >= Target.Defense + 10
Damage Calculation:
Base Damage = Weapon.Damage + STR modifier
For Players:
Weapon.Damage = EquippedWeapon.Attributes["damage"] OR 1 (unarmed)
For NPCs:
Base Damage = EnemyTrait.AttackPower
Defense Reduction:
Reduction = Target.Defense / 2 (armor absorbs some damage)
Final Damage = max(1, Base Damage - Reduction)
If Critical: Final Damage *= 2
Future Phases:
- Ranged Weapons (Bows): DEX-based to-hit and damage
- Spells: INT/WIS-based, mana cost, spell effects
Modifier = (Attribute - 10) / 2
Example:
STR 14 → +2 modifier
STR 8 → -1 modifier
STR 10 → 0 modifier
When a combatant defends:
- Skip offensive action
- Gain +50% defense bonus until next turn
- Defense bonus is applied to
CombatantRef.DefenseBonus - Cleared at start of combatant's next turn
Flee Chance = BaseChance + (DEX modifier * FleeDexBonus)
Default:
BaseChance = 50%
FleeDexBonus = 2% per DEX point above 10
Example:
DEX 14 (+2 modifier): 50% + (2 * 2%) = 54% chance to flee
On Success:
- Remove player from combat instance
- Clear player's combat status
- Player remains in origin room
- Notify remaining participants
- If last player fled → combat ends with "fled" state
On Failure:
- Player loses their turn
- Message: "You fail to escape! The enemies block your path."
- Combat continues
Simple priority-based AI:
1. If HP <= FleeThreshold AND FleeThreshold > 0:
→ Attempt flee
2. If any ally NPC has "healer" CombatStyle AND self HP < 50%:
→ Request heal (future feature)
3. Attack player with lowest HP percentage
→ Basic attack using AttackPower
When a player's HP reaches 0:
- Mark as dead (
IsAlive = false) - Remove from turn order
- Check if all players dead → Defeat
When an NPC's HP reaches 0:
- Mark as dead (
IsAlive = false) - Remove from turn order
- Execute
OnDeathScriptif defined - Check if all enemies dead → Victory
When combat ends in victory:
Total XP = Sum of all enemy XPReward values
Per Player XP = Total XP / Number of living players at victory
XP is NOT split if player died during combat but others won.
Dead players get 0 XP.
Total Gold = Sum of all enemy GoldDrop rolls
Per Player Gold = Total Gold / Number of living players at victory
Same rules as XP - dead players get nothing.
- Roll loot for each defeated enemy (using existing loot table system)
- All items drop to the origin room floor
- Players can pick up items after combat ends
- First-come-first-serve (free for all)
Future enhancement: Need/Greed/Pass rolling system for group loot.
| Command | Syntax | Description |
|---|---|---|
attack |
attack <target> |
Initiate combat with target NPC |
| Command | Syntax | Description |
|---|---|---|
bind |
bind |
Bind to current room (if room allows) |
| Command | Aliases | Syntax | Description | Phase |
|---|---|---|---|---|
attack |
a, hit |
attack <target> |
Melee attack target enemy | 1 |
defend |
d, guard |
defend |
Defend for damage reduction | 3 |
flee |
run, escape |
flee |
Attempt to escape combat | 3 |
item |
use |
item <item> |
Use an item (potion, etc.) | 3 |
status |
combat, cs |
status |
View combat status | 3 |
log |
combatlog |
log [lines] |
View combat log | 7 |
shoot |
fire |
shoot <target> |
Ranged attack (bow) | Future |
spell |
cast |
spell <spell> [target] |
Cast a spell | Future |
> attack goblin
You swing your Iron Sword at Goblin Scout!
Roll: 15 + 2 (STR) = 17 vs Defense 12 - HIT!
Damage: 8 + 2 = 10, reduced by 2 armor = 8 damage
Goblin Scout takes 8 damage! (12/20 HP remaining)
> defend
You raise your guard, preparing for incoming attacks.
Defense increased by 50% until your next turn.
[Your turn ends]
> flee
You attempt to escape from combat...
Flee roll: 47 vs 54% chance - SUCCESS!
You escape from combat!
[You are removed from the fight]
Or on failure:
> flee
You attempt to escape from combat...
Flee roll: 62 vs 54% chance - FAILED!
The enemies block your escape! You lose your turn.
> status
═══════════════════════════════════════════════════
COMBAT STATUS - Round 3
═══════════════════════════════════════════════════
YOUR PARTY:
► Alice (YOU) ████████░░ 42/50 HP
Bob ███░░░░░░░ 15/50 HP
ENEMIES:
Goblin Scout ██████░░░░ 12/20 HP
Goblin Warrior ████████░░ 35/45 HP
TURN ORDER:
1. Alice (12) ← CURRENT TURN [45s remaining]
2. Goblin Warrior (10)
3. Bob (9)
4. Goblin Scout (6)
ACTIONS: attack | defend | item | flee | status
═══════════════════════════════════════════════════
- Combat trigger: Check
EnemyTrait.AggroOnSighton room entry - Aggro radius: NPC update loop checks
AggroRadiusfor nearby players - Combat stats: Use
EnemyTrait.AttackPower,Defense - Flee behavior: Check
EnemyTrait.FleeThreshold - Call for help: If
EnemyTrait.CallForHelp, pull nearby enemies - Scripts: Execute
OnAggroScript,OnDeathScript
- Weapon damage: Read from
EquippedItems[MainHand].Attributes["damage"] - Armor defense: Sum defense from all equipped armor pieces
- Consumables:
itemcommand uses items during combat - Loot drops: Use existing loot table system on victory
- HP tracking: Use
Character.CurrentHitPoints,MaxHitPoints - Attributes: Use STR, DEX, CON for modifiers
- Death handling: Set HP, handle respawn location
- Gold management: Deduct gold on death
- Combat in room: Players and NPCs remain "in" the origin room
- Loot placement: Items dropped to room's
Itemsarray - Room visibility: Other players see "X is in combat" status
- Bind points: Rooms with
CanBind: trueallow/bindfor respawn
When combat is initiated, all players currently in the room may be pulled into combat:
- Aggressive NPC attacks: All players in room are targeted
- Player attacks NPC: Only the attacking player enters combat initially
- Other players in room: Can choose to
attackthe same NPC to join the fight - Join window: Players can only join within Round 1 of combat
This allows cooperative play without requiring a formal party invite system. Party system (invite, leave, party chat, shared XP settings) is a future enhancement.
New Lua functions:
-- Combat queries
tales.combat.isInCombat(characterId)
tales.combat.getCombatInstance(characterId)
tales.combat.getCombatants(instanceId)
-- Combat manipulation (for scripts)
tales.combat.dealDamage(instanceId, targetId, amount)
tales.combat.healTarget(instanceId, targetId, amount)
tales.combat.addCombatant(instanceId, npcId)
tales.combat.endCombat(instanceId, result) -- "victory", "defeat", "draw"
-- Events
-- combat.start: {instance, players, enemies, room}
-- combat.turn.start: {instance, combatant, round}
-- combat.turn.end: {instance, combatant, action, result}
-- combat.damage: {instance, attacker, target, damage}
-- combat.death: {instance, victim, killer}
-- combat.end: {instance, result, survivors, loot}Scope: ~15 files
Note: Phase 1 supports melee weapons only. Ranged weapons (bows) and spells are added in later phases.
-
Combat Instance Model
- Create
pkg/entities/combat/instance.go - Define all combat types and structs
- Create in-memory combat instance manager
- Create
-
Combat Service
- Create
pkg/service/combat.go - Instance lifecycle (create, update, destroy)
- Turn management logic
- Combat state machine
- Create
-
Initiative System
- Roll initiative on combat start
- Sort turn order
- Track current turn
-
Basic Melee Attack Command
- Implement
attackcommand for combat initiation - Implement
attackfor in-combat targeting - Melee damage calculation (STR-based)
- Unarmed combat fallback (1 base damage)
- Implement
Scope: ~8 files
-
Damage Calculation
- Weapon damage extraction
- Armor reduction
- Critical hits
- Attribute modifiers
-
HP Management
- Track damage in combat instance
- Sync to Character/NPC on combat end
- Death detection
-
Victory/Defeat Handling
- Victory: Loot distribution, XP rewards
- Defeat: Gold loss, respawn
- Combat instance cleanup
-
Turn Timer
- 60-second turn timeout
- Auto-defend on timeout
- AFK detection
Scope: ~6 files
-
Defend Command
- Defense bonus application
- Bonus clearing on next turn
-
Flee Command
- Flee chance calculation
- Success/failure handling
- Combat exit logic
-
Item Command (Basic)
- Use consumable items
- Health potion support
- Inventory integration
-
Status Command
- Combat status display
- Turn order visualization
- HP bars
Scope: ~5 files
-
Multi-Enemy Encounters
- Multiple NPCs in combat
- Target selection (
attack goblin 2orattack [2]) - Aggro grouping (CallForHelp)
-
Multi-Player Combat
- Multiple players in same combat instance
- Players in room when combat starts are included
- Turn order with multiple players
- Note: Formal party system (invite, party chat) is a separate feature
-
Loot/XP Distribution
- Split rewards among living players at victory
- Dead player exclusion (0 XP/gold if dead at end)
- Room loot drops (free-for-all pickup)
Scope: ~3 files
-
AI Decision Engine
- Priority-based action selection
- Target selection logic
- Flee threshold behavior
-
Combat Styles
- Different behaviors for melee/ranged/magic
- Aggro management (future)
Scope: ~4 files
-
AggroOnSight
- Room entry trigger
- Auto-combat initiation
-
Aggro Radius
- NPC update loop integration
- Proximity detection
- Movement toward player
-
Attack Command (Non-Combat)
- Initiate combat from world
- Validate target is enemy
Scope: ~4 files
-
Combat Persistence
- Store active combat instances
- Restore on player reconnect
- Handle server restart (optional)
-
Combat Log
- Detailed action logging
- Log command implementation
-
Lua Integration
- Combat events
- Scripting functions
- Combat instance continues (NPCs still act)
- Player's turn is auto-defended
- After 3 auto-defends, player auto-flees
- On reconnect, player rejoins instance if still active
- Combat instances are in-memory only (MVP)
- On restart, all combat ends:
- Players return to origin room
- NPCs reset to pre-combat state
- No loot distributed
- Future: Persist combat state to database
- Cannot attack NPC without EnemyTrait
- Cannot attack NPC already in different combat
- Cannot attack player (PvP not in scope)
- Clear error messages for each case
- If all players flee, combat ends with "fled" state
- If all enemies somehow die outside combat, check and end
- Validate at least 1 player and 1 enemy before starting
- Combat has 30-minute global timeout
- If reached, combat ends in "timeout" state
- All participants returned to normal state
- NPCs reset, no loot/XP distributed
- Non-combat commands rejected during combat (most)
- Exception:
say,party,who,quit - Clear message: "You're in combat! Available actions: attack, defend, item, flee"
═══════════════════════════════════════════════════
COMBAT INITIATED!
═══════════════════════════════════════════════════
A Goblin Scout attacks you!
YOUR PARTY:
Alice (50/50 HP)
ENEMIES:
Goblin Scout (20/20 HP)
Rolling initiative...
Alice: 14
Goblin Scout: 8
Turn order: Alice → Goblin Scout
═══════════════════════════════════════════════════
It's your turn! What do you do?
Actions: attack | defend | item | flee | status
═══════════════════════════════════════════════════
───────────────────────────────────────────────────
Your turn! (Round 2) [55s remaining]
HP: 35/50 | Enemies: Goblin Scout (8/20 HP)
───────────────────────────────────────────────────
>
═══════════════════════════════════════════════════
VICTORY!
═══════════════════════════════════════════════════
You defeated: Goblin Scout
REWARDS:
Experience: 25 XP
Gold: 12 gold pieces
LOOT DROPPED:
- Rusty Dagger
- Minor Health Potion
The items have been dropped on the ground.
Use 'pickup <item>' to collect them.
═══════════════════════════════════════════════════
═══════════════════════════════════════════════════
DEFEAT
═══════════════════════════════════════════════════
You have been slain by Goblin Scout.
PENALTY:
Gold lost: 15 gold pieces (10%)
You awaken at the Town Square with 25/50 HP.
═══════════════════════════════════════════════════
- Players can initiate combat with
attack <npc>command - Aggressive NPCs auto-initiate combat on player room entry
- Combat follows turn-based order based on initiative
- Players can attack (melee), defend, use items, and flee
- NPCs execute basic AI combat actions
- Combat ends when all enemies or all players are defeated
- Victory grants XP, gold, and loot drops
- Defeat causes gold loss and respawn at bound location
- Players can
/bindat designated rooms (inns, temples) - Multiple enemies can be fought simultaneously
- Multiple players can join the same combat
- Players return to combat on reconnect
- 60-second turn timer enforced
- Combat status visible to participants
- Ranged weapons (bows) with DEX-based attacks
- Spell system with mana
- Formal party system
- Lua scripting for combat events
- Ranged Weapons (Bows) - DEX-based attacks, ammo system
- Spell System - Magic attacks with mana costs, spell slots
- Party System - Formal party invite/join, party chat, shared XP options
- Status Effects - Poison, stun, bleed, buffs
- PvP Combat - Player vs player duels
- Boss Mechanics - Special abilities, phases
- Combat Formations - Front/back row positioning
- Aggro/Threat System - Tank mechanics
- Need/Greed Loot - Loot rolling system
- Combat Achievements - Kill tracking, titles
- Arena System - Structured PvP/PvE challenges
- Combo System - Chained attacks for bonus damage
1. Alice types: attack goblin
2. System finds Goblin Scout in room with EnemyTrait
3. Combat instance created:
- ID: "combat-abc123"
- OriginRoomID: "forest-clearing-01"
- Players: [Alice]
- Enemies: [Goblin Scout]
4. Initiative rolled:
- Alice: 1d20(12) + DEX mod(+2) = 14
- Goblin: 1d20(6) + 2 = 8
5. Turn order: Alice (14) → Goblin (8)
6. Round 1, Turn 1 (Alice):
- Alice types: attack goblin
- Hit roll: 1d20(15) + STR(+2) = 17 vs Defense(12) = HIT
- Damage: Sword(6) + STR(+2) = 8 - Armor(2) = 6 damage
- Goblin HP: 20 → 14
7. Round 1, Turn 2 (Goblin):
- AI checks: HP(14) > FleeThreshold(20%) = true, won't flee
- AI attacks Alice
- Hit roll: 1d20(11) + 3 = 14 vs Defense(14) = HIT
- Damage: 5 - Armor(3) = 2 damage
- Alice HP: 50 → 48
8. Round 2, Turn 1 (Alice):
- Alice types: attack goblin
- Critical hit! Roll: 20
- Damage: (6 + 2) * 2 = 16 - 2 = 14 damage
- Goblin HP: 14 → 0
9. Goblin dies:
- Execute OnDeathScript (if any)
- Remove from turn order
- All enemies dead → VICTORY
10. Combat resolution:
- XP awarded: 25 to Alice
- Gold rolled: 8 gold to Alice
- Loot rolled: Rusty Dagger dropped to room
- Combat instance destroyed
- Alice.InCombat = false
| File | Purpose |
|---|---|
pkg/entities/combat/instance.go |
Combat instance entity |
pkg/entities/combat/types.go |
Combat enums and types |
pkg/mudserver/game/combat/manager.go |
In-memory combat instance manager |
pkg/mudserver/game/combat/engine.go |
Combat logic engine |
pkg/mudserver/game/combat/ai.go |
NPC combat AI |
pkg/mudserver/game/commands/combat.go |
Combat commands |
pkg/service/combat.go |
Combat service layer |
| File | Changes |
|---|---|
pkg/entities/characters/character.go |
Add InCombat, CombatInstanceID, BoundRoomID |
pkg/entities/npcs/npc.go |
Add InCombat, CombatInstanceID |
pkg/entities/rooms/rooms.go |
Add CanBind property |
pkg/mudserver/game/game.go |
Add combat manager, combat tick |
pkg/mudserver/game/commands/commandprocessor.go |
Combat command routing |
pkg/mudserver/game/commands/bind.go |
New bind command |
pkg/scripts/runner/lua/modules/combat.go |
New Lua module |
Document version 1.0 - Initial draft based on design session