Files
fvtt-les-heritiers/DEVELOPER_INSTRUCTIONS.md
LeRatierBretonnier 038aa37838
All checks were successful
Release Creation / build (release) Successful in 51s
Correction sur combat des PNJs
2026-03-16 23:04:21 +01:00

22 KiB

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)

"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:

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)
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:

{
  "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):

export class HeritiersActor extends Actor {
  static async create(data, options) { ... }
  // Custom methods and hooks
}

Example (models/personnage.mjs):

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+):

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):

"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):

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):

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

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 <commit>

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


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