# FoundryVTT Les Héritiers System - Developer Instructions ## Executive Summary **Les Héritiers** is an unofficial FoundryVTT system for the French RPG "Les Héritiers" (published by Titam France/Sombres Projets). The system implements a complete actor and item management framework with support for characters (personnage), NPCs (pnj), and 13 item types. Recent development includes a migration to Foundry v13+ with DataModels and AppV2 architecture. **Repository**: https://www.uberwald.me/gitea/public/fvtt-les-heritiers **Current Version**: 13.0.7 **Compatibility**: Foundry 13+ **Language**: French (single language localization) --- ## 1. BUILD & DEVELOPMENT COMMANDS ### Build System - **Build Tool**: Gulp 4 with LESS compilation - **Package Manager**: npm ### Scripts (package.json) ```json "build": "gulp build" # Compile LESS to CSS (primary task) "watch": "gulp watch" # Watch LESS files and rebuild on changes ``` ### Gulp Pipeline (gulpfile.js) The gulpfile defines three main tasks: | Task | Source | Output | Features | |------|--------|--------|----------| | `styles` | `less/heritiers.less` | `styles/heritiers.css` | LESS→CSS compilation with source maps | | `watchFiles` | `less/**/*.less` | Watches recursively | Auto-rebuild on LESS file changes | | `build` | - | - | Runs `styles` (default export) | | `watch` | - | - | Runs `build` then `watchFiles` | **Development Workflow**: ```bash npm install # Install dependencies (gulp, gulp-less, gulp-sourcemaps) npm run build # One-time CSS compilation npm run watch # Development: continuous LESS watching ``` **Key Files**: - `/package.json` - Minimal deps (only gulp toolchain) - `/gulpfile.js` - 36 lines defining LESS tasks - `/less/heritiers.less` - Entry point (imports `simple-converted.less`) - `/styles/heritiers.css` - Generated output + source maps --- ## 2. SYSTEM ARCHITECTURE ### 2.1 System Metadata (system.json) | Field | Value | |-------|-------| | **id** | `fvtt-les-heritiers` | | **title** | Les Héritiers | | **version** | 13.0.7 | | **description** | Les Héritiers pour FoundryVTT (French) | | **authors** | Uberwald/LeRatierBretonnien, Prêtre | | **compatibility** | min: "13", verified: "13" | | **manifest** | Hosted on Uberwald Gitea | | **languages** | French only (fr.json) | | **license** | LICENCE.txt (proprietary) | | **grid** | 5m squares | **Key Configuration Flags**: - `hotReload.extensions`: `css`, `html`, `hbs`, `json` - `hotReload.paths`: `styles`, `./`, `templates`, `lang/fr.json` - `primaryTokenAttribute`: `sante.vigueur` (health/vigor) - `secondaryTokenAttribute`: `bonneaventure.actuelle` (current good fortune) - **Socket Support**: Enabled (`socket: true`) ### 2.2 Data Model (template.json.backup) The system defines a complex hierarchical data model with 2 Actor types and 14 Item types: #### **Actor Types** **1. `personnage` (Player Character)** - Templates: `biodata`, `core` - Key characteristics (8 attributes): - Physical: Agilité (agi), Constitution (con), Force (for), Précision (prec) - Mental: Esprit (esp), Perception (per), Prestance (pres), Sang-Froid (san) - Fields include biodata (name, appearance variants masked/unmasked, age, personality traits), ranks (Tricherie, Féerie, Masque, Héritage with scenario tracking), PV (health), combat skills - Profile-based competences (6 profiles + magic) **2. `pnj` (NPC)** - Templates: `biodata`, `core` - Identical structure to `personnage` with simpler NPC-specific metadata **Core Actor Data** (template.core): ``` caracteristiques: { agi, con, for, prec, esp, per, pres, san └─ label, labelnorm, abbrev, kind(physical|mental), value, rang, max } rang: { tricherie, feerie, masque, heritage (with scenarios subfield) } pv: { value, max, mod } competences: { aventurier, combattant, erudit, gentleman, roublard, savant } magie: { pointsame (value, max) } experience: { value, pourtricher } combat: { esquive, parade, resistancephysique, resistancepsychique, protection, effetssecondaires, dissimulation, initiative, corpsacorps, tir } ``` #### **Item Types** (14 total) | Item Type | Key Fields | Use Case | |-----------|-----------|----------| | `arme` (Weapon) | degats, precision, cadence, portee, dissimulation, armetype, rarete, prix | Combat equipment | | `protection` | points, malusagilite, protectiontype, effetsecondaire | Armor/shields | | `equipement` | rarete, quantite, prix | General gear | | `accessoire` | lieu (location code) | Small items | | `competence` | categorie, profil, niveau, specialites[], ismagie, nomniveau | Skills (6 profiles) | | `profil` | profiltype (majeur|mineur) | Character archetypes | | `contact` | contacttype (contact, allie, ennemi, interet) | NPC contacts | | `avantage` | description | Advantages (benefits) | | `desavantage` | description | Disadvantages (flaws) | | `capacitenaturelle` | pouvoirtype, activation, effet, portee, resistance, cibles, virulence | Natural abilities | | `pouvoir` | pouvoirtype, masquetype, niveau, istest, feeriemasque, carac, zoneffet, pointsusagecourant | Powers/spells | | `atoutfeerique` | description | Fairy/magical perks | | `fee` | feetype, avantages, desavantages, pouvoirsfeeriques*, atoutsfeeriques, competences, capacitenaturelles | Fairy character sheet | | `sort` (Spell) | niveau, rang, competence (Druidisme), carac1, carac2, duree, portee, ingredients, resistance | Magic spells | **Item Templates**: - `base`: description (HTMLField) - `basequip`: rarete, quantite, prix, equipped (for equipable items) ### 2.3 Directory Structure ``` modules/ # ES6 source code (12,273 LOC total) ├── heritiers-main.js # Entry point: init, hook setup, document class config ├── heritiers-actor.js # HeritiersActor class with creation hooks ├── heritiers-item.js # HeritiersItem class ├── heritiers-config.js # HERITIERS_CONFIG object (enums, constants) ├── heritiers-commands.js # Chat command system ├── heritiers-utility.js # Static utility class (dice, rolls, templates, socket) ├── heritiers-combat.js # HeritiersCombat class ├── xregexp-all.js # RegExp library ├── models/ │ ├── index.mjs # Exports all DataModels │ ├── personnage.mjs # PersonnageDataModel (complex, 12K+ lines) │ ├── pnj.mjs # PnjDataModel │ ├── arme.mjs # ArmeDataModel (updated Jan 21) │ ├── competence.mjs # CompetenceDataModel (updated Jan 21) │ ├── capacitenaturelle.mjs # Natural ability model (updated Jan 21) │ ├── pouvoir.mjs # PouvoirDataModel (updated Jan 21) │ ├── protection.mjs # ProtectionDataModel (updated Jan 21) │ ├── [11 more models] # accessoire, atoutfeerique, avantage, contact, │ │ # desavantage, equipement, fee, profil, sort │ └── base-item.mjs # Base item template ├── applications/ │ ├── sheets/ │ │ ├── _module.mjs # Exports all sheet classes │ │ ├── base-actor-sheet.mjs # HeritiersActorSheet (HandlebarsApplicationMixin, AppV2) │ │ ├── base-item-sheet.mjs # HeritiersItemSheet base │ │ ├── personnage-sheet.mjs # Character sheet (specific) │ │ ├── pnj-sheet.mjs # NPC sheet (specific) │ │ └── [11 item sheets] # Type-specific sheets: arme, protection, competence, etc. │ └── heritiers-roll-dialog.mjs # Dialog for roll resolution ``` #### **Key Module Details**: **heritiers-main.js** (100+ lines): - Hooks.once("init") - Registers templates, combat, actor/item classes, DataModels - Registers AppV2 sheets for all actor and item types - Creates `game.system.lesheritiers` namespace with utilities, config, models, sheets - Socket message handling **heritiers-config.js**: - `HERITIERS_CONFIG` object with ~40 enum dictionaries: - `caracList`: 8 characteristics with labels - `competenceProfil`: 6 profiles (aventurier, roublard, combattant, erudit, savant, gentleman) + magic - `baseTestPouvoir`, `resistancePouvoir`, `typePouvoir` - `seuilsDifficulte`: 30-level difficulty scale (5=Enfantine to 30=Divine) - `attaqueCible`: target localization (body part damage tracking) - Game-specific constants **heritiers-utility.js** (60+ custom Handlebars helpers): - `rollDataStore`, `defenderStore` for roll tracking - Handlebars helpers: count, includes, upper, lower, upperFirst, notEmpty, mul, and, or, eq, isTest, etc. - `preloadHandlebarsTemplates()` - loads 27 template files - `chatListeners()` - click handlers for chat - `loadCompendium()` - loads packs dynamically - `onSocketMesssage()` - inter-client communication **heritiers-actor.js**: - Custom creation logic: auto-adds useful skills from compendium for personnage type - Extends Foundry Actor class **heritiers-item.js**: - Custom Item class with item-type-specific business logic ### 2.4 Templates Directory (27 Handlebars files) Organized by purpose: **Actor Sheets** (2 files): - `actor-sheet.hbs` - Personnage character sheet (complex form with tabs) - `actor-pnj-sheet.hbs` - NPC sheet (simplified) **Item Sheets** (14 files): - `item-[type]-sheet.hbs` for each item type - E.g., `item-arme-sheet.hbs`, `item-competence-sheet.hbs`, `item-sort-sheet.hbs` **Partials** (5 files): - `partial-actor-equipment.hbs` - Equipment list rendering - `partial-item-header.hbs` - Item sheet header (common) - `partial-item-nav.hbs` - Tabbed navigation - `partial-item-description.hbs` - Description editor - `partial-utile-skills.hbs` - Skill list filtering - `post-item.hbs` - Chat card for item description - `editor-notes-gm.hbs` - GM notes editor **Chat Results** (3 files): - `chat-generic-result.hbs` - Generic roll result - `chat-cc-result.hbs` - Close combat result - `chat-assommer-result.hbs` - Stun attack result **Dialogs** (1 file): - `roll-dialog-generic.hbs` - Roll dialog with modifiers **Design Notes**: - Heavy use of Handlebars conditionals ({{#if}}, {{#each}}) - Data-action attributes for action routing - Flexbox-based layout (`flexrow`, `flexcol` CSS classes) - Partial templates for reusability ### 2.5 Localization (lang/fr.json) **Minimal localization** - only 24 lines: ```json { "TYPES": { "Actor": { "personnage": "Personnage", "pnj": "PNJ" }, "Item": { "accessoire": "Accessoire", "arme": "Arme", [12 more item types...] } } } ``` **Localization Strategy**: - Labels hardcoded in code/templates in French - No string keys for UI text outside TYPES - Template labels defined in DataModel schema (initial values) - Seeded localization keys in heritiers-config.js (no i18n lookup) ### 2.6 Styles (less/ and styles/) **LESS Structure** (2 files): - `heritiers.less` (4 lines) - Entry point, imports converted template - `simple-converted.less` - Full stylesheet (converted from Bootstrap/template.css) **Output**: - Compiled to `/styles/heritiers.css` (referenced in system.json) - Source maps generated (`.map` files) **Styling Approach**: - Utility classes: `flexrow`, `flexcol`, `padd-right`, `status-small-label` - Color classes: `color-class-common`, etc. - Section classes: `background-sheet-header` - Responsive design via flexbox ### 2.7 Compendium Packs (packs/) 11 packs defined in system.json, stored as `.db` (LevelDB format): | Pack Name | Type | Label | Folder | Contents | |-----------|------|-------|--------|----------| | `competences` | Item | Compétences | Creation | Skills | | `avantages` | Item | Avantages | Creation | Advantages | | `desavantages` | Item | Désavantages | Creation | Disadvantages | | `capacites` | Item | Capacités Naturelles | Creation | Natural abilities | | `atouts-feeriques` | Item | Atouts Féériques | Creation | Fairy perks | | `magie-sorts` | Item | Sorts | Creation | Spells (5 spell schools) | | `archetypes-fees` | Item | Fées | Creation | Fairy archetypes | | `pouvoirs` | Item | Pouvoirs | Creation | Powers | | `profils` | Item | Profils | Creation | Character profiles | | `armes-et-protection` | Item | Armes et Protections | Equipment | Weapons & armor | | `scenes` | Scene | Scènes | Root | Sample scenes | | `journaux` | JournalEntry | Journaux | Root | Game journal entries | **Ownership Model** (PLAYER: OBSERVER, ASSISTANT: OWNER): - Players can observe (read) items in packs - Assistants have full control **Source Data** (`srcdata/`): - 5 JSON files for spell normalization: - `sort_druidisme.json`, `sort_faeomancie.json`, `sort_magieduclan.json`, `sort_necromancie.json`, `sort_theurgie.json` - `normalize.py` - Python script to transform spell data to compendium format --- ## 3. KEY CONVENTIONS ### 3.1 Module/Class Structure **Pattern**: ES6 Classes extending Foundry base classes - **Naming**: `Heritiers[Type]` (e.g., `HeritiersActor`, `HeritiersItem`, `HeritiersCombat`) - **Exports**: Named exports via `export class`/`export default` **Example (heritiers-actor.js)**: ```javascript export class HeritiersActor extends Actor { static async create(data, options) { ... } // Custom methods and hooks } ``` **Example (models/personnage.mjs)**: ```javascript export default class PersonnageDataModel extends foundry.abstract.TypeDataModel { static defineSchema() { const fields = foundry.data.fields; return { biodata: new fields.SchemaField({ ... }), // nested SchemaFields with detailed field definitions } } } ``` **Sheet Pattern (AppV2 - Foundry v13+)**: ```javascript const { HandlebarsApplicationMixin } = foundry.applications.api export default class HeritiersPersonnageSheet extends HandlebarsApplicationMixin( foundry.applications.sheets.ActorSheetV2 ) { static DEFAULT_OPTIONS = { classes: ["fvtt-les-heritiers", "sheet", "actor"], position: { width: 780, height: 840 }, form: { submitOnChange: true, closeOnSubmit: false }, actions: { editImage, toggleSheet, editItem, deleteItem, createItem, equipItem, rollCarac, ... } } // Static action handlers (#onEditImage, etc.) } ``` ### 3.2 Data Model Conventions **Field Types** (foundry.data.fields.*): - `StringField` - Text values, default initial values - `HTMLField` - Rich-text fields (description, notes, etc.) - `NumberField` - Integers (integer: true), floats - `BooleanField` - Boolean flags - `ArrayField` - Lists (with element type) - `SchemaField` - Nested objects **Naming Conventions**: - Snake_case for internal field names: `biodata`, `caracteristiques`, `pointsame` - Abbreviations for characteristics: `agi`, `con`, `for`, `prec`, `esp`, `per`, `pres`, `san` - French names for labels and UI: "Agilité", "Constitution", etc. **Special Fields**: - `labelnorm` - Normalized label for lookups (lowercase, no accents) - `kind` - Classification (physical, mental, magical) - `initial` - Default value in schema definition ### 3.3 Handlebars Template Conventions **File Naming**: - `actor-sheet.hbs` - Main sheet template (not item-specific) - `actor-[type]-sheet.hbs` - Type-specific actor sheet - `item-[type]-sheet.hbs` - Type-specific item sheet - `partial-[purpose].hbs` - Reusable component - `chat-[result-type].hbs` - Chat message template - `editor-[context].hbs` - Editor component **Data Binding**: - Actor data: `{{system.field.subfield}}`, `{{actor.name}}` - Item data: `{{system.field}}` - Loops: `{{#each system.array as |item key|}}` - Conditionals: `{{#if condition}}...{{/if}}` **Custom Helpers** (60+): - Comparison: `eq`, `ne`, `lt`, `gt` - Array: `includes`, `count`, `notEmpty` - String: `upper`, `lower`, `upperFirst` - Math: `mul`, `add`, `sub`, `and`, `or` - Game: `isTest` (checks test type) **CSS Classes**: - Layout: `flexrow`, `flexcol`, `item`, `item-list` - Styling: `status-small-label`, `color-class-common`, `background-sheet-header` - Action: `data-action="actionName"` for click routing ### 3.4 Localization Key Naming **Pattern**: `TYPES.Actor.[type]`, `TYPES.Item.[type]` Current localization (lang/fr.json): ```json "TYPES": { "Actor": { "personnage": "Personnage", "pnj": "PNJ" }, "Item": { "accessoire": "Accessoire", "arme": "Arme", "atoutfeerique": "Atout féerique", ... } } ``` **Strategy**: - **Type labels**: Centralized in TYPES - **Field labels**: Defined in DataModel schema as `initial` values - **Config labels**: In heritiers-config.js (caracList, competenceProfil, etc.) - **Template text**: Hardcoded in .hbs files (all French) **No i18n System**: System is French-only; no game.i18n lookups used in code ### 3.5 Dice & Roll System **Initiative Formula** (heritiers-config.js): ```javascript CONFIG.Combat.initiative = { formula: "1d10", decimals: 1 }; ``` **Roll Data Storage** (heritiers-utility.js): - `rollDataStore = {}` - Tracks active rolls by ID - `defenderStore = {}` - Tracks defenders for opposed rolls - Socket-based roll updates for multi-client scenarios **Bonus/Malus**: - Range: -6 to +6 (signed integers) - Generated as: `Array.from({ length: 7 }, (v, k) => toString(k - 6))` **Dice Mechanics**: - D8, D10, D12 support with face adjacency tables (unused in some contexts) - Example: `__facesAdjacentes` object maps die faces to adjacent faces ### 3.6 Socket Message Handling **Game Socket** (configured in system.json): - Enabled via `"socket": true` - Message channel: `"system.fvtt-les-heritiers"` **Message Flow** (heritiers-utility.js): ```javascript game.socket.on("system.fvtt-les-heritiers", data => { HeritiersUtility.onSocketMesssage(data) }) ``` Used for: - Inter-client roll notifications - Multiplayer combat updates ### 3.7 Recent Migration Notes (v13.0.7) **Latest Changes** (from git log): - Migrated from legacy v1 sheets to **AppV2** (HandlebarsApplicationMixin + ActorSheetV2) - Migrated to **DataModels** (foundry.abstract.TypeDataModel) - All sheets converted to `.mjs` (ES6 modules) - Specification & competence fixes (Jan 21) - Armor (protection) and weapon (arme) model refinements (Jan 21) **Key Commit**: `4722fdf - Migration vers DataModels et appv2` (major architecture update) --- ## 4. EXISTING AI & DEVELOPER CONFIGURATIONS ### No Pre-Existing Configs Found The following configuration files **do NOT exist** in the repository: - `.github/copilot-instructions.md` ❌ - `CLAUDE.md` ❌ - `.cursorrules` ❌ - `AGENTS.md` ❌ - `.windsurfrules` ❌ - `CONVENTIONS.md` ❌ - `CONTRIBUTING.md` ❌ Only **README.md** exists (29 lines): - Credits Titam France/Sombres Projets - Lists contributors: LeRatierBretonnien (dev), Prêtre (testing/data entry) - Notes official authorization - Links to books at titam-france.fr --- ## 5. DEVELOPMENT WORKFLOW ### 5.1 Setup ```bash cd /home/morr/work/foundryvtt/fvtt-les-heritiers npm install npm run watch ``` ### 5.2 File Organization When Adding Features | Purpose | Location | Pattern | |---------|----------|---------| | New item type logic | `modules/heritiers-item.js` | Extend HeritiersItem | | New item data model | `modules/models/[type].mjs` | Extend TypeDataModel | | New item sheet | `modules/applications/sheets/[type]-sheet.mjs` | Extend HeritiersItemSheet | | New item template | `templates/item-[type]-sheet.hbs` | Handlebars + data-action | | New actor type | `modules/models/[type].mjs` | Extend TypeDataModel | | New actor sheet | `modules/applications/sheets/[type]-sheet.mjs` | Extend HeritiersActorSheet | | New chat message | `templates/chat-[result]-result.hbs` | HTML template | | Style updates | `less/heritiers.less` or new import | LESS → npm run build | | New config constants | `modules/heritiers-config.js` | Add to HERITIERS_CONFIG | | Game mechanics | `modules/heritiers-utility.js` or -commands.js | Static utilities or commands | ### 5.3 Registration Steps for New Item Type 1. **Update template.json.backup** - Add schema definition 2. **Create DataModel** - `modules/models/[type].mjs` 3. **Update heritiers-config.js** - Add enums if needed 4. **Create Sheet** - `modules/applications/sheets/[type]-sheet.mjs` 5. **Create Template** - `templates/item-[type]-sheet.hbs` 6. **Update heritiers-main.js** - Register sheet class 7. **Add to models/index.mjs** - Export DataModel 8. **Add to applications/sheets/_module.mjs** - Export Sheet class 9. **Update localization** - Add type to lang/fr.json TYPES.Item 10. **Update system.json** - If exposing in UI ### 5.4 Debugging - Check browser console for JS errors - Use Chrome DevTools on http://localhost:30000 (Foundry dev port) - Hot reload enabled for: `.css`, `.html`, `.hbs`, `.json` files (from system.json flags) - Git history available via `git log` or `git show ` --- ## 6. KEY STATISTICS | Metric | Value | |--------|-------| | **System ID** | fvtt-les-heritiers | | **Version** | 13.0.7 | | **Total Source LOC** | 12,273 lines | | **Actor Types** | 2 (personnage, pnj) | | **Item Types** | 14 (arme, protection, competence, etc.) | | **Compendium Packs** | 11 | | **Template Files** | 27 (.hbs) | | **Module Files** | 28 (.js/.mjs) | | **Model Files** | 16 (DataModels) | | **Sheet Files** | 14 (+ 1 base) | | **LESS Files** | 2 | | **Localization Files** | 1 (fr.json, 24 lines) | | **Dev Dependencies** | 3 (gulp, gulp-less, gulp-sourcemaps) | | **Characteristics** | 8 (agi, con, for, prec, esp, per, pres, san) | | **Competence Profiles** | 6 + magic (aventurier, roublard, combattant, erudit, savant, gentleman) | | **Difficulty Scale** | 30 levels (-1 to 30) | | **Last Commit** | "Correction sur calcul du rang" (recent) | --- ## 7. EXTERNAL RESOURCES - **Official Publisher**: [Titam France / Sombres Projets](http://www.titam-france.fr) - **System Repository**: https://www.uberwald.me/gitea/public/fvtt-les-heritiers - **Foundry Documentation**: https://foundryvtt.com/articles/ - **Foundry v13 API**: DataModels, AppV2 sheets (major changes in this version) --- ## 8. RECOMMENDATIONS FOR DEVELOPERS 1. **Use AppV2 Sheet API** for all new sheets (do not use legacy v1) 2. **Define DataModels** for type data rather than inline templates 3. **Keep French localization** in code/templates (minimal i18n setup) 4. **Test with `npm run watch`** during development 5. **Use socket messages** for multiplayer features 6. **Follow naming conventions** (Heritiers[Type], snake_case for fields, French labels) 7. **Document dice mechanics** when adding new rolls 8. **Keep configuration constants** in heritiers-config.js 9. **Use Handlebars helpers** rather than inline logic in templates 10. **Register sheets in heritiers-main.js** and export from _module.mjs files