5cf42a5e5d
Frontend: - HTML5 Canvas isometric tilemap renderer - Eichenhafen starting city (procedural) - Click-to-move A* pathfinding - Player stats, HP/SP/EXP bars, skill bar, minimap - 3 NPCs (merchant, class master, innkeeper) - 6 monster spawns with aggro AI - Combat: auto-attack, damage numbers, EXP/gold - Player death + respawn Backend: - FastAPI server with SQLite - Ollama LLM bridge for events + dialogue - Event validation (no soft-lock) - NPC dialogue generation Design: - Full DESIGN.md with architecture, formulas, milestones - 6 base classes + 6 advanced classes - 3 fixed cities, dynamic events
260 lines
7.5 KiB
Markdown
260 lines
7.5 KiB
Markdown
# Aether Chronicles — Design Document
|
|
|
|
## 1. Architecture
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────┐
|
|
│ Browser (JS) │
|
|
│ ┌─────────────┐ ┌──────────┐ ┌─────────────┐ │
|
|
│ │ Renderer │ │ Input │ │ UI Manager │ │
|
|
│ │ (Canvas) │ │ Handler │ │ (DOM) │ │
|
|
│ └──────┬──────┘ └────┬─────┘ └──────┬──────┘ │
|
|
│ └───────────────┴───────────────┘ │
|
|
│ │ │
|
|
│ Game Client (JS) │
|
|
└────────────────────────┬─────────────────────────┘
|
|
│ REST + WebSocket
|
|
┌────────────────────────┴─────────────────────────┐
|
|
│ Python Backend (FastAPI) │
|
|
│ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
|
|
│ │ Game │ │ LLM │ │ World State │ │
|
|
│ │ Engine │ │ Bridge │ │ (SQLite) │ │
|
|
│ └────┬─────┘ └────┬─────┘ └───────┬───────┘ │
|
|
│ │ │ │ │
|
|
│ └─────────────┴─────────────────┘ │
|
|
│ │ │
|
|
│ ┌──────┴──────┐ │
|
|
│ │ Ollama │ │
|
|
│ │ (gemma4) │ │
|
|
│ └─────────────┘ │
|
|
└──────────────────────────────────────────────────┘
|
|
```
|
|
|
|
## 2. Game State (SQLite Schema)
|
|
|
|
```sql
|
|
-- Player
|
|
CREATE TABLE player (
|
|
id INTEGER PRIMARY KEY,
|
|
name TEXT,
|
|
class TEXT DEFAULT 'wanderer',
|
|
level INTEGER DEFAULT 1,
|
|
exp INTEGER DEFAULT 0,
|
|
hp INTEGER DEFAULT 100,
|
|
max_hp INTEGER DEFAULT 100,
|
|
sp INTEGER DEFAULT 50,
|
|
max_sp INTEGER DEFAULT 50,
|
|
str INTEGER DEFAULT 10,
|
|
agi INTEGER DEFAULT 10,
|
|
int INTEGER DEFAULT 10,
|
|
vit INTEGER DEFAULT 10,
|
|
dex INTEGER DEFAULT 10,
|
|
luk INTEGER DEFAULT 5,
|
|
x REAL DEFAULT 400,
|
|
y REAL DEFAULT 300,
|
|
map_id TEXT DEFAULT 'eichenhafen',
|
|
gold INTEGER DEFAULT 100
|
|
);
|
|
|
|
-- Inventory
|
|
CREATE TABLE inventory (
|
|
id INTEGER PRIMARY KEY,
|
|
player_id INTEGER,
|
|
item_id TEXT,
|
|
quantity INTEGER DEFAULT 1,
|
|
equipped INTEGER DEFAULT 0
|
|
);
|
|
|
|
-- World Events (LLM-generated)
|
|
CREATE TABLE world_events (
|
|
id INTEGER PRIMARY KEY,
|
|
map_id TEXT,
|
|
event_type TEXT,
|
|
description TEXT,
|
|
data_json TEXT,
|
|
active INTEGER DEFAULT 1,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- NPC Dialogues (LLM-generated, cached)
|
|
CREATE TABLE npc_dialogues (
|
|
id INTEGER PRIMARY KEY,
|
|
npc_id TEXT,
|
|
mood TEXT,
|
|
dialogue TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Quests
|
|
CREATE TABLE quests (
|
|
id INTEGER PRIMARY KEY,
|
|
quest_type TEXT,
|
|
name TEXT,
|
|
description TEXT,
|
|
npc_id TEXT,
|
|
map_id TEXT,
|
|
min_level INTEGER,
|
|
reward_gold INTEGER,
|
|
reward_exp INTEGER,
|
|
status TEXT DEFAULT 'available'
|
|
);
|
|
```
|
|
|
|
## 3. LLM Integration
|
|
|
|
### Prompt Templates
|
|
|
|
```python
|
|
# Event Generation
|
|
EVENT_PROMPT = """You are the Dungeon Master for Aether Chronicles.
|
|
Current map: {map_name}
|
|
Current time: {time_of_day}
|
|
Player level: {player_level}
|
|
Recent events: {recent_events}
|
|
|
|
Generate ONE optional event for this map. Rules:
|
|
- Must be optional (player can ignore it)
|
|
- Must not block any paths
|
|
- Must not move any NPCs
|
|
- Must not be required for progression
|
|
- Keep it short (2-3 sentences)
|
|
|
|
Respond in JSON:
|
|
{
|
|
"type": "weather|encounter|discovery|npc_mood",
|
|
"description": "...",
|
|
"effect": "buff|debuff|spawn|dialogue",
|
|
"data": { ... }
|
|
}
|
|
"""
|
|
|
|
# NPC Dialogue
|
|
DIALOGUE_PROMPT = """You are {npc_name}, a {npc_role} in {city_name}.
|
|
Your personality: {personality}
|
|
Current mood: {mood}
|
|
The player ({player_class}, level {player_level}) approaches you.
|
|
|
|
Say something in character (2-3 sentences). Be brief.
|
|
"""
|
|
```
|
|
|
|
### Validation Rules
|
|
|
|
```python
|
|
def validate_event(event: dict, map_id: str) -> bool:
|
|
# Never block paths
|
|
if event.get("effect") == "block_path": return False
|
|
# Never move NPCs
|
|
if event.get("effect") == "move_npc": return False
|
|
# Never required for main quest
|
|
if event.get("required") == True: return False
|
|
# Must be optional
|
|
if event.get("optional") == False: return False
|
|
return True
|
|
```
|
|
|
|
## 4. Map System
|
|
|
|
### Fixed Maps
|
|
```
|
|
eichenhafen — Starting city (harbor)
|
|
eichenhafen_field — Field outside starting city (main road)
|
|
sonnenfeld — Central trade city
|
|
sonnenfeld_field — Field outside trade city
|
|
nebelgipfel — Mountain fortress city
|
|
nebelgipfel_path — Mountain path (dangerous)
|
|
```
|
|
|
|
### Dynamic Maps (LLM-generated layouts)
|
|
```
|
|
side_dungeon_1 — Generated dungeon layout
|
|
side_dungeon_2 — Generated dungeon layout
|
|
cave_random — Generated cave layout
|
|
```
|
|
|
|
## 5. Combat Formulas
|
|
|
|
```python
|
|
# Physical damage
|
|
damage = (atk * (1 + str/100)) - (target_def * 0.5)
|
|
damage = max(1, damage) # minimum 1 damage
|
|
|
|
# Magic damage
|
|
magic_damage = (matk * (1 + int/100)) * element_multiplier
|
|
|
|
# Hit rate
|
|
hit_rate = min(95, 80 + (dex - target_agi) * 2)
|
|
|
|
# Critical rate
|
|
crit_rate = min(50, 5 + luk * 2)
|
|
|
|
# EXP needed for next level
|
|
exp_needed = int(100 * (level ** 1.5))
|
|
```
|
|
|
|
## 6. Milestone Details
|
|
|
|
### M1: Project Setup + Tilemap (1-2 hours)
|
|
- HTML5 Canvas setup
|
|
- Isometric tilemap renderer
|
|
- Tile loading from JSON
|
|
- Camera with mouse pan/zoom
|
|
- Basic tileset (grass, water, path, building)
|
|
|
|
### M2: Click-to-Move (1-2 hours)
|
|
- A* pathfinding implementation
|
|
- Click destination → character walks path
|
|
- Collision detection (walls, water)
|
|
- Smooth movement animation
|
|
|
|
### M3: Player Stats + UI (1-2 hours)
|
|
- HP/SP bars (DOM overlay)
|
|
- Skill bar (1-0 keys)
|
|
- Character info panel
|
|
- EXP bar
|
|
|
|
### M4: Combat (2-3 hours)
|
|
- Click enemy → auto-attack
|
|
- Damage numbers floating
|
|
- Death animation
|
|
- EXP gain on kill
|
|
- Aggro range for monsters
|
|
|
|
### M5: Monster AI (2-3 hours)
|
|
- Spawn system
|
|
- Patrol behavior
|
|
- Aggro + chase
|
|
- Respawn timer
|
|
- Drop table
|
|
|
|
### M6: City + NPCs (3-4 hours)
|
|
- Eichenhafen map layout
|
|
- NPC sprites + interaction
|
|
- Shop interface
|
|
- Storage interface
|
|
- Class master NPC
|
|
|
|
### M7: LLM Integration (3-4 hours)
|
|
- Ollama API bridge
|
|
- Event generation (periodic)
|
|
- NPC dialogue generation
|
|
- Event validation
|
|
- Caching to reduce LLM calls
|
|
|
|
### M8: Quest System (2-3 hours)
|
|
- Fixed main quests
|
|
- LLM side quests (validated)
|
|
- Quest log UI
|
|
- Turn-in mechanics
|
|
|
|
### M9: Inventory + Equipment (2-3 hours)
|
|
- Item system
|
|
- Equipment slots
|
|
- Stats from equipment
|
|
- Drop/pickup
|
|
|
|
### M10: Class System (3-4 hours)
|
|
- Class change at level 10
|
|
- Skill trees
|
|
- Skill effects in combat
|
|
- 2nd class at level 40 |