No description
  • Python 65.6%
  • Lua 34.4%
Find a file
McNieps 11bffd97b7 Broaden charge/potential rules, add clause display support, refine rune roster
Formalizes weapon-scoped potential and the output-toll default in
charge_system.md, adds programmatic clause display rendering with tests,
migrates the rune roster (Vigil/Thorn/Cleaver/Mender/Windfall/Spark/Siphon/
Herald/Ripple/Pyramid/Basher/Sentry) onto the updated conventions, and
archives superseded design docs in favor of rune_design_rationale.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-08 16:27:56 +02:00
.claude Broaden charge/potential rules, add clause display support, refine rune roster 2026-07-08 16:27:56 +02:00
battle Broaden charge/potential rules, add clause display support, refine rune roster 2026-07-08 16:27:56 +02:00
docs Broaden charge/potential rules, add clause display support, refine rune roster 2026-07-08 16:27:56 +02:00
scripts Broaden charge/potential rules, add clause display support, refine rune roster 2026-07-08 16:27:56 +02:00
world docs: add rune/weapon/event design rationale for playtest batch v1 2026-06-13 20:28:36 +02:00
.gitignore chore: layout graph positions, faction Lua helper, doc link fixes, sprite generator 2026-06-12 01:11:35 +02:00
CLAUDE.md Broaden charge/potential rules, add clause display support, refine rune roster 2026-07-08 16:27:56 +02:00
old_discussion_summary.txt docs: add charge system, rune design grid, playtest batch v1 drafts + new weapons 2026-06-26 20:41:30 +02:00
pyproject.toml feat: Lua engine integration — comparison script, profiler, serialization 2026-05-20 16:04:40 +02:00
README.md Broaden charge/potential rules, add clause display support, refine rune roster 2026-07-08 16:27:56 +02:00
uv.lock feat: Lua engine integration — comparison script, profiler, serialization 2026-05-20 16:04:40 +02:00

Data

Game content definitions. Pure data, no engine logic. Changes here affect balance and content without touching battle_engine, server, or world_generation.

Format

Python files instantiating models from battle/models/. One file per concept (rune name, weapon name), named by concept ID. Content files import exclusively from battle.models — never from battle_engine or battle/plugins/ directly.

A file may contain multiple tier variants as separate entry variables, listed in __all__ in ascending tier order:

# runes/patterns/pulse/the_bell.py
from battle.models import entries, Clause, triggers, effects, value_sources, query
from battle.models import Tier

the_bell_novice = entries.RuneEntry(
    id="the_bell_novice",
    tier=Tier.NOVICE,
    name="the Bell",
    index_status="listed",
    clauses=[
        Clause(
            trigger=triggers.OnAttackTrigger(),
            effects=[effects.DamageEffect(targets=query.ENEMY_TEAM, amount=value_sources.Flat(2))],
        ),
    ],
)

the_bell_journeyman = entries.RuneEntry(
    id="the_bell_journeyman",
    tier=Tier.JOURNEYMAN,
    name="the Bell",
    index_status="listed",
    previous_tier=the_bell_novice,
    clauses=[...],  # novice clause + journeyman addition
)

the_bell_novice.next_tier = the_bell_journeyman

__all__ = ["the_bell_novice", "the_bell_journeyman"]

Full IDE autocompletion. Pydantic validates on construction. No JSON schemas to maintain.

Structure

data/
  docs/              # Writing guide and content authoring references
  primitives/        # Engine wrappers and entry types (import source for all content)
  runes/
    patterns/        # RuneEntry definitions (effects, tier progression, Index status)
  weapons/           # WeaponEntry definitions (stats, charge config, rune slots)
  world/
    encounters/      # Events that happen on the map
    geography/       # Terrain types, biomes, movement costs
    topography/      # Layers, zones, landmarks
  scripts/           # Utility scripts (not definitions)

Entry Types

The primitives/ package provides entry types that wrap the engine's game-agnostic models:

Entry type Represents Key method
RuneEntry A rune at a specific tier to_engine_instance(faction)
WeaponEntry A weapon with rune slots to_engine_instance(faction)
TeamEntry A team with weapon slots to_engine_instance()
WorldEntry The battle root (two teams) to_engine_instance()

A battle is run as:

log = run_battle(world.to_engine_instance(), config)

Schema Ownership

Entry types in primitives/ are the data layer's own models — changes to them are data changes only. Changes to the underlying engine models (EntityDefinition, Clause, triggers, effects) require an engine change first.

Asset Mapping

Sprites live in client/assets/. The id field is the contract:

  • runes/patterns/blitz/monteil_press.py (id: monteil_press) → client/assets/runes/patterns/monteil_press.png

See Also

  • CLAUDE.md — full authoring reference: models, target constants, HP model, scope boundaries.
  • runes/README.md — rune system design, naming conventions, tier model.
  • weapons/README.md — weapon fields, slot graph authoring.
  • docs/charge_system.md — source of truth for charge, counters, production/toll, and loop-safety rules.
  • docs/rune_design_rationale.md — single source of truth for rune design: design axes, tier model, and the morphological design grid.
  • docs/writing_guide.md — description format and style rules for player-facing text.
  • battle_engine/docs/keywords.md — canonical token→display-text mappings.