Phase 3 — Combat & Classes
Version: v0.3.0 Status: 🔲 Planned
Goal
Bring the dungeon to life with real-time, server-authoritative combat. Three classes fight enemies using melee and spells, each with a fixed starter ability. Combat feels responsive on the Miyoo through client-side prediction while the server stays fully authoritative.
Deliverable
A complete combat loop on real hardware: pick a class, fight enemies, use your starter ability, drink potions, see health bars and floating damage numbers — all feeling smooth over WiFi.
Planned
The Three Classes
All classes are solo-viable. Power differences are in playstyle, not raw strength.
| Class | Identity | Health | Starter Ability |
|---|---|---|---|
| Warrior | High health, strong melee | High | Second Wind — burst heal + brief damage reduction |
| Mage | Spell power, crowd control | Low | Arcane Restore — mana refill + small heal, short cast time |
| Rogue | High mobility, loot find bonus | Medium | Shadow Mend — heal-over-time while moving |
Starter abilities are permanent and never lost on death. Additional abilities come later (Phase 4) as Ability Tome loot drops.
Shared Crate Additions
New types added to shared/src/lib.rs — used by both server and client:
pub enum Class { Warrior, Mage, Rogue }
pub struct ClassStats {
pub max_health: f32,
pub max_mana: f32,
pub damage_multiplier: f32,
pub move_speed: f32,
}
pub enum Ability {
BasicAttack,
SecondWind, // Warrior
ArcaneRestore, // Mage
ShadowMend, // Rogue
}
pub struct EntityState {
pub id: u32,
pub x: f32, pub y: f32,
pub health: f32, pub max_health: f32,
pub class: Option<Class>,
}
WorldSnapshot (sent via UDP every tick) carries a Vec<EntityState> — players and enemies both.
Server: Combat Tick Loop
The server runs a 30Hz tick using a Tokio interval. Each tick:
- Process all pending player input packets
- Move enemies (AI)
- Run hit detection and damage calculation
- Apply class stat modifiers
- Broadcast compact
WorldSnapshotvia UDP
All damage math is server-side only. The client never calculates authoritative damage — it only renders what the server tells it.
Server: Enemy AI
Simple chase-and-attack loop:
- Move toward nearest player each tick
- Attack when within melee range
- Back off briefly after attacking (prevents stunlocking)
- Mage-type enemies: fire projectile, then reposition
Enemies are seeded into the dungeon at generation time and their state lives entirely on the server.
Client: Input & Hotbar
Button mapping for combat (Miyoo SDL2 scancodes):
| Button | Action |
|---|---|
A (SDLK_SPACE) |
Basic attack |
X (SDLK_LSHIFT) |
Starter ability |
R1 (SDLK_t) |
Use potion |
On button press: send PlayerInput packet via UDP immediately, then play local animation (prediction). Server confirms or corrects on next snapshot.
Client: Prediction & Reconciliation
- Movement and basic attack animations play instantly on button press
- Server sends authoritative
WorldSnapshotevery tick (~33ms) - If server position disagrees with predicted position, client smoothly corrects (lerp over 2–3 frames)
- Damage numbers only appear when confirmed by server snapshot — no prediction on damage
This keeps combat feeling console-responsive even over a home WiFi connection.
Client: Visual Feedback
- Health bars — thin SDL2 rectangles above each entity (green → red as health drops)
- Floating damage numbers — red for damage, green for heals, white for misses; drift upward and fade over ~0.8 seconds
- Attack animations — class-specific swing/cast frames from the 32×32 sprite sheets
- Projectiles — 16×16 sprite for Mage spells; moves client-side until server confirms hit
Potions
Basic consumable bought from Bargus Crowe (placeholder vendor, full hub comes in Phase 4).
- Instant health restore
- Limited carry count (e.g. 3 per run)
- Server validates use — no client-side healing authority
Deploy & Test Loop
# Server
cargo run -p server
# Miyoo build (replace 192.0.0.1 with your Miyoo's local IP)
cargo build -p client --target armv7-unknown-linux-musleabihf
scp target/armv7-unknown-linux-musleabihf/debug/client root@192.0.0.1:/tmp/rpg98_client
ssh root@192.0.0.1 "/tmp/rpg98_client"
Key things to test on hardware:
- Solo combat with each class (feel + FPS)
- 2-player WiFi session (check sync, rubber-banding)
- Starter ability timing and cooldowns
- FPS with 6+ enemies on screen
Completion Checklist (Planned)
- Three classes defined in shared crate with distinct base stats
- Server combat tick loop at 30Hz
- Basic melee attack (Warrior, Rogue) and projectile (Mage) working
- Starter ability implemented for each class with cooldown
- Simple chase-and-attack enemy AI
-
WorldSnapshotbroadcast via UDP each tick - Client prediction + reconciliation for movement
- Health bars on all entities
- Floating damage/heal numbers
- Attack animations per class
- Potions usable in-run
- 30+ FPS on Miyoo with multiple enemies
Actual
— Not yet started. To be filled in when Phase 3 is complete. —
What Was Built
Deviations & Discoveries
What Was Deferred
Completion Checklist (Actual)
- Three classes defined in shared crate with distinct base stats
- Server combat tick loop at 30Hz
- Basic melee attack (Warrior, Rogue) and projectile (Mage) working
- Starter ability implemented for each class with cooldown
- Simple chase-and-attack enemy AI
-
WorldSnapshotbroadcast via UDP each tick - Client prediction + reconciliation for movement
- Health bars on all entities
- Floating damage/heal numbers
- Attack animations per class
- Potions usable in-run
- 30+ FPS on Miyoo with multiple enemies
Previous: Phase 2 — World & Movement Next: Phase 4 — Loot, Extraction & Hub