Browse Source

Add documentation and fix data persistence race condition

- Create SKILLS.md with base skill reference documentation
- Update CLAUDE.md with comprehensive RPG system documentation
- Update README.md with game features and mechanics overview
- Fix race condition where auto-save could overwrite server data
- Add statsLoadedFromServer flag to prevent premature saves
- Move startAutoSave() to after server data loads
- Add save error notifications to user

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
master
HikeMap User 1 month ago
parent
commit
9a78adfa97
  1. 303
      CLAUDE.md
  2. 135
      README.md
  3. 288
      SKILLS.md
  4. 963
      index.html

303
CLAUDE.md

@ -4,55 +4,270 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Project Overview ## Project Overview
KML Track Editor is a single-page web application for viewing, editing, and navigating KML/GPS tracks on an interactive map. The entire application is contained in `index.html`.
HikeMap is a location-based RPG web application with trail/GPS track editing capabilities. Players walk in the real world to explore, battle monsters, and level up their characters. The frontend is a single-page application in `index.html` with a Node.js/Express backend in `server.js`.
## Development ## Development
To run locally, serve via HTTP (required for GPS geolocation API):
### Docker (Recommended)
```bash ```bash
python -m http.server 8000
docker-compose up -d
``` ```
Then open http://localhost:8000
Access at http://localhost:880
### Local Development
```bash
npm install
node server.js
```
Then open http://localhost:8080
## Architecture ## Architecture
### Single-File Application
Everything is in `index.html`:
- **Lines 1-325**: CSS styles
- **Lines 326-420**: HTML structure (map, controls sidebar, overlays)
- **Lines 421-end**: JavaScript application code
### Key Libraries (loaded from CDN)
- **Leaflet.js 1.9.4**: Map rendering and interaction
- **leaflet-rotate 0.2.8**: Map rotation for navigation mode
### Core State Variables (around line 457-514)
- `tracks[]`: All loaded track objects with `{id, name, coords, layer, color}`
- `selectedTracks[]`: Currently selected tracks for multi-selection operations
- `currentTool`: Active editing tool ('select', 'draw', 'reshape', 'smooth', 'delete')
- `navMode`: Whether in navigation mode vs edit mode
- `currentRoute`: Pathfinding result for navigation
### Major Feature Areas
**Track Editing**:
- Draw new tracks, reshape existing ones with rope physics, smooth brush tool
- Track snapping at endpoints (auto-splits target track at snap point)
- Multi-track selection and merge operations
- Undo system with 20-step history
**Navigation Mode**:
- Graph-based pathfinding using Dijkstra's algorithm across connected trails
- Trail intersections detected within 5 meters (`INTERSECTION_THRESHOLD`)
- Real-time route recalculation when user deviates >50m from path
- Map rotation to face direction of travel (uses `map.setBearing()`)
- Auto-center on GPS position (toggleable)
- Destination persistence in localStorage
**GPS Integration**:
- Uses `navigator.geolocation.watchPosition` with backup polling every 3 seconds
- Requires HTTPS or localhost to function
### File Loading
- Automatically loads `default.kml` on startup if present
- KML parsing via DOMParser extracting `<Placemark>` coordinates
### File Structure
| File | Purpose |
|------|---------|
| `index.html` | Frontend SPA (CSS, HTML, JavaScript) |
| `server.js` | Express API server, WebSocket handling |
| `database.js` | SQLite database layer (better-sqlite3) |
| `docker-compose.yml` | Container configuration |
| `hikemap.db` | SQLite database (auto-created) |
| `SKILLS.md` | Complete skills documentation |
### Key Libraries
- **Frontend**: Leaflet.js 1.9.4, leaflet-rotate 0.2.8
- **Backend**: Express, better-sqlite3, jsonwebtoken, ws (WebSocket)
---
## RPG System
### Core Concepts
**Character Creation**:
- Player chooses Race (Human, Elf, Dwarf, Halfling) and Class (Trail Runner)
- Race provides stat bonuses, Class determines skills and growth
**Stats**:
| Stat | Description |
|------|-------------|
| HP | Health points - reach 0 and you die |
| MP | Mana points - used for skills |
| ATK | Attack power |
| DEF | Defense (reduces damage taken) |
| Accuracy | Hit chance modifier |
| Dodge | Evasion chance |
**Home Base**:
- Set by player, 20-meter radius (`HOME_BASE_RADIUS`)
- 3x HP regeneration when at home
- Required to respawn after death
- Skill loadout can only be changed at home
### Combat System
**Monster Spawning**:
- Monsters spawn while walking (configurable distance)
- No spawns within home base radius
- Multiple monsters can accumulate (entourage)
**Combat Flow**:
1. Player taps monster to engage
2. Turn-based combat with skill selection
3. Hit/miss calculated per skill accuracy
4. XP awarded on victory
5. Death sends player to respawn state
**Damage Formula**:
```javascript
damage = (skillPower * playerATK / 100) - enemyDEF
hitChance = skillAccuracy + (attackerAccuracy - 90) - defenderDodge
```
### Skill System
**Skill Tiers**: Skills unlock at level milestones (2, 3, 4, 5, 6, 7)
**Skill Types**:
- `damage`: Deal damage to enemies
- `heal`: Restore HP
- `buff`: Temporary stat boosts (defense, accuracy)
- `utility`: Out-of-combat effects (MP regen boost)
- `status`: Apply effects like poison
**Loadout System**:
- On level-up: ALL offered skills unlock, player picks one to activate
- `unlockedSkills`: Everything learned
- `activeSkills`: Currently equipped (one per tier)
- Swap active skills at home base only
See `SKILLS.md` for complete skill reference.
### Classes
**Trail Runner** (currently the only class):
| Base Stat | Value | Per Level |
|-----------|-------|-----------|
| HP | 100 | +10 |
| MP | 50 | +5 |
| ATK | 12 | +2 |
| DEF | 8 | +1 |
| Accuracy | 90 | - |
| Dodge | 15 | - |
### Races
| Race | HP | MP | ATK | DEF |
|------|-----|-----|-----|-----|
| Human | +5 | +5 | +0 | +0 |
| Elf | -5 | +15 | +0 | -2 |
| Dwarf | +15 | -5 | +0 | +3 |
| Halfling | -5 | +0 | +2 | +5 |
### Monsters
**Current Monster Types**:
| Monster | Level Range | Notes |
|---------|-------------|-------|
| Moop | 1-5 | Basic enemy |
| Fancy Moop | 1-5 | Higher ATK |
| Fanciest Moop | 3-5 | Stronger variant |
| Sub Par Moop | 1-1 | Very weak, tutorial enemy |
*MOOP = Matter Out Of Place (litter-themed enemies)*
---
## Database Schema (database.js)
### Key Tables
**Users & Auth**:
- `users`: id, username, password_hash, is_admin, created_at
**RPG Stats**:
- `rpg_stats`: player_id, name, race, class, level, xp, hp, maxHp, mp, maxMp, atk, def, home_base_lat/lng, unlocked_skills, active_skills, is_dead, home_base_icon
**Skills**:
- `skills`: id, name, description, type, mp_cost, base_power, accuracy, hit_count, target, status_effect
- `class_skills`: Links skills to classes with unlock_level and choice_group
- `class_skill_names`: Class-specific skill renames
**Monsters**:
- `monster_types`: id, name, icon, base_hp/atk/def, xp_reward, level scaling, dialogues
**Buffs**:
- `player_buffs`: Active buffs with expiry times (e.g., Second Wind)
### Important Methods
```javascript
// database.js key methods
db.getRpgStats(userId) // Get player stats
db.saveRpgStats(userId, stats) // Save player stats
db.resetUserProgress(userId) // Admin: reset player
db.swapActiveSkill(userId, tier, newSkillId) // Swap loadout
```
---
## API Endpoints (server.js)
### Authentication
| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | `/api/auth/register` | Create account |
| POST | `/api/auth/login` | Login, returns JWT |
### RPG
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/user/has-character` | Check if character exists |
| POST | `/api/user/character` | Create character |
| GET | `/api/user/rpg-stats` | Get player stats |
| PUT | `/api/user/rpg-stats` | Save player stats |
| POST | `/api/user/swap-skill` | Swap active skill (at home) |
| POST | `/api/user/activate-buff` | Activate utility skill |
| GET | `/api/user/buffs` | Get active buffs |
### Game Data
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/skills` | All skills |
| GET | `/api/classes` | All classes with skills |
| GET | `/api/monster-types` | All monster types |
| GET | `/api/spawn-settings` | Monster spawn config |
### Admin
| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | `/api/admin/reset-progress/:userId` | Reset player |
| POST | `/api/admin/reset-homebase/:userId` | Clear home base |
| PUT | `/api/admin/spawn-settings` | Update spawn config |
---
## Frontend Structure (index.html)
### Line Ranges (approximate)
| Lines | Content |
|-------|---------|
| 1-3000 | CSS styles |
| 3000-3700 | HTML structure |
| 3700-4500 | Constants, state, skill definitions |
| 4500-10000 | Map, track editing, geocaches |
| 10000-11000 | Character creation, sheet |
| 11000-12000 | Stats management, saving |
| 12000-13500 | Combat system, monsters |
### Key State Variables
```javascript
playerStats // Player RPG data
combatState // Active combat info
monsterEntourage // Spawned monsters
statsLoadedFromServer // Prevents stale saves
pendingSkillChoice // Level-up skill selection
```
### Key Functions
```javascript
initializePlayerStats(username) // Load from server
savePlayerStats() // Save to server
showSkillChoiceModal(level) // Level-up skill pick
swapSkillFromHomebase(tier, id) // Change loadout
startCombat(monsters) // Begin combat
useSkill(skillId) // Execute skill in combat
```
---
## Data Persistence
**Server-Authoritative Model**:
1. On page load, fetch stats from server
2. `statsLoadedFromServer` flag prevents premature saves
3. Auto-save every 30 seconds after initial load
4. `beforeunload` uses `sendBeacon` for reliable final save
5. localStorage used as read-only backup
**Critical**: Never save to server until `statsLoadedFromServer = true`
---
## Common Tasks
### Adding a New Skill
1. Insert into `skills` table (database.js or admin panel)
2. Add to `class_skills` with unlock_level and choice_group
3. Optionally add class rename in `class_skill_names`
4. Add icon/calculate function in `SKILLS` constant if special behavior needed
### Adding a New Class
1. Insert into `classes` table
2. Create `class_skills` entries for skill progression
3. Add `class_skill_names` for thematic renames
4. Update `getClassIcon()` for display
### Adding a New Monster
1. Insert into `monster_types` via admin panel or database
2. Set level range, stats, dialogues
3. Optionally add to `monster_skills` for special abilities

135
README.md

@ -1,68 +1,137 @@
# HikeMap - KML Track Editor
# HikeMap - Location-Based RPG
A single-page web application for viewing, editing, and navigating KML/GPS tracks on an interactive map.
A location-based RPG web application where you walk in the real world to explore trails, battle monsters, and level up your character. Also includes GPS track editing tools for trail mapping.
## Features ## Features
### RPG System
**Character Creation**
- Choose from 4 races: Human, Elf, Dwarf, Halfling
- Select your class (Trail Runner with running-themed skills)
- Set your home base for respawning and skill management
**Combat**
- Turn-based battles against MOOP (Matter Out Of Place) monsters
- Skill-based combat with damage, healing, buffs, and multi-hit attacks
- Hit/miss mechanics based on accuracy and dodge stats
- XP rewards and leveling system
**Skills & Progression**
- Unlock new skills at levels 2, 3, 4, 5, 6, and 7
- Choose between two skills at each milestone (both unlock, one activates)
- Swap your active skill loadout at your home base
- Class-specific skill names (e.g., "Gel Pack" instead of "Heal")
**Home Base**
- Set anywhere on the map as your respawn point
- 3x HP regeneration when within 20 meters
- Required destination when defeated
- Skill loadout management location
### Track Editing ### Track Editing
- Draw new tracks directly on the map
- Draw new GPS tracks directly on the map
- Reshape existing tracks with rope physics simulation - Reshape existing tracks with rope physics simulation
- Smooth tracks with a brush tool - Smooth tracks with a brush tool
- Smart track snapping at endpoints with auto-splitting - Smart track snapping at endpoints with auto-splitting
- Multi-track selection and merge operations - Multi-track selection and merge operations
- 20-step undo/redo history - 20-step undo/redo history
- Import/export KML files
### Navigation Mode ### Navigation Mode
- Graph-based pathfinding using Dijkstra's algorithm - Graph-based pathfinding using Dijkstra's algorithm
- Automatic trail intersection detection (within 5 meters)
- Real-time route recalculation when deviating >50m from path
- Automatic trail intersection detection
- Real-time route recalculation when deviating from path
- Map rotation to face direction of travel - Map rotation to face direction of travel
- Auto-center on GPS position (toggleable)
- Persistent destination storage
### GPS Integration
- Real-time location tracking using device GPS
- Automatic position updates every 3 seconds
- Requires HTTPS or localhost for geolocation API
- Auto-center on GPS position
## Quick Start ## Quick Start
### Local Development
### Docker (Recommended)
```bash ```bash
# Serve via HTTP (required for GPS geolocation API)
python -m http.server 8000
docker-compose up -d
``` ```
Then open http://localhost:8000
Access at http://localhost:880
### Docker Deployment
### Local Development
```bash ```bash
# Build and run with Docker Compose
docker-compose up
npm install
node server.js
``` ```
Access at http://localhost:8080 Access at http://localhost:8080
## Game Mechanics
### Stats
| Stat | Description |
|------|-------------|
| HP | Health - reach 0 and you're defeated |
| MP | Mana - used for skills, regenerates while walking |
| ATK | Attack power |
| DEF | Reduces damage taken |
| Accuracy | Affects hit chance |
| Dodge | Chance to evade attacks |
### Trail Runner Skills
| Level | Skill Choice A | Skill Choice B |
|-------|---------------|----------------|
| 1 | Kick-ems! (basic) | - |
| 2 | Brand New Hokas (2x hit) | Gel Pack (heal) |
| 3 | Downhill Sprint (power) | Pace Yourself (defense) |
| 4 | Trail Blaze (AoE) | Quick Feet (accurate) |
| 5 | Second Wind (MP buff) | Trail Mix (quick heal) |
| 6 | Finish Line Sprint (3x hit) | Zone In (accuracy buff) |
| 7 | Ultra Marathon (full heal) | The Bonk (devastating) |
See [SKILLS.md](SKILLS.md) for complete skill details.
### Monsters
| Monster | Level Range | Description |
|---------|-------------|-------------|
| Sub Par Moop | 1 | Tutorial enemy |
| Moop | 1-5 | Standard enemy |
| Fancy Moop | 1-5 | Higher attack |
| Fanciest Moop | 3-5 | Stronger variant |
*MOOP = Matter Out Of Place (litter-themed enemies encouraging trail cleanup)*
## Technical Details ## Technical Details
### Architecture ### Architecture
- **Single-file application**: Everything contained in `index.html`
- **No build process required**: Pure HTML/CSS/JavaScript
- **CDN dependencies**: Leaflet.js 1.9.4, leaflet-rotate 0.2.8
- **Frontend**: Single-page app in `index.html`
- **Backend**: Node.js/Express server in `server.js`
- **Database**: SQLite via better-sqlite3 in `database.js`
- **Real-time**: WebSocket for live updates
### File Structure
The entire application is in `index.html`:
- Lines 1-325: CSS styles
- Lines 326-420: HTML structure
- Lines 421-end: JavaScript application code
### Dependencies
- Leaflet.js 1.9.4 (maps)
- leaflet-rotate 0.2.8 (navigation rotation)
- Express (API server)
- better-sqlite3 (database)
- jsonwebtoken (authentication)
- ws (WebSocket)
### Data Format
- Supports standard KML files with Placemark elements
- Automatically loads `default.kml` on startup if present
- Exports edited tracks back to KML format
### Data Storage
- User accounts with JWT authentication
- Server-authoritative game state
- LocalStorage as offline backup only
## Browser Requirements ## Browser Requirements
- Modern browser with ES6 support - Modern browser with ES6 support
- HTTPS connection or localhost for GPS features
- Location services permission for navigation mode
- HTTPS or localhost for GPS features
- Location services permission
## Documentation
- [SKILLS.md](SKILLS.md) - Complete skill reference
- [CLAUDE.md](CLAUDE.md) - Development guide
## License ## License
[Add your license information here] [Add your license information here]

288
SKILLS.md

@ -0,0 +1,288 @@
# HikeMap RPG - Skills Reference
This document contains base skill definitions for the HikeMap RPG system.
## Table of Contents
- [Skill Types](#skill-types)
- [Base Skills](#base-skills)
- [Skill Unlock Levels](#skill-unlock-levels)
- [Skill Loadout System](#skill-loadout-system)
- [Combat Formulas](#combat-formulas)
- [Database Schema](#database-schema)
---
## Skill Types
| Type | Description |
|------|-------------|
| `damage` | Deals damage to enemy/enemies |
| `heal` | Restores HP to self |
| `buff` | Applies a temporary stat boost |
| `status` | Applies a status effect (poison, etc.) |
| `utility` | Out-of-combat effects (MP regen, etc.) |
---
## Base Skills
### Basic Attack
| Property | Value |
|----------|-------|
| **ID** | `basic_attack` |
| **Type** | Damage |
| **MP Cost** | 0 |
| **Base Power** | 100% ATK |
| **Accuracy** | 95% |
| **Target** | Single enemy |
| **Description** | A basic physical attack |
### Double Attack
| Property | Value |
|----------|-------|
| **ID** | `double_attack` |
| **Type** | Damage |
| **MP Cost** | 5 |
| **Base Power** | 60% ATK |
| **Hits** | 2 |
| **Accuracy** | 85% |
| **Target** | Single enemy |
| **Description** | Strike twice in quick succession |
### Heal
| Property | Value |
|----------|-------|
| **ID** | `heal` |
| **Type** | Heal |
| **MP Cost** | 8 |
| **Base Power** | 50% of max HP |
| **Accuracy** | 100% |
| **Target** | Self |
| **Description** | Restore HP |
### Power Strike
| Property | Value |
|----------|-------|
| **ID** | `power_strike` |
| **Type** | Damage |
| **MP Cost** | 10 |
| **Base Power** | 180% ATK |
| **Accuracy** | 80% |
| **Target** | Single enemy |
| **Description** | A powerful blow with extra force |
### Defend
| Property | Value |
|----------|-------|
| **ID** | `defend` |
| **Type** | Buff |
| **MP Cost** | 3 |
| **Effect** | DEF +50% for 2 turns |
| **Accuracy** | 100% |
| **Target** | Self |
| **Description** | Raise defense temporarily |
### Whirlwind
| Property | Value |
|----------|-------|
| **ID** | `whirlwind` |
| **Type** | Damage |
| **MP Cost** | 12 |
| **Base Power** | 75% ATK |
| **Accuracy** | 85% |
| **Target** | All enemies |
| **Description** | A spinning attack that hits all enemies |
### Quick Strike
| Property | Value |
|----------|-------|
| **ID** | `quick_strike` |
| **Type** | Damage |
| **MP Cost** | 4 |
| **Base Power** | 80% ATK |
| **Accuracy** | 98% |
| **Target** | Single enemy |
| **Description** | A fast attack with high accuracy |
### Focus
| Property | Value |
|----------|-------|
| **ID** | `focus` |
| **Type** | Buff |
| **MP Cost** | 6 |
| **Effect** | Accuracy +20% for 3 turns |
| **Accuracy** | 100% |
| **Target** | Self |
| **Description** | Concentrate to boost accuracy |
### Second Wind
| Property | Value |
|----------|-------|
| **ID** | `second_wind` |
| **Type** | Utility |
| **MP Cost** | 0 |
| **Effect** | 2x MP regen while walking for 1 hour |
| **Cooldown** | Once per day |
| **Target** | Self |
| **Description** | Double your MP regeneration while walking |
### Heavy Blow
| Property | Value |
|----------|-------|
| **ID** | `heavy_blow` |
| **Type** | Damage |
| **MP Cost** | 15 |
| **Base Power** | 250% ATK |
| **Accuracy** | 60% |
| **Target** | Single enemy |
| **Description** | A devastating attack that is hard to land |
### Quick Heal
| Property | Value |
|----------|-------|
| **ID** | `quick_heal` |
| **Type** | Heal |
| **MP Cost** | 4 |
| **Base Power** | 25% of max HP |
| **Accuracy** | 100% |
| **Target** | Self |
| **Description** | A small but efficient heal |
### Triple Strike
| Property | Value |
|----------|-------|
| **ID** | `triple_strike` |
| **Type** | Damage |
| **MP Cost** | 18 |
| **Base Power** | 50% ATK |
| **Hits** | 3 |
| **Accuracy** | 80% |
| **Target** | Single enemy |
| **Description** | Strike three times in rapid succession |
### Full Restore
| Property | Value |
|----------|-------|
| **ID** | `full_restore` |
| **Type** | Heal |
| **MP Cost** | 30 |
| **Base Power** | 100% of max HP |
| **Accuracy** | 100% |
| **Target** | Self |
| **Description** | Fully restore HP at great MP cost |
### Poison (Monster Only)
| Property | Value |
|----------|-------|
| **ID** | `poison` |
| **Type** | Status |
| **MP Cost** | 0 |
| **Effect** | 5 damage per turn for 3 turns |
| **Accuracy** | 75% |
| **Target** | Single enemy |
| **Player Usable** | No |
| **Description** | Inflict poison that deals damage over time |
---
## Skill Unlock Levels
Skills are unlocked at level milestones. Each level offers a choice between two skills:
| Player Level | Choice A | Choice B |
|--------------|----------|----------|
| 1 | Basic Attack | - |
| 2 | Double Attack | Heal |
| 3 | Power Strike | Defend |
| 4 | Whirlwind | Quick Strike |
| 5 | Second Wind | Quick Heal |
| 6 | Triple Strike | Focus |
| 7 | Full Restore | Heavy Blow |
---
## Skill Loadout System
### How It Works
1. **On Level-Up**: When reaching a skill unlock level, the player chooses one skill to make **active**. However, **all skills offered at that level are unlocked**.
2. **Active vs Unlocked**:
- `unlockedSkills`: All skills the player has learned
- `activeSkills`: Skills currently equipped for combat (one per tier)
3. **Swapping Skills**: At home base, players can swap which skill is active for each tier.
4. **Combat**: Only skills in `activeSkills` appear in the combat skill menu.
### Skill Tiers
| Tier | Level | Skills |
|------|-------|--------|
| 0 | 1 | Basic Attack (always active) |
| 1 | 2 | Double Attack, Heal |
| 2 | 3 | Power Strike, Defend |
| 3 | 4 | Whirlwind, Quick Strike |
| 4 | 5 | Second Wind, Quick Heal |
| 5 | 6 | Triple Strike, Focus |
| 6 | 7 | Full Restore, Heavy Blow |
**Note**: Utility skills (like Second Wind) don't appear in combat loadout - they are activated from the character sheet.
---
## Combat Formulas
### Damage Calculation
```
finalDamage = (skillPower * playerATK / 100) - enemyDEF
```
### Hit Chance
```
hitChance = skillAccuracy + (attackerAccuracy - 90) - defenderDodge
```
- Clamped between 5% and 99%
### Defense Buff
When Defend is active:
```
effectiveDEF = baseDEF * 1.5
```
---
## Database Schema
### skills table
| Column | Type | Description |
|--------|------|-------------|
| id | TEXT | Skill identifier (primary key) |
| name | TEXT | Display name |
| description | TEXT | Skill description |
| type | TEXT | damage/heal/buff/status/utility |
| mp_cost | INTEGER | MP required to use |
| base_power | INTEGER | Base power percentage |
| accuracy | INTEGER | Base accuracy (default 100) |
| hit_count | INTEGER | Number of hits (default 1) |
| target | TEXT | enemy/self/all_enemies |
| status_effect | TEXT | JSON for status effects |
| player_usable | BOOLEAN | Can players use this? |
| monster_usable | BOOLEAN | Can monsters use this? |
| enabled | BOOLEAN | Is skill active in game? |
### class_skills table
| Column | Type | Description |
|--------|------|-------------|
| class_id | TEXT | Class ID |
| skill_id | TEXT | Base skill ID |
| unlock_level | INTEGER | Level when skill becomes available |
| choice_group | INTEGER | Skills with same group are offered together |
### class_skill_names table
| Column | Type | Description |
|--------|------|-------------|
| skill_id | TEXT | Base skill ID |
| class_id | TEXT | Class ID |
| custom_name | TEXT | Class-specific name |
| custom_description | TEXT | Class-specific description |

963
index.html
File diff suppressed because it is too large
View File

Loading…
Cancel
Save