Roadmap

RPG98 Roadmap Phase 3 — Combat & Classes

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:

  1. Process all pending player input packets
  2. Move enemies (AI)
  3. Run hit detection and damage calculation
  4. Apply class stat modifiers
  5. Broadcast compact WorldSnapshot via 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 WorldSnapshot every 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
  • WorldSnapshot broadcast 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
  • WorldSnapshot broadcast 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