diff --git a/CHANGELOG.md b/CHANGELOG.md index f5202c5..656d359 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,85 @@ -# CHANGELOG +# CHANGELOG - Vermine2047 System + +## 0.1.14 - 2026-06-04 + +### 🚀 NouveautĂ©s + +#### SystĂšme +- **Mise Ă  jour de la compatibilitĂ©**: Support officiel de FoundryVTT v14 (tout en maintenant la compatibilitĂ© v11-v12) +- **Nouvelle classe GroupLink**: Gestion complĂšte des liens bidirectionnels entre acteurs et groupes + - Synchronisation automatique des membres et rencontres + - Hooks pour la crĂ©ation, mise Ă  jour et suppression d'acteurs + - MĂ©thodes utilitaires pour gĂ©rer les relations + +#### Configuration +- **Domaines des totems**: Ajout de `CONFIG.VERMINE.totemDomains` avec les domaines d'influence pour chaque totem +- **Configurations Ă©tendues**: Ajout des configurations pour PNJ et crĂ©atures + - `npcThreatLevels`, `npcExperienceLevels`, `npcRoleLevels` + - `creaturePatternLevels`, `creatureSizeLevels`, `creatureRoleLevels`, `creaturePackLevels` + +#### Fiches +- **Fiche PNJ**: Remplacement des inputs numĂ©riques par des sĂ©lecteurs pour menace, expĂ©rience et rĂŽle +- **Fiche CrĂ©ature**: Remplacement des inputs numĂ©riques par des sĂ©lecteurs pour gabarit, taille, rĂŽle et meute +- **Ajout du champ encounters**: Les personnages peuvent maintenant appartenir Ă  des groupes + +#### Jets de dĂ©s +- **Redesign complet du RollDialog**: Interface plus compacte et organisĂ©e + - Utilisation de `
`/`` pour une meilleure organisation + - Affichage du total du pool de dĂ©s en temps rĂ©el + - SĂ©lecteur pour choisir quel totem garder (humain ou adaptĂ©) + - Affichage des bonus/malus par domaine de totem + +- **Bonus/malus par domaine**: ImplĂ©mentation des bonus de totem basĂ©s sur le domaine de prĂ©dilection + - Bonus: +1 dĂ© si le domaine de prĂ©dilection est dans les domaines du totem + - Malus: -1 dĂ© si le domaine de prĂ©dilection est dans les domaines du totem opposĂ© + +- **RĂ©ussites automatiques**: ImplĂ©mentation des rĂ©ussites automatiques basĂ©es sur le niveau de maĂźtrise + - Niveau 2 + spĂ©cialitĂ©: +1 rĂ©ussite automatique + - Niveau 3: +1 rĂ©ussite automatique + - Niveau 4 + spĂ©cialitĂ©: +2 rĂ©ussites automatiques + - Niveau 5: +2 rĂ©ussites automatiques + +- **Seuils automatiques**: ImplĂ©mentation des seuils automatiques pour les compĂ©tences non maĂźtrisĂ©es + - Niveau 0 (IncompĂ©tent): seuil = 9 + - Niveau 1 (DĂ©butant): seuil = 7 + - Niveau >= 2: utilise la difficultĂ© spĂ©cifiĂ©e + +#### Items +- **Correction des templates de chat cards**: Tous les templates sont maintenant en `.hbs` +- **Chat cards amĂ©liorĂ©es**: Affichage plus complet des informations pour chaque type d'item + - Armes: dĂ©gĂąts, type, portĂ©e, munitions + - Protections: niveau, mobilitĂ©, bouclier + - CapacitĂ©s: type, totem, niveau, effets + - etc. + +#### Traductions +- Ajout de nombreuses nouvelles traductions pour les nouvelles fonctionnalitĂ©s +- Correction des traductions existantes + +#### Documentation +- **Documentation technique complĂšte**: `docs/technical/ARCHITECTURE.md` + - Structure du projet + - Configuration du systĂšme + - Architecture des documents + - SystĂšme de dĂ©s + - SystĂšme de combat + - Gestion des groupes + - Bonnes pratiques de dĂ©veloppement + +### 🐛 Corrections + +- Correction des rĂ©fĂ©rences de templates (`.html` → `.hbs`) +- Correction des erreurs dans les templates de chat cards +- AmĂ©lioration de la gestion des totems dans les rolls +- Nettoyage du code et suppression des logs de dĂ©bogage + +### 📝 Modifications mineures + +- Mise Ă  jour des mĂ©tadonnĂ©es du systĂšme dans `system.json` +- Ajout du champ `encounters` au template des personnages +- AmĂ©lioration des helpers Handlebars avec de nouveaux helpers pour les configurations PNJ/CrĂ©ature + +--- ## 0.1.13 - ajout des historiques @@ -36,4 +117,25 @@ ## 0.1.5 - dĂ©but de mise en forme des feuilles crĂ©ature et pnj -- possibilitĂ© de changer le type de capacitĂ© (pour ajouter des capacitĂ©s de totem) \ No newline at end of file +- possibilitĂ© de changer le type de capacitĂ© (pour ajouter des capacitĂ©s de totem) + +--- + +## Notes de migration + +### Pour les utilisateurs + +1. **CompatibilitĂ©**: Le systĂšme est maintenant compatible avec FoundryVTT v14 +2. **Nouveaux champs**: Les personnages ont maintenant un champ `encounters` pour gĂ©rer leurs groupes +3. **RollDialog**: L'interface du dialogue de jet a Ă©tĂ© complĂštement redessinĂ©e pour ĂȘtre plus intuitive +4. **Bonus de totem**: Les bonus de domaine sont maintenant automatiquement appliquĂ©s + +### Pour les dĂ©veloppeurs + +1. **GroupLink**: Utilisez la classe GroupLink pour gĂ©rer les relations entre acteurs et groupes +2. **Nouveaux helpers**: De nombreux nouveaux helpers Handlebars ont Ă©tĂ© ajoutĂ©s pour les configurations PNJ/CrĂ©ature +3. **CONFIG.VERMINE**: De nombreuses nouvelles configurations ont Ă©tĂ© ajoutĂ©es + +--- + +*GĂ©nĂ©rĂ© le 2026-06-04* diff --git a/README.md b/README.md index c79ad06..f0e5ea5 100644 --- a/README.md +++ b/README.md @@ -10,23 +10,23 @@ - [X] dialog d'edition des min-max ### fiche de groupe -- [ ] pas encore penchĂ© dessus +- [X] pas encore penchĂ© dessus #### Members et encounters - - [ ] faire une classe GroupLink pour avoir les actors en objets dans les array group.members[], group.encounters[], et character.encounters[], - - [ ] faire une fonction sur le Hook.onUpdateActor => update des groupes dans characters, update des encounters et members dans groups + - [X] faire une classe GroupLink pour avoir les actors en objets dans les array group.members[], group.encounters[], et character.encounters[], + - [X] faire une fonction sur le Hook.onUpdateActor => update des groupes dans characters, update des encounters et members dans groups ### fiche de pnj crĂ©ature -- [ ] Ă  faire, -- [ ] lister les gabarit/taille/roles(creatures) et menace/experience/role(pnj)... stocker les modifs dans CONFIG.VERMINE, +- [X] Ă  faire, +- [X] lister les gabarit/taille/roles(creatures) et menace/experience/role(pnj)... stocker les modifs dans CONFIG.VERMINE, ### les jets de dĂ©s -- [ ] redesign de rollDialog => `
+`=> rendre moins dense +- [X] redesign de rollDialog => `
+`=> rendre moins dense - [X] envoyer les spĂ©cialitĂ©s utilisables au rollDialog - [X] envoyer les items utilisables au rollDialog -- [ ] gĂ©rer le fait de choisir quel totem garder : recalcul des rĂ©ussites +- [X] gĂ©rer le fait de choisir quel totem garder : recalcul des rĂ©ussites - [X] refacto des template chat de roll - [X] gĂ©rer les dĂ©s de totems humains et adaptĂ© : couleur diffĂ©rente/double succĂšs +update actor - [X] gĂ©rer les rerolls depuis chat(cf noc) @@ -34,20 +34,20 @@ - [X] faire l'update l' l'actor juste aprĂšs s'etre accorder des rerolls, et avoir utiliser le sang-froid - [X] update des reserves de sang-froids lors de jets - [X] ajout des domaines de prĂ©dilections -- [ ] gĂ©rer le dĂ©s en +/- selon l'influence du totem adaptĂ© ou humain selon les domaines -- [ ] gĂ©rer les rĂ©ussites auto -- [ ] gĂ©rer les seuils auto si compĂ©tence non maitrisĂ©e +- [X] gĂ©rer le dĂ©s en +/- selon l'influence du totem adaptĂ© ou humain selon les domaines +- [X] gĂ©rer les rĂ©ussites auto +- [X] gĂ©rer les seuils auto si compĂ©tence non maitrisĂ©e ### le combat - [X] modifier la difficultĂ© en fonction de l'Ă©tat du combatant /offensif/actif/passif/ ### les items -- [X]ajouter apprentissage aux abilities +- [X] ajouter apprentissage aux abilities - [X] passer le type d'arme en select/options - [X] ajouter handicap de raretĂ© - [X] ajouter pour items Item "competence nĂ©cessaire" -- [-] gĂ©rer les rolls d'items dans le chat +- [X] gĂ©rer les rolls d'items dans le chat - [X] repasser sur les diffĂ©rents itemTypes et sheets - [X] verifier le selector de traits (trait pratique cf : msg pretre) - [X] construire une selecteur de traits, traits= CONFIG.VERMINE.traits diff --git a/docs/technical/ARCHITECTURE.md b/docs/technical/ARCHITECTURE.md new file mode 100644 index 0000000..f3ce33a --- /dev/null +++ b/docs/technical/ARCHITECTURE.md @@ -0,0 +1,1054 @@ +# Vermine2047 System - Architecture Technique + +## Table des matiĂšres +1. [Introduction](#introduction) +2. [Structure du Projet](#structure-du-projet) +3. [Configuration du SystĂšme](#configuration-du-systĂšme) +4. [Documents](#documents) +5. [Fiches (Sheets)](#fiches-sheets) +6. [SystĂšme de DĂ©s](#systĂšme-de-dĂ©s) +7. [Combat](#combat) +8. [Gestion des Groupes](#gestion-des-groupes) +9. [Synchronisation](#synchronisation) +10. [Templates](#templates) +11. [Traductions](#traductions) + +--- + +## Introduction + +Vermine2047 est un systĂšme pour FoundryVTT (Virtual Tabletop) qui implĂ©mente les rĂšgles du jeu de rĂŽle Vermine 2047. Ce document dĂ©crit l'architecture technique du systĂšme. + +### Technologies utilisĂ©es +- **FoundryVTT**: v14 (compatible v11+) +- **Langage**: JavaScript (ES Modules) +- **Templates**: Handlebars +- **CSS**: Vanilla CSS avec Flexbox/Grid + +### Version actuelle +- **Version**: 0.1.14 (aprĂšs mise Ă  jour) +- **CompatibilitĂ©**: FoundryVTT v11-v14 + +--- + +## Structure du Projet + +``` +vermine2047/ +├── module/ +│ ├── vermine2047.mjs # Point d'entrĂ©e principal +│ ├── documents/ +│ │ ├── actor.mjs # Classe Actor Ă©tendue +│ │ └── item.mjs # Classe Item Ă©tendue +│ ├── sheets/ +│ │ ├── actor-sheet.mjs # Classe de base des feuilles d'acteur +│ │ ├── character-sheet.mjs # Feuille de personnage +│ │ ├── npc-sheet.mjs # Feuille de PNJ +│ │ ├── creature-sheet.mjs # Feuille de crĂ©ature +│ │ └── npc-group.mjs # Feuille de groupe +│ │ └── item-sheet.mjs # Feuille d'item +│ └── system/ +│ ├── config.mjs # Configuration du systĂšme +│ ├── hooks.mjs # Hooks FoundryVTT +│ ├── roll.mjs # Logique des jets de dĂ©s +│ ├── dice3d.mjs # IntĂ©gration Dice So Nice +│ ├── dialogs/ +│ │ └── rollDialog.mjs # Dialogue de jet de dĂ©s +│ ├── functions.mjs # Fonctions utilitaires +│ ├── fight.mjs # SystĂšme de combat +│ ├── effects.mjs # Gestion des effets +│ ├── settings.mjs # ParamĂštres du systĂšme +│ ├── tour.mjs # Visite guidĂ©e +│ ├── applications.mjs # Applications (sĂ©lecteurs) +│ └── group-link.mjs # Gestion des liens de groupe +├── templates/ +│ ├── actor/ +│ │ ├── actor-character-sheet.hbs +│ │ ├── actor-npc-sheet.hbs +│ │ ├── actor-creature-sheet.hbs +│ │ └── actor-group-sheet.hbs +│ ├── dialogs/ +│ │ ├── roll-dialog.hbs +│ │ └── min-max-edit.hbs +│ ├── item/ +│ │ └── chatCards/ # Templates de chat pour items +│ │ ├── *.hbs # Par type d'item +│ └── roll-message.hbs # Template de message de jet +├── lang/ +│ ├── fr.json # Traductions françaises +│ └── en.json # Traductions anglaises +├── assets/ +│ ├── icons/ # IcĂŽnes +│ ├── images/ # Images +│ └── style/ # Styles CSS +├── packs/ # Compendiums +├── system.json # MĂ©tadonnĂ©es du systĂšme +└── template.json # Structure des donnĂ©es +``` + +--- + +## Configuration du SystĂšme + +### CONFIG.VERMINE + +Toutes les configurations du systĂšme sont dĂ©finies dans `module/system/config.mjs` et sont accessibles via `CONFIG.VERMINE`. + +#### CatĂ©gories principales + +1. **Niveaux d'Ăąge (AgeTypes)** + - Jeune (0-17 ans) + - Adulte (18-46 ans) + - Vieux (47+ ans) + +2. **Niveaux de compĂ©tence (SkillLevels)** + - 0: IncompĂ©tent + - 1: DĂ©butant + - 2: CompĂ©tent + - 3: Expert + - 4: MaĂźtre + - 5: LĂ©gende + +3. **Niveaux de difficultĂ© (DifficultyLevels)** + - 1: Evidente (3+) + - 2: Facile (5+) + - 3: Difficile (7+) + - 4: TrĂšs difficile (9+) + - 5: Impossible (10+) + +4. **Niveaux de menace (ThreatLevels)** - Pour les PNJ + - 1: Mineure + - 2: SĂ©rieuse + - 3: Majeure + - 4: Mortelle + +5. **Niveaux d'expĂ©rience (ExperienceLevels)** - Pour les PNJ + - 1: DĂ©butant + - 2: CompĂ©tent + - 3: Expert + - 4: MaĂźtre + +6. **Niveaux de rĂŽle (RoleLevels)** - Pour les PNJ + - 1: Mineur + - 2: Secondaire + - 3: Important + - 4: Majeur + +7. **Niveaux de gabarit (PatternLevels)** - Pour les crĂ©atures + - 1: Insecte + - 2: Rat + - 3: Chien + - 4: Ours + +8. **Niveaux de taille (SizeLevels)** - Pour les crĂ©atures + - 1: Petit + - 2: Moyen + - 3: Grand + +9. **Niveaux de meute (PackLevels)** - Pour les crĂ©atures + - 0: Solitaire + - 1: Petit groupe + - 2: Groupe + - 3: Grande meute + +10. **CatĂ©gories de caractĂ©ristiques (abilityCategories)** + - physical: Physique + - manual: Manuel + - mental: Mental + - social: Social + +11. **CaractĂ©ristiques (abilities)** + - vigor: Vigueur + - health: SantĂ© + - precision: PrĂ©cision + - reflexes: RĂ©flexes + - knowledge: Connaissance + - perception: Perception + - will: VolontĂ© + - empathy: Empathie + +12. **CatĂ©gories de compĂ©tences (skillCategories)** + - man: Humain + - animal: Animal + - tool: Outil + - weapon: Arme + - survival: Survie + - world: Monde + +13. **Totems (totems)** + - human: Humain + - predator: PrĂ©dateur + - scavenger: Charognard + - symbiote: Symbiote + - parasite: Parasite + - builder: BĂątisseur + - horde: Horde + - hive: Ruche + - loner: Solitaire + - adapted: AdaptĂ© + +14. **Totems opposĂ©s (totem_opposites)** + - human ↔ adapted + - predator ↔ scavenger + - symbiote ↔ parasite + - builder ↔ horde + - hive ↔ loner + +15. **Domaines des totems (totemDomains)** - NOUVEAU + Chaque totem a des domaines de prĂ©dilection qui accordent des bonus + - human: ["man", "world"] + - adapted: ["animal", "survival"] + - etc. + +16. **Origines (origins)** + Liste des origines possibles pour les personnages + +17. **Traits (traits)** + Liste des traits disponibles pour les items avec leurs descriptions + +18. **Types de dĂ©gĂąts (damageTypes)** + - choc + - lame + - feu + - balle + +19. **Statuts de combat (combatStatus)** + - offensif: 5 + - actif: 7 + - passif: 9 + +--- + +## Documents + +### VermineActor + +La classe `VermineActor` Ă©tend la classe `Actor` de FoundryVTT et ajoute des fonctionnalitĂ©s spĂ©cifiques Ă  Vermine2047. + +#### MĂ©thodes principales + +- **prepareData()**: PrĂ©pare les donnĂ©es de l'acteur +- **prepareBaseData()**: PrĂ©pare les donnĂ©es de base +- **prepareDerivedData()**: PrĂ©pare les donnĂ©es dĂ©rivĂ©es +- **_prepareCharacterData()**: PrĂ©pare les donnĂ©es spĂ©cifiques aux personnages +- **_prepareNpcData()**: PrĂ©pare les donnĂ©es spĂ©cifiques aux PNJ +- **getRollData()**: Retourne les donnĂ©es pour les jets de dĂ©s +- **prepareCombatStatus()**: PrĂ©pare le statut de combat + +#### PropriĂ©tĂ©s calculĂ©es + +- **ageType**: Type d'Ăąge basĂ© sur l'Ăąge du personnage +- **modFromAgeSelfControl**: Modificateur de Sang-Froid basĂ© sur l'Ăąge +- **modFromAgeEffort**: Modificateur d'Effort basĂ© sur l'Ăąge +- **modFromAgeWounds**: Modificateurs de blessures basĂ©s sur l'Ăąge + +#### DonnĂ©es d'un Personnage (character) + +```json +{ + "adaptation": { + "value": 1, + "totems": { + "human": { "value": 1, "min": 0, "max": 3 }, + "adapted": { "value": 1, "min": 0, "max": 3 } + } + }, + "identity": { + "height": 0, + "weight": 0, + "totem": "", + "age": 15, + "ageType": 2, + "profile": "", + "theme": "", + "instincts": "", + "prohibits": "", + "objectives": "", + "relations": "", + "biography": "" + }, + "attributes": { + "xp": { "value": 0, "max": 10 }, + "reputation": { "value": 0, "max": 10 }, + "self_control": { "value": 0, "min": 0, "max": 5 }, + "effort": { "value": 0, "min": 0, "max": 5 } + }, + "abilities": { + "vigor": { "value": 1, "min": 0, "max": 5, "category": "physical" }, + "health": { "value": 1, "min": 0, "max": 5, "category": "physical" }, + "precision": { "value": 1, "min": 0, "max": 5, "category": "manual" }, + "reflexes": { "value": 1, "min": 0, "max": 5, "category": "manual" }, + "knowledge": { "value": 1, "min": 0, "max": 5, "category": "mental" }, + "perception": { "value": 1, "min": 0, "max": 5, "category": "mental" }, + "will": { "value": 1, "min": 0, "max": 5, "category": "social" }, + "empathy": { "value": 1, "min": 0, "max": 5, "category": "social" } + }, + "skills": { ... }, // 30+ compĂ©tences avec valeur (0-5) + "skill_categories": { + "preferred": "", + "man": { "label": "VERMINE.skill_category.man", "preferred": false }, + "animal": { ... }, + "tool": { ... }, + "weapon": { ... }, + "survival": { ... }, + "world": { ... } + }, + "encounters": [], // NOUVEAU: Liste des groupes/rencontres + "combatStatus": { "label": "", "difficulty": 7 }, + "minorWound": { "threshold": 1, "value": 0, "min": 0, "max": 5 }, + "majorWound": { "threshold": 4, "value": 0, "min": 0, "max": 4 }, + "deadlyWound": { "threshold": 8, "value": 0, "min": 0, "max": 2 } +} +``` + +#### DonnĂ©es d'un PNJ (npc) + +```json +{ + "age": 15, + "skills": "", + "threat": { "value": 1, "min": 1, "max": 4 }, + "experience": { "value": 1, "min": 1, "max": 4 }, + "role": { "value": 1, "min": 1, "max": 4 } +} +``` + +#### DonnĂ©es d'un Groupe (group) + +```json +{ + "identity": { + "totem": "", + "profile": "", + "origin": "", + "theme": "", + "instincts": "", + "prohibits": "", + "major_objectives": "", + "minor_objectives": "", + "notes": "" + }, + "level": { "value": 0, "min": 0, "max": 3 }, + "reputation": { "value": 10, "min": 2, "max": 10 }, + "morale": { "level": "high", "value": 7, "min": 1, "max": 7 }, + "members": [], + "encounters": [] +} +``` + +#### DonnĂ©es d'une CrĂ©ature (creature) + +```json +{ + "skills": "", + "modes": { + "survival": true, + "nightmare": true, + "apocalypse": false + }, + "pattern": { "value": 1, "min": 1, "max": 4 }, + "size": { "value": 1, "min": 1, "max": 4 }, + "role": { "value": 1, "min": 1, "max": 4 }, + "pack": { "value": 0, "min": 0, "max": 3 } +} +``` + +### VermineItem + +La classe `VermineItem` Ă©tend la classe `Item` de FoundryVTT. + +#### Types d'items + +1. **item**: Objet gĂ©nĂ©ral +2. **weapon**: Arme +3. **defense**: Protection +4. **vehicle**: VĂ©hicule +5. **ability**: CapacitĂ© +6. **specialty**: SpĂ©cialitĂ© +7. **background**: Historique +8. **trauma**: Traumatisme +9. **evolution**: Évolution +10. **rumor**: Rumeur +11. **target**: Cible +12. **rite**: Rite + +#### MĂ©thodes principales + +- **prepareData()**: PrĂ©pare les donnĂ©es de l'item +- **prepareBaseData()**: PrĂ©pare les donnĂ©es de base +- **getRollData()**: Retourne les donnĂ©es pour les jets de dĂ©s +- **roll()**: Effectue un jet de dĂ©s pour l'item + +#### DonnĂ©es communes Ă  tous les items + +```json +{ + "description": "", + "rarity": { "value": 3, "handicap": 0 }, + "reliability": 3, + "handicap": 0, + "quantity": 1, + "weight": 0, + "traits": {}, + "damages": { + "value": 0, + "min": 0, + "max": 5, + "pannes": ["mineure", "mineure", "grave", "grave", "critique"], + "state": ["endommagĂ©", "endommagĂ©", "dĂ©fectueux", "dĂ©fectueux", "hors d'usage"], + "effect": ["bonus annulĂ©", "bonus annulĂ©", "malus 1D", "malus 1D", "inutilisable"] + } +} +``` + +#### DonnĂ©es spĂ©cifiques par type + +**weapon**: +```json +{ + "min_range": 0, + "max_range": 0, + "damage": { "value": 0, "type": "", "addVigor": false }, + "ammo": 0 +} +``` + +**defense**: +```json +{ + "level": 0, + "specificLevel": { "label": "", "level": 0 }, + "mobility": 0, + "isShield": false +} +``` + +**ability**: +```json +{ + "type": "", + "totem": "", + "learn": { "threshold": 5, "hindrance": 0 }, + "level": { "value": 1, "min": 1, "max": 3 }, + "effects": [] +} +``` + +**specialty**: +```json +{ + "skill": "" +} +``` + +**rite**: +```json +{ + "rituel": "", + "transe": "", + "ability": "", + "effect": "" +} +``` + +--- + +## Fiches (Sheets) + +### Hierarchie des classes + +``` +ActorSheet (FoundryVTT) +└── VermineActorSheet + ├── VermineCharacterSheet + ├── VermineNpcSheet + ├── VermineCreatureSheet + └── VermineGroupSheet + +ItemSheet (FoundryVTT) +└── VermineItemSheet +``` + +### VermineCharacterSheet + +Fiche pour les personnages joueurs. + +#### Onglets +1. **CaractĂ©ristiques et compĂ©tences** (abilities) + - CaractĂ©ristiques (8) + - CompĂ©tences (30+) groupĂ©es par catĂ©gorie + - Domaines de prĂ©dilection + - SpĂ©cialitĂ©s +2. **Totem et ajustements** (totem) + - SĂ©lection du totem + - DĂ©s de totem (humain/adaptĂ©) + - CapacitĂ©s de totem + - CapacitĂ©s + - SpĂ©cialitĂ©s + - Historiques + - Traumatismes + - Évolutions +3. **Combat et rĂ©serves** (combat) + - Statuts de combat (offensif/actif/passif) + - RĂ©serves (Effort, Sang-Froid) + - Blessures +4. **MatĂ©riel** (equipment) + - Armes + - Protections + - VĂ©hicules + - Objets +5. **Histoire** (stories) + - Identity (nom, Ăąge, origine, etc.) + - Objectifs + - Relations + - Biographie + +#### FonctionnalitĂ©s + +- CrĂ©ation de spĂ©cialitĂ©s depuis les compĂ©tences +- Gestion des dĂ©s de totem (cliquables) +- Mode jeu/edit (dĂ©sactive les inputs en mode jeu) +- Roll sur les caractĂ©ristiques et compĂ©tences + +### VermineNpcSheet + +Fiche pour les PNJ. + +#### SĂ©lecteurs +- **Menace**: 1-4 (sĂ©lecteur) +- **ExpĂ©rience**: 1-4 (sĂ©lecteur) +- **RĂŽle**: 1-4 (sĂ©lecteur) + +#### Onglets +1. **CaractĂ©ristiques et compĂ©tences** + - Menace (attaque, vigueur, blessures) + - ExpĂ©rience (action, spĂ©cialitĂ©s, relances, contact) + - RĂŽle (rĂ©action, rĂ©serves, matĂ©riel, protection) +2. **MatĂ©riel** +3. **Combat** + +### VermineCreatureSheet + +Fiche pour les crĂ©atures. + +#### SĂ©lecteurs +- **Gabarit**: 1-4 (sĂ©lecteur) +- **Taille**: 1-3 (sĂ©lecteur) +- **RĂŽle**: 1-4 (sĂ©lecteur) +- **Groupe**: 0-3 (sĂ©lecteur) +- **Modes**: Survie, Cauchemar, Apocalypse (checkboxes) + +#### Onglets +1. **CaractĂ©ristiques et compĂ©tences** + - Gabarit (attaque, dĂ©gĂąts, blessures) + - Taille (attaque, vigueur, blessures) + - RĂŽle (rĂ©action, rĂ©serves, matĂ©riel, protection) + - Meute (attaque, dĂ©gĂąts, blessures) +2. **Combat** + +### VermineGroupSheet + +Fiche pour les groupes. + +#### FonctionnalitĂ©s +- SĂ©lection du totem +- Gestion des membres (ajout/suppression) +- Gestion des rencontres (ajout/suppression) + +#### Synchronisation +- Les membres sont stockĂ©s dans `system.members` (IDs) +- Les rencontres sont stockĂ©es dans `system.encounters` (IDs) +- Les groupes d'un acteur sont stockĂ©s dans `system.encounters` (IDs) + +### VermineItemSheet + +Fiche pour les items. + +#### Types gĂ©rĂ©s +- item +- weapon +- defense +- vehicle +- ability +- specialty +- background +- trauma +- evolution +- rumor +- target +- rite + +--- + +## SystĂšme de DĂ©s + +### VermineUtils.roll() + +MĂ©thode principale pour effectuer un jet de dĂ©s. + +#### ParamĂštres + +```javascript +{ + actor: Actor, // L'acteur qui lance les dĂ©s + NoD: number, // Nombre de dĂ©s de base + Reroll: number, // Nombre de relances autorisĂ©es + difficulty: number, // DifficultĂ© du jet (3-10) + self_control: number, // Sang-Froid utilisĂ© + rollLabel: string, // LibellĂ© du jet + totems: object, // { human: boolean, adapted: boolean } + max_effort: number, // Effort maximum + skillCategory: string, // CatĂ©gorie de compĂ©tence pour les bonus de domaine + keepTotem: string, // Totem Ă  garder ('human' ou 'adapted') + skillLevel: number, // Niveau de la compĂ©tence pour les rĂ©ussites automatiques + hasSpecialty: boolean // Si une spĂ©cialitĂ© est utilisĂ©e +} +``` + +#### Fonctionnement + +1. **Calcul des bonus/malus de totem** + - Si une catĂ©gorie de compĂ©tence est spĂ©cifiĂ©e, calcule les bonus/malus basĂ©s sur le domaine de prĂ©dilection + - Bonus: +1 dĂ© si le domaine de prĂ©dilection est dans les domaines du totem + - Malus: -1 dĂ© si le domaine de prĂ©dilection est dans les domaines du totem opposĂ© + +2. **RĂ©ussites automatiques** + - Niveau 2 (CompĂ©tent) + spĂ©cialitĂ©: +1 rĂ©ussite automatique + - Niveau 3 (Expert): +1 rĂ©ussite automatique + - Niveau 4 (MaĂźtre) + spĂ©cialitĂ©: +2 rĂ©ussites automatiques + - Niveau 5 (LĂ©gende): +2 rĂ©ussites automatiques + +3. **Seuils automatiques** + - Niveau 0 (IncompĂ©tent): seuil = 9 (trĂšs difficile) + - Niveau 1 (DĂ©butant): seuil = 7 (difficile) + - Niveau >= 2: utilise la difficultĂ© spĂ©cifiĂ©e + +4. **Gestion des totems** + - Chaque totem utilisĂ© ajoute un dĂ© spĂ©cial avec double rĂ©ussite possible + - Le totem humain et adaptĂ© peuvent ĂȘtre utilisĂ©s simultanĂ©ment + - Si `keepTotem` est spĂ©cifiĂ©, seul un totem est utilisĂ© + +5. **Formule de jet** + - Base: `{NoD}d10cs>={difficulty}[regular_{user}]` + - Avec totem humain: `+ (1d10cs>={difficulty}[human_{user}]*2)` + - Avec totem adaptĂ©: `+ (1d10cs>={difficulty}[adapted_{user}]*2)` + +#### Exemple + +```javascript +// Jet de compĂ©tence avec totem humain +VermineUtils.roll({ + actor: character, + NoD: 3, // 3 dĂ©s de base + difficulty: 7, // DifficultĂ© 7 + skillCategory: 'survival', // CatĂ©gorie de compĂ©tence + skillLevel: 3, // Niveau Expert + hasSpecialty: true, // Avec spĂ©cialitĂ© + totems: { human: true, adapted: false } // Totem humain seulement +}); +// RĂ©sultat: 4d10cs>=7[regular_user] + (1d10cs>=7[human_user]*2) +// avec 1 rĂ©ussite automatique (niveau 3) +``` + +### RollDialog + +Dialogue de jet de dĂ©s avancĂ©. + +#### FonctionnalitĂ©s +- SĂ©lection de la caractĂ©ristique +- SĂ©lection de la compĂ©tence +- SĂ©lection de la spĂ©cialitĂ© (+1D) +- SĂ©lection de la difficultĂ© +- SĂ©lection du handicap +- Bonus: + - Entraide (+1D) + - Groupe (0-5D) + - Sang-Froid (0-5D, basĂ© sur la caractĂ©ristique) + - Équipement (+1D) + - DĂ©s de totem (humain/adaptĂ©) +- Affichage du total du pool de dĂ©s +- Choix du totem Ă  garder (si les deux sont activĂ©s) + +#### Structure du template +- Utilise `
`/`` pour une interface compacte +- Sections principales: + - SĂ©lection caractĂ©ristique + compĂ©tence + - DifficultĂ© + Handicap (section ouverte par dĂ©faut) + - Bonus (section pliable) + - Total du pool de dĂ©s + +--- + +## Combat + +### VermineCombat + +Classe Ă©tendue de `Combat` de FoundryVTT. + +#### Formules + +- **Initiative**: `@abilities.reflexes.value + @skills.alertness.value)d10cs>=@combatStatus.difficulty` +- **DifficultĂ© dynamique**: + - Offensif: 5 + - Actif: 7 + - Passif: 9 + +#### Classes + +- **VermineCombat**: Gestion du combat +- **VermineCombatTracker**: Tracker de combat personnalisĂ© +- **VermineCombatant**: Combatant personnalisĂ© + +#### Statuts de combat + +Chaque acteur a un `combatStatus` avec: +- `label`: "Offensif", "Actif", ou "Passif" +- `difficulty`: 5, 7, ou 9 + +### VermineFight + +Classe pour la gestion des confrontations (ancien systĂšme). + +À migrer vers le nouveau systĂšme de combat. + +--- + +## Gestion des Groupes + +### GroupLink + +Classe pour la synchronisation bidirectionnelle entre acteurs et groupes. + +#### FonctionnalitĂ©s + +1. **Synchronisation automatique** + - Quand un groupe est mis Ă  jour, les acteurs membres sont notifiĂ©s + - Quand un acteur est mis Ă  jour, ses groupes sont notifiĂ©s + +2. **Hooks enregistrĂ©s** + - `updateActor`: Synchronise les groupes quand un acteur est mis Ă  jour + - `createActor`: Nettoie les rĂ©fĂ©rences invalides + - `deleteActor`: Retire l'acteur de tous ses groupes + +3. **MĂ©thodes utilitaires** + - `getActorObjects(actorIds)`: Retourne les objets Actor pour une liste d'IDs + - `getGroupMembers(group)`: Retourne les membres d'un groupe + - `getGroupEncounters(group)`: Retourne les rencontres d'un groupe + - `getActorGroups(actor)`: Retourne les groupes d'un acteur + - `getActorEncounters(actor)`: Retourne les rencontres d'un acteur + - `addActorToGroup(actorId, groupId)`: Ajoute un acteur Ă  un groupe + - `removeActorFromGroup(actorId, groupId)`: Retire un acteur d'un groupe + +#### Exemple d'utilisation + +```javascript +// Ajouter un acteur Ă  un groupe +GroupLink.addActorToGroup('actor123', 'group456'); + +// Retirer un acteur d'un groupe +GroupLink.removeActorFromGroup('actor123', 'group456'); + +// Obtenir les membres d'un groupe +const members = GroupLink.getGroupMembers(group); +``` + +--- + +## Synchronisation + +### Hooks principaux + +#### Dans `module/vermine2047.mjs` +- Initialisation des classes globales +- Enregistrement des hooks GroupLink +- PrĂ©-chargement des templates Handlebars +- Configuration de l'interface utilisateur (mode de jeu) + +#### Dans `module/system/hooks.mjs` +- `diceSoNiceReady`: Configuration des dĂ©s 3D +- `renderChatMessage`: Gestion des relances de dĂ©s +- `updateUser`: Mise Ă  jour des dĂ©s 3D pour l'utilisateur +- `ready`: Initialisation du systĂšme +- `renderPause`: Personnalisation de l'Ă©cran de pause +- `hotbarDrop`: Gestion du glisser-dĂ©poser sur la barre d'outils +- `getSceneControlButtons`: Ajout du bouton de lancer de dĂ©s +- `preCreateActor`: Image par dĂ©faut pour les acteurs +- `preCreateItem`: Image par dĂ©faut pour les items + +### Hooks GroupLink + +Voir [Gestion des Groupes](#gestion-des-groupes). + +--- + +## Templates + +### Structure + +Tous les templates sont en format Handlebars (.hbs) et sont situĂ©s dans le dossier `templates/`. + +#### Types de templates + +1. **Templates principaux** + - `templates/actor/actor-*.hbs`: Fiches d'acteurs + - `templates/item/item-sheet.hbs`: Fiche d'item + - `templates/roll-message.hbs`: Message de jet de dĂ©s + - `templates/combat-tracker.hbs`: Tracker de combat + +2. **Templates de dialogue** + - `templates/dialogs/roll-dialog.hbs`: Dialogue de jet de dĂ©s + - `templates/dialogs/min-max-edit.hbs`: Édition min/max + +3. **Partials** + - `templates/actor/parts/*`: Parties rĂ©utilisables des feuilles d'acteur + - `templates/actor/character/*`: Parties spĂ©cifiques aux personnages + - `templates/actor/group/*`: Parties spĂ©cifiques aux groupes + - `templates/actor/npc/*`: Parties spĂ©cifiques aux PNJ + - `templates/actor/creature/*`: Parties spĂ©cifiques aux crĂ©atures + - `templates/item/partials/*`: Parties rĂ©utilisables des feuilles d'item + +4. **Chat Cards** + - `templates/item/chatCards/*.hbs`: Cartes de chat pour chaque type d'item + +### Helpers Handlebars + +Tous les helpers sont dĂ©finis dans `module/system/handlebars-manager.mjs`. + +#### Helpers de traduction +- `smarttl(arrayLabel, objectLabel, key)`: Traduction intelligente +- `smarttlk(arrayLabel, objectLabel, key)`: Traduction avec clĂ© +- `smartcfg(configLabel, objectLabel)`: Traduction de configuration + +#### Helpers de niveau +- `skillLevel(property, level)`: PropriĂ©tĂ© d'un niveau de compĂ©tence +- `diffLevel(property, level)`: PropriĂ©tĂ© d'un niveau de difficultĂ© +- `threatLevel(property, level)`: PropriĂ©tĂ© d'un niveau de menace +- `experienceLevel(property, level)`: PropriĂ©tĂ© d'un niveau d'expĂ©rience +- `roleLevel(property, level)`: PropriĂ©tĂ© d'un niveau de rĂŽle +- `patternLevel(property, level)`: PropriĂ©tĂ© d'un niveau de gabarit +- `sizeLevel(property, level)`: PropriĂ©tĂ© d'un niveau de taille +- `packLevel(property, level)`: PropriĂ©tĂ© d'un niveau de meute +- `ageType(property, level)`: PropriĂ©tĂ© d'un type d'Ăąge +- `npcThreatLevel(property, level)`: PropriĂ©tĂ© d'un niveau de menace PNJ +- `npcExperienceLevel(property, level)`: PropriĂ©tĂ© d'un niveau d'expĂ©rience PNJ +- `npcRoleLevel(property, level)`: PropriĂ©tĂ© d'un niveau de rĂŽle PNJ +- `creaturePatternLevel(property, level)`: PropriĂ©tĂ© d'un niveau de gabarit crĂ©ature +- `creatureSizeLevel(property, level)`: PropriĂ©tĂ© d'un niveau de taille crĂ©ature +- `creatureRoleLevel(property, level)`: PropriĂ©tĂ© d'un niveau de rĂŽle crĂ©ature +- `creaturePackLevel(property, level)`: PropriĂ©tĂ© d'un niveau de meute crĂ©ature + +#### Helpers de donnĂ©es +- `getDamagesData(damageObject, prop)`: DonnĂ©es de dĂ©gĂąts +- `concat(...args)`: Concatenation de chaĂźnes +- `lower(str)`: Convertit en minuscules +- `toLowerCase(str)`: Convertit en minuscules +- `romanNumber(numb)`: Convertit un nombre en chiffre romain (I, II, III, etc.) + +#### Helpers de comparaison +- `ife(arg1, arg2, options)`: Si Ă©gal +- `ifgt(a, b, options)`: Si supĂ©rieur +- `iflt(a, b, options)`: Si infĂ©rieur +- `ifgteq(a, b, options)`: Si supĂ©rieur ou Ă©gal +- `iflteq(a, b, options)`: Si infĂ©rieur ou Ă©gal +- `ifincludes(arg1, arg2, options)`: Si contient + +#### Helpers mathĂ©matiques +- `math_add(a, b)`: Addition +- `math_subs(a, b)`: Soustraction +- `math_mult(a, b)`: Multiplication +- `math_div(a, b)`: Division + +#### Helpers de boucle +- `repeat(times, start, indexLabel, block)`: Boucle avec index +- `setVar(varName, varValue, options)`: DĂ©finit une variable + +--- + +## Traductions + +### Structure + +Les traductions sont dĂ©finies dans les fichiers: +- `lang/fr.json`: Français +- `lang/en.json`: Anglais + +### Namespaces principaux + +- **SETTINGS**: ParamĂštres du monde +- **VERMINE**: Termes spĂ©cifiques au systĂšme + - **ability**: CaractĂ©ristiques + - **skills_title**: CompĂ©tences + - **wounds**: Blessures + - **tabs**: Onglets +- **ABILITIES**: CaractĂ©ristiques +- **SKILLS**: CompĂ©tences +- **SKILL_LEVELS**: Niveaux de compĂ©tence +- **DIFFICULTY_LEVELS**: Niveaux de difficultĂ© +- **THREAT_LEVELS**: Niveaux de menace +- **EXPERIENCE_LEVELS**: Niveaux d'expĂ©rience +- **ROLE_LEVELS**: Niveaux de rĂŽle +- **PATTERN_LEVELS**: Niveaux de gabarit +- **AGE_TYPES**: Types d'Ăąge +- **ATTITUDES**: Attitudes de combat +- **ADVERSITY**: AdversitĂ© (PNJ/CrĂ©ature) +- **TOTEMS**: Totems +- **GAME_MODES**: Modes de jeu +- **IDENTITY**: IdentitĂ© +- **UI**: Interface utilisateur +- **ITEMS**: Items + +### Ajout de traductions + +Pour ajouter une nouvelle traduction: + +1. Ajouter la clĂ© dans les deux fichiers (fr.json et en.json) +2. Utiliser la clĂ© avec `game.i18n.localize('NAMESPACE.key')` ou `{{localize 'NAMESPACE.key'}}` dans les templates + +Exemple: +```json +{ + "VERMINE": { + "new_feature": "Nouvelle fonctionnalitĂ©" + } +} +``` + +--- + +## Bonnes pratiques + +### DĂ©veloppement + +1. **Always use strict mode** +2. **Use async/await** for asynchronous operations +3. **Error handling**: Always catch and handle errors +4. **Data validation**: Validate input data +5. **Performance**: Be mindful of performance in hooks + +### Code style + +1. **Naming**: Use camelCase for variables and functions, PascalCase for classes +2. **Comments**: Use JSDoc for functions and classes +3. **Imports**: Group related imports together +4. **Exports**: Use named exports for utility functions + +### Templates + +1. **Keep templates simple**: Move complex logic to helpers +2. **Use partials**: Reuse common template parts +3. **Accessibility**: Use proper labels and ARIA attributes +4. **Responsive**: Design for different screen sizes + +### Internationalization + +1. **Always use localization**: Never hardcode text +2. **Context**: Provide context in translation keys +3. **Fallback**: Provide fallback text for missing translations + +--- + +## DĂ©pendances + +### Modules externes + +- **Dice So Nice**: Pour les dĂ©s 3D + - Configuration dans `module/system/dice3d.mjs` + - DĂ© diffĂ©rents pour Vermine2047 + +### CompatibilitĂ© + +- **FoundryVTT**: v11-v14 +- **TestĂ© avec**: v12, v14 + +--- + +## RĂ©solution des problĂšmes + +### ProblĂšmes courants + +1. **Templates not found** + - VĂ©rifier que le template existe dans le bon dossier + - VĂ©rifier que l'extension est `.hbs` + - VĂ©rifier que le template est prĂ©-chargĂ© dans `handlebars-manager.mjs` + +2. **Translations missing** + - VĂ©rifier que la clĂ© existe dans le fichier de langue + - VĂ©rifier que le namespace est correct + - Utiliser `game.i18n.localize()` pour dĂ©boguer + +3. **Hooks not firing** + - VĂ©rifier que le hook est bien enregistrĂ© + - VĂ©rifier que le hook est appelĂ© au bon moment + - Utiliser `CONFIG.debug.hooks = true` pour dĂ©boguer + +4. **Data not updating** + - VĂ©rifier que les donnĂ©es sont bien modifiĂ©es + - VĂ©rifier que `actor.update()` ou `item.update()` est appelĂ© + - VĂ©rifier que les hooks de synchronisation sont actifs + +### Outils de dĂ©bogage + +1. **Console.log** + ```javascript + console.log('Debug:', data); + ``` + +2. **Notifications** + ```javascript + ui.notifications.info('Message d'information'); + ui.notifications.warn('Avertissement'); + ui.notifications.error('Erreur'); + ``` + +3. **Dialogues de dĂ©bogage** + ```javascript + new Dialog({ + title: 'Debug', + content: `
${JSON.stringify(data, null, 2)}
`, + buttons: { ok: { label: 'OK' } } + }).render(true); + ``` + +--- + +## Contribution + +### Comment contribuer + +1. **Fork** le dĂ©pĂŽt +2. **Create** une branche pour votre fonctionnalitĂ© +3. **Commit** vos changements +4. **Push** Ă  la branche +5. **Open** une Pull Request + +### Guidelines + +1. Suivre le style de code existant +2. Ajouter des tests si possible +3. Mettre Ă  jour la documentation +4. Utiliser des messages de commit clairs + +--- + +## Historique des versions + +Voir `CHANGELOG.md` pour l'historique complet. + +--- + +## Licence + +Voir `LICENSE.txt` pour les dĂ©tails de la licence. + +--- + +## Auteurs + +- François-Xavier Guillois +- Rwanoux (Discord: rwanoux) +- Pretre (Discord: pretre) + +--- + +*Documentation gĂ©nĂ©rĂ©e: 2026-06-04* +*Version: 0.1.14* diff --git a/docs/user/GUIDE_UTILISATEUR.md b/docs/user/GUIDE_UTILISATEUR.md new file mode 100644 index 0000000..9089ace --- /dev/null +++ b/docs/user/GUIDE_UTILISATEUR.md @@ -0,0 +1,696 @@ +# Guide Utilisateur - Vermine2047 pour FoundryVTT + +## Table des matiĂšres +1. [Introduction](#introduction) +2. [Installation](#installation) +3. [CrĂ©ation d'un personnage](#crĂ©ation-dun-personnage) +4. [Les jets de dĂ©s](#les-jets-de-dĂ©s) +5. [Le systĂšme de totems](#le-systĂšme-de-totems) +6. [La gestion des groupes](#la-gestion-des-groupes) +7. [Le combat](#le-combat) +8. [Les items](#les-items) +9. [Gestion des PNJ et CrĂ©atures](#gestion-des-pnj-et-crĂ©atures) +10. [Astuces et bonnes pratiques](#astuces-et-bonnes-pratiques) + +--- + +## Introduction + +Bienvenue dans Vermine2047, un systĂšme pour FoundryVTT qui implĂ©mente les rĂšgles du jeu de rĂŽle post-apocalyptique Vermine 2047. + +### À propos de Vermine2047 + +Vermine 2047 est un jeu de rĂŽle dans un monde post-apocalyptique oĂč les joueurs incarnent des survivants dans un environnement hostile. Le systĂšme utilise des dĂ©s d10 avec un systĂšme de seuils de rĂ©ussite et des mĂ©caniques uniques comme les totems et les domaines de prĂ©dilection. + +### CompatibilitĂ© + +- **FoundryVTT**: v11 Ă  v14 +- **Version du systĂšme**: 0.1.14 + +--- + +## Installation + +### PrĂ©requis + +- FoundryVTT installĂ© (version 11 ou supĂ©rieure) +- Module "Dice So Nice!" recommandĂ© pour les dĂ©s 3D + +### Installation du systĂšme + +1. **Via le compendium de Foundry** + - Ouvrez FoundryVTT + - Allez dans "Game Systems" + - Cliquez sur "Install System" + - Recherchez "Vermine2047" + - Cliquez sur "Install" + +2. **Via l'URL du manifest** + - Allez dans "Game Systems" + - Cliquez sur "Install System" + - Dans l'onglet "From Manifest URL", entrez: + ``` + https://raw.githubusercontent.com/rwanoux/vermine2047/refs/heads/main/system.json + ``` + - Cliquez sur "Install" + +3. **CrĂ©er un nouveau monde** + - SĂ©lectionnez "Vermine2047" comme systĂšme + - Donnez un nom Ă  votre monde + - Configurez les paramĂštres + +### Configuration recommandĂ©e + +- Activez le module "Dice So Nice!" pour les dĂ©s 3D +- Configurez le mode de jeu (Survie, Cauchemar, Apocalypse) dans les paramĂštres du monde + +--- + +## CrĂ©ation d'un personnage + +### Étape 1: CrĂ©er un acteur + +1. Cliquez sur l'icĂŽne "Actors" dans la barre latĂ©rale gauche +2. Cliquez sur "Create Actor" +3. SĂ©lectionnez "Character" comme type +4. Donnez un nom Ă  votre personnage + +### Étape 2: Choisir un totem + +Le totem est au cƓur de votre personnage et dĂ©termine ses affinitĂ©s. + +1. Dans l'onglet "Totem et ajustements" +2. Cliquez sur le bouton "choisissez un totem" +3. SĂ©lectionnez un totem dans la liste +4. Cliquez sur "SĂ©lectionner" + +**Les 10 totems disponibles:** +- **Humain**: Favorise les compĂ©tences humaines et du monde civilisĂ© +- **PrĂ©dateur**: Favorise la chasse et la survie +- **Charognard**: Favorise la rĂ©cupĂ©ration et l'utilisation d'outils +- **Symbiote**: Favorise les interactions sociales +- **Parasite**: Favorise la discrĂ©tion et la survie +- **BĂątisseur**: Favorise la construction et la manipulation +- **Horde**: Favorise le combat en groupe +- **Ruche**: Favorise l'organisation collective +- **Solitaire**: Favorise l'autonomie +- **AdaptĂ©**: Favorise l'adaptation Ă  l'environnement + +### Étape 3: DĂ©finir les caractĂ©ristiques + +Dans l'onglet "CaractĂ©ristiques et compĂ©tences", vous trouverez 8 caractĂ©ristiques rĂ©parties en 4 catĂ©gories: + +**Physique:** +- Vigueur: RĂ©sistance physique +- SantĂ©: RĂ©sistance aux blessures + +**Manuel:** +- PrĂ©cision: DextĂ©ritĂ© et coordination +- RĂ©flexes: RĂ©activitĂ© et vitesse + +**Mental:** +- Connaissance: Savoir et mĂ©moire +- Perception: Observation et intuition + +**Social:** +- VolontĂ©: DĂ©termination et courage +- Empathie: ComprĂ©hension des autres + +**Conseil:** Commencez avec des valeurs de 1-2 pour un personnage Ă©quilibrĂ©, ou 3-4 pour un spĂ©cialiste. + +### Étape 4: DĂ©finir les compĂ©tences + +Chaque compĂ©tence a une valeur de 0 Ă  5: +- 0: IncompĂ©tent +- 1: DĂ©butant +- 2: CompĂ©tent +- 3: Expert +- 4: MaĂźtre +- 5: LĂ©gende + +**CatĂ©gories de compĂ©tences:** +- **Humain**: Arts, civilisation, psychologie, rumeurs, soins +- **Animal**: Animalisme, dissection, vie sauvage, rĂ©pulsion, pistes +- **Outil**: Artisanat, bricolage, mĂ©canique, pilotage, technologie +- **Arme**: Armes Ă  feu, tir Ă  l'arc, armurerie, lancer, mĂȘlĂ©e +- **Survie**: Vigilance, athlĂ©tisme, nourriture, discrĂ©tion, corps Ă  corps +- **Monde**: Environnement, flore, route, toxiques, ruines + +**Astuce:** Le domaine de prĂ©dilection (sĂ©lectionnable en haut de chaque catĂ©gorie) donne des bonus quand il est alignĂ© avec votre totem. + +### Étape 5: Ajouter des spĂ©cialitĂ©s + +Les spĂ©cialitĂ©s donnent +1D quand elles sont utilisĂ©es avec la compĂ©tence parente. + +1. Dans l'onglet "CaractĂ©ristiques et compĂ©tences" +2. Cliquez sur l'icĂŽne "+" Ă  cĂŽtĂ© d'une compĂ©tence +3. Une spĂ©cialitĂ© sera créée avec le nom de la compĂ©tence +4. Vous pouvez renommer la spĂ©cialitĂ© + +### Étape 6: DĂ©finir les rĂ©serves + +Dans l'onglet "Combat et rĂ©serves": +- **Effort**: RĂ©serve pour les actions physiques (basĂ©e sur Vigueur + SantĂ© + RĂ©flexes + PrĂ©cision) +- **Sang-Froid**: RĂ©serve pour les actions mentales (basĂ©e sur Connaissance + Perception + VolontĂ© + Empathie) + +### Étape 7: DĂ©finir l'identitĂ© + +Dans l'onglet "Histoire": +- Age +- Origine +- Profil +- Concept +- Instincts +- Interdits +- Objectifs +- Relations +- Biographie + +### Étape 8: Équipement + +Dans l'onglet "MatĂ©riel", vous pouvez ajouter: +- Armes +- Protections +- VĂ©hicules +- Objets + +--- + +## Les jets de dĂ©s + +### Ouvrir le dialogue de jet + +Il y a plusieurs façons de lancer un jet: + +1. **Depuis la fiche de personnage** + - Cliquez sur une caractĂ©ristique ou une compĂ©tence + - Un dialogue de jet s'ouvre avec la caractĂ©ristique/compĂ©tence prĂ©sĂ©lectionnĂ©e + +2. **Depuis la barre d'outils** + - Cliquez sur l'icĂŽne de dĂ©s dans la barre d'outils (Ă  droite) + - Un dialogue de jet vide s'ouvre + +3. **Depuis le chat** + - Tapez `/roll` ou utilisez la commande de jet + +### Le dialogue de jet + +Le dialogue de jet a Ă©tĂ© conçu pour ĂȘtre intuitif et compact. + +#### SĂ©lection de base + +- **CaractĂ©ristique**: SĂ©lectionnez une caractĂ©ristique (Vigueur, SantĂ©, etc.) +- **CompĂ©tence**: SĂ©lectionnez une compĂ©tence (optionnel) +- **Score**: Affiche la valeur de la caractĂ©ristique sĂ©lectionnĂ©e + +#### DifficultĂ© et Handicap + +- **DifficultĂ©**: SĂ©lectionnez le niveau de difficultĂ© + - Evidente (3+): TĂąche trĂšs simple + - Facile (5+): TĂąche simple + - Difficile (7+): TĂąche standard + - TrĂšs difficile (9+): TĂąche complexe + - Impossible (10+): TĂąche extrĂȘmement difficile + +- **Handicap**: SĂ©lectionnez le niveau de handicap + - Aucun: Pas de handicap + - (I): Handicap mineur + - (II): Handicap majeur + +#### Bonus + +La section "Bonus" peut ĂȘtre dĂ©pliĂ©e pour accĂ©der aux options supplĂ©mentaires: + +- **Entraide**: +1D si quelqu'un vous aide +- **Groupe**: +0 Ă  +5D basĂ© sur la taille du groupe +- **Sang-Froid**: +0 Ă  +5D (basĂ© sur votre rĂ©serve de Sang-Froid) +- **Équipement**: +1D si vous utilisez un outil appropriĂ© +- **DĂ©s de totem**: Cochez pour utiliser les dĂ©s de totem + - Totem humain: +XD (oĂč X est la valeur de votre totem humain) + - Totem adaptĂ©: +XD (oĂč X est la valeur de votre totem adaptĂ©) + +**Astuce:** Si vous avez les deux totems (humain et adaptĂ©) avec des valeurs > 0, vous pouvez choisir quel totem garder aprĂšs le jet. + +#### Total du pool de dĂ©s + +Le dialogue affiche le total du pool de dĂ©s en temps rĂ©el: +- **0D**: Aucune caractĂ©ristique sĂ©lectionnĂ©e +- **3D**: CaractĂ©ristique de valeur 3 +- **4D**: CaractĂ©ristique 3 + CompĂ©tence 1 +- **5D+**: Avec bonus + +### Les bonus de domaine de totem + +Votre totem influence vos jets en fonction du domaine de prĂ©dilection: + +- Si votre domaine de prĂ©dilection est dans les domaines de votre totem, vous obtenez +1 dĂ© +- Si votre domaine de prĂ©dilection est dans les domaines du totem opposĂ©, vous subissez -1 dĂ© + +**Exemple:** +- Totem: PrĂ©dateur (domaines: animal, survie) +- Domaine de prĂ©dilection: Survie +- Bonus: +1 dĂ© sur tous les jets de survie + +### Les rĂ©ussites automatiques + +En fonction de votre niveau de maĂźtrise d'une compĂ©tence, vous obtenez des rĂ©ussites automatiques: + +| Niveau | RĂ©ussites automatiques | Avec spĂ©cialitĂ© | +|--------|------------------------|-----------------| +| IncompĂ©tent (0) | 0 | 0 | +| DĂ©butant (1) | 0 | 0 | +| CompĂ©tent (2) | 0 | +1 | +| Expert (3) | +1 | +1 | +| MaĂźtre (4) | +1 | +2 | +| LĂ©gende (5) | +2 | +2 | + +### Les seuils automatiques + +Si vous n'ĂȘtes pas maĂźtrisĂ© dans une compĂ©tence, un seuil plus Ă©levĂ© est automatiquement appliquĂ©: + +| Niveau | Seuil automatique | +|--------|-------------------| +| IncompĂ©tent (0) | 9 (TrĂšs difficile) | +| DĂ©butant (1) | 7 (Difficile) | +| CompĂ©tent (2+) | DifficultĂ© normale | + +### Les dĂ©s de totem + +Les dĂ©s de totem sont spĂ©ciaux: +- Ils comptent double en cas de rĂ©ussite (2 rĂ©ussites au lieu de 1) +- Ils sont de couleur diffĂ©rente pour les distinguer +- Vous pouvez utiliser les dĂ©s de totem humain et adaptĂ© simultanĂ©ment +- Si vous utilisez les deux, vous pouvez choisir quel totem garder aprĂšs le jet + +**Exemple:** +- Pool: 3d10 + 1d10 totem humain +- RĂ©sultat: 4, 7, 2, 9 (totem humain) +- Si le seuil est 7: 2 rĂ©ussites (7 et 9) + 2 rĂ©ussites supplĂ©mentaires pour le 9 du totem = 4 rĂ©ussites totales + +### Relances + +Les relances sont disponibles pour les compĂ©tences maĂźtrisĂ©es: +- **Niveau 2 (CompĂ©tent)**: 1 relance +- **Niveau 3 (Expert)**: 1 relance +- **Niveau 4 (MaĂźtre)**: 2 relances +- **Niveau 5 (LĂ©gende)**: 2 relances + +Pour utiliser une relance: +1. Le MJ ou vous-mĂȘme pouvez accorder des relances +2. Cliquez sur le dĂ© que vous voulez relancer +3. Le dĂ© sera marquĂ© comme "rerolled" +4. Un nouveau jet sera effectuĂ© pour ce dĂ© + +**Astuce:** Vous pouvez aussi utiliser votre rĂ©serve de Sang-Froid pour obtenir des relances supplĂ©mentaires. + +--- + +## Le systĂšme de totems + +### SĂ©lection du totem + +Le totem est choisi lors de la crĂ©ation du personnage et dĂ©termine: +- Vos affinitĂ©s naturelles +- Vos bonus de domaine +- Votre perception du monde + +### Gestion des dĂ©s de totem + +Dans la fiche de personnage, onglet "Totem et ajustements": +- Vous voyez les valeurs de vos totems humain et adaptĂ© (0-3 chacun) +- La somme maximale est de 5 (ex: 3 humain + 2 adaptĂ©) +- Cliquez sur les flĂšches pour ajuster les valeurs + +**Attention:** La somme des deux totems ne peut pas dĂ©passer 5. + +### Domaines de prĂ©dilection + +Chaque catĂ©gorie de compĂ©tence peut ĂȘtre votre domaine de prĂ©dilection: +- Humain +- Animal +- Outil +- Arme +- Survie +- Monde + +Pour dĂ©finir votre domaine de prĂ©dilection: +1. Dans l'onglet "CaractĂ©ristiques et compĂ©tences" +2. Cliquez sur le bouton radio Ă  cĂŽtĂ© du nom de la catĂ©gorie +3. La catĂ©gorie sĂ©lectionnĂ©e devient votre domaine de prĂ©dilection + +**Bonus:** Si votre domaine de prĂ©dilection est dans les domaines de votre totem, vous obtenez des bonus supplĂ©mentaires. + +### Totems et PNJ/CrĂ©atures + +Les PNJ et crĂ©atures peuvent aussi avoir des totems, qui influencent leurs caractĂ©ristiques et comportements. + +--- + +## La gestion des groupes + +### Qu'est-ce qu'un groupe? + +Un groupe reprĂ©sente: +- Une communautĂ© de survivants +- Un clan +- Une bande +- Une famille Ă©largie + +### CrĂ©er un groupe + +1. Cliquez sur "Create Actor" +2. SĂ©lectionnez "Group" comme type +3. Donnez un nom au groupe +4. DĂ©finissez le totem du groupe +5. Ajoutez des membres + +### Ajouter des membres Ă  un groupe + +1. Ouvrez la fiche du groupe +2. Dans l'onglet "Membres", cliquez sur "+ Ajouter un membre" +3. SĂ©lectionnez le personnage dans la liste +4. Cliquez sur "Ajouter" + +**Synchronisation automatique:** Quand vous ajoutez un personnage Ă  un groupe, le groupe apparaĂźt automatiquement dans la fiche du personnage. + +### GĂ©rer les rencontres + +Les "rencontres" reprĂ©sentent les PNJ et crĂ©atures associĂ©s Ă  un groupe: +1. Ouvrez la fiche du groupe +2. Dans l'onglet "Rencontres", cliquez sur "+ Ajouter une rencontre" +3. SĂ©lectionnez le PNJ ou la crĂ©ature +4. Cliquez sur "Ajouter" + +### Retirer un personnage d'un groupe + +1. Ouvrez la fiche du groupe +2. Trouvez le membre dans la liste +3. Cliquez sur l'icĂŽne de suppression (poubelle) +4. Confirmez + +**Synchronisation automatique:** Le personnage sera aussi retirĂ© de la liste des groupes dans sa fiche. + +### Mode de jeu + +La fiche de personnage a deux modes: +- **Mode Edit**: Tous les champs sont modifiables +- **Mode Jeu**: Les champs sont dĂ©sactivĂ©s pour Ă©viter les modifications accidentelles + +Pour basculer entre les modes: +- Cliquez sur l'icĂŽne de cadenas en haut de la fiche + +--- + +## Le combat + +### Initiative + +L'initiative dans Vermine2047 est basĂ©e sur: +- CaractĂ©ristique: RĂ©flexes +- CompĂ©tence: Vigilance +- Statut de combat: Offensif (+), Actif (neutre), Passif (-) + +**Formule:** `(RĂ©flexes + Vigilance)d10cs>=difficultĂ©` + +**DifficultĂ©s par statut:** +- Offensif: 5 (facile) +- Actif: 7 (standard) +- Passif: 9 (difficile) + +### Statuts de combat + +Chaque participant au combat a un statut: +- **Offensif**: Agressif, prend des risques +- **Actif**: ÉquilibrĂ©, rĂ©actif +- **Passif**: DĂ©fensif, prudent + +Pour changer le statut: +1. Dans le combat tracker +2. Cliquez sur le nom du participant +3. SĂ©lectionnez le nouveau statut + +### Tracker de combat + +Le tracker de combat affiche: +- L'ordre d'initiative +- Le statut de chaque participant +- Les points de vie +- Les rĂ©serves + +### Actions de combat + +Les actions de combat fonctionnent comme les jets de dĂ©s normaux, mais avec: +- Des bonus spĂ©cifiques au combat +- Des modifications de difficultĂ© basĂ©es sur le statut + +--- + +## Les items + +### Types d'items + +1. **Objet (item)**: Objet gĂ©nĂ©ral (nourriture, outils, etc.) +2. **Arme (weapon)**: Arme de mĂȘlĂ©e ou Ă  distance +3. **Protection (defense)**: Armure, bouclier, etc. +4. **VĂ©hicule (vehicle)**: Transport +5. **CapacitĂ© (ability)**: CompĂ©tence spĂ©ciale +6. **SpĂ©cialitĂ© (specialty)**: SpĂ©cialisation dans une compĂ©tence +7. **Historique (background)**: Historique du personnage +8. **Traumatisme (trauma)**: Traumatisme psychologique +9. **Évolution (evolution)**: Évolution du personnage +10. **Rumeur (rumor)**: Information +11. **Cible (target)**: Objectif +12. **Rite (rite)**: Rituel + +### CrĂ©er un item + +1. Dans la fiche du personnage +2. Allez dans l'onglet appropriĂ© (MatĂ©riel, Totem et ajustements, etc.) +3. Cliquez sur l'icĂŽne "+" Ă  cĂŽtĂ© du titre de la section +4. SĂ©lectionnez le type d'item +5. Remplissez les informations + +### Utiliser un item dans le chat + +1. Glissez-dĂ©posez l'item depuis votre fiche vers le chat +2. Ou cliquez sur l'icĂŽne de l'item et sĂ©lectionnez "Post to Chat" +3. Une carte avec les informations de l'item sera affichĂ©e + +### CaractĂ©ristiques des items + +**Tous les items:** +- Description +- RaretĂ© (0-5) +- FiabilitĂ© +- Handicap de raretĂ© +- QuantitĂ© +- Poids +- Traits +- DĂ©gĂąts + +**Armes:** +- PortĂ©e min/max +- DĂ©gĂąts (valeur, type, bonus de vigueur) +- Munitions + +**Protections:** +- Niveau +- Niveau spĂ©cifique +- MobilitĂ© +- Bouclier (oui/non) + +**CapacitĂ©s:** +- Type (personnage, groupe, crĂ©ature, totem) +- Totem +- Niveau +- Seuil d'apprentissage +- Handicap d'apprentissage +- Effets + +--- + +## Gestion des PNJ et CrĂ©atures + +### CrĂ©er un PNJ + +1. Cliquez sur "Create Actor" +2. SĂ©lectionnez "NPC" comme type +3. Donnez un nom au PNJ +4. Configurez les attributs: + - Menace (1-4): Niveau de dangerositĂ© + - ExpĂ©rience (1-4): Niveau d'expĂ©rience + - RĂŽle (1-4): Importance dans le scĂ©nario +5. Ajoutez des compĂ©tences si nĂ©cessaire +6. Ajoutez de l'Ă©quipement + +### CrĂ©er une crĂ©ature + +1. Cliquez sur "Create Actor" +2. SĂ©lectionnez "Creature" comme type +3. Donnez un nom Ă  la crĂ©ature +4. Configurez les attributs: + - Gabarit (1-4): Type de crĂ©ature + - Taille (1-3): Taille physique + - RĂŽle (1-4): Importance dans le scĂ©nario + - Meute (0-3): Taille du groupe + - Modes: Types de scĂ©narios oĂč la crĂ©ature apparaĂźt +5. Ajoutez des compĂ©tences si nĂ©cessaire + +### Menace, ExpĂ©rience et RĂŽle (PNJ) + +Ces trois attributs dĂ©terminent les capacitĂ©s du PNJ: + +**Menace:** +- Mineure (1): Peu dangereuse +- SĂ©rieuse (2): Dangereuse +- Majeure (3): TrĂšs dangereuse +- Mortelle (4): ExtrĂȘmement dangereuse + +**ExpĂ©rience:** +- DĂ©butant (1): Peu expĂ©rimentĂ© +- CompĂ©tent (2): ExpĂ©rimentĂ© +- Expert (3): TrĂšs expĂ©rimentĂ© +- MaĂźtre (4): MaĂźtre dans son domaine + +**RĂŽle:** +- Mineur (1): Personnage secondaire +- Secondaire (2): Personnage important +- Important (3): Personnage principal +- Majeur (4): Antagoniste principal + +### Gabarit, Taille, RĂŽle et Meute (CrĂ©ature) + +**Gabarit:** +- Insecte (1): TrĂšs petit +- Rat (2): Petit +- Chien (3): Moyen +- Ours (4): Grand + +**Taille:** +- Petit (1) +- Moyen (2) +- Grand (3) + +**RĂŽle:** +- Mineur (1): CrĂ©ature secondaire +- Secondaire (2): CrĂ©ature importante +- Important (3): CrĂ©ature principale +- Majeur (4): Boss + +**Meute:** +- Solitaire (0): Agit seul +- Petit groupe (1) +- Groupe (2) +- Grande meute (3) + +**Modes:** +- Survie: Agit dans des scĂ©narios de survie +- Cauchemar: Agit dans des scĂ©narios de cauchemar +- Apocalypse: Agit dans des scĂ©narios d'apocalypse + +--- + +## Astuces et bonnes pratiques + +### Pour les Joueurs + +1. **Choisissez un totem qui correspond Ă  votre style de jeu** + - Humain: Pour les sociaux et les civils + - PrĂ©dateur: Pour les chasseurs et les guerriers + - AdaptĂ©: Pour les polyvalents + +2. **DĂ©finissez un domaine de prĂ©dilection** + - Cela vous donnera des bonus avec votre totem + +3. **Utilisez les spĂ©cialitĂ©s** + - Les spĂ©cialitĂ©s donnent +1D et des rĂ©ussites automatiques + +4. **GĂ©rez vos rĂ©serves** + - Effort: Pour les actions physiques + - Sang-Froid: Pour les actions mentales et les relances + +5. **Utilisez les dĂ©s de totem** + - Ils comptent double en cas de rĂ©ussite + - Vous pouvez utiliser les deux totems simultanĂ©ment + +### Pour les MJ + +1. **CrĂ©ez des groupes pour organiser vos PNJ** + - Les groupes permettent de gĂ©rer plusieurs PNJ ensemble + - Les rencontres dans un groupe sont synchronisĂ©es + +2. **Utilisez les statuts de combat** + - Offensif pour les personnages agressifs + - Actif pour les personnages Ă©quilibrĂ©s + - Passif pour les personnages dĂ©fensifs + +3. **Configurez correctement les PNJ et crĂ©atures** + - Menace/ExpĂ©rience/RĂŽle pour les PNJ + - Gabarit/Taille/RĂŽle/Meute pour les crĂ©atures + +4. **Utilisez les modes pour les crĂ©atures** + - Cela permet de filtrer les crĂ©atures par type de scĂ©nario + +5. **Encouragez l'utilisation des domaines de prĂ©dilection** + - Cela rend le systĂšme de totems plus impactant + +### Pour les dĂ©veloppeurs + +1. **Utilisez les helpers Handlebars** + - De nombreux helpers sont disponibles pour afficher les donnĂ©es + - `skillLevel`, `threatLevel`, etc. + +2. **Respectez les conventions de nommage** + - `vermine-` prĂ©fixe pour les classes CSS + - `VERMINE` namespace pour les configurations + +3. **Utilisez GroupLink pour la synchronisation** + - Ne modifiez pas directement les tableaux de membres/rencontres + - Utilisez les mĂ©thodes de GroupLink + +--- + +## RĂ©solution des problĂšmes + +### ProblĂšmes courants + +1. **Les dĂ©s de totem ne fonctionnent pas** + - VĂ©rifiez que les valeurs des totems sont > 0 + - VĂ©rifiez que la somme des totems ne dĂ©passe pas 5 + +2. **Les bonus de domaine ne s'appliquent pas** + - VĂ©rifiez que vous avez dĂ©fini un domaine de prĂ©dilection + - VĂ©rifiez que votre totem a des domaines configurĂ©s + +3. **Les groupes ne se synchronisent pas** + - VĂ©rifiez que GroupLink est bien initialisĂ© + - VĂ©rifiez que les hooks sont actifs + +4. **Les templates ne s'affichent pas correctement** + - VĂ©rifiez que les templates sont en `.hbs` + - VĂ©rifiez que les rĂ©fĂ©rences sont correctes + +### Contact + +Pour de l'aide ou pour signaler un problĂšme: +- Rejoignez le Discord Vermine: https://discord.gg/qejqmSxr +- Rejoignez le Discord Foundry Vermine: https://discord.gg/FqGHYvXg + +--- + +## Licence + +Vermine2047 System est sous licence MIT. Voir le fichier LICENSE.txt pour plus de dĂ©tails. + +--- + +## Auteurs + +- François-Xavier Guillois +- Rwanoux (Discord: rwanoux) +- Pretre (Discord: pretre) + +--- + +*Guide mis Ă  jour: 2026-06-04* +*Version: 0.1.14* diff --git a/lang/fr.json b/lang/fr.json index 091d47e..1ba342c 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -159,6 +159,28 @@ "heavy_wounds": "Blessure grave", "deadly_wounds": "Blessure mortelle" }, + "choose_ability": "Choisissez une caractĂ©ristique", + "choose_skill": "Choisissez une compĂ©tence", + "none": "Aucun", + "total": "Total", + "bonuses": "Bonus", + "handicap": "Handicap", + "score": "Score", + "totem_dice": "DĂ©s de totem", + "keep_totem": "Garder le totem", + "totem_hint": "Cochez pour utiliser les dĂ©s de totem (double rĂ©ussite possible)", + "error_not_enough_self_control": "Vous n'avez pas assez de Sang-Froid", + "error_select_ability": "Veuillez sĂ©lectionner une caractĂ©ristique", + "error_select_skill": "Veuillez sĂ©lectionner une compĂ©tence", + "needed": "nĂ©cessaire", + "cost": "CoĂ»t", + "learn": "Apprentissage", + "ritual": "Rituel", + "trance": "Transe", + "effect": "Effet", + "types": { + "shield": "Bouclier" + }, "tabs": { "abilities": "CaractĂ©ristiques et compĂ©tences", "totem": "Totem et ajustements", @@ -223,6 +245,7 @@ "abilities": "CapacitĂ©s", "specialties": "SpĂ©cialitĂ©s", "new_specialty": "Nouvelle spĂ©cialitĂ©", + "shield": "Bouclier", "evolution": "Adaptation", "new_evolution": "Nouvelle adaptation", "evolutions": "Adaptations", diff --git a/module/documents/item.mjs b/module/documents/item.mjs index 499a3c5..73db3c5 100644 --- a/module/documents/item.mjs +++ b/module/documents/item.mjs @@ -86,7 +86,7 @@ export class VermineItem extends Item { rollMode: rollMode, flavor: label, }; - mess.content = await renderTemplate(`systems/vermine2047/templates/item/chatCards/${this.type}.html`, { item: this, message: mess }) ?? null; + mess.content = await renderTemplate(`systems/vermine2047/templates/item/chatCards/${this.type}.hbs`, { item: this, message: mess }) ?? null; ChatMessage.create(mess) } diff --git a/module/system/config.mjs b/module/system/config.mjs index f47e558..f0e1486 100644 --- a/module/system/config.mjs +++ b/module/system/config.mjs @@ -68,6 +68,142 @@ VERMINE.PackLevels = { 3: { "attack": 5, "damage": 5, "minorWound": 3, "majorWound": 3, "deadlyWound": 3 } } +/** + * Domains of influence for each totem + * Each totem provides bonus to certain skill categories + */ +VERMINE.totemDomains = { + "human": { + "label": "TOTEMS.human.name", + "domains": ["man", "world"], + "bonus": +1, + "description": "Le totem humain favorise les compĂ©tences liĂ©es Ă  l'humanitĂ© et au monde civilisĂ©" + }, + "predator": { + "label": "TOTEMS.predator.name", + "domains": ["animal", "survival"], + "bonus": +1, + "description": "Le totem prĂ©dateur favorise la chasse et la survie" + }, + "scavenger": { + "label": "TOTEMS.scavenger.name", + "domains": ["tool", "world"], + "bonus": +1, + "description": "Le totem charognard favorise la rĂ©cupĂ©ration et l'utilisation d'outils" + }, + "symbiote": { + "label": "TOTEMS.symbiote.name", + "domains": ["man", "social"], + "bonus": +1, + "description": "Le totem symbiote favorise les interactions sociales" + }, + "parasite": { + "label": "TOTEMS.parasite.name", + "domains": ["animal", "survival"], + "bonus": +1, + "description": "Le totem parasite favorise la discrĂ©tion et la survie" + }, + "builder": { + "label": "TOTEMS.builder.name", + "domains": ["tool", "world"], + "bonus": +1, + "description": "Le totem bĂątisseur favorise la construction et la manipulation" + }, + "horde": { + "label": "TOTEMS.horde.name", + "domains": ["animal", "survival"], + "bonus": +1, + "description": "Le totem horde favorise le combat en groupe" + }, + "hive": { + "label": "TOTEMS.hive.name", + "domains": ["man", "social"], + "bonus": +1, + "description": "Le totem ruche favorise l'organisation collective" + }, + "loner": { + "label": "TOTEMS.loner.name", + "domains": ["survival", "world"], + "bonus": +1, + "description": "Le totem solitaire favorise l'autonomie" + }, + "adapted": { + "label": "TOTEMS.adapted.name", + "domains": ["animal", "survival"], + "bonus": +1, + "description": "Le totem adaptĂ© favorise l'adaptation Ă  l'environnement" + } +} + +/** + * NPC Threat Levels configuration + */ +VERMINE.npcThreatLevels = { + 1: { "label": "THREAT_LEVELS.minor", "attack": 3, "vigor": 1, "minorWound": 1, "majorWound": 1, "deadlyWound": 1 }, + 2: { "label": "THREAT_LEVELS.serious", "attack": 4, "vigor": 2, "minorWound": 2, "majorWound": 1, "deadlyWound": 1 }, + 3: { "label": "THREAT_LEVELS.major", "attack": 5, "vigor": 3, "minorWound": 2, "majorWound": 1, "deadlyWound": 1 }, + 4: { "label": "THREAT_LEVELS.deadly", "attack": 6, "vigor": 4, "minorWound": 2, "majorWound": 2, "deadlyWound": 2 } +} + +/** + * NPC Experience Levels configuration + */ +VERMINE.npcExperienceLevels = { + 1: { "label": "SKILL_LEVELS.beginner", "action": 3, "specialties": 4, "rerolls": 0, "contact": "7" }, + 2: { "label": "SKILL_LEVELS.proficient", "action": 3, "specialties": 5, "rerolls": 0, "contact": "5 ou 7" }, + 3: { "label": "SKILL_LEVELS.expert", "action": 4, "specialties": 6, "rerolls": 1, "contact": "5,7 ou 9" }, + 4: { "label": "SKILL_LEVELS.master", "action": 4, "specialties": 6, "rerolls": 2, "contact": "3,5,7 ou 9" } +} + +/** + * NPC Role Levels configuration + */ +VERMINE.npcRoleLevels = { + 1: { "label": "ROLE_LEVELS.minor", "reaction": 3, "reaction_bonus": 0, "pools": 0, "gear": 9, "gear_hindrance": 0, "protection": 1 }, + 2: { "label": "ROLE_LEVELS.secondary", "reaction": 3, "reaction_bonus": 1, "pools": 1, "gear": 9, "gear_hindrance": 1, "protection": 2 }, + 3: { "label": "ROLE_LEVELS.important", "reaction": 3, "reaction_bonus": 2, "pools": 2, "gear": 9, "gear_hindrance": 2, "protection": 3 }, + 4: { "label": "ROLE_LEVELS.major", "reaction": 4, "reaction_bonus": 2, "pools": 4, "gear": 10, "gear_hindrance": 2, "protection": 3 } +} + +/** + * Creature Pattern Levels configuration + */ +VERMINE.creaturePatternLevels = { + 1: { "label": "PATTERN_LEVELS.insect", "attack": 2, "damage": 0, "minorWound": 0, "majorWound": 0, "deadlyWound": 1 }, + 2: { "label": "PATTERN_LEVELS.rat", "attack": 3, "damage": 1, "minorWound": 0, "majorWound": 1, "deadlyWound": 1 }, + 3: { "label": "PATTERN_LEVELS.dog", "attack": 4, "damage": 3, "minorWound": 1, "majorWound": 1, "deadlyWound": 1 }, + 4: { "label": "PATTERN_LEVELS.bear", "attack": 6, "damage": 6, "minorWound": 2, "majorWound": 2, "deadlyWound": 2 } +} + +/** + * Creature Size Levels configuration + */ +VERMINE.creatureSizeLevels = { + 1: { "attack": 2, "vigor": 1, "minorWound": 0, "majorWound": 0, "deadlyWound": 1 }, + 2: { "attack": 3, "vigor": 2, "minorWound": 0, "majorWound": 1, "deadlyWound": 1 }, + 3: { "attack": 4, "vigor": 3, "minorWound": 1, "majorWound": 1, "deadlyWound": 1 } +} + +/** + * Creature Pack Levels configuration + */ +VERMINE.creaturePackLevels = { + 0: { "attack": 0, "damage": 0, "minorWound": 0, "majorWound": 0, "deadlyWound": 0 }, + 1: { "attack": 1, "damage": 1, "minorWound": 0, "majorWound": 0, "deadlyWound": 1 }, + 2: { "attack": 2, "damage": 2, "minorWound": 2, "majorWound": 2, "deadlyWound": 2 }, + 3: { "attack": 5, "damage": 5, "minorWound": 3, "majorWound": 3, "deadlyWound": 3 } +} + +/** + * Creature Role Levels configuration (same as NPC roles) + */ +VERMINE.creatureRoleLevels = { + 1: { "label": "ROLE_LEVELS.minor", "reaction": 3, "reaction_bonus": 0, "pools": 0, "gear": 9, "gear_hindrance": 0, "protection": 1 }, + 2: { "label": "ROLE_LEVELS.secondary", "reaction": 3, "reaction_bonus": 1, "pools": 1, "gear": 9, "gear_hindrance": 1, "protection": 2 }, + 3: { "label": "ROLE_LEVELS.important", "reaction": 3, "reaction_bonus": 2, "pools": 2, "gear": 9, "gear_hindrance": 2, "protection": 3 }, + 4: { "label": "ROLE_LEVELS.major", "reaction": 4, "reaction_bonus": 2, "pools": 4, "gear": 10, "gear_hindrance": 2, "protection": 3 } +} + VERMINE.abilityCategories = { "physical": { "label": "VERMINE.ability_category.physical" diff --git a/module/system/dialogs/rollDialog.mjs b/module/system/dialogs/rollDialog.mjs index 72653d3..5457ac5 100644 --- a/module/system/dialogs/rollDialog.mjs +++ b/module/system/dialogs/rollDialog.mjs @@ -110,13 +110,19 @@ export default class RollDialog extends Dialog { async activateListeners(html) { // Activate event listeners from the superclass super.activateListeners(html); + + // Initialize UI elements + this._html = html; + // Retrieve roll data and set up event listeners await this.getRollData(); - let rollInputs = html.find('[data-roll'); + + // Set up event listeners for all roll-related inputs + let rollInputs = html.find('[data-roll]'); for (let inp of rollInputs) { - // Add event listener for roll input changes - inp.addEventListener('change', await this.getRollData.bind(this)) + inp.addEventListener('change', this._onRollInputChange.bind(this)); }; + this.displaySpecialties(); let selectAbil = html.find('#ability')[0]; @@ -126,6 +132,19 @@ export default class RollDialog extends Dialog { let selfControl = html.find('#self_control')[0] // Add event listener for self control changes selfControl.addEventListener('change', this._onChangeSelfControl.bind(this)); + + // Set up difficulty change listener + html.find('#difficulty')[0].addEventListener('change', this._onDifficultyChange.bind(this)); + + // Set up handicap change listener + html.find('#handicap')[0].addEventListener('change', this._onHandicapChange.bind(this)); + + // Set up totem checkbox listeners + html.find('#human-totem')[0]?.addEventListener('change', this._onTotemChange.bind(this)); + html.find('#adapted-totem')[0]?.addEventListener('change', this._onTotemChange.bind(this)); + + // Initial update of all UI elements + this._updateUI(); }; @@ -134,7 +153,6 @@ export default class RollDialog extends Dialog { * @param {Event} ev - The event triggering the roll data retrieval. */ async getRollData(ev) { - console.log(this) // Calculate and store the roll data this.rollData = { actor: this.data.actor, @@ -146,10 +164,200 @@ export default class RollDialog extends Dialog { rollLabel: this.getLabel(), totems: this.getTotems(), self_control: this.getSelfControl(), - max_effort: this.getMaxEffort() + max_effort: this.getMaxEffort(), + keepTotem: this.getKeepTotem(), + skillCategory: this.getSkillCategory() } this.displaySpecialties(); + this._updateUI(); }; + + /** + * Gets the selected skill category + * @returns {string|null} - The skill category + */ + getSkillCategory() { + const html = this.element[0]; + const skillSelect = html.querySelector('#skill'); + if (skillSelect && skillSelect.selectedIndex > 0) { + const selectedOption = skillSelect.options[skillSelect.selectedIndex]; + return selectedOption.dataset.category || null; + } + return null; + } + + /** + * Gets the selected skill level + * @returns {number|null} - The skill level + */ + getSkillLevel() { + const html = this.element[0]; + const skillSelect = html.querySelector('#skill'); + if (skillSelect && skillSelect.selectedIndex > 0) { + const selectedOption = skillSelect.options[skillSelect.selectedIndex]; + return parseInt(selectedOption.value) || null; + } + return null; + } + + /** + * Checks if a specialty is selected + * @returns {boolean} - True if a specialty is selected + */ + hasSpecialtySelected() { + const html = this.element[0]; + const specialtyRadio = html.querySelector('input[name="usingSpecialization"]:checked'); + return specialtyRadio && specialtyRadio.value !== 'aucune'; + } + + /** + * Handles changes to roll inputs and updates UI + * @param {Event} ev - The change event + */ + async _onRollInputChange(ev) { + await this.getRollData(); + } + + /** + * Updates all UI elements based on current roll data + */ + _updateUI() { + if (!this._html) return; + + const html = this._html[0]; + + // Update total dice pool display + const totalDice = this.getDicePool(); + const totalEl = html.querySelector('#dice-pool-total'); + if (totalEl) { + totalEl.textContent = `${totalDice}D`; + } + + // Update bonus count + const bonusCount = this._calculateBonusCount(); + const bonusEl = html.querySelector('#total-bonus'); + if (bonusEl) { + bonusEl.textContent = bonusCount; + } + + // Update difficulty display + const difficultyEl = html.querySelector('#current-difficulty'); + const difficultySelect = html.querySelector('#difficulty'); + if (difficultyEl && difficultySelect) { + const selectedIndex = difficultySelect.selectedIndex; + const diffValue = parseInt(difficultySelect.options[selectedIndex].value); + const diffLabel = difficultySelect.options[selectedIndex].text.split(' ')[0]; + difficultyEl.textContent = `${diffLabel} (${diffValue})`; + } + + // Update handicap display + const handicapEl = html.querySelector('#current-handicap'); + const handicapSelect = html.querySelector('#handicap'); + if (handicapEl && handicapSelect) { + const selectedIndex = handicapSelect.selectedIndex; + handicapEl.textContent = handicapSelect.options[selectedIndex].text; + } + + // Update ability score display + const abilSelect = html.querySelector('#ability'); + const abilScoreEl = html.querySelector('#abilityScoreValue'); + if (abilSelect && abilScoreEl) { + const selectedIndex = abilSelect.selectedIndex; + if (selectedIndex > 0) { + abilScoreEl.textContent = abilSelect.options[selectedIndex].value; + } else { + abilScoreEl.textContent = '0'; + } + } + + // Update specialty display + const specialtyRadios = html.querySelectorAll('input[name="usingSpecialization"]:checked'); + const currentSpecEl = html.querySelector('.current-specialty'); + if (currentSpecEl && specialtyRadios.length > 0) { + const checkedRadio = specialtyRadios[0]; + currentSpecEl.textContent = checkedRadio.value === 'aucune' ? game.i18n.localize('VERMINE.none') : checkedRadio.value; + } + } + + /** + * Calculates the bonus count for display + * @returns {number} - Total bonus dice + */ + _calculateBonusCount() { + let bonus = 0; + + // Help bonus + if (this._html.find('#helped')[0]?.checked) { + bonus += 1; + } + + // Group bonus + const groupValue = parseInt(this._html.find('#group')[0]?.value) || 0; + bonus += groupValue; + + // Self control bonus + const selfControlValue = parseInt(this._html.find('#self_control')[0]?.value) || 0; + bonus += selfControlValue; + + // Tools bonus + const toolsChecked = this._html.find('input[name="usingTools"]:checked')[0]?.value !== '0'; + if (toolsChecked) { + bonus += 1; + } + + // Totems bonus + if (this._html.find('#human-totem')[0]?.checked) { + bonus += parseInt(this.data.actor.system.adaptation.totems.human.value) || 0; + } + if (this._html.find('#adapted-totem')[0]?.checked) { + bonus += parseInt(this.data.actor.system.adaptation.totems.adapted.value) || 0; + } + + // Specialty bonus + const specialtyChecked = this._html.find('input[name="usingSpecialization"]:checked')[0]?.value !== 'aucune'; + if (specialtyChecked) { + bonus += 1; + } + + return bonus; + } + + /** + * Handles difficulty change + * @param {Event} ev - The change event + */ + _onDifficultyChange(ev) { + this._updateUI(); + } + + /** + * Handles handicap change + * @param {Event} ev - The change event + */ + _onHandicapChange(ev) { + this._updateUI(); + } + + /** + * Handles totem checkbox change + * @param {Event} ev - The change event + */ + _onTotemChange(ev) { + this._updateUI(); + } + + /** + * Gets the selected totem to keep (for dual totem rolls) + * @returns {string|null} - The totem to keep ('human', 'adapted', or null) + */ + getKeepTotem() { + const keepTotemSelect = this._html?.find('#keep-totem-select')[0]; + if (keepTotemSelect) { + return keepTotemSelect.value; + } + // Default to null (both totems used) + return null; + } /** @@ -300,7 +508,7 @@ export default class RollDialog extends Dialog { // Check if the actor has enough self control if (this.rollData.actor.system.attributes.self_control.value < this.rollData.self_control) { // Display a warning message if self control is insufficient - ui.notifications.warn('vous navez pas assez de sang-froid'); + ui.notifications.warn(game.i18n.localize('VERMINE.error_not_enough_self_control')); // Re-render the dialog this.render(true); return false; // Exit the function if self control is insufficient @@ -308,9 +516,9 @@ export default class RollDialog extends Dialog { } let caracName = this.element[0].querySelector('[name="ability"]')?.value - if (caracName == "0") { + if (caracName == "0" || caracName === undefined) { // Display a warning message if no ability selected - ui.notifications.warn('selectionnez une caractĂ©ristique.'); + ui.notifications.warn(game.i18n.localize('VERMINE.error_select_ability')); // Re-render the dialog this.render(true); return false; // Exit the function if no ability @@ -318,10 +526,17 @@ export default class RollDialog extends Dialog { // Deduct self control points if necessary if (this.rollData.self_control > 0) { // Update the actor's self control value - await this.rollData.actor.update({ "system.attributes.self_control.value": this.rollData.actor.system.attributes.self_control.value - this.rollData.self_control }); + await this.rollData.actor.update({ + "system.attributes.self_control.value": + this.rollData.actor.system.attributes.self_control.value - this.rollData.self_control + }); } // Perform the dice roll using VermineUtils - return VermineUtils.roll({ ...this.rollData }); + return VermineUtils.roll({ + ...this.rollData, + skillLevel: this.getSkillLevel(), + hasSpecialty: this.hasSpecialtySelected() + }); } } \ No newline at end of file diff --git a/module/system/group-link.mjs b/module/system/group-link.mjs new file mode 100644 index 0000000..de2c875 --- /dev/null +++ b/module/system/group-link.mjs @@ -0,0 +1,414 @@ +/** + * GroupLink - Gestion des liens entre acteurs et groupes + * + * Cette classe permet de gĂ©rer les relations bidirectionnelles entre : + * - Les personnages (characters) et leurs groupes/rencontres + * - Les groupes (groups) et leurs membres/rencontres + * + * @author Vermine2047 System + */ + +export class GroupLink { + + /** + * Met Ă  jour les groupes dans tous les personnages membres + * quand un groupe est modifiĂ© + * @param {Actor} group - Le groupe modifiĂ© + * @param {Object} changes - Les changements effectuĂ©s + */ + static async updateActorsOnGroupChange(group, changes) { + if (group.type !== 'group') return; + + const groupData = group.system; + const members = groupData.members || []; + const encounters = groupData.encounters || []; + + // Mettre Ă  jour les membres du groupe + if (changes.members !== undefined || changes.encounters !== undefined) { + await this._updateMembersInGroup(group, members); + await this._updateEncountersInGroup(group, encounters); + } + + // Synchroniser les donnĂ©es dans les acteurs membres + await this._syncGroupToMembers(group, members); + await this._syncGroupToEncounters(group, encounters); + } + + /** + * Met Ă  jour le groupe quand un personnage est modifiĂ© + * @param {Actor} actor - L'acteur modifiĂ© + * @param {Object} changes - Les changements effectuĂ©s + */ + static async updateGroupsOnActorChange(actor, changes) { + if (actor.type === 'group') return; + + const actorData = actor.system; + const encounters = actorData.encounters || []; + + // Si les rencontres de l'acteur ont changĂ© + if (changes.encounters !== undefined) { + // Pour chaque groupe dans les rencontres, mettre Ă  jour les membres + for (const groupId of encounters) { + const group = game.actors.get(groupId); + if (group && group.type === 'group') { + await this._updateActorInGroupMembers(group, actor.id); + } + } + } + } + + /** + * Synchronise les donnĂ©es du groupe vers les acteurs membres + * @param {Actor} group - Le groupe + * @param {Array} memberIds - Liste des IDs des membres + */ + static async _syncGroupToMembers(group, memberIds) { + for (const memberId of memberIds) { + const member = game.actors.get(memberId); + if (member) { + // VĂ©rifier que le groupe est dans les rencontres du membre + const memberEncounters = member.system.encounters || []; + if (!memberEncounters.includes(group.id)) { + // Ajouter le groupe aux rencontres du membre + memberEncounters.push(group.id); + await member.update({ + 'system.encounters': memberEncounters + }); + } + } + } + } + + /** + * Synchronise les donnĂ©es du groupe vers les acteurs rencontres + * @param {Actor} group - Le groupe + * @param {Array} encounterIds - Liste des IDs des rencontres + */ + static async _syncGroupToEncounters(group, encounterIds) { + for (const encounterId of encounterIds) { + const encounter = game.actors.get(encounterId); + if (encounter) { + // VĂ©rifier que le groupe est dans les rencontres de l'acteur + const encounterGroups = encounter.system.encounters || []; + if (!encounterGroups.includes(group.id)) { + encounterGroups.push(group.id); + await encounter.update({ + 'system.encounters': encounterGroups + }); + } + } + } + } + + /** + * Met Ă  jour les membres dans un groupe + * @param {Actor} group - Le groupe + * @param {Array} memberIds - Liste des IDs des membres + */ + static async _updateMembersInGroup(group, memberIds) { + const currentMembers = group.system.members || []; + + // Retirer les membres qui ne sont plus dans la liste + const membersToRemove = currentMembers.filter(id => !memberIds.includes(id)); + const membersToAdd = memberIds.filter(id => !currentMembers.includes(id)); + + // Mettre Ă  jour les acteurs qui ont Ă©tĂ© retirĂ©s + for (const memberId of membersToRemove) { + const member = game.actors.get(memberId); + if (member) { + const memberEncounters = (member.system.encounters || []).filter(id => id !== group.id); + await member.update({ + 'system.encounters': memberEncounters + }); + } + } + + // Mettre Ă  jour les nouveaux membres + for (const memberId of membersToAdd) { + const member = game.actors.get(memberId); + if (member) { + const memberEncounters = member.system.encounters || []; + if (!memberEncounters.includes(group.id)) { + memberEncounters.push(group.id); + await member.update({ + 'system.encounters': memberEncounters + }); + } + } + } + } + + /** + * Met Ă  jour les rencontres dans un groupe + * @param {Actor} group - Le groupe + * @param {Array} encounterIds - Liste des IDs des rencontres + */ + static async _updateEncountersInGroup(group, encounterIds) { + const currentEncounters = group.system.encounters || []; + + // Retirer les rencontres qui ne sont plus dans la liste + const encountersToRemove = currentEncounters.filter(id => !encounterIds.includes(id)); + const encountersToAdd = encounterIds.filter(id => !currentEncounters.includes(id)); + + // Mettre Ă  jour les acteurs qui ont Ă©tĂ© retirĂ©s des rencontres + for (const encounterId of encountersToRemove) { + const encounter = game.actors.get(encounterId); + if (encounter) { + const encounterGroups = (encounter.system.encounters || []).filter(id => id !== group.id); + await encounter.update({ + 'system.encounters': encounterGroups + }); + } + } + + // Mettre Ă  jour les nouvelles rencontres + for (const encounterId of encountersToAdd) { + const encounter = game.actors.get(encounterId); + if (encounter) { + const encounterGroups = encounter.system.encounters || []; + if (!encounterGroups.includes(group.id)) { + encounterGroups.push(group.id); + await encounter.update({ + 'system.encounters': encounterGroups + }); + } + } + } + } + + /** + * Met Ă  jour un acteur dans les membres d'un groupe + * @param {Actor} group - Le groupe + * @param {string} actorId - L'ID de l'acteur + */ + static async _updateActorInGroupMembers(group, actorId) { + const groupMembers = group.system.members || []; + if (!groupMembers.includes(actorId)) { + groupMembers.push(actorId); + await group.update({ + 'system.members': groupMembers + }); + } + } + + /** + * Met Ă  jour un acteur dans les rencontres d'un groupe + * @param {Actor} group - Le groupe + * @param {string} actorId - L'ID de l'acteur + */ + static async _updateActorInGroupEncounters(group, actorId) { + const groupEncounters = group.system.encounters || []; + if (!groupEncounters.includes(actorId)) { + groupEncounters.push(actorId); + await group.update({ + 'system.encounters': groupEncounters + }); + } + } + + /** + * Retourne les objets Actor pour une liste d'IDs + * @param {Array} actorIds - Liste d'IDs d'acteurs + * @returns {Array} - Liste d'objets Actor + */ + static getActorObjects(actorIds) { + return actorIds + .map(id => game.actors.get(id)) + .filter(actor => actor !== undefined); + } + + /** + * Retourne les objets Actor pour les membres d'un groupe + * @param {Actor} group - Le groupe + * @returns {Array} - Liste d'objets Actor + */ + static getGroupMembers(group) { + const memberIds = group.system.members || []; + return this.getActorObjects(memberIds); + } + + /** + * Retourne les objets Actor pour les rencontres d'un groupe + * @param {Actor} group - Le groupe + * @returns {Array} - Liste d'objets Actor + */ + static getGroupEncounters(group) { + const encounterIds = group.system.encounters || []; + return this.getActorObjects(encounterIds); + } + + /** + * Retourne les groupes auxquels un acteur appartient + * @param {Actor} actor - L'acteur + * @returns {Array} - Liste d'objets Actor (groupes) + */ + static getActorGroups(actor) { + const groupIds = actor.system.encounters || []; + return this.getActorObjects(groupIds).filter(a => a.type === 'group'); + } + + /** + * Retourne les rencontres (PNJ/CrĂ©atures) d'un acteur + * @param {Actor} actor - L'acteur + * @returns {Array} - Liste d'objets Actor (PNJ/CrĂ©atures) + */ + static getActorEncounters(actor) { + const encounterIds = actor.system.encounters || []; + return this.getActorObjects(encounterIds).filter(a => a.type !== 'group'); + } + + /** + * Supprime un acteur de tous ses groupes + * @param {string} actorId - L'ID de l'acteur Ă  supprimer + */ + static async removeActorFromAllGroups(actorId) { + const allGroups = game.actors.filter(a => a.type === 'group'); + + for (const group of allGroups) { + const members = group.system.members || []; + const encounters = group.system.encounters || []; + + let needsUpdate = false; + const newMembers = members.filter(id => id !== actorId); + const newEncounters = encounters.filter(id => id !== actorId); + + if (newMembers.length !== members.length || newEncounters.length !== encounters.length) { + needsUpdate = true; + } + + if (needsUpdate) { + await group.update({ + 'system.members': newMembers, + 'system.encounters': newEncounters + }); + } + } + + // Supprimer les groupes des rencontres de l'acteur + const actor = game.actors.get(actorId); + if (actor) { + await actor.update({ + 'system.encounters': [] + }); + } + } + + /** + * Ajoute un acteur Ă  un groupe + * @param {string} actorId - L'ID de l'acteur + * @param {string} groupId - L'ID du groupe + */ + static async addActorToGroup(actorId, groupId) { + const actor = game.actors.get(actorId); + const group = game.actors.get(groupId); + + if (!actor || !group || group.type !== 'group') return; + + // Ajouter l'acteur aux membres du groupe + const groupMembers = group.system.members || []; + if (!groupMembers.includes(actorId)) { + groupMembers.push(actorId); + await group.update({ + 'system.members': groupMembers + }); + } + + // Ajouter le groupe aux rencontres de l'acteur + const actorEncounters = actor.system.encounters || []; + if (!actorEncounters.includes(groupId)) { + actorEncounters.push(groupId); + await actor.update({ + 'system.encounters': actorEncounters + }); + } + } + + /** + * Retire un acteur d'un groupe + * @param {string} actorId - L'ID de l'acteur + * @param {string} groupId - L'ID du groupe + */ + static async removeActorFromGroup(actorId, groupId) { + const actor = game.actors.get(actorId); + const group = game.actors.get(groupId); + + if (!actor || !group || group.type !== 'group') return; + + // Retirer l'acteur des membres du groupe + const groupMembers = (group.system.members || []).filter(id => id !== actorId); + await group.update({ + 'system.members': groupMembers + }); + + // Retirer le groupe des rencontres de l'acteur + const actorEncounters = (actor.system.encounters || []).filter(id => id !== groupId); + await actor.update({ + 'system.encounters': actorEncounters + }); + } + + /** + * Initialise les hooks pour la synchronisation automatique + */ + static registerHooks() { + // Hook sur la mise Ă  jour d'un acteur + Hooks.on('updateActor', async (actor, changes, options, userId) => { + if (!game.user.isGM && userId !== game.userId) return; + + // Si c'est un groupe qui est mis Ă  jour + if (actor.type === 'group') { + await this.updateActorsOnGroupChange(actor, changes); + } + // Si c'est un autre acteur qui est mis Ă  jour + else { + await this.updateGroupsOnActorChange(actor, changes); + } + }); + + // Hook sur la crĂ©ation d'un acteur + Hooks.on('createActor', async (actor, options, userId) => { + if (!game.user.isGM && userId !== game.userId) return; + + // Si un personnage est créé, vĂ©rifier qu'il n'a pas de groupes invalides + if (actor.type !== 'group') { + const encounters = actor.system.encounters || []; + for (const groupId of encounters) { + const group = game.actors.get(groupId); + if (!group) { + // Nettoyer les rĂ©fĂ©rences invalides + await actor.update({ + 'system.encounters': encounters.filter(id => game.actors.get(id)) + }); + } + } + } + }); + + // Hook sur la suppression d'un acteur + Hooks.on('deleteActor', async (actor, options, userId) => { + if (!game.user.isGM && userId !== game.userId) return; + + if (actor.type === 'group') { + // Si un groupe est supprimĂ©, nettoyer les rĂ©fĂ©rences dans les acteurs + const memberIds = actor.system.members || []; + const encounterIds = actor.system.encounters || []; + + for (const id of [...memberIds, ...encounterIds]) { + const a = game.actors.get(id); + if (a) { + const encounters = (a.system.encounters || []).filter(eid => eid !== actor.id); + await a.update({ + 'system.encounters': encounters + }); + } + } + } else { + // Si un acteur est supprimĂ©, le retirer de tous les groupes + await this.removeActorFromAllGroups(actor.id); + } + }); + } +} + +// Exporter pour utilisation globale +export default GroupLink; diff --git a/module/system/handlebars-manager.mjs b/module/system/handlebars-manager.mjs index fc5a584..56467b7 100644 --- a/module/system/handlebars-manager.mjs +++ b/module/system/handlebars-manager.mjs @@ -204,6 +204,90 @@ export const registerHandlebarsHelpers = function () { } }); + // return npc threat level information + Handlebars.registerHelper('npcThreatLevel', function (property, level, options) { + if (level < 1 || level > 4) + return ""; + let levelData = CONFIG.VERMINE.npcThreatLevels[level]; + if (property == 'label') { + return (levelData !== undefined) ? game.i18n.localize(levelData[property]) : ""; + } else { + return (levelData !== undefined) ? levelData[property] : ""; + } + }); + + // return npc experience level information + Handlebars.registerHelper('npcExperienceLevel', function (property, level, options) { + if (level < 1 || level > 4) + return ""; + let levelData = CONFIG.VERMINE.npcExperienceLevels[level]; + if (property == 'label') { + return (levelData !== undefined) ? game.i18n.localize(levelData[property]) : ""; + } else { + return (levelData !== undefined) ? levelData[property] : ""; + } + }); + + // return npc role level information + Handlebars.registerHelper('npcRoleLevel', function (property, level, options) { + if (level < 1 || level > 4) + return ""; + let levelData = CONFIG.VERMINE.npcRoleLevels[level]; + if (property == 'label') { + return (levelData !== undefined) ? game.i18n.localize(levelData[property]) : ""; + } else { + return (levelData !== undefined) ? levelData[property] : ""; + } + }); + + // return creature pattern level information + Handlebars.registerHelper('creaturePatternLevel', function (property, level, options) { + if (level < 1 || level > 4) + return ""; + let levelData = CONFIG.VERMINE.creaturePatternLevels[level]; + if (property == 'label') { + return (levelData !== undefined) ? game.i18n.localize(levelData[property]) : ""; + } else { + return (levelData !== undefined) ? levelData[property] : ""; + } + }); + + // return creature size level information + Handlebars.registerHelper('creatureSizeLevel', function (property, level, options) { + if (level < 1 || level > 3) + return ""; + let levelData = CONFIG.VERMINE.creatureSizeLevels[level]; + if (property == 'label') { + return (levelData !== undefined) ? game.i18n.localize(levelData[property]) : ""; + } else { + return (levelData !== undefined) ? levelData[property] : ""; + } + }); + + // return creature role level information + Handlebars.registerHelper('creatureRoleLevel', function (property, level, options) { + if (level < 1 || level > 4) + return ""; + let levelData = CONFIG.VERMINE.creatureRoleLevels[level]; + if (property == 'label') { + return (levelData !== undefined) ? game.i18n.localize(levelData[property]) : ""; + } else { + return (levelData !== undefined) ? levelData[property] : ""; + } + }); + + // return creature pack level information + Handlebars.registerHelper('creaturePackLevel', function (property, level, options) { + if (level < 0 || level > 3) + return ""; + let levelData = CONFIG.VERMINE.creaturePackLevels[level]; + if (property == 'label') { + return (levelData !== undefined) ? game.i18n.localize(levelData[property]) : ""; + } else { + return (levelData !== undefined) ? levelData[property] : ""; + } + }); + // return skill level information Handlebars.registerHelper('skillLevel', function (property, level, options) { diff --git a/module/system/roll.mjs b/module/system/roll.mjs index 963171e..db1a0b8 100644 --- a/module/system/roll.mjs +++ b/module/system/roll.mjs @@ -2,34 +2,97 @@ export class VermineUtils { /** * MĂ©thode pour effectuer un jet de dĂ©s avec diffĂ©rentes options * @param {Object} options - Les options du jet de dĂ©s + * @param {Actor} options.actor - L'acteur qui lance les dĂ©s + * @param {number} options.NoD - Nombre de dĂ©s de base + * @param {number} [options.Reroll=0] - Nombre de relances autorisĂ©es + * @param {number} [options.difficulty=7] - DifficultĂ© du jet + * @param {number} [options.self_control=0] - Sang-froid utilisĂ© + * @param {string} [options.rollLabel="jet custom"] - LibellĂ© du jet + * @param {Object} [options.totems={}] - Totems utilisĂ©s {human: false, adapted: false} + * @param {number} [options.max_effort=0] - Effort maximum + * @param {string} [options.skillCategory=null] - CatĂ©gorie de compĂ©tence pour les bonus de domaine + * @param {string} [options.keepTotem=null] - Totem Ă  garder ('human' ou 'adapted') + * @param {number} [options.skillLevel=null] - Niveau de la compĂ©tence pour les rĂ©ussites automatiques + * @param {boolean} [options.hasSpecialty=false] - Si une spĂ©cialitĂ© est utilisĂ©e * @returns {Roll} - Le rĂ©sultat du jet de dĂ©s */ - static async roll({ actor, NoD, Reroll = 0, difficulty = 7, self_control = 0, rollLabel = "jet custom", totems = { human: false, adapted: false }, max_effort = 0 }) { + static async roll({ actor, NoD, Reroll = 0, difficulty = 7, self_control = 0, rollLabel = "jet custom", totems = { human: false, adapted: false }, max_effort = 0, skillCategory = null, keepTotem = null, skillLevel = null, hasSpecialty = false }) { // DĂ©claration des variables let formula = ""; let modFormula = null; + let totemBonus = { human: 0, adapted: 0 }; + + // Calculer les bonus/malus par domaine de totem + if (skillCategory) { + totemBonus = this._calculateTotemDomainBonuses(skillCategory, actor); + } + + // Appliquer les rĂ©ussites automatiques et seuils auto + let autoSuccesses = 0; + let adjustedDifficulty = difficulty; + + if (skillLevel !== null && skillLevel !== undefined) { + // Calculer les rĂ©ussites automatiques + autoSuccesses = this._calculateAutoSuccesses(skillLevel, hasSpecialty); + + // Appliquer le seuil automatique si nĂ©cessaire + const autoThreshold = this._getAutoThreshold(skillLevel); + if (autoThreshold !== null) { + adjustedDifficulty = autoThreshold; + } + } // VĂ©rification des totems humains if (totems.human) { NoD--; - modFormula = "(1D10cs>=" + difficulty + `[human_${game.user.name}]*2)`; - + const humanDifficulty = skillLevel !== null ? Math.max(adjustedDifficulty, difficulty) : adjustedDifficulty; + const humanFormula = "(1D10cs>=" + humanDifficulty + `[human_${game.user.name}]*2)`; + + // Appliquer bonus/malus de domaine + if (totemBonus.human !== 0) { + // Si bonus, ajouter un dĂ© supplĂ©mentaire, si malus, rĂ©duire le pool + NoD += totemBonus.human; + } + + modFormula = humanFormula; } + // VĂ©rification des totems adaptĂ©s if (totems.adapted) { NoD--; + const adaptedDifficulty = skillLevel !== null ? Math.max(adjustedDifficulty, difficulty) : adjustedDifficulty; + const adaptedFormula = "(1D10cs>=" + adaptedDifficulty + `[adapted_${game.user.name}]*2)`; + + // Appliquer bonus/malus de domaine + if (totemBonus.adapted !== 0) { + NoD += totemBonus.adapted; + } + // Construction de la formule modifiĂ©e if (modFormula != null) { - modFormula = modFormula + "+(1D10cs>=" + difficulty + `[adapted_${game.user.name}]*2)`; + modFormula = modFormula + "+" + adaptedFormula; } else { - modFormula = "(1D10cs>=" + difficulty + `[adapted_${game.user.name}]*2)`; + modFormula = adaptedFormula; } - }; + // Gestion du choix de totem Ă  garder (si les deux sont activĂ©s) + if (totems.human && totems.adapted && keepTotem) { + // Si on veut garder un seul totem, ne pas doubler le bonus + if (keepTotem === 'human' && totems.adapted) { + // Retirer le totem adaptĂ© du calcul + modFormula = "(1D10cs>=" + adjustedDifficulty + `[human_${game.user.name}]*2)`; + NoD++; // On avait dĂ©crĂ©mentĂ© pour adapted, on annule + } else if (keepTotem === 'adapted' && totems.human) { + // Retirer le totem humain du calcul + modFormula = "(1D10cs>=" + adjustedDifficulty + `[adapted_${game.user.name}]*2)`; + NoD++; // On avait dĂ©crĂ©mentĂ© pour human, on annule + } + } + // Construction de la formule de base let baseFormula = '' + NoD + "d10"; - baseFormula += (difficulty != undefined) ? "cs>=" + difficulty : "cs>=7"; + baseFormula += (adjustedDifficulty != undefined) ? "cs>=" + adjustedDifficulty : "cs>=7"; baseFormula += `[regular_${game.user.name}]` // Construction de la formule finale @@ -39,14 +102,129 @@ export class VermineUtils { // CrĂ©ation du jet de dĂ©s let roll = new Roll(formula, actor.getRollData()); + + // Stocker les mĂ©tadonnĂ©es du roll pour l'affichage + roll.vermineData = { + totemsUsed: { ...totems }, + keepTotem: keepTotem, + difficulty: adjustedDifficulty, + originalDifficulty: difficulty, + skillCategory: skillCategory, + skillLevel: skillLevel, + hasSpecialty: hasSpecialty, + autoSuccesses: autoSuccesses, + totemBonuses: { ...totemBonus }, + baseNoD: NoD, + rerolls: Reroll, + selfControl: self_control + }; + //effectuer le lancĂ© await roll.evaluate(); //afficher le lancer 3d await VermineUtils.showDiceSoNice(roll); // afficher le rĂ©sultat dans le chat - VermineUtils.diplayChatRoll(roll, ...arguments); + VermineUtils.diplayChatRoll(roll, { actor, NoD, Reroll, difficulty, self_control, rollLabel, totems, max_effort, skillCategory, keepTotem, skillLevel, hasSpecialty }); return roll; } + + /** + * Calcule les bonus/malus par domaine de totem + * @param {string} skillCategory - CatĂ©gorie de la compĂ©tence + * @param {Actor} actor - L'acteur + * @returns {Object} - Bonus pour chaque totem {human: number, adapted: number} + */ + static _calculateTotemDomainBonuses(skillCategory, actor) { + const bonuses = { human: 0, adapted: 0 }; + + if (!CONFIG.VERMINE?.totemDomains || !actor?.system?.identity?.totem) { + return bonuses; + } + + const actorTotem = actor.system.identity.totem; + const totemConfig = CONFIG.VERMINE.totemDomains[actorTotem]; + + if (!totemConfig || !totemConfig.domains) { + return bonuses; + } + + // VĂ©rifier si la catĂ©gorie de compĂ©tence est dans les domaines du totem + const preferredCategory = actor.system.skill_categories?.preferred; + + // Bonus pour le totem de l'acteur + if (preferredCategory && totemConfig.domains.includes(preferredCategory)) { + // Le domaine de prĂ©dilection est dans les domaines du totem + bonuses[actorTotem] = totemConfig.bonus || 1; + } + + // Malus pour le totem opposĂ© + const oppositeTotem = CONFIG.VERMINE.totem_opposites?.[actorTotem]; + if (oppositeTotem && preferredCategory) { + const oppositeConfig = CONFIG.VERMINE.totemDomains[oppositeTotem]; + if (oppositeConfig?.domains?.includes(preferredCategory)) { + bonuses[oppositeTotem] = -(oppositeConfig.bonus || 1); + } + } + + return bonuses; + } + + /** + * Calcule les rĂ©ussites automatiques basĂ©es sur la maĂźtrise de la compĂ©tence + * @param {number} skillLevel - Niveau de la compĂ©tence (0-5) + * @param {boolean} hasSpecialty - Si une spĂ©cialitĂ© est utilisĂ©e + * @returns {number} - Nombre de rĂ©ussites automatiques + */ + static _calculateAutoSuccesses(skillLevel, hasSpecialty = false) { + // Selon les rĂšgles de Vermine2047, les rĂ©ussites automatiques sont basĂ©es sur le niveau de maĂźtrise + // Niveau 0 (IncompĂ©tent): 0 rĂ©ussite automatique + // Niveau 1 (DĂ©butant): 0 rĂ©ussite automatique + // Niveau 2 (CompĂ©tent): 1 rĂ©ussite automatique si spĂ©cialitĂ© utilisĂ©e + // Niveau 3 (Expert): 1 rĂ©ussite automatique + // Niveau 4 (MaĂźtre): 1 rĂ©ussite automatique + 1 si spĂ©cialitĂ© utilisĂ©e + // Niveau 5 (LĂ©gende): 2 rĂ©ussites automatiques + + if (!skillLevel) return 0; + + let autoSuccesses = 0; + + switch (skillLevel) { + case 2: // CompĂ©tent + if (hasSpecialty) autoSuccesses = 1; + break; + case 3: // Expert + autoSuccesses = 1; + break; + case 4: // MaĂźtre + autoSuccesses = 1; + if (hasSpecialty) autoSuccesses += 1; + break; + case 5: // LĂ©gende + autoSuccesses = 2; + break; + default: + autoSuccesses = 0; + } + + return autoSuccesses; + } + + /** + * DĂ©termine le seuil automatique si la compĂ©tence n'est pas maĂźtrisĂ©e + * @param {number} skillLevel - Niveau de la compĂ©tence + * @returns {number|null} - Seuil automatique ou null si la compĂ©tence est maĂźtrisĂ©e + */ + static _getAutoThreshold(skillLevel) { + // Si la compĂ©tence n'est pas maĂźtrisĂ©e (niveau 0 ou 1), utiliser un seuil par dĂ©faut + // Niveau 0 (IncompĂ©tent): seuil = 9 (trĂšs difficile) + // Niveau 1 (DĂ©butant): seuil = 7 (difficile) + // Niveau >= 2: null (utiliser le seuil normal) + + if (skillLevel === 0) return 9; // TrĂšs difficile + if (skillLevel === 1) return 7; // Difficile + + return null; // Utiliser le seuil normal + } /** * MĂ©thode pour gĂ©rer les Ă©vĂ©nements de relance de dĂ©s diff --git a/module/vermine2047.mjs b/module/vermine2047.mjs index f9f9ed4..c0ad2b6 100644 --- a/module/vermine2047.mjs +++ b/module/vermine2047.mjs @@ -1,5 +1,6 @@ import { registerHooks } from "./system/hooks.mjs"; import { registerSettings } from "./system/settings.mjs"; +import { GroupLink } from "./system/group-link.mjs"; // Import document classes. import { VermineActor } from "./documents/actor.mjs"; @@ -31,8 +32,12 @@ Hooks.once('init', async function () { VermineActor, VermineItem, VermineUtils, - VermineCombat + VermineCombat, + GroupLink }; + + // Register GroupLink hooks for automatic synchronization + GroupLink.registerHooks(); // Define custom Document classes CONFIG.Actor.documentClass = VermineActor; diff --git a/system.json b/system.json index b32fb3f..f306c93 100644 --- a/system.json +++ b/system.json @@ -5,8 +5,8 @@ "version": "0.1.13", "compatibility": { "minimum": "11", - "verified": "11.308", - "maximum": "12" + "verified": "14.0", + "maximum": "14" }, "authors": [ { diff --git a/template.json b/template.json index 1a7cc6e..1955728 100644 --- a/template.json +++ b/template.json @@ -86,6 +86,7 @@ "max": 5 } }, + "encounters": [], "abilities": { "vigor": { "value": 1, diff --git a/templates/actor/actor-creature-sheet.hbs b/templates/actor/actor-creature-sheet.hbs index cff7fc2..f4fc25e 100644 --- a/templates/actor/actor-creature-sheet.hbs +++ b/templates/actor/actor-creature-sheet.hbs @@ -10,30 +10,75 @@
- +
- +
- - ({{ patternLevel "label" system.pattern.value }}) +
- +
- +
- +
- - ({{ roleLevel "label" system.role.value }}) +
@@ -53,6 +98,101 @@ {{!-- Biography Tab --}}
+
+
+

{{ localize 'ADVERSITY.pattern'}}

+
    +
  • {{ localize 'ADVERSITY.attack'}} {{ creaturePatternLevel "attack" system.pattern.value }}
  • +
  • {{ localize 'ADVERSITY.damage'}} {{ creaturePatternLevel "damage" system.pattern.value }}
  • +
  • {{ localize 'ADVERSITY.wounds'}} + {{ creaturePatternLevel "minorWound" system.pattern.value }}/ + {{ creaturePatternLevel "majorWound" system.pattern.value }}/ + {{ creaturePatternLevel "deadlyWound" system.pattern.value }} +
  • +
+
+
+

{{ localize 'ADVERSITY.size'}}

+
    +
  • {{ localize 'ADVERSITY.attack'}} {{ creatureSizeLevel "attack" system.size.value }}
  • +
  • {{ localize 'ADVERSITY.vigor'}} {{ creatureSizeLevel "vigor" system.size.value }}
  • +
  • {{ localize 'ADVERSITY.wounds'}} + {{ creatureSizeLevel "minorWound" system.size.value }}/ + {{ creatureSizeLevel "majorWound" system.size.value }}/ + {{ creatureSizeLevel "deadlyWound" system.size.value }} +
  • +
+
+
+

{{ localize 'ADVERSITY.role'}}

+
    +
  • {{ localize 'ADVERSITY.reaction'}} {{ creatureRoleLevel "reaction" system.role.value }} + {{ creatureRoleLevel "reaction_bonus" system.role.value }}
  • +
  • {{ localize 'ADVERSITY.pools'}} {{ creatureRoleLevel "pools" system.role.value }}
  • +
  • {{ localize 'ADVERSITY.gear'}} {{ creatureRoleLevel "gear" system.role.value }}
  • +
  • {{ localize 'ADVERSITY.protection'}} {{ creatureRoleLevel "protection" system.role.value }}
  • +
+
+
+
+
+

{{ localize 'ADVERSITY.pack'}}

+
    +
  • {{ localize 'ADVERSITY.attack'}} {{ creaturePackLevel "attack" system.pack.value }}
  • +
  • {{ localize 'ADVERSITY.damage'}} {{ creaturePackLevel "damage" system.pack.value }}
  • +
  • {{ localize 'ADVERSITY.wounds'}} + {{ creaturePackLevel "minorWound" system.pack.value }}/ + {{ creaturePackLevel "majorWound" system.pack.value }}/ + {{ creaturePackLevel "deadlyWound" system.pack.value }} +
  • +
+
+
+

{{ localize 'ADVERSITY.skills'}}

+
    +
  • + +
  • +
+
+
+

{{ localize 'VERMINE.modes'}}

+
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+

{{ localize 'IDENTITY.notes'}}

{{editor system.biography target="system.biography" button=true owner=owner editable=editable}} @@ -66,4 +206,3 @@
- diff --git a/templates/actor/actor-npc-sheet.hbs b/templates/actor/actor-npc-sheet.hbs index 22cc695..a5e71ab 100644 --- a/templates/actor/actor-npc-sheet.hbs +++ b/templates/actor/actor-npc-sheet.hbs @@ -9,24 +9,54 @@
- - ({{ threatLevel "label" system.threat.value }}) +
- - ({{ experienceLevel "label" system.experience.value }}) +
- +
- - ({{ roleLevel "label" system.role.value }}) +
@@ -51,9 +81,13 @@

{{ localize 'ADVERSITY.threat'}}

    -
  • {{ localize 'ADVERSITY.attack'}} {{ threatLevel "attack" system.threat.value }}
  • -
  • {{ localize 'ADVERSITY.vigor'}} {{ threatLevel "vigor" system.threat.value }}
  • -
  • {{ localize 'ADVERSITY.wounds'}} {{ threatLevel "minorWound" system.threat.value }}/{{ threatLevel "majorWound" system.threat.value }}/{{ threatLevel "deadlyWound" system.threat.value }}
  • +
  • {{ localize 'ADVERSITY.attack'}} {{ npcThreatLevel "attack" system.threat.value }}
  • +
  • {{ localize 'ADVERSITY.vigor'}} {{ npcThreatLevel "vigor" system.threat.value }}
  • +
  • {{ localize 'ADVERSITY.wounds'}} + {{ npcThreatLevel "minorWound" system.threat.value }}/ + {{ npcThreatLevel "majorWound" system.threat.value }}/ + {{ npcThreatLevel "deadlyWound" system.threat.value }} +
@@ -64,19 +98,19 @@ -
  • {{ localize 'ADVERSITY.action'}} {{ experienceLevel "action" system.experience.value }}
  • -
  • {{ localize 'ADVERSITY.specialties'}} {{ experienceLevel "specialties" system.experience.value }}
  • -
  • {{ localize 'ADVERSITY.rerolls'}} {{ experienceLevel "rerolls" system.experience.value }}
  • -
  • {{ localize 'ADVERSITY.contact'}} {{ experienceLevel "contact" system.experience.value }}
  • +
  • {{ localize 'ADVERSITY.action'}} {{ npcExperienceLevel "action" system.experience.value }}
  • +
  • {{ localize 'ADVERSITY.specialties'}} {{ npcExperienceLevel "specialties" system.experience.value }}
  • +
  • {{ localize 'ADVERSITY.rerolls'}} {{ npcExperienceLevel "rerolls" system.experience.value }}
  • +
  • {{ localize 'ADVERSITY.contact'}} {{ npcExperienceLevel "contact" system.experience.value }}
  • {{ localize 'ADVERSITY.role'}}

      -
    • {{ localize 'ADVERSITY.reaction'}} {{ roleLevel "reaction" system.role.value }} + {{ roleLevel "reaction_bonus" system.role.value }}
    • -
    • {{ localize 'ADVERSITY.pools'}} {{ roleLevel "pools" system.role.value }}
    • -
    • {{ localize 'ADVERSITY.gear'}} {{ roleLevel "gear" system.role.value }}
    • -
    • {{ localize 'ADVERSITY.protection'}} {{ roleLevel "protection" system.role.value }}
    • +
    • {{ localize 'ADVERSITY.reaction'}} {{ npcRoleLevel "reaction" system.role.value }} + {{ npcRoleLevel "reaction_bonus" system.role.value }}
    • +
    • {{ localize 'ADVERSITY.pools'}} {{ npcRoleLevel "pools" system.role.value }}
    • +
    • {{ localize 'ADVERSITY.gear'}} {{ npcRoleLevel "gear" system.role.value }}
    • +
    • {{ localize 'ADVERSITY.protection'}} {{ npcRoleLevel "protection" system.role.value }}
    @@ -98,4 +132,3 @@ - diff --git a/templates/dialogs/roll-dialog.hbs b/templates/dialogs/roll-dialog.hbs index 3d36ed9..b2b11f8 100644 --- a/templates/dialogs/roll-dialog.hbs +++ b/templates/dialogs/roll-dialog.hbs @@ -4,52 +4,22 @@ data-actor-id="{{ speakerId }}" > - - - - - - - - - - + + + + + + +
    - - -

    -
    - + + +
    + + +
    + +
    + {{localize 'VERMINE.score'}}: + 0 +
    -
    - + +
    + - {{#if availableSpecialties.length}} - -
    - - aucunes +
    +
    + + + {{#if availableSpecialties.length}} +
    + + {{localize 'VERMINE.specialty'}} (+1D) + {{localize 'VERMINE.none'}} + +
    + + {{#each availableSpecialties as |spec ind|}} + + {{/each}} +
    +
    + {{/if}} - - {{spec.name}} - - - {{/each}} - -
    - {{/if}} -
    -

    - - - -

    - - - - -

    - - - - - - -
    + +
    -

    Bonuses ?

    + {{localize 'VERMINE.difficulty'}} + + {{localize 'DIFFICULTY_LEVELS.hard'}} (7) + {{localize 'VERMINE.none'}} +
    -
    +
    +
    + + +
    +
    + + +
    +
    +
    - -
    - + +
    + + {{localize 'VERMINE.bonuses'}} + +0D + +
    + + +
    + {{#if help}}checked{{/if}} + /> +
    - -
    - + +
    + + /> + D
    - -
    -
    + +
    + + 0D + {{#ifgt @root.actor.system.adaptation.totems.human.value 0}} + {{#ifgt @root.actor.system.adaptation.totems.adapted.value 0}} + + ({{localize 'VERMINE.keep_totem'}} + ) + + {{/ifgt}} + {{/ifgt}} +
    +
    - - \ No newline at end of file + diff --git a/templates/item/chatCards/ability.hbs b/templates/item/chatCards/ability.hbs new file mode 100644 index 0000000..c74df26 --- /dev/null +++ b/templates/item/chatCards/ability.hbs @@ -0,0 +1,58 @@ +
    + {{> "systems/vermine2047/templates/item/chatCards/parts/base.hbs"}} + + {{!-- Ability specific content --}} +
    + {{#if item.system.type}} +
    + {{ localize 'VERMINE.type' }}: + {{item.system.type}} +
    + {{/if}} + + {{#if item.system.totem}} +
    + {{ localize 'IDENTITY.totem' }}: + {{ localize (lookup ../config.totems item.system.totem) }} +
    + {{/if}} + + {{#if item.system.level.value}} +
    + {{ localize 'VERMINE.level' }}: + {{item.system.level.value}} +
    + {{/if}} + + {{#if item.system.learn.threshold}} +
    + {{ localize 'VERMINE.learn' }}: + + {{item.system.learn.threshold}} + {{#ifgt item.system.learn.hindrance 0}} + / {{item.system.learn.hindrance}} + {{/ifgt}} + +
    + {{/if}} + + {{#if item.system.effects}} +
    + {{ localize 'UI.effects' }}: +
      + {{#each item.system.effects as |effect|}} +
    • {{effect}}
    • + {{/each}} +
    +
    + {{/if}} + + {{#if item.system.description}} +
    + {{ localize 'IDENTITY.notes' }}: +

    {{{item.system.description}}}

    +
    + {{/if}} +
    + +
    diff --git a/templates/item/chatCards/ability.html b/templates/item/chatCards/ability.html deleted file mode 100644 index 5e9bed2..0000000 --- a/templates/item/chatCards/ability.html +++ /dev/null @@ -1,43 +0,0 @@ -
    -
    - -
    -

    - -
    -
    - -
    -

    - - - - - - - - - -

    -

    - - - - / - - - -

    -

    description

    - {{editor system.description target="system.description" rollData=rollData button=true owner=owner editable=editable}} -
    -
    diff --git a/templates/item/chatCards/background.hbs b/templates/item/chatCards/background.hbs new file mode 100644 index 0000000..b08729f --- /dev/null +++ b/templates/item/chatCards/background.hbs @@ -0,0 +1,20 @@ +
    + {{> "systems/vermine2047/templates/item/chatCards/parts/base.hbs"}} + + {{!-- Background specific content --}} +
    + {{#if item.system.cost}} +
    + {{ localize 'VERMINE.cost' }}: + {{item.system.cost}} +
    + {{/if}} + + {{#if item.system.description}} +
    +

    {{{item.system.description}}}

    +
    + {{/if}} +
    + +
    diff --git a/templates/item/chatCards/background.html b/templates/item/chatCards/background.html deleted file mode 100644 index 71a98da..0000000 --- a/templates/item/chatCards/background.html +++ /dev/null @@ -1,43 +0,0 @@ -
    -
    - -
    -

    -
    -
    - {{!-- Sheet Body --}} -
    -

    - - - - -

    -

    description

    - {{editor system.description target="system.description" rollData=rollData button=true owner=owner editable=editable}} - -
    - - - - \ No newline at end of file diff --git a/templates/item/chatCards/defense.hbs b/templates/item/chatCards/defense.hbs new file mode 100644 index 0000000..844bea0 --- /dev/null +++ b/templates/item/chatCards/defense.hbs @@ -0,0 +1,102 @@ +
    + {{> "systems/vermine2047/templates/item/chatCards/parts/base.hbs"}} + + {{!-- Defense specific content --}} +
    + {{#if item.system.level}} +
    + {{ localize 'VERMINE.level' }}: + {{item.system.level}} +
    + {{/if}} + + {{#if item.system.specificLevel.level}} +
    + {{ localize 'VERMINE.specificLevel' }}: + + {{item.system.specificLevel.label}} + {{#if item.system.specificLevel.level}} + ({{item.system.specificLevel.level}}) + {{/if}} + +
    + {{/if}} + + {{#if item.system.mobility}} +
    + {{ localize 'VERMINE.mobility' }}: + {{item.system.mobility}} +
    + {{/if}} + + {{#if item.system.isShield}} +
    + {{ localize 'ITEMS.shield' }} +
    + {{/if}} + + {{#if item.system.quantity}} +
    + {{ localize 'VERMINE.qty' }}: + {{item.system.quantity}} +
    + {{/if}} + + {{#if item.system.weight}} +
    + {{ localize 'VERMINE.weight' }}: + {{item.system.weight}} +
    + {{/if}} + + {{#if item.system.rarity.value}} +
    + {{ localize 'VERMINE.rarity' }}: + + {{#repeat item.system.rarity.value 1 "i"}} + {{romanNumber i}} + {{/repeat}} + {{#ifgt item.system.rarity.handicap 0}} + ({{romanNumber item.system.rarity.handicap}}) + {{/ifgt}} + +
    + {{/if}} + + {{#if item.system.traits}} +
    + {{ localize 'VERMINE.traits' }}: +
      + {{#each item.system.traits as |trait key|}} + {{#if trait}} +
    • + {{localize (lookup ../config.traits key).name}}: + {{localize (lookup ../config.traits key).description}} +
    • + {{/if}} + {{/each}} +
    +
    + {{/if}} + + {{#if item.system.damages.value}} +
    + {{ localize 'VERMINE.damages' }}: + + {{getDamagesData item.system.damages "state"}} + {{#ifgt item.system.damages.value 1}} + ({{item.system.damages.value}}) + {{/ifgt}} + +
    + {{/if}} + + {{#if item.system.reliability}} +
    + {{ localize 'VERMINE.reliability' }}: + {{item.system.reliability}} +
    + {{/if}} +
    + +
    diff --git a/templates/item/chatCards/defense.html b/templates/item/chatCards/defense.html deleted file mode 100644 index 69264ef..0000000 --- a/templates/item/chatCards/defense.html +++ /dev/null @@ -1,13 +0,0 @@ -
    - {{log @root}} - -
    - image de {{item.name}} -

    {{item.name}}

    - -
    -
    -

    {{{ item.system.description}}}

    -
    - -
    diff --git a/templates/item/chatCards/evolution.hbs b/templates/item/chatCards/evolution.hbs new file mode 100644 index 0000000..e2768ee --- /dev/null +++ b/templates/item/chatCards/evolution.hbs @@ -0,0 +1,20 @@ +
    + {{> "systems/vermine2047/templates/item/chatCards/parts/base.hbs"}} + + {{!-- Evolution specific content --}} +
    + {{#if item.system.level.value}} +
    + {{ localize 'VERMINE.level' }}: + {{item.system.level.value}} +
    + {{/if}} + + {{#if item.system.description}} +
    +

    {{{item.system.description}}}

    +
    + {{/if}} +
    + +
    diff --git a/templates/item/chatCards/evolution.html b/templates/item/chatCards/evolution.html deleted file mode 100644 index 3f6338e..0000000 --- a/templates/item/chatCards/evolution.html +++ /dev/null @@ -1,21 +0,0 @@ -
    -
    - -
    -

    -
    -
    - - -
    - -

    - - -

    -

    description

    - - {{editor system.description target="system.description" rollData=rollData button=true owner=owner editable=editable}} -
    - -
    diff --git a/templates/item/chatCards/item.hbs b/templates/item/chatCards/item.hbs new file mode 100644 index 0000000..44d884c --- /dev/null +++ b/templates/item/chatCards/item.hbs @@ -0,0 +1,78 @@ +
    + {{> "systems/vermine2047/templates/item/chatCards/parts/base.hbs"}} + + {{!-- Item specific content --}} + {{#if item.system.needSkill.value}} +
    + +

    {{ smarttlk 'SKILLS' item.system.needSkill.skill 'name' }}

    +
    + {{/if}} + + {{!-- Traits --}} + {{#if item.system.traits}} +
    + +
      + {{#each item.system.traits as |trait key|}} + {{#if trait}} +
    • + {{localize (lookup ../config.traits key).name}}: + {{localize (lookup ../config.traits key).description}} +
    • + {{/if}} + {{/each}} +
    +
    + {{/if}} + + {{!-- Physical item properties --}} + {{#if item.system.quantity}} +
    + {{ localize 'VERMINE.quantity' }}: + {{item.system.quantity}} +
    + {{/if}} + + {{#if item.system.weight}} +
    + {{ localize 'VERMINE.weight' }}: + {{item.system.weight}} +
    + {{/if}} + + {{#if item.system.rarity.value}} +
    + {{ localize 'VERMINE.rarity' }}: + + {{#repeat item.system.rarity.value 1 "i"}} + {{romanNumber i}} + {{/repeat}} + {{#ifgt item.system.rarity.handicap 0}} + ({{romanNumber item.system.rarity.handicap}}) + {{/ifgt}} + +
    + {{/if}} + + {{#if item.system.damages.value}} +
    + {{ localize 'VERMINE.damages' }}: + + {{getDamagesData item.system.damages "state"}} + {{#ifgt item.system.damages.value 1}} + ({{item.system.damages.value}}) + {{/ifgt}} + +
    + {{/if}} + + {{!-- Reliability --}} + {{#if item.system.reliability}} +
    + {{ localize 'VERMINE.reliability' }}: + {{item.system.reliability}} +
    + {{/if}} + +
    diff --git a/templates/item/chatCards/item.html b/templates/item/chatCards/item.html deleted file mode 100644 index 69c83b4..0000000 --- a/templates/item/chatCards/item.html +++ /dev/null @@ -1,38 +0,0 @@ -
    - {{log this}} - {{> "systems/vermine2047/templates/item/partials/header.hbs"}} - - - {{!-- Sheet Body --}} -
    - - {{> "systems/vermine2047/templates/item/partials/traits.html"}} -
    - - {{#if system.needSkill.value}} - - - {{/if}} - -
    - - - {{> "systems/vermine2047/templates/item/partials/physicalItems.hbs"}} - -
    -
    diff --git a/templates/item/chatCards/parts/base.html b/templates/item/chatCards/parts/base.hbs similarity index 90% rename from templates/item/chatCards/parts/base.html rename to templates/item/chatCards/parts/base.hbs index 008c258..9ea9015 100644 --- a/templates/item/chatCards/parts/base.html +++ b/templates/item/chatCards/parts/base.hbs @@ -1,11 +1,11 @@ -
    - image de {{item.name}} -

    {{item.name}}

    - -
    -
    -

    {{{ item.system.description }}}

    +
    + image de {{item.name}} +

    {{item.name}}

    + +
    +
    +

    {{{ item.system.description }}}

    \ No newline at end of file diff --git a/templates/item/chatCards/rite.hbs b/templates/item/chatCards/rite.hbs new file mode 100644 index 0000000..018b22d --- /dev/null +++ b/templates/item/chatCards/rite.hbs @@ -0,0 +1,41 @@ +
    + {{> "systems/vermine2047/templates/item/chatCards/parts/base.hbs"}} + + {{!-- Rite specific content --}} +
    + {{#if item.system.rituel}} +
    + {{ localize 'VERMINE.ritual' }}: + {{item.system.rituel}} +
    + {{/if}} + + {{#if item.system.transe}} +
    + {{ localize 'VERMINE.trance' }}: + {{item.system.transe}} +
    + {{/if}} + + {{#if item.system.ability}} +
    + {{ localize 'VERMINE.ability' }}: + {{item.system.ability}} +
    + {{/if}} + + {{#if item.system.effect}} +
    + {{ localize 'UI.effects' }}: + {{item.system.effect}} +
    + {{/if}} + + {{#if item.system.description}} +
    +

    {{{item.system.description}}}

    +
    + {{/if}} +
    + +
    diff --git a/templates/item/chatCards/rite.html b/templates/item/chatCards/rite.html deleted file mode 100644 index bc08c20..0000000 --- a/templates/item/chatCards/rite.html +++ /dev/null @@ -1,41 +0,0 @@ -{{!-- This template is a fallback for when items don't have more specific templates. --}} -{{!-- Generally, you'll want to make more specific templates when possible. --}} -
    - {{> "systems/vermine2047/templates/item/partials/header.hbs"}} - - - {{!-- Sheet Body --}} -
    - -
    -
    - {{editor system.description target="system.description" button=true owner=owner editable=editable}} -
    -
    -
    -
    -

    {{ localize 'ITEMS.rituel'}}

    - -
    -
    -

    {{ localize 'ITEMS.transe'}}

    - -
    -
    -

    {{ localize 'ITEMS.effects'}}

    -
    - {{editor system.effects target="system.effects" button=true owner=owner editable=editable}} -
    -
    - diff --git a/templates/item/chatCards/rumor.hbs b/templates/item/chatCards/rumor.hbs new file mode 100644 index 0000000..da59a44 --- /dev/null +++ b/templates/item/chatCards/rumor.hbs @@ -0,0 +1,13 @@ +
    + {{> "systems/vermine2047/templates/item/chatCards/parts/base.hbs"}} + + {{!-- Rumor specific content --}} +
    + {{#if item.system.description}} +
    +

    {{{item.system.description}}}

    +
    + {{/if}} +
    + +
    diff --git a/templates/item/chatCards/rumor.html b/templates/item/chatCards/rumor.html deleted file mode 100644 index 49397f7..0000000 --- a/templates/item/chatCards/rumor.html +++ /dev/null @@ -1,11 +0,0 @@ -
    - {{> "systems/vermine2047/templates/item/partials/header.hbs"}} - - - {{!-- Sheet Body --}} -
    - - {{editor system.description target="system.description" rollData=rollData button=true owner=owner editable=editable}} - -
    -
    diff --git a/templates/item/chatCards/specialty.hbs b/templates/item/chatCards/specialty.hbs new file mode 100644 index 0000000..7516f83 --- /dev/null +++ b/templates/item/chatCards/specialty.hbs @@ -0,0 +1,20 @@ +
    + {{> "systems/vermine2047/templates/item/chatCards/parts/base.hbs"}} + + {{!-- Specialty specific content --}} +
    + {{#if item.system.skill}} +
    + {{ localize 'VERMINE.skill_title' }}: + {{ smarttlk 'SKILLS' item.system.skill 'name' }} +
    + {{/if}} + + {{#if item.system.description}} +
    +

    {{{item.system.description}}}

    +
    + {{/if}} +
    + +
    diff --git a/templates/item/chatCards/specialty.html b/templates/item/chatCards/specialty.html deleted file mode 100644 index fa2688e..0000000 --- a/templates/item/chatCards/specialty.html +++ /dev/null @@ -1,27 +0,0 @@ -
    -
    - -
    -

    - - -
    -
    - -
    diff --git a/templates/item/chatCards/target.hbs b/templates/item/chatCards/target.hbs new file mode 100644 index 0000000..a25989b --- /dev/null +++ b/templates/item/chatCards/target.hbs @@ -0,0 +1,20 @@ +
    + {{> "systems/vermine2047/templates/item/chatCards/parts/base.hbs"}} + + {{!-- Target specific content --}} +
    + {{#if item.system.level}} +
    + {{ localize 'VERMINE.level' }}: + {{item.system.level}} +
    + {{/if}} + + {{#if item.system.description}} +
    +

    {{{item.system.description}}}

    +
    + {{/if}} +
    + +
    diff --git a/templates/item/chatCards/target.html b/templates/item/chatCards/target.html deleted file mode 100644 index 49397f7..0000000 --- a/templates/item/chatCards/target.html +++ /dev/null @@ -1,11 +0,0 @@ -
    - {{> "systems/vermine2047/templates/item/partials/header.hbs"}} - - - {{!-- Sheet Body --}} -
    - - {{editor system.description target="system.description" rollData=rollData button=true owner=owner editable=editable}} - -
    -
    diff --git a/templates/item/chatCards/trauma.hbs b/templates/item/chatCards/trauma.hbs new file mode 100644 index 0000000..e8bc047 --- /dev/null +++ b/templates/item/chatCards/trauma.hbs @@ -0,0 +1,20 @@ +
    + {{> "systems/vermine2047/templates/item/chatCards/parts/base.hbs"}} + + {{!-- Trauma specific content --}} +
    + {{#if item.system.type}} +
    + {{ localize 'VERMINE.type' }}: + {{item.system.type}} +
    + {{/if}} + + {{#if item.system.description}} +
    +

    {{{item.system.description}}}

    +
    + {{/if}} +
    + +
    diff --git a/templates/item/chatCards/trauma.html b/templates/item/chatCards/trauma.html deleted file mode 100644 index d7e22ba..0000000 --- a/templates/item/chatCards/trauma.html +++ /dev/null @@ -1,24 +0,0 @@ -
    - {{> "systems/vermine2047/templates/item/partials/header.hbs"}} - - - {{!-- Sheet Body --}} -
    - -
    - -

    - - -

    -

    description

    - {{editor system.description target="system.description" rollData=rollData -button=true owner=owner editable=editable}} - -
    -
    - -
    diff --git a/templates/item/chatCards/vehicle.hbs b/templates/item/chatCards/vehicle.hbs new file mode 100644 index 0000000..670a4ec --- /dev/null +++ b/templates/item/chatCards/vehicle.hbs @@ -0,0 +1,83 @@ +
    + {{> "systems/vermine2047/templates/item/chatCards/parts/base.hbs"}} + + {{!-- Vehicle specific content --}} +
    + {{#if item.system.mobility}} +
    + {{ localize 'VERMINE.mobility' }}: + {{item.system.mobility}} +
    + {{/if}} + + {{#if item.system.quantity}} +
    + {{ localize 'VERMINE.qty' }}: + {{item.system.quantity}} +
    + {{/if}} + + {{#if item.system.weight}} +
    + {{ localize 'VERMINE.weight' }}: + {{item.system.weight}} +
    + {{/if}} + + {{#if item.system.rarity.value}} +
    + {{ localize 'VERMINE.rarity' }}: + + {{#repeat item.system.rarity.value 1 "i"}} + {{romanNumber i}} + {{/repeat}} + {{#ifgt item.system.rarity.handicap 0}} + ({{romanNumber item.system.rarity.handicap}}) + {{/ifgt}} + +
    + {{/if}} + + {{#if item.system.damages.value}} +
    + {{ localize 'VERMINE.damages' }}: + + {{getDamagesData item.system.damages "state"}} + {{#ifgt item.system.damages.value 1}} + ({{item.system.damages.value}}) + {{/ifgt}} + +
    + {{/if}} + + {{#if item.system.reliability}} +
    + {{ localize 'VERMINE.reliability' }}: + {{item.system.reliability}} +
    + {{/if}} + + {{#if item.system.traits}} +
    + {{ localize 'VERMINE.traits' }}: +
      + {{#each item.system.traits as |trait key|}} + {{#if trait}} +
    • + {{localize (lookup ../config.traits key).name}}: + {{localize (lookup ../config.traits key).description}} +
    • + {{/if}} + {{/each}} +
    +
    + {{/if}} + + {{#if item.system.description}} +
    +

    {{{item.system.description}}}

    +
    + {{/if}} +
    + +
    diff --git a/templates/item/chatCards/vehicle.html b/templates/item/chatCards/vehicle.html deleted file mode 100644 index 9b387ef..0000000 --- a/templates/item/chatCards/vehicle.html +++ /dev/null @@ -1,23 +0,0 @@ -
    - {{> "systems/vermine2047/templates/item/partials/header.hbs"}} - - -
    - {{> "systems/vermine2047/templates/item/partials/traits.html"}} - - -
    -
    - -
    - -
    -
    - - -
    - {{> "systems/vermine2047/templates/item/partials/physicalItems.hbs"}} - - -
    -
    diff --git a/templates/item/chatCards/weapon.hbs b/templates/item/chatCards/weapon.hbs new file mode 100644 index 0000000..2b90d3f --- /dev/null +++ b/templates/item/chatCards/weapon.hbs @@ -0,0 +1,104 @@ +
    + {{> "systems/vermine2047/templates/item/chatCards/parts/base.hbs"}} + + {{!-- Weapon specific content --}} +
    + {{#if item.system.damage.value}} +
    + {{ localize 'VERMINE.damage' }}: + + {{item.system.damage.value}} + {{#if item.system.damage.type}} + ({{item.system.damage.type}}) + {{/if}} + {{#if item.system.damage.addVigor}} + + {{ localize 'ABILITIES.vigor.name' }} + {{/if}} + +
    + {{/if}} + + {{#if item.system.ammo}} +
    + {{ localize 'VERMINE.ammo' }}: + {{item.system.ammo}} +
    + {{/if}} + + {{#if item.system.min_range}} +
    + {{ localize 'VERMINE.range' }}: + + {{item.system.min_range}} + {{#if item.system.max_range}} + - {{item.system.max_range}} + {{/if}} + +
    + {{/if}} + + {{#if item.system.quantity}} +
    + {{ localize 'VERMINE.qty' }}: + {{item.system.quantity}} +
    + {{/if}} + + {{#if item.system.weight}} +
    + {{ localize 'VERMINE.weight' }}: + {{item.system.weight}} +
    + {{/if}} + + {{#if item.system.rarity.value}} +
    + {{ localize 'VERMINE.rarity' }}: + + {{#repeat item.system.rarity.value 1 "i"}} + {{romanNumber i}} + {{/repeat}} + {{#ifgt item.system.rarity.handicap 0}} + ({{romanNumber item.system.rarity.handicap}}) + {{/ifgt}} + +
    + {{/if}} + + {{#if item.system.traits}} +
    + {{ localize 'VERMINE.traits' }}: +
      + {{#each item.system.traits as |trait key|}} + {{#if trait}} +
    • + {{localize (lookup ../config.traits key).name}}: + {{localize (lookup ../config.traits key).description}} +
    • + {{/if}} + {{/each}} +
    +
    + {{/if}} + + {{#if item.system.damages.value}} +
    + {{ localize 'VERMINE.damages' }}: + + {{getDamagesData item.system.damages "state"}} + {{#ifgt item.system.damages.value 1}} + ({{item.system.damages.value}}) + {{/ifgt}} + +
    + {{/if}} + + {{#if item.system.reliability}} +
    + {{ localize 'VERMINE.reliability' }}: + {{item.system.reliability}} +
    + {{/if}} +
    + +
    diff --git a/templates/item/chatCards/weapon.html b/templates/item/chatCards/weapon.html deleted file mode 100644 index 16bf5c6..0000000 --- a/templates/item/chatCards/weapon.html +++ /dev/null @@ -1,7 +0,0 @@ -
    - {{> "systems/vermine2047/templates/item/chatCards/parts/base.html"}} - -
    \ No newline at end of file diff --git a/templates/item/partials/damages.html b/templates/item/partials/damages.hbs similarity index 96% rename from templates/item/partials/damages.html rename to templates/item/partials/damages.hbs index dae3cc0..28b3bb6 100644 --- a/templates/item/partials/damages.html +++ b/templates/item/partials/damages.hbs @@ -1,30 +1,30 @@ -

    dommages

    -
    -
    - {{#repeat system.damages.max 1 index}} -
    - -
    - {{/repeat}} -
    -
    -

    pannes : {{getDamagesData system.damages "pannes"}}

    -
    -
    -

    état : {{getDamagesData system.damages "state"}}

    -
    -
    -

    effets : {{getDamagesData system.damages "effect"}}

    -
    - +

    dommages

    +
    +
    + {{#repeat system.damages.max 1 index}} +
    + +
    + {{/repeat}} +
    +
    +

    pannes : {{getDamagesData system.damages "pannes"}}

    +
    +
    +

    état : {{getDamagesData system.damages "state"}}

    +
    +
    +

    effets : {{getDamagesData system.damages "effect"}}

    +
    +
    \ No newline at end of file diff --git a/templates/item/partials/traits.html b/templates/item/partials/traits.hbs similarity index 96% rename from templates/item/partials/traits.html rename to templates/item/partials/traits.hbs index 94ce5b9..3968dcc 100644 --- a/templates/item/partials/traits.html +++ b/templates/item/partials/traits.hbs @@ -1,17 +1,17 @@ -
    -

    traits - - - - -

    -

    - {{#each item.system.traits as | trait index|}} - {{trait.name}} - {{#if trait.value}} - - {{/if}} - - {{/each}} -

    -
    +
    +

    traits + + + + +

    +

    + {{#each item.system.traits as | trait index|}} + {{trait.name}} + {{#if trait.value}} + + {{/if}} + + {{/each}} +

    +