Files
COC_API/docs/char_gen.md

7.7 KiB

🧩 Code of Conquest — Character Generation (Flask API)

Overview

This document describes how character generation operates inside the Flask API. The goal is to produce a fully realized Entity (hero, enemy, or NPC) based on race, profession, abilities, and level using YAML-defined data and procedural logic.


⚙️ Directory Overview

app/
├── blueprints/
│   ├── main.py          # Root routes
│   └── char.py          # Character creation and progression endpoints
│
├── game/
│   ├── generators/      # Procedural content
│   │   ├── abilities_factory.py   # Generates abilities / skills
│   │   ├── entity_factory.py      # Builds complete entity objects
│   │   ├── level_progression.py   # XP and level curve logic
│   │   └── ... (compiled files)
│   │
│   ├── loaders/         # YAML loaders for static templates
│   │   ├── profession_loader.py
│   │   ├── races_loader.py
│   │   └── spells_loader.py       # May be deprecated in favor of skills
│   │
│   ├── models/          # Dataclasses for core game objects
│   │   ├── abilities.py
│   │   ├── entities.py
│   │   ├── professions.py
│   │   ├── races.py
│   │   └── enemies.py
│   │
│   ├── systems/
│   │   └── leveling.py  # Handles XP gain, set_level, and skill growth
│   │
│   ├── templates/
│   │   ├── ability_paths.yaml     # Defines thematic skill sets (paths)
│   │   ├── professions/*.yaml     # Defines all professions
│   │   └── races/*.yaml           # Defines all playable races
│   │
│   └── utils/
│       └── common.py
│
├── models/              # Shared models for the Flask layer
│   ├── hero.py
│   ├── enums.py
│   └── primitives.py
│
└── utils/
    ├── catalogs/        # Compiled catalog data for fast lookups
    │   ├── race_catalog.py
    │   ├── hero_catalog.py
    │   └── skill_catalog.py
    ├── api_response.py
    └── settings.py

🧬 Entity Generation Pipeline

1. entity_factory.build_entity()

Creates a base entity by combining Race and Profession definitions.

Steps:

  1. Load race + profession data from YAML via loaders.
  2. Apply racial ability modifiers.
  3. Apply profession base stats and per-level growth rates.
  4. Initialize HP, MP, XP, and skill lists.

2. leveling.set_level(entity, target_level)

Handles level setting and skill gain.

  • Calculates XP using level_progression.py.
  • Calls calculate_skills_gained() (randomized 30% chance per level).
  • Generates new skills via abilities_factory.

🧝 Races

Located in app/game/templates/races/.

Each race defines:

  • Base ability modifiers (STR, DEX, CON, INT, WIS, CHA)
  • Optional descriptive text
  • Tags for gameplay classification

Example (elf.yaml):

name: Elf
description: Graceful and attuned to magic.
ability_mods:
  DEX: 2
  INT: 1
  CON: -1
tags: ["playable"]

⚔️ Professions

Located in app/game/templates/professions/.

Each profession file defines:

  • Base HP / MP
  • Scaling per level
  • Primary stat (INT, WIS, etc.)
  • Flavor / lore fields

Example (warlock.yaml):

id: warlock
name: Warlock
description: A wielder of forbidden demonic power.
primary_stat: CHA
base_hp: 40
base_mp: 80
physical_attack_per_level: 1.0
physical_defense_per_level: 0.5
magic_attack_per_level: 2.5
magic_defense_per_level: 1.5
tags: ["caster","dark"]

🧠 Ability / Skill Generation

Path Themes

Defined in templates/ability_paths.yaml:

Hellknight:
  elements: ["fire", "shadow"]
  adjectives: ["Infernal", "Hellfire", "Brimstone", "Abyssal"]
  nouns: ["Edict", "Judgment", "Brand", "Smite"]
  of_things: ["Dominion", "Torment", "Cinders", "Night"]

Generator Function

Located in abilities_factory.py:

def generate_spells_direct_damage(
    class_name: str,
    path: str,
    level: int,
    per_tier: int = 2,
    content_version: int = 1,
    primary: str = "INT"
) -> List[Spell]:
    ...

Features:

  • Deterministic random seed based on (class, path, level, version)
  • Generates direct-damage only
  • Scales power and cost by level
  • Names and effects are thematically consistent

Example Output

Infernal Judgment — Deal fire damage (power 120, CHA+125%). MP 30, CD 1
Brand of Cinders — Deal shadow damage (power 118, CHA+125%). MP 30, CD 0

📈 Level Progression

Handled in level_progression.py.

  • Defines XP thresholds per level (exponential curve)
  • Provides helper: get_xp_for_level(level)
  • Ensures entity.xp_to_next_level is always accurate after XP updates.

🎲 Skill Gain Logic

Implemented in systems/leveling.py.

def calculate_skills_gained(current_level, target_level, chance_per_level=0.3):
    levels_gained = max(0, target_level - current_level)
    if levels_gained == 0:
        return 0

    gained = sum(1 for _ in range(levels_gained) if random.random() < chance_per_level)
    if levels_gained < 3:
        gained = max(gained, 2)

    cap = math.ceil(levels_gained * 0.4)
    return min(gained, cap)
  • 30% random chance per level to gain a new skill
  • Guarantees ≥ 2 if leveling fewer than 3 levels
  • Caps maximum growth to 40% of total levels gained

🧮 XP / Level Curve Example

Level XP Needed (example) XP Delta Notes
1 0 Starting level
2 100 +100 Fast early growth
5 625 +175 Moderate
10 2500 +350 Midgame plateau
20 10000 +750 Late-game scaling

(Values may differ depending on level_progression.py formula)


⚙️ API Integration

Blueprint: char.py

Handles player-facing endpoints such as:

  • POST /char/create → build entity from race + profession
  • POST /char/level → level up existing entity and add new skills
  • GET /char/:id → return current character stats, XP, and skills

Example:

@char_bp.route("/create", methods=["POST"])
def create_character():
    data = request.json
    entity = build_entity(data["race"], data["profession"])
    return jsonify(entity.to_dict())

📁 Data Flow Summary

graph TD
    A[API Request] --> B[char.py Blueprint]
    B --> C[entity_factory.build_entity()]
    C --> D[races_loader / profession_loader]
    C --> E[level_progression]
    C --> F[abilities_factory]
    F --> G[ability_paths.yaml]
    C --> H[Entity Model]
    H --> I[API Response JSON]

🧾 Design Notes

  • All YAML templates are static assets — easy to edit without code changes.
  • Procedural factories (abilities_factory, entity_factory) ensure deterministic generation for the same input.
  • Systems (leveling.py) handle simulation and logic, isolated from API routes.
  • utils/catalogs may eventually cache or precompute available skills, professions, and races for faster response times.
  • The entire pipeline can operate statelessly inside Flask routes or persisted in a database later.

🔮 Future Ideas

  • Add passive traits per race or profession.
  • Implement rarity or tiered skills (common → legendary).
  • Generate enemy entities using the same system with difficulty scaling.
  • Add a training system or skill mastery mechanic tied to XP.
  • Create hero_catalog.py entries for pre-built templates used in story mode.